diff --git a/services/clsi/.dockerignore b/services/clsi/.dockerignore new file mode 100644 index 0000000000..bcbd758418 --- /dev/null +++ b/services/clsi/.dockerignore @@ -0,0 +1,11 @@ +node_modules/* +gitrev +.git +.gitignore +.npm +.nvmrc +nodemon.json +cache/ +compiles/ +db/ +output/ diff --git a/services/clsi/.eslintrc b/services/clsi/.eslintrc new file mode 100644 index 0000000000..a97661b15f --- /dev/null +++ b/services/clsi/.eslintrc @@ -0,0 +1,86 @@ +// this file was auto-generated, do not edit it directly. +// instead run bin/update_build_scripts from +// https://github.com/sharelatex/sharelatex-dev-environment +{ + "extends": [ + "eslint:recommended", + "standard", + "prettier" + ], + "parserOptions": { + "ecmaVersion": 2018 + }, + "plugins": [ + "mocha", + "chai-expect", + "chai-friendly" + ], + "env": { + "node": true, + "mocha": true + }, + "rules": { + // TODO(das7pad): remove overrides after fixing all the violations manually (https://github.com/overleaf/issues/issues/3882#issuecomment-878999671) + // START of temporary overrides + "array-callback-return": "off", + "no-dupe-else-if": "off", + "no-var": "off", + "no-empty": "off", + "node/handle-callback-err": "off", + "no-loss-of-precision": "off", + "node/no-callback-literal": "off", + "node/no-path-concat": "off", + "prefer-regex-literals": "off", + // END of temporary overrides + + // Swap the no-unused-expressions rule with a more chai-friendly one + "no-unused-expressions": 0, + "chai-friendly/no-unused-expressions": "error", + + // Do not allow importing of implicit dependencies. + "import/no-extraneous-dependencies": "error" + }, + "overrides": [ + { + // Test specific rules + "files": ["test/**/*.js"], + "globals": { + "expect": true + }, + "rules": { + // mocha-specific rules + "mocha/handle-done-callback": "error", + "mocha/no-exclusive-tests": "error", + "mocha/no-global-tests": "error", + "mocha/no-identical-title": "error", + "mocha/no-nested-tests": "error", + "mocha/no-pending-tests": "error", + "mocha/no-skipped-tests": "error", + "mocha/no-mocha-arrows": "error", + + // chai-specific rules + "chai-expect/missing-assertion": "error", + "chai-expect/terminating-properties": "error", + + // prefer-arrow-callback applies to all callbacks, not just ones in mocha tests. + // we don't enforce this at the top-level - just in tests to manage `this` scope + // based on mocha's context mechanism + "mocha/prefer-arrow-callback": "error" + } + }, + { + // Backend specific rules + "files": ["app/**/*.js", "app.js", "index.js"], + "rules": { + // don't allow console.log in backend code + "no-console": "error", + + // Do not allow importing of implicit dependencies. + "import/no-extraneous-dependencies": ["error", { + // Do not allow importing of devDependencies. + "devDependencies": false + }] + } + } + ] +} diff --git a/services/clsi/.github/ISSUE_TEMPLATE.md b/services/clsi/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000000..e0093aa90c --- /dev/null +++ b/services/clsi/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,38 @@ + + +## Steps to Reproduce + + + +1. +2. +3. + +## Expected Behaviour + + +## Observed Behaviour + + + +## Context + + +## Technical Info + + +* URL: +* Browser Name and version: +* Operating System and version (desktop or mobile): +* Signed in as: +* Project and/or file: + +## Analysis + + +## Who Needs to Know? + + + +- +- diff --git a/services/clsi/.github/PULL_REQUEST_TEMPLATE.md b/services/clsi/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000000..12bb2eeb3f --- /dev/null +++ b/services/clsi/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,48 @@ + + + + + +### Description + + + +#### Screenshots + + + +#### Related Issues / PRs + + + +### Review + + + +#### Potential Impact + + + +#### Manual Testing Performed + +- [ ] +- [ ] + +#### Accessibility + + + +### Deployment + + + +#### Deployment Checklist + +- [ ] Update documentation not included in the PR (if any) +- [ ] + +#### Metrics and Monitoring + + + +#### Who Needs to Know? diff --git a/services/clsi/.github/dependabot.yml b/services/clsi/.github/dependabot.yml new file mode 100644 index 0000000000..c856753655 --- /dev/null +++ b/services/clsi/.github/dependabot.yml @@ -0,0 +1,23 @@ +version: 2 +updates: + - package-ecosystem: "npm" + directory: "/" + schedule: + interval: "daily" + + pull-request-branch-name: + # Separate sections of the branch name with a hyphen + # Docker images use the branch name and do not support slashes in tags + # https://github.com/overleaf/google-ops/issues/822 + # https://docs.github.com/en/github/administering-a-repository/configuration-options-for-dependency-updates#pull-request-branch-nameseparator + separator: "-" + + # Block informal upgrades -- security upgrades use a separate queue. + # https://docs.github.com/en/github/administering-a-repository/configuration-options-for-dependency-updates#open-pull-requests-limit + open-pull-requests-limit: 0 + + # currently assign team-magma to all dependabot PRs - this may change in + # future if we reorganise teams + labels: + - "dependencies" + - "type:maintenance" diff --git a/services/clsi/.gitignore b/services/clsi/.gitignore new file mode 100644 index 0000000000..dee3eca1f5 --- /dev/null +++ b/services/clsi/.gitignore @@ -0,0 +1,17 @@ +**.swp +node_modules +test/acceptance/fixtures/tmp +compiles +output +.DS_Store +*~ +cache +.vagrant +db.sqlite +db.sqlite-wal +db.sqlite-shm +config/* +npm-debug.log + +# managed by dev-environment$ bin/update_build_scripts +.npmrc diff --git a/services/clsi/.mocharc.json b/services/clsi/.mocharc.json new file mode 100644 index 0000000000..dc3280aa96 --- /dev/null +++ b/services/clsi/.mocharc.json @@ -0,0 +1,3 @@ +{ + "require": "test/setup.js" +} diff --git a/services/clsi/.nvmrc b/services/clsi/.nvmrc new file mode 100644 index 0000000000..5a80a7e912 --- /dev/null +++ b/services/clsi/.nvmrc @@ -0,0 +1 @@ +12.22.3 diff --git a/services/clsi/.prettierrc b/services/clsi/.prettierrc new file mode 100644 index 0000000000..c92c3526e7 --- /dev/null +++ b/services/clsi/.prettierrc @@ -0,0 +1,11 @@ +# This file was auto-generated, do not edit it directly. +# Instead run bin/update_build_scripts from +# https://github.com/sharelatex/sharelatex-dev-environment +{ + "arrowParens": "avoid", + "semi": false, + "singleQuote": true, + "trailingComma": "es5", + "tabWidth": 2, + "useTabs": false +} diff --git a/services/clsi/.viminfo b/services/clsi/.viminfo new file mode 100644 index 0000000000..78c0129851 --- /dev/null +++ b/services/clsi/.viminfo @@ -0,0 +1,35 @@ +# This viminfo file was generated by Vim 7.4. +# You may edit it if you're careful! + +# Value of 'encoding' when this file was written +*encoding=latin1 + + +# hlsearch on (H) or off (h): +~h +# Command Line History (newest to oldest): +:x + +# Search String History (newest to oldest): + +# Expression History (newest to oldest): + +# Input Line History (newest to oldest): + +# Input Line History (newest to oldest): + +# Registers: + +# File marks: +'0 1 0 ~/hello + +# Jumplist (newest first): +-' 1 0 ~/hello + +# History of marks within files (newest to oldest): + +> ~/hello + " 1 0 + ^ 1 1 + . 1 0 + + 1 0 diff --git a/services/clsi/Dockerfile b/services/clsi/Dockerfile new file mode 100644 index 0000000000..8bd4b9c62f --- /dev/null +++ b/services/clsi/Dockerfile @@ -0,0 +1,28 @@ +# This file was auto-generated, do not edit it directly. +# Instead run bin/update_build_scripts from +# https://github.com/sharelatex/sharelatex-dev-environment + +FROM node:12.22.3 as base + +WORKDIR /app +COPY install_deps.sh /app +RUN chmod 0755 ./install_deps.sh && ./install_deps.sh +ENTRYPOINT ["/bin/sh", "entrypoint.sh"] +COPY entrypoint.sh /app + +FROM base as app + +#wildcard as some files may not be in all repos +COPY package*.json npm-shrink*.json /app/ + +RUN npm ci --quiet + +COPY . /app + +FROM base + +COPY --from=app /app /app +RUN mkdir -p cache compiles db output \ +&& chown node:node cache compiles db output + +CMD ["node", "--expose-gc", "app.js"] diff --git a/services/clsi/LICENSE b/services/clsi/LICENSE new file mode 100644 index 0000000000..dba13ed2dd --- /dev/null +++ b/services/clsi/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero 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 Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/services/clsi/Makefile b/services/clsi/Makefile new file mode 100644 index 0000000000..45a4bc0400 --- /dev/null +++ b/services/clsi/Makefile @@ -0,0 +1,90 @@ +# This file was auto-generated, do not edit it directly. +# Instead run bin/update_build_scripts from +# https://github.com/sharelatex/sharelatex-dev-environment + +BUILD_NUMBER ?= local +BRANCH_NAME ?= $(shell git rev-parse --abbrev-ref HEAD) +PROJECT_NAME = clsi +BUILD_DIR_NAME = $(shell pwd | xargs basename | tr -cd '[a-zA-Z0-9_.\-]') + +DOCKER_COMPOSE_FLAGS ?= -f docker-compose.yml +DOCKER_COMPOSE := BUILD_NUMBER=$(BUILD_NUMBER) \ + BRANCH_NAME=$(BRANCH_NAME) \ + PROJECT_NAME=$(PROJECT_NAME) \ + MOCHA_GREP=${MOCHA_GREP} \ + docker-compose ${DOCKER_COMPOSE_FLAGS} + +DOCKER_COMPOSE_TEST_ACCEPTANCE = \ + COMPOSE_PROJECT_NAME=test_acceptance_$(BUILD_DIR_NAME) $(DOCKER_COMPOSE) + +DOCKER_COMPOSE_TEST_UNIT = \ + COMPOSE_PROJECT_NAME=test_unit_$(BUILD_DIR_NAME) $(DOCKER_COMPOSE) + +clean: + -docker rmi ci/$(PROJECT_NAME):$(BRANCH_NAME)-$(BUILD_NUMBER) + -docker rmi gcr.io/overleaf-ops/$(PROJECT_NAME):$(BRANCH_NAME)-$(BUILD_NUMBER) + -$(DOCKER_COMPOSE_TEST_UNIT) down --rmi local + -$(DOCKER_COMPOSE_TEST_ACCEPTANCE) down --rmi local + +format: + $(DOCKER_COMPOSE) run --rm test_unit npm run --silent format + +format_fix: + $(DOCKER_COMPOSE) run --rm test_unit npm run --silent format:fix + +lint: + $(DOCKER_COMPOSE) run --rm test_unit npm run --silent lint + +test: format lint test_unit test_acceptance + +test_unit: +ifneq (,$(wildcard test/unit)) + $(DOCKER_COMPOSE_TEST_UNIT) run --rm test_unit + $(MAKE) test_unit_clean +endif + +test_clean: test_unit_clean +test_unit_clean: +ifneq (,$(wildcard test/unit)) + $(DOCKER_COMPOSE_TEST_UNIT) down -v -t 0 +endif + +test_acceptance: test_acceptance_clean test_acceptance_pre_run test_acceptance_run + $(MAKE) test_acceptance_clean + +test_acceptance_debug: test_acceptance_clean test_acceptance_pre_run test_acceptance_run_debug + $(MAKE) test_acceptance_clean + +test_acceptance_run: +ifneq (,$(wildcard test/acceptance)) + $(DOCKER_COMPOSE_TEST_ACCEPTANCE) run --rm test_acceptance +endif + +test_acceptance_run_debug: +ifneq (,$(wildcard test/acceptance)) + $(DOCKER_COMPOSE_TEST_ACCEPTANCE) run -p 127.0.0.9:19999:19999 --rm test_acceptance npm run test:acceptance -- --inspect=0.0.0.0:19999 --inspect-brk +endif + +test_clean: test_acceptance_clean +test_acceptance_clean: + $(DOCKER_COMPOSE_TEST_ACCEPTANCE) down -v -t 0 + +test_acceptance_pre_run: +ifneq (,$(wildcard test/acceptance/js/scripts/pre-run)) + $(DOCKER_COMPOSE_TEST_ACCEPTANCE) run --rm test_acceptance test/acceptance/js/scripts/pre-run +endif + +build: + docker build --pull --tag ci/$(PROJECT_NAME):$(BRANCH_NAME)-$(BUILD_NUMBER) \ + --tag gcr.io/overleaf-ops/$(PROJECT_NAME):$(BRANCH_NAME)-$(BUILD_NUMBER) \ + . + +tar: + $(DOCKER_COMPOSE) up tar + +publish: + + docker push $(DOCKER_REPO)/$(PROJECT_NAME):$(BRANCH_NAME)-$(BUILD_NUMBER) + + +.PHONY: clean test test_unit test_acceptance test_clean build publish diff --git a/services/clsi/README.md b/services/clsi/README.md new file mode 100644 index 0000000000..302cb34932 --- /dev/null +++ b/services/clsi/README.md @@ -0,0 +1,184 @@ +overleaf/clsi +=============== + +A web api for compiling LaTeX documents in the cloud + +The Common LaTeX Service Interface (CLSI) provides a RESTful interface to traditional LaTeX tools (or, more generally, any command line tool for composing marked-up documents into a display format such as PDF or HTML). The CLSI listens on the following ports by default: + +* TCP/3013 - the RESTful interface +* TCP/3048 - reports load information +* TCP/3049 - HTTP interface to control the CLSI service + +These defaults can be modified in `config/settings.defaults.js`. + +The provided `Dockerfile` builds a Docker image which has the Docker command line tools installed. The configuration in `docker-compose-config.yml` mounts the Docker socket, in order that the CLSI container can talk to the Docker host it is running in. This allows it to spin up `sibling containers` running an image with a TeX distribution installed to perform the actual compiles. + +The CLSI can be configured through the following environment variables: + +* `ALLOWED_COMPILE_GROUPS` - Space separated list of allowed compile groups +* `ALLOWED_IMAGES` - Space separated list of allowed Docker TeX Live images +* `CATCH_ERRORS` - Set to `true` to log uncaught exceptions +* `COMPILE_GROUP_DOCKER_CONFIGS` - JSON string of Docker configs for compile groups +* `COMPILES_HOST_DIR` - Working directory for LaTeX compiles +* `COMPILE_SIZE_LIMIT` - Sets the body-parser [limit](https://github.com/expressjs/body-parser#limit) +* `DOCKER_RUNNER` - Set to true to use sibling containers +* `DOCKER_RUNTIME` - +* `FILESTORE_DOMAIN_OVERRIDE` - The url for the filestore service e.g.`http://$FILESTORE_HOST:3009` +* `FILESTORE_PARALLEL_FILE_DOWNLOADS` - Number of parallel file downloads +* `FILESTORE_PARALLEL_SQL_QUERY_LIMIT` - Number of parallel SQL queries +* `LISTEN_ADDRESS` - The address for the RESTful service to listen on. Set to `0.0.0.0` to listen on all network interfaces +* `PROCESS_LIFE_SPAN_LIMIT_MS` - Process life span limit in milliseconds +* `SENTRY_DSN` - Sentry [Data Source Name](https://docs.sentry.io/product/sentry-basics/dsn-explainer/) +* `SMOKE_TEST` - Whether to run smoke tests +* `SQLITE_PATH` - Path to SQLite database +* `SYNCTEX_BIN_HOST_PATH` - Path to SyncTeX binary +* `TEXLIVE_IMAGE` - The TeX Live Docker image to use for sibling containers, e.g. `gcr.io/overleaf-ops/texlive-full:2017.1` +* `TEX_LIVE_IMAGE_NAME_OVERRIDE` - The name of the registry for the Docker image e.g. `gcr.io/overleaf-ops` +* `TEXLIVE_IMAGE_USER` - When using sibling containers, the user to run as in the TeX Live image. Defaults to `tex` +* `TEXLIVE_OPENOUT_ANY` - Sets the `openout_any` environment variable for TeX Live (see the `\openout` primitive [documentation](http://tug.org/texinfohtml/web2c.html#tex-invocation)) + +Further environment variables configure the [metrics module](https://github.com/overleaf/metrics-module) + +Installation +------------ + +The CLSI can be installed and set up as part of the entire [Overleaf stack](https://github.com/overleaf/overleaf) (complete with front end editor and document storage), or it can be run as a standalone service. To run is as a standalone service, first checkout this repository: + + $ git clone git@github.com:overleaf/clsi.git + +Then build the Docker image: + + $ docker build . -t overleaf/clsi + +Then pull the TeX Live image: + + $ docker pull texlive/texlive + +Then start the Docker container: + + $ docker run --rm \ + -p 127.0.0.1:3013:3013 \ + -e LISTEN_ADDRESS=0.0.0.0 \ + -e DOCKER_RUNNER=true \ + -e TEXLIVE_IMAGE=texlive/texlive \ + -e TEXLIVE_IMAGE_USER=root \ + -e COMPILES_HOST_DIR="$PWD/compiles" \ + -v "$PWD/compiles:/app/compiles" \ + -v "$PWD/cache:/app/cache" \ + -v /var/run/docker.sock:/var/run/docker.sock \ + --name clsi \ + overleaf/clsi + +Note: if you're running the CLSI in macOS you may need to use `-v /var/run/docker.sock.raw:/var/run/docker.sock` instead. + +The CLSI should then be running at + +Important note for Linux users +============================== + +The Node application runs as user `node` in the CLSI, which has uid `1000`. As a consequence of this, the `compiles` folder gets created on your host with `uid` and `gid` set to `1000`. +``` +ls -lnd compiles +drwxr-xr-x 2 1000 1000 4096 Mar 19 12:41 compiles +``` + +If there is a user/group on your host which also happens to have `uid` / `gid` `1000` then that user/group will have ownership of the compiles folder on your host. + +LaTeX runs in the sibling containers as the user specified in the `TEXLIVE_IMAGE_USER` environment variable. In the example above this is set to `root`, which has uid `0`. This creates a problem with the above permissions, as the root user does not have permission to write to subfolders of `compiles`. + +A quick fix is to give the `root` group ownership and read write permissions to `compiles`, with `setgid` set so that new subfolders also inherit this ownership: +``` +sudo chown -R 1000:root compiles +sudo chmod -R g+w compiles +sudo chmod g+s compiles +``` +Another solution is to create a `sharelatex` group and add both `root` and the user with `uid` `1000` to it. If the host does not have a user with that `uid`, you will need to create one first. +``` +sudo useradd --uid 1000 host-node-user # If required +sudo groupadd sharelatex +sudo usermod -a -G sharelatex root +sudo usermod -a -G sharelatex $(id -nu 1000) +sudo chown -R 1000:sharelatex compiles +sudo chmod -R g+w compiles +sudo chmod g+s compiles +``` + +This is a facet of the way docker works on Linux. See this [upstream issue](https://github.com/moby/moby/issues/7198) + + +Config +------ + +The CLSI will use a SQLite database by default, but you can optionally set up a MySQL database and then fill in the database name, username and password in the config file at `config/settings.development.js`. + +API +--- + +The CLSI is based on a JSON API. + +#### Example Request + +(Note that valid JSON should not contain any comments like the example below). + + POST /project//compile + +```json5 +{ + "compile": { + "options": { + // Which compiler to use. Can be latex, pdflatex, xelatex or lualatex + "compiler": "lualatex", + // How many seconds to wait before killing the process. Default is 60. + "timeout": 40 + }, + // The main file to run LaTeX on + "rootResourcePath": "main.tex", + // An array of files to include in the compilation. May have either the content + // passed directly, or a URL where it can be downloaded. + "resources": [ + { + "path": "main.tex", + "content": "\\documentclass{article}\n\\begin{document}\nHello World\n\\end{document}" + } + // ,{ + // "path": "image.png", + // "url": "www.example.com/image.png", + // "modified": 123456789 // Unix time since epoch + // } + ] + } +} +``` + +With `curl`, if you place the above JSON in a file called `data.json`, the request would look like this: + +``` shell +$ curl -X POST -H 'Content-Type: application/json' -d @data.json http://localhost:3013/project//compile +``` + +You can specify any project-id in the URL, and the files and LaTeX environment will be persisted between requests. +URLs will be downloaded and cached until provided with a more recent modified date. + +#### Example Response + +```json +{ + "compile": { + "status": "success", + "outputFiles": [{ + "type": "pdf", + "url": "http://localhost:3013/project//output/output.pdf" + }, { + "type": "log", + "url": "http://localhost:3013/project//output/output.log" + }] + } +} +``` + +License +------- + +The code in this repository is released under the GNU AFFERO GENERAL PUBLIC LICENSE, version 3. A copy can be found in the `LICENSE` file. + +Copyright (c) Overleaf, 2014-2021. diff --git a/services/clsi/app.js b/services/clsi/app.js new file mode 100644 index 0000000000..8916c0a04a --- /dev/null +++ b/services/clsi/app.js @@ -0,0 +1,425 @@ +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * DS103: Rewrite code to no longer use __guard__ + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const tenMinutes = 10 * 60 * 1000 +const Metrics = require('@overleaf/metrics') +Metrics.initialize('clsi') + +const CompileController = require('./app/js/CompileController') +const ContentController = require('./app/js/ContentController') +const Settings = require('@overleaf/settings') +const logger = require('logger-sharelatex') +logger.initialize('clsi') +if ((Settings.sentry != null ? Settings.sentry.dsn : undefined) != null) { + logger.initializeErrorReporting(Settings.sentry.dsn) +} + +const smokeTest = require('./test/smoke/js/SmokeTests') +const ContentTypeMapper = require('./app/js/ContentTypeMapper') +const Errors = require('./app/js/Errors') + +const Path = require('path') + +Metrics.open_sockets.monitor(logger) +Metrics.memory.monitor(logger) + +const ProjectPersistenceManager = require('./app/js/ProjectPersistenceManager') +const OutputCacheManager = require('./app/js/OutputCacheManager') +const ContentCacheManager = require('./app/js/ContentCacheManager') + +require('./app/js/db').sync() + +const express = require('express') +const bodyParser = require('body-parser') +const app = express() + +Metrics.injectMetricsRoute(app) +app.use(Metrics.http.monitor(logger)) + +// Compile requests can take longer than the default two +// minutes (including file download time), so bump up the +// timeout a bit. +const TIMEOUT = 10 * 60 * 1000 +app.use(function (req, res, next) { + req.setTimeout(TIMEOUT) + res.setTimeout(TIMEOUT) + res.removeHeader('X-Powered-By') + return next() +}) + +app.param('project_id', function (req, res, next, projectId) { + if (projectId != null ? projectId.match(/^[a-zA-Z0-9_-]+$/) : undefined) { + return next() + } else { + return next(new Error('invalid project id')) + } +}) + +app.param('user_id', function (req, res, next, userId) { + if (userId != null ? userId.match(/^[0-9a-f]{24}$/) : undefined) { + return next() + } else { + return next(new Error('invalid user id')) + } +}) + +app.param('build_id', function (req, res, next, buildId) { + if ( + buildId != null ? buildId.match(OutputCacheManager.BUILD_REGEX) : undefined + ) { + return next() + } else { + return next(new Error(`invalid build id ${buildId}`)) + } +}) + +app.param('contentId', function (req, res, next, contentId) { + if ( + contentId != null + ? contentId.match(OutputCacheManager.CONTENT_REGEX) + : undefined + ) { + return next() + } else { + return next(new Error(`invalid content id ${contentId}`)) + } +}) + +app.param('hash', function (req, res, next, hash) { + if (hash != null ? hash.match(ContentCacheManager.HASH_REGEX) : undefined) { + return next() + } else { + return next(new Error(`invalid hash ${hash}`)) + } +}) + +app.post( + '/project/:project_id/compile', + bodyParser.json({ limit: Settings.compileSizeLimit }), + CompileController.compile +) +app.post('/project/:project_id/compile/stop', CompileController.stopCompile) +app.delete('/project/:project_id', CompileController.clearCache) + +app.get('/project/:project_id/sync/code', CompileController.syncFromCode) +app.get('/project/:project_id/sync/pdf', CompileController.syncFromPdf) +app.get('/project/:project_id/wordcount', CompileController.wordcount) +app.get('/project/:project_id/status', CompileController.status) +app.post('/project/:project_id/status', CompileController.status) + +// Per-user containers +app.post( + '/project/:project_id/user/:user_id/compile', + bodyParser.json({ limit: Settings.compileSizeLimit }), + CompileController.compile +) +app.post( + '/project/:project_id/user/:user_id/compile/stop', + CompileController.stopCompile +) +app.delete('/project/:project_id/user/:user_id', CompileController.clearCache) + +app.get( + '/project/:project_id/user/:user_id/sync/code', + CompileController.syncFromCode +) +app.get( + '/project/:project_id/user/:user_id/sync/pdf', + CompileController.syncFromPdf +) +app.get( + '/project/:project_id/user/:user_id/wordcount', + CompileController.wordcount +) + +const ForbidSymlinks = require('./app/js/StaticServerForbidSymlinks') + +// create a static server which does not allow access to any symlinks +// avoids possible mismatch of root directory between middleware check +// and serving the files +const staticCompileServer = ForbidSymlinks( + express.static, + Settings.path.compilesDir, + { + setHeaders(res, path, stat) { + if (Path.basename(path) === 'output.pdf') { + // Calculate an etag in the same way as nginx + // https://github.com/tj/send/issues/65 + const etag = (path, stat) => + `"${Math.ceil(+stat.mtime / 1000).toString(16)}` + + '-' + + Number(stat.size).toString(16) + + '"' + res.set('Etag', etag(path, stat)) + } + return res.set('Content-Type', ContentTypeMapper.map(path)) + }, + } +) + +const staticOutputServer = ForbidSymlinks( + express.static, + Settings.path.outputDir, + { + setHeaders(res, path, stat) { + if (Path.basename(path) === 'output.pdf') { + // Calculate an etag in the same way as nginx + // https://github.com/tj/send/issues/65 + const etag = (path, stat) => + `"${Math.ceil(+stat.mtime / 1000).toString(16)}` + + '-' + + Number(stat.size).toString(16) + + '"' + res.set('Etag', etag(path, stat)) + } + return res.set('Content-Type', ContentTypeMapper.map(path)) + }, + } +) + +app.get( + '/project/:project_id/user/:user_id/build/:build_id/output/*', + function (req, res, next) { + // for specific build get the path from the OutputCacheManager (e.g. .clsi/buildId) + req.url = + `/${req.params.project_id}-${req.params.user_id}/` + + OutputCacheManager.path(req.params.build_id, `/${req.params[0]}`) + return staticOutputServer(req, res, next) + } +) + +app.get( + '/project/:projectId/content/:contentId/:hash', + ContentController.getPdfRange +) +app.get( + '/project/:projectId/user/:userId/content/:contentId/:hash', + ContentController.getPdfRange +) + +app.get( + '/project/:project_id/build/:build_id/output/*', + function (req, res, next) { + // for specific build get the path from the OutputCacheManager (e.g. .clsi/buildId) + req.url = + `/${req.params.project_id}/` + + OutputCacheManager.path(req.params.build_id, `/${req.params[0]}`) + return staticOutputServer(req, res, next) + } +) + +app.get( + '/project/:project_id/user/:user_id/output/*', + function (req, res, next) { + // for specific user get the path to the top level file + logger.warn( + { url: req.url }, + 'direct request for file in compile directory' + ) + req.url = `/${req.params.project_id}-${req.params.user_id}/${req.params[0]}` + return staticCompileServer(req, res, next) + } +) + +app.get('/project/:project_id/output/*', function (req, res, next) { + logger.warn({ url: req.url }, 'direct request for file in compile directory') + if ( + (req.query != null ? req.query.build : undefined) != null && + req.query.build.match(OutputCacheManager.BUILD_REGEX) + ) { + // for specific build get the path from the OutputCacheManager (e.g. .clsi/buildId) + req.url = + `/${req.params.project_id}/` + + OutputCacheManager.path(req.query.build, `/${req.params[0]}`) + } else { + req.url = `/${req.params.project_id}/${req.params[0]}` + } + return staticCompileServer(req, res, next) +}) + +app.get('/oops', function (req, res, next) { + logger.error({ err: 'hello' }, 'test error') + return res.send('error\n') +}) + +app.get('/oops-internal', function (req, res, next) { + setTimeout(function () { + throw new Error('Test error') + }, 1) +}) + +app.get('/status', (req, res, next) => res.send('CLSI is alive\n')) + +Settings.processTooOld = false +if (Settings.processLifespanLimitMs) { + Settings.processLifespanLimitMs += + Settings.processLifespanLimitMs * (Math.random() / 10) + logger.info( + 'Lifespan limited to ', + Date.now() + Settings.processLifespanLimitMs + ) + + setTimeout(() => { + logger.log('shutting down, process is too old') + Settings.processTooOld = true + }, Settings.processLifespanLimitMs) +} + +function runSmokeTest() { + if (Settings.processTooOld) return + logger.log('running smoke tests') + smokeTest.triggerRun(err => { + if (err) logger.error({ err }, 'smoke tests failed') + setTimeout(runSmokeTest, 30 * 1000) + }) +} +if (Settings.smokeTest) { + runSmokeTest() +} + +app.get('/health_check', function (req, res) { + if (Settings.processTooOld) { + return res.status(500).json({ processTooOld: true }) + } + smokeTest.sendLastResult(res) +}) + +app.get('/smoke_test_force', (req, res) => smokeTest.sendNewResult(res)) + +app.use(function (error, req, res, next) { + if (error instanceof Errors.NotFoundError) { + logger.log({ err: error, url: req.url }, 'not found error') + return res.sendStatus(404) + } else if (error.code === 'EPIPE') { + // inspect container returns EPIPE when shutting down + return res.sendStatus(503) // send 503 Unavailable response + } else { + logger.error({ err: error, url: req.url }, 'server error') + return res.sendStatus((error != null ? error.statusCode : undefined) || 500) + } +}) + +const net = require('net') +const os = require('os') + +let STATE = 'up' + +const loadTcpServer = net.createServer(function (socket) { + socket.on('error', function (err) { + if (err.code === 'ECONNRESET') { + // this always comes up, we don't know why + return + } + logger.err({ err }, 'error with socket on load check') + return socket.destroy() + }) + + if (STATE === 'up' && Settings.internal.load_balancer_agent.report_load) { + let availableWorkingCpus + const currentLoad = os.loadavg()[0] + + // staging clis's have 1 cpu core only + if (os.cpus().length === 1) { + availableWorkingCpus = 1 + } else { + availableWorkingCpus = os.cpus().length - 1 + } + + const freeLoad = availableWorkingCpus - currentLoad + let freeLoadPercentage = Math.round((freeLoad / availableWorkingCpus) * 100) + if (freeLoadPercentage <= 0) { + freeLoadPercentage = 1 // when its 0 the server is set to drain and will move projects to different servers + } + socket.write(`up, ${freeLoadPercentage}%\n`, 'ASCII') + return socket.end() + } else { + socket.write(`${STATE}\n`, 'ASCII') + return socket.end() + } +}) + +const loadHttpServer = express() + +loadHttpServer.post('/state/up', function (req, res, next) { + STATE = 'up' + logger.info('getting message to set server to down') + return res.sendStatus(204) +}) + +loadHttpServer.post('/state/down', function (req, res, next) { + STATE = 'down' + logger.info('getting message to set server to down') + return res.sendStatus(204) +}) + +loadHttpServer.post('/state/maint', function (req, res, next) { + STATE = 'maint' + logger.info('getting message to set server to maint') + return res.sendStatus(204) +}) + +const port = + __guard__( + Settings.internal != null ? Settings.internal.clsi : undefined, + x => x.port + ) || 3013 +const host = + __guard__( + Settings.internal != null ? Settings.internal.clsi : undefined, + x1 => x1.host + ) || 'localhost' + +const loadTcpPort = Settings.internal.load_balancer_agent.load_port +const loadHttpPort = Settings.internal.load_balancer_agent.local_port + +if (!module.parent) { + // Called directly + + // handle uncaught exceptions when running in production + if (Settings.catchErrors) { + process.removeAllListeners('uncaughtException') + process.on('uncaughtException', error => + logger.error({ err: error }, 'uncaughtException') + ) + } + + app.listen(port, host, error => { + if (error) { + logger.fatal({ error }, `Error starting CLSI on ${host}:${port}`) + } else { + logger.info(`CLSI starting up, listening on ${host}:${port}`) + } + }) + + loadTcpServer.listen(loadTcpPort, host, function (error) { + if (error != null) { + throw error + } + return logger.info(`Load tcp agent listening on load port ${loadTcpPort}`) + }) + + loadHttpServer.listen(loadHttpPort, host, function (error) { + if (error != null) { + throw error + } + return logger.info(`Load http agent listening on load port ${loadHttpPort}`) + }) +} + +module.exports = app + +setInterval(() => { + ProjectPersistenceManager.refreshExpiryTimeout(() => { + ProjectPersistenceManager.clearExpiredProjects() + }) +}, tenMinutes) + +function __guard__(value, transform) { + return typeof value !== 'undefined' && value !== null + ? transform(value) + : undefined +} diff --git a/services/clsi/app/js/CommandRunner.js b/services/clsi/app/js/CommandRunner.js new file mode 100644 index 0000000000..782707b3a8 --- /dev/null +++ b/services/clsi/app/js/CommandRunner.js @@ -0,0 +1,20 @@ +// TODO: This file was created by bulk-decaffeinate. +// Sanity-check the conversion and remove this comment. +/* + * decaffeinate suggestions: + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +let commandRunnerPath +const Settings = require('@overleaf/settings') +const logger = require('logger-sharelatex') + +if ((Settings.clsi != null ? Settings.clsi.dockerRunner : undefined) === true) { + commandRunnerPath = './DockerRunner' +} else { + commandRunnerPath = './LocalCommandRunner' +} +logger.info({ commandRunnerPath }, 'selecting command runner for clsi') +const CommandRunner = require(commandRunnerPath) + +module.exports = CommandRunner diff --git a/services/clsi/app/js/CompileController.js b/services/clsi/app/js/CompileController.js new file mode 100644 index 0000000000..488d818157 --- /dev/null +++ b/services/clsi/app/js/CompileController.js @@ -0,0 +1,269 @@ +/* eslint-disable + camelcase, + handle-callback-err, + no-unused-vars, +*/ +// TODO: This file was created by bulk-decaffeinate. +// Fix any style issues and re-enable lint. +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +let CompileController +const RequestParser = require('./RequestParser') +const CompileManager = require('./CompileManager') +const Settings = require('@overleaf/settings') +const Metrics = require('./Metrics') +const ProjectPersistenceManager = require('./ProjectPersistenceManager') +const logger = require('logger-sharelatex') +const Errors = require('./Errors') + +function isImageNameAllowed(imageName) { + const ALLOWED_IMAGES = + Settings.clsi && Settings.clsi.docker && Settings.clsi.docker.allowedImages + return !ALLOWED_IMAGES || ALLOWED_IMAGES.includes(imageName) +} + +module.exports = CompileController = { + compile(req, res, next) { + if (next == null) { + next = function (error) {} + } + const timer = new Metrics.Timer('compile-request') + return RequestParser.parse(req.body, function (error, request) { + if (error != null) { + return next(error) + } + request.project_id = req.params.project_id + if (req.params.user_id != null) { + request.user_id = req.params.user_id + } + return ProjectPersistenceManager.markProjectAsJustAccessed( + request.project_id, + function (error) { + if (error != null) { + return next(error) + } + return CompileManager.doCompileWithLock( + request, + function (error, outputFiles, stats, timings) { + let code, status + if (outputFiles == null) { + outputFiles = [] + } + if (error instanceof Errors.AlreadyCompilingError) { + code = 423 // Http 423 Locked + status = 'compile-in-progress' + } else if (error instanceof Errors.FilesOutOfSyncError) { + code = 409 // Http 409 Conflict + status = 'retry' + } else if (error && error.code === 'EPIPE') { + // docker returns EPIPE when shutting down + code = 503 // send 503 Unavailable response + status = 'unavailable' + } else if (error != null ? error.terminated : undefined) { + status = 'terminated' + } else if (error != null ? error.validate : undefined) { + status = `validation-${error.validate}` + } else if (error != null ? error.timedout : undefined) { + status = 'timedout' + logger.log( + { err: error, project_id: request.project_id }, + 'timeout running compile' + ) + } else if (error != null) { + status = 'error' + code = 500 + logger.warn( + { err: error, project_id: request.project_id }, + 'error running compile' + ) + } else { + let file + status = 'failure' + for (file of Array.from(outputFiles)) { + if (file.path === 'output.pdf' && file.size > 0) { + status = 'success' + } + } + + if (status === 'failure') { + logger.warn( + { project_id: request.project_id, outputFiles }, + 'project failed to compile successfully, no output.pdf generated' + ) + } + + // log an error if any core files are found + for (file of Array.from(outputFiles)) { + if (file.path === 'core') { + logger.error( + { project_id: request.project_id, req, outputFiles }, + 'core file found in output' + ) + } + } + } + + if (error != null) { + outputFiles = error.outputFiles || [] + } + + timer.done() + return res.status(code || 200).send({ + compile: { + status, + error: (error != null ? error.message : undefined) || error, + stats, + timings, + outputFiles: outputFiles.map(file => { + return { + url: + `${Settings.apis.clsi.url}/project/${request.project_id}` + + (request.user_id != null + ? `/user/${request.user_id}` + : '') + + (file.build != null ? `/build/${file.build}` : '') + + `/output/${file.path}`, + ...file, + } + }), + }, + }) + } + ) + } + ) + }) + }, + + stopCompile(req, res, next) { + const { project_id, user_id } = req.params + return CompileManager.stopCompile(project_id, user_id, function (error) { + if (error != null) { + return next(error) + } + return res.sendStatus(204) + }) + }, + + clearCache(req, res, next) { + if (next == null) { + next = function (error) {} + } + return ProjectPersistenceManager.clearProject( + req.params.project_id, + req.params.user_id, + function (error) { + if (error != null) { + return next(error) + } + return res.sendStatus(204) + } + ) + }, // No content + + syncFromCode(req, res, next) { + if (next == null) { + next = function (error) {} + } + const { file } = req.query + const line = parseInt(req.query.line, 10) + const column = parseInt(req.query.column, 10) + const { imageName } = req.query + const { project_id } = req.params + const { user_id } = req.params + + if (imageName && !isImageNameAllowed(imageName)) { + return res.status(400).send('invalid image') + } + + return CompileManager.syncFromCode( + project_id, + user_id, + file, + line, + column, + imageName, + function (error, pdfPositions) { + if (error != null) { + return next(error) + } + return res.json({ + pdf: pdfPositions, + }) + } + ) + }, + + syncFromPdf(req, res, next) { + if (next == null) { + next = function (error) {} + } + const page = parseInt(req.query.page, 10) + const h = parseFloat(req.query.h) + const v = parseFloat(req.query.v) + const { imageName } = req.query + const { project_id } = req.params + const { user_id } = req.params + + if (imageName && !isImageNameAllowed(imageName)) { + return res.status(400).send('invalid image') + } + return CompileManager.syncFromPdf( + project_id, + user_id, + page, + h, + v, + imageName, + function (error, codePositions) { + if (error != null) { + return next(error) + } + return res.json({ + code: codePositions, + }) + } + ) + }, + + wordcount(req, res, next) { + if (next == null) { + next = function (error) {} + } + const file = req.query.file || 'main.tex' + const { project_id } = req.params + const { user_id } = req.params + const { image } = req.query + if (image && !isImageNameAllowed(image)) { + return res.status(400).send('invalid image') + } + logger.log({ image, file, project_id }, 'word count request') + + return CompileManager.wordcount( + project_id, + user_id, + file, + image, + function (error, result) { + if (error != null) { + return next(error) + } + return res.json({ + texcount: result, + }) + } + ) + }, + + status(req, res, next) { + if (next == null) { + next = function (error) {} + } + return res.send('OK') + }, +} diff --git a/services/clsi/app/js/CompileManager.js b/services/clsi/app/js/CompileManager.js new file mode 100644 index 0000000000..07a9033b3d --- /dev/null +++ b/services/clsi/app/js/CompileManager.js @@ -0,0 +1,761 @@ +/* eslint-disable + camelcase, + handle-callback-err, + no-return-assign, + no-undef, + no-unused-vars, +*/ +// TODO: This file was created by bulk-decaffeinate. +// Fix any style issues and re-enable lint. +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * DS103: Rewrite code to no longer use __guard__ + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +let CompileManager +const ResourceWriter = require('./ResourceWriter') +const LatexRunner = require('./LatexRunner') +const OutputFileFinder = require('./OutputFileFinder') +const OutputCacheManager = require('./OutputCacheManager') +const Settings = require('@overleaf/settings') +const Path = require('path') +const logger = require('logger-sharelatex') +const Metrics = require('./Metrics') +const child_process = require('child_process') +const DraftModeManager = require('./DraftModeManager') +const TikzManager = require('./TikzManager') +const LockManager = require('./LockManager') +const fs = require('fs') +const fse = require('fs-extra') +const os = require('os') +const async = require('async') +const Errors = require('./Errors') +const CommandRunner = require('./CommandRunner') +const { emitPdfStats } = require('./ContentCacheMetrics') + +const getCompileName = function (project_id, user_id) { + if (user_id != null) { + return `${project_id}-${user_id}` + } else { + return project_id + } +} + +const getCompileDir = (project_id, user_id) => + Path.join(Settings.path.compilesDir, getCompileName(project_id, user_id)) + +const getOutputDir = (project_id, user_id) => + Path.join(Settings.path.outputDir, getCompileName(project_id, user_id)) + +module.exports = CompileManager = { + doCompileWithLock(request, callback) { + if (callback == null) { + callback = function (error, outputFiles) {} + } + const compileDir = getCompileDir(request.project_id, request.user_id) + const lockFile = Path.join(compileDir, '.project-lock') + // use a .project-lock file in the compile directory to prevent + // simultaneous compiles + return fse.ensureDir(compileDir, function (error) { + if (error != null) { + return callback(error) + } + return LockManager.runWithLock( + lockFile, + releaseLock => CompileManager.doCompile(request, releaseLock), + callback + ) + }) + }, + + doCompile(request, callback) { + if (callback == null) { + callback = function (error, outputFiles) {} + } + const compileDir = getCompileDir(request.project_id, request.user_id) + const outputDir = getOutputDir(request.project_id, request.user_id) + + const timerE2E = new Metrics.Timer('compile-e2e') + let timer = new Metrics.Timer('write-to-disk') + logger.log( + { project_id: request.project_id, user_id: request.user_id }, + 'syncing resources to disk' + ) + return ResourceWriter.syncResourcesToDisk( + request, + compileDir, + function (error, resourceList) { + // NOTE: resourceList is insecure, it should only be used to exclude files from the output list + if (error != null && error instanceof Errors.FilesOutOfSyncError) { + logger.warn( + { project_id: request.project_id, user_id: request.user_id }, + 'files out of sync, please retry' + ) + return callback(error) + } else if (error != null) { + logger.err( + { + err: error, + project_id: request.project_id, + user_id: request.user_id, + }, + 'error writing resources to disk' + ) + return callback(error) + } + logger.log( + { + project_id: request.project_id, + user_id: request.user_id, + time_taken: Date.now() - timer.start, + }, + 'written files to disk' + ) + const syncStage = timer.done() + + const injectDraftModeIfRequired = function (callback) { + if (request.draft) { + return DraftModeManager.injectDraftMode( + Path.join(compileDir, request.rootResourcePath), + callback + ) + } else { + return callback() + } + } + + const createTikzFileIfRequired = callback => + TikzManager.checkMainFile( + compileDir, + request.rootResourcePath, + resourceList, + function (error, needsMainFile) { + if (error != null) { + return callback(error) + } + if (needsMainFile) { + return TikzManager.injectOutputFile( + compileDir, + request.rootResourcePath, + callback + ) + } else { + return callback() + } + } + ) + // set up environment variables for chktex + const env = {} + if (Settings.texliveOpenoutAny && Settings.texliveOpenoutAny !== '') { + // override default texlive openout_any environment variable + env.openout_any = Settings.texliveOpenoutAny + } + // only run chktex on LaTeX files (not knitr .Rtex files or any others) + const isLaTeXFile = + request.rootResourcePath != null + ? request.rootResourcePath.match(/\.tex$/i) + : undefined + if (request.check != null && isLaTeXFile) { + env.CHKTEX_OPTIONS = '-nall -e9 -e10 -w15 -w16' + env.CHKTEX_ULIMIT_OPTIONS = '-t 5 -v 64000' + if (request.check === 'error') { + env.CHKTEX_EXIT_ON_ERROR = 1 + } + if (request.check === 'validate') { + env.CHKTEX_VALIDATE = 1 + } + } + + // apply a series of file modifications/creations for draft mode and tikz + return async.series( + [injectDraftModeIfRequired, createTikzFileIfRequired], + function (error) { + if (error != null) { + return callback(error) + } + timer = new Metrics.Timer('run-compile') + // find the image tag to log it as a metric, e.g. 2015.1 (convert . to - for graphite) + let tag = + __guard__( + __guard__( + request.imageName != null + ? request.imageName.match(/:(.*)/) + : undefined, + x1 => x1[1] + ), + x => x.replace(/\./g, '-') + ) || 'default' + if (!request.project_id.match(/^[0-9a-f]{24}$/)) { + tag = 'other' + } // exclude smoke test + Metrics.inc('compiles') + Metrics.inc(`compiles-with-image.${tag}`) + const compileName = getCompileName( + request.project_id, + request.user_id + ) + return LatexRunner.runLatex( + compileName, + { + directory: compileDir, + mainFile: request.rootResourcePath, + compiler: request.compiler, + timeout: request.timeout, + image: request.imageName, + flags: request.flags, + environment: env, + compileGroup: request.compileGroup, + }, + function (error, output, stats, timings) { + // request was for validation only + let metric_key, metric_value + if (request.check === 'validate') { + const result = (error != null ? error.code : undefined) + ? 'fail' + : 'pass' + error = new Error('validation') + error.validate = result + } + // request was for compile, and failed on validation + if ( + request.check === 'error' && + (error != null ? error.message : undefined) === 'exited' + ) { + error = new Error('compilation') + error.validate = 'fail' + } + // compile was killed by user, was a validation, or a compile which failed validation + if ( + (error != null ? error.terminated : undefined) || + (error != null ? error.validate : undefined) || + (error != null ? error.timedout : undefined) + ) { + OutputFileFinder.findOutputFiles( + resourceList, + compileDir, + function (err, outputFiles) { + if (err != null) { + return callback(err) + } + error.outputFiles = outputFiles // return output files so user can check logs + return callback(error) + } + ) + return + } + // compile completed normally + if (error != null) { + return callback(error) + } + Metrics.inc('compiles-succeeded') + stats = stats || {} + const object = stats || {} + for (metric_key in object) { + metric_value = object[metric_key] + Metrics.count(metric_key, metric_value) + } + timings = timings || {} + const object1 = timings || {} + for (metric_key in object1) { + metric_value = object1[metric_key] + Metrics.timing(metric_key, metric_value) + } + const loadavg = + typeof os.loadavg === 'function' ? os.loadavg() : undefined + if (loadavg != null) { + Metrics.gauge('load-avg', loadavg[0]) + } + const ts = timer.done() + logger.log( + { + project_id: request.project_id, + user_id: request.user_id, + time_taken: ts, + stats, + timings, + loadavg, + }, + 'done compile' + ) + if ((stats != null ? stats['latex-runs'] : undefined) > 0) { + Metrics.timing( + 'run-compile-per-pass', + ts / stats['latex-runs'] + ) + } + if ( + (stats != null ? stats['latex-runs'] : undefined) > 0 && + (timings != null ? timings['cpu-time'] : undefined) > 0 + ) { + Metrics.timing( + 'run-compile-cpu-time-per-pass', + timings['cpu-time'] / stats['latex-runs'] + ) + } + // Emit compile time. + timings.compile = ts + + timer = new Metrics.Timer('process-output-files') + + return OutputFileFinder.findOutputFiles( + resourceList, + compileDir, + function (error, outputFiles) { + if (error != null) { + return callback(error) + } + return OutputCacheManager.saveOutputFiles( + { request, stats, timings }, + outputFiles, + compileDir, + outputDir, + (err, newOutputFiles) => { + if (err) { + const { project_id: projectId, user_id: userId } = + request + logger.err( + { projectId, userId, err }, + 'failed to save output files' + ) + } + + const outputStage = timer.done() + timings.sync = syncStage + timings.output = outputStage + + // Emit e2e compile time. + timings.compileE2E = timerE2E.done() + + if (stats['pdf-size']) { + emitPdfStats(stats, timings) + } + + callback(null, newOutputFiles, stats, timings) + } + ) + } + ) + } + ) + } + ) + } + ) + }, + + stopCompile(project_id, user_id, callback) { + if (callback == null) { + callback = function (error) {} + } + const compileName = getCompileName(project_id, user_id) + return LatexRunner.killLatex(compileName, callback) + }, + + clearProject(project_id, user_id, _callback) { + if (_callback == null) { + _callback = function (error) {} + } + const callback = function (error) { + _callback(error) + return (_callback = function () {}) + } + + const compileDir = getCompileDir(project_id, user_id) + const outputDir = getOutputDir(project_id, user_id) + + return CompileManager._checkDirectory(compileDir, function (err, exists) { + if (err != null) { + return callback(err) + } + if (!exists) { + return callback() + } // skip removal if no directory present + + const proc = child_process.spawn('rm', [ + '-r', + '-f', + '--', + compileDir, + outputDir, + ]) + + proc.on('error', callback) + + let stderr = '' + proc.stderr.setEncoding('utf8').on('data', chunk => (stderr += chunk)) + + return proc.on('close', function (code) { + if (code === 0) { + return callback(null) + } else { + return callback( + new Error(`rm -r ${compileDir} ${outputDir} failed: ${stderr}`) + ) + } + }) + }) + }, + + _findAllDirs(callback) { + if (callback == null) { + callback = function (error, allDirs) {} + } + const root = Settings.path.compilesDir + return fs.readdir(root, function (err, files) { + if (err != null) { + return callback(err) + } + const allDirs = Array.from(files).map(file => Path.join(root, file)) + return callback(null, allDirs) + }) + }, + + clearExpiredProjects(max_cache_age_ms, callback) { + if (callback == null) { + callback = function (error) {} + } + const now = Date.now() + // action for each directory + const expireIfNeeded = (checkDir, cb) => + fs.stat(checkDir, function (err, stats) { + if (err != null) { + return cb() + } // ignore errors checking directory + const age = now - stats.mtime + const hasExpired = age > max_cache_age_ms + if (hasExpired) { + return fse.remove(checkDir, cb) + } else { + return cb() + } + }) + // iterate over all project directories + return CompileManager._findAllDirs(function (error, allDirs) { + if (error != null) { + return callback() + } + return async.eachSeries(allDirs, expireIfNeeded, callback) + }) + }, + + _checkDirectory(compileDir, callback) { + if (callback == null) { + callback = function (error, exists) {} + } + return fs.lstat(compileDir, function (err, stats) { + if ((err != null ? err.code : undefined) === 'ENOENT') { + return callback(null, false) // directory does not exist + } else if (err != null) { + logger.err( + { dir: compileDir, err }, + 'error on stat of project directory for removal' + ) + return callback(err) + } else if (!(stats != null ? stats.isDirectory() : undefined)) { + logger.err( + { dir: compileDir, stats }, + 'bad project directory for removal' + ) + return callback(new Error('project directory is not directory')) + } else { + return callback(null, true) + } + }) + }, // directory exists + + syncFromCode( + project_id, + user_id, + file_name, + line, + column, + imageName, + callback + ) { + // If LaTeX was run in a virtual environment, the file path that synctex expects + // might not match the file path on the host. The .synctex.gz file however, will be accessed + // wherever it is on the host. + if (callback == null) { + callback = function (error, pdfPositions) {} + } + const compileName = getCompileName(project_id, user_id) + const base_dir = Settings.path.synctexBaseDir(compileName) + const file_path = base_dir + '/' + file_name + const compileDir = getCompileDir(project_id, user_id) + const synctex_path = `${base_dir}/output.pdf` + const command = ['code', synctex_path, file_path, line, column] + CompileManager._runSynctex( + project_id, + user_id, + command, + imageName, + function (error, stdout) { + if (error != null) { + return callback(error) + } + logger.log( + { project_id, user_id, file_name, line, column, command, stdout }, + 'synctex code output' + ) + return callback( + null, + CompileManager._parseSynctexFromCodeOutput(stdout) + ) + } + ) + }, + + syncFromPdf(project_id, user_id, page, h, v, imageName, callback) { + if (callback == null) { + callback = function (error, filePositions) {} + } + const compileName = getCompileName(project_id, user_id) + const compileDir = getCompileDir(project_id, user_id) + const base_dir = Settings.path.synctexBaseDir(compileName) + const synctex_path = `${base_dir}/output.pdf` + const command = ['pdf', synctex_path, page, h, v] + CompileManager._runSynctex( + project_id, + user_id, + command, + imageName, + function (error, stdout) { + if (error != null) { + return callback(error) + } + logger.log( + { project_id, user_id, page, h, v, stdout }, + 'synctex pdf output' + ) + return callback( + null, + CompileManager._parseSynctexFromPdfOutput(stdout, base_dir) + ) + } + ) + }, + + _checkFileExists(dir, filename, callback) { + if (callback == null) { + callback = function (error) {} + } + const file = Path.join(dir, filename) + return fs.stat(dir, function (error, stats) { + if ((error != null ? error.code : undefined) === 'ENOENT') { + return callback(new Errors.NotFoundError('no output directory')) + } + if (error != null) { + return callback(error) + } + return fs.stat(file, function (error, stats) { + if ((error != null ? error.code : undefined) === 'ENOENT') { + return callback(new Errors.NotFoundError('no output file')) + } + if (error != null) { + return callback(error) + } + if (!(stats != null ? stats.isFile() : undefined)) { + return callback(new Error('not a file')) + } + return callback() + }) + }) + }, + + _runSynctex(project_id, user_id, command, imageName, callback) { + if (callback == null) { + callback = function (error, stdout) {} + } + const seconds = 1000 + + command.unshift('/opt/synctex') + + const directory = getCompileDir(project_id, user_id) + const timeout = 60 * 1000 // increased to allow for large projects + const compileName = getCompileName(project_id, user_id) + const compileGroup = 'synctex' + CompileManager._checkFileExists(directory, 'output.synctex.gz', error => { + if (error) { + return callback(error) + } + return CommandRunner.run( + compileName, + command, + directory, + imageName || + (Settings.clsi && Settings.clsi.docker + ? Settings.clsi.docker.image + : undefined), + timeout, + {}, + compileGroup, + function (error, output) { + if (error != null) { + logger.err( + { err: error, command, project_id, user_id }, + 'error running synctex' + ) + return callback(error) + } + return callback(null, output.stdout) + } + ) + }) + }, + + _parseSynctexFromCodeOutput(output) { + const results = [] + for (const line of Array.from(output.split('\n'))) { + const [node, page, h, v, width, height] = Array.from(line.split('\t')) + if (node === 'NODE') { + results.push({ + page: parseInt(page, 10), + h: parseFloat(h), + v: parseFloat(v), + height: parseFloat(height), + width: parseFloat(width), + }) + } + } + return results + }, + + _parseSynctexFromPdfOutput(output, base_dir) { + const results = [] + for (let line of Array.from(output.split('\n'))) { + let column, file_path, node + ;[node, file_path, line, column] = Array.from(line.split('\t')) + if (node === 'NODE') { + const file = file_path.slice(base_dir.length + 1) + results.push({ + file, + line: parseInt(line, 10), + column: parseInt(column, 10), + }) + } + } + return results + }, + + wordcount(project_id, user_id, file_name, image, callback) { + if (callback == null) { + callback = function (error, pdfPositions) {} + } + logger.log({ project_id, user_id, file_name, image }, 'running wordcount') + const file_path = `$COMPILE_DIR/${file_name}` + const command = [ + 'texcount', + '-nocol', + '-inc', + file_path, + `-out=${file_path}.wc`, + ] + const compileDir = getCompileDir(project_id, user_id) + const timeout = 60 * 1000 + const compileName = getCompileName(project_id, user_id) + const compileGroup = 'wordcount' + return fse.ensureDir(compileDir, function (error) { + if (error != null) { + logger.err( + { error, project_id, user_id, file_name }, + 'error ensuring dir for sync from code' + ) + return callback(error) + } + return CommandRunner.run( + compileName, + command, + compileDir, + image, + timeout, + {}, + compileGroup, + function (error) { + if (error != null) { + return callback(error) + } + return fs.readFile( + compileDir + '/' + file_name + '.wc', + 'utf-8', + function (err, stdout) { + if (err != null) { + // call it node_err so sentry doesn't use random path error as unique id so it can't be ignored + logger.err( + { node_err: err, command, compileDir, project_id, user_id }, + 'error reading word count output' + ) + return callback(err) + } + const results = CompileManager._parseWordcountFromOutput(stdout) + logger.log( + { project_id, user_id, wordcount: results }, + 'word count results' + ) + return callback(null, results) + } + ) + } + ) + }) + }, + + _parseWordcountFromOutput(output) { + const results = { + encode: '', + textWords: 0, + headWords: 0, + outside: 0, + headers: 0, + elements: 0, + mathInline: 0, + mathDisplay: 0, + errors: 0, + messages: '', + } + for (const line of Array.from(output.split('\n'))) { + const [data, info] = Array.from(line.split(':')) + if (data.indexOf('Encoding') > -1) { + results.encode = info.trim() + } + if (data.indexOf('in text') > -1) { + results.textWords = parseInt(info, 10) + } + if (data.indexOf('in head') > -1) { + results.headWords = parseInt(info, 10) + } + if (data.indexOf('outside') > -1) { + results.outside = parseInt(info, 10) + } + if (data.indexOf('of head') > -1) { + results.headers = parseInt(info, 10) + } + if (data.indexOf('Number of floats/tables/figures') > -1) { + results.elements = parseInt(info, 10) + } + if (data.indexOf('Number of math inlines') > -1) { + results.mathInline = parseInt(info, 10) + } + if (data.indexOf('Number of math displayed') > -1) { + results.mathDisplay = parseInt(info, 10) + } + if (data === '(errors') { + // errors reported as (errors:123) + results.errors = parseInt(info, 10) + } + if (line.indexOf('!!! ') > -1) { + // errors logged as !!! message !!! + results.messages += line + '\n' + } + } + return results + }, +} + +function __guard__(value, transform) { + return typeof value !== 'undefined' && value !== null + ? transform(value) + : undefined +} diff --git a/services/clsi/app/js/ContentCacheManager.js b/services/clsi/app/js/ContentCacheManager.js new file mode 100644 index 0000000000..2036057064 --- /dev/null +++ b/services/clsi/app/js/ContentCacheManager.js @@ -0,0 +1,273 @@ +/** + * ContentCacheManager - maintains a cache of stream hashes from a PDF file + */ + +const { callbackify } = require('util') +const fs = require('fs') +const crypto = require('crypto') +const Path = require('path') +const Settings = require('@overleaf/settings') +const OError = require('@overleaf/o-error') +const pLimit = require('p-limit') +const { parseXrefTable } = require('../lib/pdfjs/parseXrefTable') +const { TimedOutError } = require('./Errors') + +/** + * + * @param {String} contentDir path to directory where content hash files are cached + * @param {String} filePath the pdf file to scan for streams + * @param {number} size the pdf size + * @param {number} compileTime + */ +async function update(contentDir, filePath, size, compileTime) { + const checkDeadline = getDeadlineChecker(compileTime) + const ranges = [] + const newRanges = [] + // keep track of hashes expire old ones when they reach a generation > N. + const tracker = await HashFileTracker.from(contentDir) + tracker.updateAge() + + checkDeadline('after init HashFileTracker') + + const rawTable = await parseXrefTable(filePath, size, checkDeadline) + rawTable.sort((a, b) => { + return a.offset - b.offset + }) + rawTable.forEach((obj, idx) => { + obj.idx = idx + }) + + checkDeadline('after parsing') + + const uncompressedObjects = [] + for (const object of rawTable) { + if (!object.uncompressed) { + continue + } + const nextObject = rawTable[object.idx + 1] + if (!nextObject) { + // Ignore this possible edge case. + // The last object should be part of the xRef table. + continue + } else { + object.endOffset = nextObject.offset + } + const size = object.endOffset - object.offset + object.size = size + if (size < Settings.pdfCachingMinChunkSize) { + continue + } + uncompressedObjects.push({ object, idx: uncompressedObjects.length }) + } + + checkDeadline('after finding uncompressed') + + const handle = await fs.promises.open(filePath) + try { + for (const { object, idx } of uncompressedObjects) { + let buffer = Buffer.alloc(object.size, 0) + const { bytesRead } = await handle.read( + buffer, + 0, + object.size, + object.offset + ) + checkDeadline('after read ' + idx) + if (bytesRead !== object.size) { + throw new OError('could not read full chunk', { + object, + bytesRead, + }) + } + const idxObj = buffer.indexOf('obj') + if (idxObj > 100) { + throw new OError('objectId is too large', { + object, + idxObj, + }) + } + const objectIdRaw = buffer.subarray(0, idxObj) + buffer = buffer.subarray(objectIdRaw.byteLength) + + const hash = pdfStreamHash(buffer) + checkDeadline('after hash ' + idx) + const range = { + objectId: objectIdRaw.toString(), + start: object.offset + objectIdRaw.byteLength, + end: object.endOffset, + hash, + } + ranges.push(range) + + // Optimization: Skip writing of duplicate streams. + if (tracker.track(range)) continue + + await writePdfStream(contentDir, hash, buffer) + checkDeadline('after write ' + idx) + newRanges.push(range) + } + } finally { + await handle.close() + } + + // NOTE: Bailing out below does not make sense. + // Let the next compile use the already written ranges. + const reclaimedSpace = await tracker.deleteStaleHashes(5) + await tracker.flush() + return [ranges, newRanges, reclaimedSpace] +} + +function getStatePath(contentDir) { + return Path.join(contentDir, '.state.v0.json') +} + +class HashFileTracker { + constructor(contentDir, { hashAge = [], hashSize = [] }) { + this.contentDir = contentDir + this.hashAge = new Map(hashAge) + this.hashSize = new Map(hashSize) + } + + static async from(contentDir) { + const statePath = getStatePath(contentDir) + let state = {} + try { + const blob = await fs.promises.readFile(statePath) + state = JSON.parse(blob) + } catch (e) {} + return new HashFileTracker(contentDir, state) + } + + track(range) { + const exists = this.hashAge.has(range.hash) + if (!exists) { + this.hashSize.set(range.hash, range.end - range.start) + } + this.hashAge.set(range.hash, 0) + return exists + } + + updateAge() { + for (const [hash, age] of this.hashAge) { + this.hashAge.set(hash, age + 1) + } + return this + } + + findStale(maxAge) { + const stale = [] + for (const [hash, age] of this.hashAge) { + if (age > maxAge) { + stale.push(hash) + } + } + return stale + } + + async flush() { + const statePath = getStatePath(this.contentDir) + const blob = JSON.stringify({ + hashAge: Array.from(this.hashAge.entries()), + hashSize: Array.from(this.hashSize.entries()), + }) + const atomicWrite = statePath + '~' + try { + await fs.promises.writeFile(atomicWrite, blob) + } catch (err) { + try { + await fs.promises.unlink(atomicWrite) + } catch (e) {} + throw err + } + try { + await fs.promises.rename(atomicWrite, statePath) + } catch (err) { + try { + await fs.promises.unlink(atomicWrite) + } catch (e) {} + throw err + } + } + + async deleteStaleHashes(n) { + // delete any hash file older than N generations + const hashes = this.findStale(n) + + let reclaimedSpace = 0 + if (hashes.length === 0) { + return reclaimedSpace + } + + await promiseMapWithLimit(10, hashes, async hash => { + await fs.promises.unlink(Path.join(this.contentDir, hash)) + this.hashAge.delete(hash) + reclaimedSpace += this.hashSize.get(hash) + this.hashSize.delete(hash) + }) + return reclaimedSpace + } +} + +function pdfStreamHash(buffer) { + const hash = crypto.createHash('sha256') + hash.update(buffer) + return hash.digest('hex') +} + +async function writePdfStream(dir, hash, buffer) { + const filename = Path.join(dir, hash) + const atomicWriteFilename = filename + '~' + if (Settings.enablePdfCachingDark) { + // Write an empty file in dark mode. + buffer = Buffer.alloc(0) + } + try { + await fs.promises.writeFile(atomicWriteFilename, buffer) + await fs.promises.rename(atomicWriteFilename, filename) + } catch (err) { + try { + await fs.promises.unlink(atomicWriteFilename) + } catch (_) { + throw err + } + } +} + +function getDeadlineChecker(compileTime) { + const maxOverhead = Math.min( + // Adding 10s to a 40s compile time is OK. + // Adding 1s to a 3s compile time is OK. + Math.max(compileTime / 4, 1000), + // Adding 30s to a 120s compile time is not OK, limit to 10s. + Settings.pdfCachingMaxProcessingTime + ) + + const deadline = Date.now() + maxOverhead + let lastStage = { stage: 'start', now: Date.now() } + let completedStages = 0 + return function (stage) { + const now = Date.now() + if (now > deadline) { + throw new TimedOutError(stage, { + completedStages, + lastStage: lastStage.stage, + diffToLastStage: now - lastStage.now, + }) + } + completedStages++ + lastStage = { stage, now } + } +} + +function promiseMapWithLimit(concurrency, array, fn) { + const limit = pLimit(concurrency) + return Promise.all(array.map(x => limit(() => fn(x)))) +} + +module.exports = { + HASH_REGEX: /^[0-9a-f]{64}$/, + update: callbackify(update), + promises: { + update, + }, +} diff --git a/services/clsi/app/js/ContentCacheMetrics.js b/services/clsi/app/js/ContentCacheMetrics.js new file mode 100644 index 0000000000..3550de70e8 --- /dev/null +++ b/services/clsi/app/js/ContentCacheMetrics.js @@ -0,0 +1,115 @@ +const logger = require('logger-sharelatex') +const Metrics = require('./Metrics') +const os = require('os') + +let CACHED_LOAD = { + expires: -1, + load: [0, 0, 0], +} +function getSystemLoad() { + if (CACHED_LOAD.expires < Date.now()) { + CACHED_LOAD = { + expires: Date.now() + 10 * 1000, + load: os.loadavg(), + } + } + return CACHED_LOAD.load +} + +const ONE_MB = 1024 * 1024 + +function emitPdfStats(stats, timings) { + if (stats['pdf-caching-timed-out']) { + Metrics.inc('pdf-caching-timed-out') + } + if (timings['compute-pdf-caching']) { + emitPdfCachingStats(stats, timings) + } else { + // How much bandwidth will the pdf incur when downloaded in full? + Metrics.summary('pdf-bandwidth', stats['pdf-size']) + } +} + +function emitPdfCachingStats(stats, timings) { + if (!stats['pdf-size']) return // double check + + // How much extra time did we spent in PDF.js? + Metrics.timing('compute-pdf-caching', timings['compute-pdf-caching']) + + // How large is the overhead of hashing up-front? + const fraction = + timings.compileE2E - timings['compute-pdf-caching'] !== 0 + ? timings.compileE2E / + (timings.compileE2E - timings['compute-pdf-caching']) + : 1 + if (fraction > 1.5 && timings.compileE2E > 10 * 1000) { + logger.warn( + { + stats, + timings, + load: getSystemLoad(), + }, + 'slow pdf caching' + ) + } + Metrics.summary('overhead-compute-pdf-ranges', fraction * 100 - 100) + + // How does the hashing scale to pdf size in MB? + Metrics.timing( + 'compute-pdf-caching-relative-to-pdf-size', + timings['compute-pdf-caching'] / (stats['pdf-size'] / ONE_MB) + ) + if (stats['pdf-caching-total-ranges-size']) { + // How does the hashing scale to total ranges size in MB? + Metrics.timing( + 'compute-pdf-caching-relative-to-total-ranges-size', + timings['compute-pdf-caching'] / + (stats['pdf-caching-total-ranges-size'] / ONE_MB) + ) + // How fast is the hashing per range on average? + Metrics.timing( + 'compute-pdf-caching-relative-to-ranges-count', + timings['compute-pdf-caching'] / stats['pdf-caching-n-ranges'] + ) + + // How many ranges are new? + Metrics.summary( + 'new-pdf-ranges-relative-to-total-ranges', + (stats['pdf-caching-n-new-ranges'] / stats['pdf-caching-n-ranges']) * 100 + ) + } + + // How much content is cacheable? + Metrics.summary( + 'cacheable-ranges-to-pdf-size', + (stats['pdf-caching-total-ranges-size'] / stats['pdf-size']) * 100 + ) + + const sizeWhenDownloadedInFull = + // All of the pdf + stats['pdf-size'] - + // These ranges are potentially cached. + stats['pdf-caching-total-ranges-size'] + + // These ranges are not cached. + stats['pdf-caching-new-ranges-size'] + + // How much bandwidth can we save when downloading the pdf in full? + Metrics.summary( + 'pdf-bandwidth-savings', + 100 - (sizeWhenDownloadedInFull / stats['pdf-size']) * 100 + ) + + // How much bandwidth will the pdf incur when downloaded in full? + Metrics.summary('pdf-bandwidth', sizeWhenDownloadedInFull) + + // How much space do the ranges use? + // This will accumulate the ranges size over time, skipping already written ranges. + Metrics.summary( + 'pdf-ranges-disk-size', + stats['pdf-caching-new-ranges-size'] - stats['pdf-caching-reclaimed-space'] + ) +} + +module.exports = { + emitPdfStats, +} diff --git a/services/clsi/app/js/ContentController.js b/services/clsi/app/js/ContentController.js new file mode 100644 index 0000000000..b154bea175 --- /dev/null +++ b/services/clsi/app/js/ContentController.js @@ -0,0 +1,24 @@ +const Path = require('path') +const send = require('send') +const Settings = require('@overleaf/settings') +const OutputCacheManager = require('./OutputCacheManager') + +const ONE_DAY_S = 24 * 60 * 60 +const ONE_DAY_MS = ONE_DAY_S * 1000 + +function getPdfRange(req, res, next) { + const { projectId, userId, contentId, hash } = req.params + const perUserDir = userId ? `${projectId}-${userId}` : projectId + const path = Path.join( + Settings.path.outputDir, + perUserDir, + OutputCacheManager.CONTENT_SUBDIR, + contentId, + hash + ) + res.setHeader('cache-control', `public, max-age=${ONE_DAY_S}`) + res.setHeader('expires', new Date(Date.now() + ONE_DAY_MS).toUTCString()) + send(req, path).pipe(res) +} + +module.exports = { getPdfRange } diff --git a/services/clsi/app/js/ContentTypeMapper.js b/services/clsi/app/js/ContentTypeMapper.js new file mode 100644 index 0000000000..6301dce489 --- /dev/null +++ b/services/clsi/app/js/ContentTypeMapper.js @@ -0,0 +1,38 @@ +/* eslint-disable + no-unused-vars, +*/ +// TODO: This file was created by bulk-decaffeinate. +// Fix any style issues and re-enable lint. +let ContentTypeMapper +const Path = require('path') + +// here we coerce html, css and js to text/plain, +// otherwise choose correct mime type based on file extension, +// falling back to octet-stream +module.exports = ContentTypeMapper = { + map(path) { + switch (Path.extname(path)) { + case '.txt': + case '.html': + case '.js': + case '.css': + case '.svg': + return 'text/plain' + case '.csv': + return 'text/csv' + case '.pdf': + return 'application/pdf' + case '.png': + return 'image/png' + case '.jpg': + case '.jpeg': + return 'image/jpeg' + case '.tiff': + return 'image/tiff' + case '.gif': + return 'image/gif' + default: + return 'application/octet-stream' + } + }, +} diff --git a/services/clsi/app/js/DbQueue.js b/services/clsi/app/js/DbQueue.js new file mode 100644 index 0000000000..ca2155d230 --- /dev/null +++ b/services/clsi/app/js/DbQueue.js @@ -0,0 +1,18 @@ +// TODO: This file was created by bulk-decaffeinate. +// Sanity-check the conversion and remove this comment. +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const async = require('async') +const Settings = require('@overleaf/settings') +const logger = require('logger-sharelatex') +const queue = async.queue( + (task, cb) => task(cb), + Settings.parallelSqlQueryLimit +) + +queue.drain = () => logger.debug('all items have been processed') + +module.exports = { queue } diff --git a/services/clsi/app/js/DockerLockManager.js b/services/clsi/app/js/DockerLockManager.js new file mode 100644 index 0000000000..d785ee46cb --- /dev/null +++ b/services/clsi/app/js/DockerLockManager.js @@ -0,0 +1,113 @@ +/* eslint-disable + handle-callback-err, +*/ +// TODO: This file was created by bulk-decaffeinate. +// Fix any style issues and re-enable lint. +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +let LockManager +const logger = require('logger-sharelatex') + +const LockState = {} // locks for docker container operations, by container name + +module.exports = LockManager = { + MAX_LOCK_HOLD_TIME: 15000, // how long we can keep a lock + MAX_LOCK_WAIT_TIME: 10000, // how long we wait for a lock + LOCK_TEST_INTERVAL: 1000, // retry time + + tryLock(key, callback) { + let lockValue + if (callback == null) { + callback = function (err, gotLock) {} + } + const existingLock = LockState[key] + if (existingLock != null) { + // the lock is already taken, check how old it is + const lockAge = Date.now() - existingLock.created + if (lockAge < LockManager.MAX_LOCK_HOLD_TIME) { + return callback(null, false) // we didn't get the lock, bail out + } else { + logger.error( + { key, lock: existingLock, age: lockAge }, + 'taking old lock by force' + ) + } + } + // take the lock + LockState[key] = lockValue = { created: Date.now() } + return callback(null, true, lockValue) + }, + + getLock(key, callback) { + let attempt + if (callback == null) { + callback = function (error, lockValue) {} + } + const startTime = Date.now() + return (attempt = () => + LockManager.tryLock(key, function (error, gotLock, lockValue) { + if (error != null) { + return callback(error) + } + if (gotLock) { + return callback(null, lockValue) + } else if (Date.now() - startTime > LockManager.MAX_LOCK_WAIT_TIME) { + const e = new Error('Lock timeout') + e.key = key + return callback(e) + } else { + return setTimeout(attempt, LockManager.LOCK_TEST_INTERVAL) + } + }))() + }, + + releaseLock(key, lockValue, callback) { + if (callback == null) { + callback = function (error) {} + } + const existingLock = LockState[key] + if (existingLock === lockValue) { + // lockValue is an object, so we can test by reference + delete LockState[key] // our lock, so we can free it + return callback() + } else if (existingLock != null) { + // lock exists but doesn't match ours + logger.error( + { key, lock: existingLock }, + 'tried to release lock taken by force' + ) + return callback() + } else { + logger.error( + { key, lock: existingLock }, + 'tried to release lock that has gone' + ) + return callback() + } + }, + + runWithLock(key, runner, callback) { + if (callback == null) { + callback = function (error) {} + } + return LockManager.getLock(key, function (error, lockValue) { + if (error != null) { + return callback(error) + } + return runner((error1, ...args) => + LockManager.releaseLock(key, lockValue, function (error2) { + error = error1 || error2 + if (error != null) { + return callback(error) + } + return callback(null, ...Array.from(args)) + }) + ) + }) + }, +} diff --git a/services/clsi/app/js/DockerRunner.js b/services/clsi/app/js/DockerRunner.js new file mode 100644 index 0000000000..28d7636f0a --- /dev/null +++ b/services/clsi/app/js/DockerRunner.js @@ -0,0 +1,625 @@ +const Settings = require('@overleaf/settings') +const logger = require('logger-sharelatex') +const Docker = require('dockerode') +const dockerode = new Docker() +const crypto = require('crypto') +const async = require('async') +const LockManager = require('./DockerLockManager') +const fs = require('fs') +const Path = require('path') +const _ = require('lodash') + +const ONE_HOUR_IN_MS = 60 * 60 * 1000 +logger.info('using docker runner') + +function usingSiblingContainers() { + return ( + Settings != null && + Settings.path != null && + Settings.path.sandboxedCompilesHostDir != null + ) +} + +let containerMonitorTimeout +let containerMonitorInterval + +const DockerRunner = { + run( + projectId, + command, + directory, + image, + timeout, + environment, + compileGroup, + callback + ) { + if (usingSiblingContainers()) { + const _newPath = Settings.path.sandboxedCompilesHostDir + logger.log( + { path: _newPath }, + 'altering bind path for sibling containers' + ) + // Server Pro, example: + // '/var/lib/sharelatex/data/compiles/' + // ... becomes ... + // '/opt/sharelatex_data/data/compiles/' + directory = Path.join( + Settings.path.sandboxedCompilesHostDir, + Path.basename(directory) + ) + } + + const volumes = { [directory]: '/compile' } + + command = command.map(arg => + arg.toString().replace('$COMPILE_DIR', '/compile') + ) + if (image == null) { + image = Settings.clsi.docker.image + } + + if ( + Settings.clsi.docker.allowedImages && + !Settings.clsi.docker.allowedImages.includes(image) + ) { + return callback(new Error('image not allowed')) + } + + if (Settings.texliveImageNameOveride != null) { + const img = image.split('/') + image = `${Settings.texliveImageNameOveride}/${img[2]}` + } + + const options = DockerRunner._getContainerOptions( + command, + image, + volumes, + timeout, + environment, + compileGroup + ) + const fingerprint = DockerRunner._fingerprintContainer(options) + const name = `project-${projectId}-${fingerprint}` + options.name = name + + // logOptions = _.clone(options) + // logOptions?.HostConfig?.SecurityOpt = "secomp used, removed in logging" + logger.log({ projectId }, 'running docker container') + DockerRunner._runAndWaitForContainer( + options, + volumes, + timeout, + (error, output) => { + if (error && error.statusCode === 500) { + logger.log( + { err: error, projectId }, + 'error running container so destroying and retrying' + ) + DockerRunner.destroyContainer(name, null, true, error => { + if (error != null) { + return callback(error) + } + DockerRunner._runAndWaitForContainer( + options, + volumes, + timeout, + callback + ) + }) + } else { + callback(error, output) + } + } + ) + + // pass back the container name to allow it to be killed + return name + }, + + kill(containerId, callback) { + logger.log({ containerId }, 'sending kill signal to container') + const container = dockerode.getContainer(containerId) + container.kill(error => { + if ( + error != null && + error.message != null && + error.message.match(/Cannot kill container .* is not running/) + ) { + logger.warn( + { err: error, containerId }, + 'container not running, continuing' + ) + error = null + } + if (error != null) { + logger.error({ err: error, containerId }, 'error killing container') + callback(error) + } else { + callback() + } + }) + }, + + _runAndWaitForContainer(options, volumes, timeout, _callback) { + const callback = _.once(_callback) + const { name } = options + + let streamEnded = false + let containerReturned = false + let output = {} + + function callbackIfFinished() { + if (streamEnded && containerReturned) { + callback(null, output) + } + } + + function attachStreamHandler(error, _output) { + if (error != null) { + return callback(error) + } + output = _output + streamEnded = true + callbackIfFinished() + } + + DockerRunner.startContainer( + options, + volumes, + attachStreamHandler, + (error, containerId) => { + if (error != null) { + return callback(error) + } + + DockerRunner.waitForContainer(name, timeout, (error, exitCode) => { + if (error != null) { + return callback(error) + } + if (exitCode === 137) { + // exit status from kill -9 + const err = new Error('terminated') + err.terminated = true + return callback(err) + } + if (exitCode === 1) { + // exit status from chktex + const err = new Error('exited') + err.code = exitCode + return callback(err) + } + containerReturned = true + if (options != null && options.HostConfig != null) { + options.HostConfig.SecurityOpt = null + } + logger.log({ exitCode, options }, 'docker container has exited') + callbackIfFinished() + }) + } + ) + }, + + _getContainerOptions( + command, + image, + volumes, + timeout, + environment, + compileGroup + ) { + const timeoutInSeconds = timeout / 1000 + + const dockerVolumes = {} + for (const hostVol in volumes) { + const dockerVol = volumes[hostVol] + dockerVolumes[dockerVol] = {} + + if (volumes[hostVol].slice(-3).indexOf(':r') === -1) { + volumes[hostVol] = `${dockerVol}:rw` + } + } + + // merge settings and environment parameter + const env = {} + for (const src of [Settings.clsi.docker.env, environment || {}]) { + for (const key in src) { + const value = src[key] + env[key] = value + } + } + // set the path based on the image year + const match = image.match(/:([0-9]+)\.[0-9]+/) + const year = match ? match[1] : '2014' + env.PATH = `/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/texlive/${year}/bin/x86_64-linux/` + const options = { + Cmd: command, + Image: image, + Volumes: dockerVolumes, + WorkingDir: '/compile', + NetworkDisabled: true, + Memory: 1024 * 1024 * 1024 * 1024, // 1 Gb + User: Settings.clsi.docker.user, + Env: Object.entries(env).map(([key, value]) => `${key}=${value}`), + HostConfig: { + Binds: Object.entries(volumes).map( + ([hostVol, dockerVol]) => `${hostVol}:${dockerVol}` + ), + LogConfig: { Type: 'none', Config: {} }, + Ulimits: [ + { + Name: 'cpu', + Soft: timeoutInSeconds + 5, + Hard: timeoutInSeconds + 10, + }, + ], + CapDrop: 'ALL', + SecurityOpt: ['no-new-privileges'], + }, + } + + if (Settings.path != null && Settings.path.synctexBinHostPath != null) { + options.HostConfig.Binds.push( + `${Settings.path.synctexBinHostPath}:/opt/synctex:ro` + ) + } + + if (Settings.clsi.docker.seccomp_profile != null) { + options.HostConfig.SecurityOpt.push( + `seccomp=${Settings.clsi.docker.seccomp_profile}` + ) + } + + if (Settings.clsi.docker.apparmor_profile != null) { + options.HostConfig.SecurityOpt.push( + `apparmor=${Settings.clsi.docker.apparmor_profile}` + ) + } + + if (Settings.clsi.docker.runtime) { + options.HostConfig.Runtime = Settings.clsi.docker.runtime + } + + if (Settings.clsi.docker.Readonly) { + options.HostConfig.ReadonlyRootfs = true + options.HostConfig.Tmpfs = { '/tmp': 'rw,noexec,nosuid,size=65536k' } + options.Volumes['/home/tex'] = {} + } + + // Allow per-compile group overriding of individual settings + if ( + Settings.clsi.docker.compileGroupConfig && + Settings.clsi.docker.compileGroupConfig[compileGroup] + ) { + const override = Settings.clsi.docker.compileGroupConfig[compileGroup] + for (const key in override) { + _.set(options, key, override[key]) + } + } + + return options + }, + + _fingerprintContainer(containerOptions) { + // Yay, Hashing! + const json = JSON.stringify(containerOptions) + return crypto.createHash('md5').update(json).digest('hex') + }, + + startContainer(options, volumes, attachStreamHandler, callback) { + LockManager.runWithLock( + options.name, + releaseLock => + // Check that volumes exist before starting the container. + // When a container is started with volume pointing to a + // non-existent directory then docker creates the directory but + // with root ownership. + DockerRunner._checkVolumes(options, volumes, err => { + if (err != null) { + return releaseLock(err) + } + DockerRunner._startContainer( + options, + volumes, + attachStreamHandler, + releaseLock + ) + }), + + callback + ) + }, + + // Check that volumes exist and are directories + _checkVolumes(options, volumes, callback) { + if (usingSiblingContainers()) { + // Server Pro, with sibling-containers active, skip checks + return callback(null) + } + + const checkVolume = (path, cb) => + fs.stat(path, (err, stats) => { + if (err != null) { + return cb(err) + } + if (!stats.isDirectory()) { + return cb(new Error('not a directory')) + } + cb() + }) + const jobs = [] + for (const vol in volumes) { + jobs.push(cb => checkVolume(vol, cb)) + } + async.series(jobs, callback) + }, + + _startContainer(options, volumes, attachStreamHandler, callback) { + callback = _.once(callback) + const { name } = options + + logger.log({ container_name: name }, 'starting container') + const container = dockerode.getContainer(name) + + function createAndStartContainer() { + dockerode.createContainer(options, (error, container) => { + if (error != null) { + return callback(error) + } + startExistingContainer() + }) + } + + function startExistingContainer() { + DockerRunner.attachToContainer( + options.name, + attachStreamHandler, + error => { + if (error != null) { + return callback(error) + } + container.start(error => { + if (error != null && error.statusCode !== 304) { + callback(error) + } else { + // already running + callback() + } + }) + } + ) + } + + container.inspect((error, stats) => { + if (error != null && error.statusCode === 404) { + createAndStartContainer() + } else if (error != null) { + logger.err( + { container_name: name, error }, + 'unable to inspect container to start' + ) + callback(error) + } else { + startExistingContainer() + } + }) + }, + + attachToContainer(containerId, attachStreamHandler, attachStartCallback) { + const container = dockerode.getContainer(containerId) + container.attach({ stdout: 1, stderr: 1, stream: 1 }, (error, stream) => { + if (error != null) { + logger.error( + { err: error, containerId }, + 'error attaching to container' + ) + return attachStartCallback(error) + } else { + attachStartCallback() + } + + logger.log({ containerId }, 'attached to container') + + const MAX_OUTPUT = 1024 * 1024 // limit output to 1MB + function createStringOutputStream(name) { + return { + data: '', + overflowed: false, + write(data) { + if (this.overflowed) { + return + } + if (this.data.length < MAX_OUTPUT) { + this.data += data + } else { + logger.error( + { + containerId, + length: this.data.length, + maxLen: MAX_OUTPUT, + }, + `${name} exceeds max size` + ) + this.data += `(...truncated at ${MAX_OUTPUT} chars...)` + this.overflowed = true + } + }, + // kill container if too much output + // docker.containers.kill(containerId, () ->) + } + } + + const stdout = createStringOutputStream('stdout') + const stderr = createStringOutputStream('stderr') + + container.modem.demuxStream(stream, stdout, stderr) + + stream.on('error', err => + logger.error( + { err, containerId }, + 'error reading from container stream' + ) + ) + + stream.on('end', () => + attachStreamHandler(null, { stdout: stdout.data, stderr: stderr.data }) + ) + }) + }, + + waitForContainer(containerId, timeout, _callback) { + const callback = _.once(_callback) + + const container = dockerode.getContainer(containerId) + + let timedOut = false + const timeoutId = setTimeout(() => { + timedOut = true + logger.log({ containerId }, 'timeout reached, killing container') + container.kill(err => { + logger.warn({ err, containerId }, 'failed to kill container') + }) + }, timeout) + + logger.log({ containerId }, 'waiting for docker container') + container.wait((error, res) => { + if (error != null) { + clearTimeout(timeoutId) + logger.error({ err: error, containerId }, 'error waiting for container') + return callback(error) + } + if (timedOut) { + logger.log({ containerId }, 'docker container timed out') + error = new Error('container timed out') + error.timedout = true + callback(error) + } else { + clearTimeout(timeoutId) + logger.log( + { containerId, exitCode: res.StatusCode }, + 'docker container returned' + ) + callback(null, res.StatusCode) + } + }) + }, + + destroyContainer(containerName, containerId, shouldForce, callback) { + // We want the containerName for the lock and, ideally, the + // containerId to delete. There is a bug in the docker.io module + // where if you delete by name and there is an error, it throws an + // async exception, but if you delete by id it just does a normal + // error callback. We fall back to deleting by name if no id is + // supplied. + LockManager.runWithLock( + containerName, + releaseLock => + DockerRunner._destroyContainer( + containerId || containerName, + shouldForce, + releaseLock + ), + callback + ) + }, + + _destroyContainer(containerId, shouldForce, callback) { + logger.log({ containerId }, 'destroying docker container') + const container = dockerode.getContainer(containerId) + container.remove({ force: shouldForce === true, v: true }, error => { + if (error != null && error.statusCode === 404) { + logger.warn( + { err: error, containerId }, + 'container not found, continuing' + ) + error = null + } + if (error != null) { + logger.error({ err: error, containerId }, 'error destroying container') + } else { + logger.log({ containerId }, 'destroyed container') + } + callback(error) + }) + }, + + // handle expiry of docker containers + + MAX_CONTAINER_AGE: Settings.clsi.docker.maxContainerAge || ONE_HOUR_IN_MS, + + examineOldContainer(container, callback) { + const name = container.Name || (container.Names && container.Names[0]) + const created = container.Created * 1000 // creation time is returned in seconds + const now = Date.now() + const age = now - created + const maxAge = DockerRunner.MAX_CONTAINER_AGE + const ttl = maxAge - age + logger.log( + { containerName: name, created, now, age, maxAge, ttl }, + 'checking whether to destroy container' + ) + return { name, id: container.Id, ttl } + }, + + destroyOldContainers(callback) { + dockerode.listContainers({ all: true }, (error, containers) => { + if (error != null) { + return callback(error) + } + const jobs = [] + for (const container of containers) { + const { name, id, ttl } = DockerRunner.examineOldContainer(container) + if (name.slice(0, 9) === '/project-' && ttl <= 0) { + // strip the / prefix + // the LockManager uses the plain container name + const plainName = name.slice(1) + jobs.push(cb => + DockerRunner.destroyContainer(plainName, id, false, () => cb()) + ) + } + } + // Ignore errors because some containers get stuck but + // will be destroyed next time + async.series(jobs, callback) + }) + }, + + startContainerMonitor() { + logger.log( + { maxAge: DockerRunner.MAX_CONTAINER_AGE }, + 'starting container expiry' + ) + + // guarantee only one monitor is running + DockerRunner.stopContainerMonitor() + + // randomise the start time + const randomDelay = Math.floor(Math.random() * 5 * 60 * 1000) + containerMonitorTimeout = setTimeout(() => { + containerMonitorInterval = setInterval( + () => + DockerRunner.destroyOldContainers(err => { + if (err) { + logger.error({ err }, 'failed to destroy old containers') + } + }), + ONE_HOUR_IN_MS + ) + }, randomDelay) + }, + + stopContainerMonitor() { + if (containerMonitorTimeout) { + clearTimeout(containerMonitorTimeout) + containerMonitorTimeout = undefined + } + if (containerMonitorInterval) { + clearInterval(containerMonitorInterval) + containerMonitorInterval = undefined + } + }, +} + +DockerRunner.startContainerMonitor() + +module.exports = DockerRunner diff --git a/services/clsi/app/js/DraftModeManager.js b/services/clsi/app/js/DraftModeManager.js new file mode 100644 index 0000000000..9be65e7afd --- /dev/null +++ b/services/clsi/app/js/DraftModeManager.js @@ -0,0 +1,57 @@ +/* eslint-disable + camelcase, + handle-callback-err, + no-useless-escape, +*/ +// TODO: This file was created by bulk-decaffeinate. +// Fix any style issues and re-enable lint. +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +let DraftModeManager +const fs = require('fs') +const logger = require('logger-sharelatex') + +module.exports = DraftModeManager = { + injectDraftMode(filename, callback) { + if (callback == null) { + callback = function (error) {} + } + return fs.readFile(filename, 'utf8', function (error, content) { + if (error != null) { + return callback(error) + } + // avoid adding draft mode more than once + if ( + (content != null + ? content.indexOf('\\documentclass[draft') + : undefined) >= 0 + ) { + return callback() + } + const modified_content = DraftModeManager._injectDraftOption(content) + logger.log( + { + content: content.slice(0, 1024), // \documentclass is normally v near the top + modified_content: modified_content.slice(0, 1024), + filename, + }, + 'injected draft class' + ) + return fs.writeFile(filename, modified_content, callback) + }) + }, + + _injectDraftOption(content) { + return ( + content + // With existing options (must be first, otherwise both are applied) + .replace(/\\documentclass\[/g, '\\documentclass[draft,') + // Without existing options + .replace(/\\documentclass\{/g, '\\documentclass[draft]{') + ) + }, +} diff --git a/services/clsi/app/js/Errors.js b/services/clsi/app/js/Errors.js new file mode 100644 index 0000000000..6b66c23421 --- /dev/null +++ b/services/clsi/app/js/Errors.js @@ -0,0 +1,41 @@ +/* eslint-disable + no-proto, + no-unused-vars, +*/ +// TODO: This file was created by bulk-decaffeinate. +// Fix any style issues and re-enable lint. +const OError = require('@overleaf/o-error') + +let Errors +var NotFoundError = function (message) { + const error = new Error(message) + error.name = 'NotFoundError' + error.__proto__ = NotFoundError.prototype + return error +} +NotFoundError.prototype.__proto__ = Error.prototype + +var FilesOutOfSyncError = function (message) { + const error = new Error(message) + error.name = 'FilesOutOfSyncError' + error.__proto__ = FilesOutOfSyncError.prototype + return error +} +FilesOutOfSyncError.prototype.__proto__ = Error.prototype + +var AlreadyCompilingError = function (message) { + const error = new Error(message) + error.name = 'AlreadyCompilingError' + error.__proto__ = AlreadyCompilingError.prototype + return error +} +AlreadyCompilingError.prototype.__proto__ = Error.prototype + +class TimedOutError extends OError {} + +module.exports = Errors = { + TimedOutError, + NotFoundError, + FilesOutOfSyncError, + AlreadyCompilingError, +} diff --git a/services/clsi/app/js/LatexRunner.js b/services/clsi/app/js/LatexRunner.js new file mode 100644 index 0000000000..7c288cef08 --- /dev/null +++ b/services/clsi/app/js/LatexRunner.js @@ -0,0 +1,237 @@ +/* eslint-disable + camelcase, + handle-callback-err, + no-return-assign, + no-unused-vars, +*/ +// TODO: This file was created by bulk-decaffeinate. +// Fix any style issues and re-enable lint. +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * DS103: Rewrite code to no longer use __guard__ + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +let LatexRunner +const Path = require('path') +const Settings = require('@overleaf/settings') +const logger = require('logger-sharelatex') +const Metrics = require('./Metrics') +const CommandRunner = require('./CommandRunner') +const fs = require('fs') + +const ProcessTable = {} // table of currently running jobs (pids or docker container names) + +const TIME_V_METRICS = Object.entries({ + 'cpu-percent': /Percent of CPU this job got: (\d+)/m, + 'cpu-time': /User time.*: (\d+.\d+)/m, + 'sys-time': /System time.*: (\d+.\d+)/m, +}) + +module.exports = LatexRunner = { + runLatex(project_id, options, callback) { + let command + if (callback == null) { + callback = function (error) {} + } + let { + directory, + mainFile, + compiler, + timeout, + image, + environment, + flags, + compileGroup, + } = options + if (!compiler) { + compiler = 'pdflatex' + } + if (!timeout) { + timeout = 60000 + } // milliseconds + + logger.log( + { + directory, + compiler, + timeout, + mainFile, + environment, + flags, + compileGroup, + }, + 'starting compile' + ) + + // We want to run latexmk on the tex file which we will automatically + // generate from the Rtex/Rmd/md file. + mainFile = mainFile.replace(/\.(Rtex|md|Rmd)$/, '.tex') + + if (compiler === 'pdflatex') { + command = LatexRunner._pdflatexCommand(mainFile, flags) + } else if (compiler === 'latex') { + command = LatexRunner._latexCommand(mainFile, flags) + } else if (compiler === 'xelatex') { + command = LatexRunner._xelatexCommand(mainFile, flags) + } else if (compiler === 'lualatex') { + command = LatexRunner._lualatexCommand(mainFile, flags) + } else { + return callback(new Error(`unknown compiler: ${compiler}`)) + } + + if (Settings.clsi != null ? Settings.clsi.strace : undefined) { + command = ['strace', '-o', 'strace', '-ff'].concat(command) + } + + const id = `${project_id}` // record running project under this id + + return (ProcessTable[id] = CommandRunner.run( + project_id, + command, + directory, + image, + timeout, + environment, + compileGroup, + function (error, output) { + delete ProcessTable[id] + if (error != null) { + return callback(error) + } + const runs = + __guard__( + __guard__(output != null ? output.stderr : undefined, x1 => + x1.match(/^Run number \d+ of .*latex/gm) + ), + x => x.length + ) || 0 + const failed = + __guard__(output != null ? output.stdout : undefined, x2 => + x2.match(/^Latexmk: Errors/m) + ) != null + ? 1 + : 0 + // counters from latexmk output + const stats = {} + stats['latexmk-errors'] = failed + stats['latex-runs'] = runs + stats['latex-runs-with-errors'] = failed ? runs : 0 + stats[`latex-runs-${runs}`] = 1 + stats[`latex-runs-with-errors-${runs}`] = failed ? 1 : 0 + // timing information from /usr/bin/time + const timings = {} + const stderr = (output && output.stderr) || '' + if (stderr.includes('Command being timed:')) { + // Add metrics for runs with `$ time -v ...` + for (const [timing, matcher] of TIME_V_METRICS) { + const match = stderr.match(matcher) + if (match) { + timings[timing] = parseFloat(match[1]) + } + } + } + // record output files + LatexRunner.writeLogOutput(project_id, directory, output, () => { + return callback(error, output, stats, timings) + }) + } + )) + }, + + writeLogOutput(project_id, directory, output, callback) { + if (!output) { + return callback() + } + // internal method for writing non-empty log files + function _writeFile(file, content, cb) { + if (content && content.length > 0) { + fs.writeFile(file, content, err => { + if (err) { + logger.error({ project_id, file }, 'error writing log file') // don't fail on error + } + cb() + }) + } else { + cb() + } + } + // write stdout and stderr, ignoring errors + _writeFile(Path.join(directory, 'output.stdout'), output.stdout, () => { + _writeFile(Path.join(directory, 'output.stderr'), output.stderr, () => { + callback() + }) + }) + }, + + killLatex(project_id, callback) { + if (callback == null) { + callback = function (error) {} + } + const id = `${project_id}` + logger.log({ id }, 'killing running compile') + if (ProcessTable[id] == null) { + logger.warn({ id }, 'no such project to kill') + return callback(null) + } else { + return CommandRunner.kill(ProcessTable[id], callback) + } + }, + + _latexmkBaseCommand(flags) { + let args = [ + 'latexmk', + '-cd', + '-f', + '-jobname=output', + '-auxdir=$COMPILE_DIR', + '-outdir=$COMPILE_DIR', + '-synctex=1', + '-interaction=batchmode', + ] + if (flags) { + args = args.concat(flags) + } + return ( + __guard__( + Settings != null ? Settings.clsi : undefined, + x => x.latexmkCommandPrefix + ) || [] + ).concat(args) + }, + + _pdflatexCommand(mainFile, flags) { + return LatexRunner._latexmkBaseCommand(flags).concat([ + '-pdf', + Path.join('$COMPILE_DIR', mainFile), + ]) + }, + + _latexCommand(mainFile, flags) { + return LatexRunner._latexmkBaseCommand(flags).concat([ + '-pdfdvi', + Path.join('$COMPILE_DIR', mainFile), + ]) + }, + + _xelatexCommand(mainFile, flags) { + return LatexRunner._latexmkBaseCommand(flags).concat([ + '-xelatex', + Path.join('$COMPILE_DIR', mainFile), + ]) + }, + + _lualatexCommand(mainFile, flags) { + return LatexRunner._latexmkBaseCommand(flags).concat([ + '-lualatex', + Path.join('$COMPILE_DIR', mainFile), + ]) + }, +} + +function __guard__(value, transform) { + return typeof value !== 'undefined' && value !== null + ? transform(value) + : undefined +} diff --git a/services/clsi/app/js/LocalCommandRunner.js b/services/clsi/app/js/LocalCommandRunner.js new file mode 100644 index 0000000000..1e4236a579 --- /dev/null +++ b/services/clsi/app/js/LocalCommandRunner.js @@ -0,0 +1,103 @@ +/* eslint-disable + camelcase, + handle-callback-err, + no-return-assign, + no-unused-vars, +*/ +// TODO: This file was created by bulk-decaffeinate. +// Fix any style issues and re-enable lint. +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +let CommandRunner +const { spawn } = require('child_process') +const _ = require('lodash') +const logger = require('logger-sharelatex') + +logger.info('using standard command runner') + +module.exports = CommandRunner = { + run( + project_id, + command, + directory, + image, + timeout, + environment, + compileGroup, + callback + ) { + let key, value + if (callback == null) { + callback = function (error) {} + } else { + callback = _.once(callback) + } + command = Array.from(command).map(arg => + arg.toString().replace('$COMPILE_DIR', directory) + ) + logger.log({ project_id, command, directory }, 'running command') + logger.warn('timeouts and sandboxing are not enabled with CommandRunner') + + // merge environment settings + const env = {} + for (key in process.env) { + value = process.env[key] + env[key] = value + } + for (key in environment) { + value = environment[key] + env[key] = value + } + + // run command as detached process so it has its own process group (which can be killed if needed) + const proc = spawn(command[0], command.slice(1), { cwd: directory, env }) + + let stdout = '' + proc.stdout.setEncoding('utf8').on('data', data => (stdout += data)) + + proc.on('error', function (err) { + logger.err( + { err, project_id, command, directory }, + 'error running command' + ) + return callback(err) + }) + + proc.on('close', function (code, signal) { + let err + logger.info({ code, signal, project_id }, 'command exited') + if (signal === 'SIGTERM') { + // signal from kill method below + err = new Error('terminated') + err.terminated = true + return callback(err) + } else if (code === 1) { + // exit status from chktex + err = new Error('exited') + err.code = code + return callback(err) + } else { + return callback(null, { stdout: stdout }) + } + }) + + return proc.pid + }, // return process id to allow job to be killed if necessary + + kill(pid, callback) { + if (callback == null) { + callback = function (error) {} + } + try { + process.kill(-pid) // kill all processes in group + } catch (err) { + return callback(err) + } + return callback() + }, +} diff --git a/services/clsi/app/js/LockManager.js b/services/clsi/app/js/LockManager.js new file mode 100644 index 0000000000..2dc09b336c --- /dev/null +++ b/services/clsi/app/js/LockManager.js @@ -0,0 +1,72 @@ +/* eslint-disable + handle-callback-err, + no-unused-vars, +*/ +// TODO: This file was created by bulk-decaffeinate. +// Fix any style issues and re-enable lint. +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +let LockManager +const Settings = require('@overleaf/settings') +const logger = require('logger-sharelatex') +const Lockfile = require('lockfile') // from https://github.com/npm/lockfile +const Errors = require('./Errors') +const fs = require('fs') +const Path = require('path') +module.exports = LockManager = { + LOCK_TEST_INTERVAL: 1000, // 50ms between each test of the lock + MAX_LOCK_WAIT_TIME: 15000, // 10s maximum time to spend trying to get the lock + LOCK_STALE: 5 * 60 * 1000, // 5 mins time until lock auto expires + + runWithLock(path, runner, callback) { + if (callback == null) { + callback = function (error) {} + } + const lockOpts = { + wait: this.MAX_LOCK_WAIT_TIME, + pollPeriod: this.LOCK_TEST_INTERVAL, + stale: this.LOCK_STALE, + } + return Lockfile.lock(path, lockOpts, function (error) { + if ((error != null ? error.code : undefined) === 'EEXIST') { + return callback(new Errors.AlreadyCompilingError('compile in progress')) + } else if (error != null) { + return fs.lstat(path, (statLockErr, statLock) => + fs.lstat(Path.dirname(path), (statDirErr, statDir) => + fs.readdir(Path.dirname(path), function (readdirErr, readdirDir) { + logger.err( + { + error, + path, + statLock, + statLockErr, + statDir, + statDirErr, + readdirErr, + readdirDir, + }, + 'unable to get lock' + ) + return callback(error) + }) + ) + ) + } else { + return runner((error1, ...args) => + Lockfile.unlock(path, function (error2) { + error = error1 || error2 + if (error != null) { + return callback(error) + } + return callback(null, ...Array.from(args)) + }) + ) + } + }) + }, +} diff --git a/services/clsi/app/js/Metrics.js b/services/clsi/app/js/Metrics.js new file mode 100644 index 0000000000..f0e57794fd --- /dev/null +++ b/services/clsi/app/js/Metrics.js @@ -0,0 +1,3 @@ +// TODO: This file was created by bulk-decaffeinate. +// Sanity-check the conversion and remove this comment. +module.exports = require('@overleaf/metrics') diff --git a/services/clsi/app/js/OutputCacheManager.js b/services/clsi/app/js/OutputCacheManager.js new file mode 100644 index 0000000000..af85f49661 --- /dev/null +++ b/services/clsi/app/js/OutputCacheManager.js @@ -0,0 +1,563 @@ +/* eslint-disable + handle-callback-err, +*/ +// TODO: This file was created by bulk-decaffeinate. +// Fix any style issues and re-enable lint. +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * DS103: Rewrite code to no longer use __guard__ + * DS104: Avoid inline assignments + * DS204: Change includes calls to have a more natural evaluation order + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +let OutputCacheManager +const async = require('async') +const fs = require('fs') +const fse = require('fs-extra') +const Path = require('path') +const logger = require('logger-sharelatex') +const _ = require('lodash') +const Settings = require('@overleaf/settings') +const crypto = require('crypto') +const Metrics = require('./Metrics') + +const OutputFileOptimiser = require('./OutputFileOptimiser') +const ContentCacheManager = require('./ContentCacheManager') +const { TimedOutError } = require('./Errors') + +module.exports = OutputCacheManager = { + CONTENT_SUBDIR: 'content', + CACHE_SUBDIR: 'generated-files', + ARCHIVE_SUBDIR: 'archived-logs', + // build id is HEXDATE-HEXRANDOM from Date.now()and RandomBytes + // for backwards compatibility, make the randombytes part optional + BUILD_REGEX: /^[0-9a-f]+(-[0-9a-f]+)?$/, + CONTENT_REGEX: /^[0-9a-f]+(-[0-9a-f]+)?$/, + CACHE_LIMIT: 2, // maximum number of cache directories + CACHE_AGE: 60 * 60 * 1000, // up to one hour old + + path(buildId, file) { + // used by static server, given build id return '.cache/clsi/buildId' + if (buildId.match(OutputCacheManager.BUILD_REGEX)) { + return Path.join(OutputCacheManager.CACHE_SUBDIR, buildId, file) + } else { + // for invalid build id, return top level + return file + } + }, + + generateBuildId(callback) { + // generate a secure build id from Date.now() and 8 random bytes in hex + if (callback == null) { + callback = function (error, buildId) {} + } + return crypto.randomBytes(8, function (err, buf) { + if (err != null) { + return callback(err) + } + const random = buf.toString('hex') + const date = Date.now().toString(16) + return callback(err, `${date}-${random}`) + }) + }, + + saveOutputFiles( + { request, stats, timings }, + outputFiles, + compileDir, + outputDir, + callback + ) { + if (callback == null) { + callback = function (error) {} + } + return OutputCacheManager.generateBuildId(function (err, buildId) { + if (err != null) { + return callback(err) + } + return OutputCacheManager.saveOutputFilesInBuildDir( + outputFiles, + compileDir, + outputDir, + buildId, + function (err, result) { + if (err != null) { + return callback(err) + } + OutputCacheManager.collectOutputPdfSize( + result, + outputDir, + stats, + (err, result) => { + if (err) return callback(err, result) + + if (!Settings.enablePdfCaching || !request.enablePdfCaching) { + return callback(null, result) + } + + OutputCacheManager.saveStreamsInContentDir( + { stats, timings }, + result, + compileDir, + outputDir, + callback + ) + } + ) + } + ) + }) + }, + + saveOutputFilesInBuildDir( + outputFiles, + compileDir, + outputDir, + buildId, + callback + ) { + // make a compileDir/CACHE_SUBDIR/build_id directory and + // copy all the output files into it + if (callback == null) { + callback = function (error) {} + } + const cacheRoot = Path.join(outputDir, OutputCacheManager.CACHE_SUBDIR) + // Put the files into a new cache subdirectory + const cacheDir = Path.join( + outputDir, + OutputCacheManager.CACHE_SUBDIR, + buildId + ) + // Is it a per-user compile? check if compile directory is PROJECTID-USERID + const perUser = Path.basename(compileDir).match( + /^[0-9a-f]{24}-[0-9a-f]{24}$/ + ) + + // Archive logs in background + if ( + (Settings.clsi != null ? Settings.clsi.archive_logs : undefined) || + (Settings.clsi != null ? Settings.clsi.strace : undefined) + ) { + OutputCacheManager.archiveLogs( + outputFiles, + compileDir, + outputDir, + buildId, + function (err) { + if (err != null) { + return logger.warn({ err }, 'erroring archiving log files') + } + } + ) + } + + // make the new cache directory + return fse.ensureDir(cacheDir, function (err) { + if (err != null) { + logger.error( + { err, directory: cacheDir }, + 'error creating cache directory' + ) + return callback(err, outputFiles) + } else { + // copy all the output files into the new cache directory + const results = [] + return async.mapSeries( + outputFiles, + function (file, cb) { + // don't send dot files as output, express doesn't serve them + if (OutputCacheManager._fileIsHidden(file.path)) { + logger.debug( + { compileDir, path: file.path }, + 'ignoring dotfile in output' + ) + return cb() + } + // copy other files into cache directory if valid + const newFile = _.clone(file) + const [src, dst] = Array.from([ + Path.join(compileDir, file.path), + Path.join(cacheDir, file.path), + ]) + return OutputCacheManager._checkFileIsSafe( + src, + function (err, isSafe) { + if (err != null) { + return cb(err) + } + if (!isSafe) { + return cb() + } + return OutputCacheManager._checkIfShouldCopy( + src, + function (err, shouldCopy) { + if (err != null) { + return cb(err) + } + if (!shouldCopy) { + return cb() + } + return OutputCacheManager._copyFile( + src, + dst, + function (err) { + if (err != null) { + return cb(err) + } + newFile.build = buildId // attach a build id if we cached the file + results.push(newFile) + return cb() + } + ) + } + ) + } + ) + }, + function (err) { + if (err != null) { + // pass back the original files if we encountered *any* error + callback(err, outputFiles) + // clean up the directory we just created + return fse.remove(cacheDir, function (err) { + if (err != null) { + return logger.error( + { err, dir: cacheDir }, + 'error removing cache dir after failure' + ) + } + }) + } else { + // pass back the list of new files in the cache + callback(err, results) + // let file expiry run in the background, expire all previous files if per-user + return OutputCacheManager.expireOutputFiles(cacheRoot, { + keep: buildId, + limit: perUser ? 1 : null, + }) + } + } + ) + } + }) + }, + + collectOutputPdfSize(outputFiles, outputDir, stats, callback) { + const outputFile = outputFiles.find(x => x.path === 'output.pdf') + if (!outputFile) return callback(null, outputFiles) + const outputFilePath = Path.join( + outputDir, + OutputCacheManager.path(outputFile.build, outputFile.path) + ) + fs.stat(outputFilePath, (err, stat) => { + if (err) return callback(err, outputFiles) + + outputFile.size = stat.size + stats['pdf-size'] = outputFile.size + callback(null, outputFiles) + }) + }, + + saveStreamsInContentDir( + { stats, timings }, + outputFiles, + compileDir, + outputDir, + callback + ) { + const cacheRoot = Path.join(outputDir, OutputCacheManager.CONTENT_SUBDIR) + // check if content dir exists + OutputCacheManager.ensureContentDir(cacheRoot, function (err, contentDir) { + if (err) return callback(err, outputFiles) + + const outputFile = outputFiles.find(x => x.path === 'output.pdf') + if (outputFile) { + // possibly we should copy the file from the build dir here + const outputFilePath = Path.join( + outputDir, + OutputCacheManager.path(outputFile.build, outputFile.path) + ) + const pdfSize = outputFile.size + const timer = new Metrics.Timer('compute-pdf-ranges') + ContentCacheManager.update( + contentDir, + outputFilePath, + pdfSize, + timings.compile, + function (err, result) { + if (err && err instanceof TimedOutError) { + logger.warn( + { err, outputDir, stats, timings }, + 'pdf caching timed out' + ) + stats['pdf-caching-timed-out'] = 1 + return callback(null, outputFiles) + } + if (err) return callback(err, outputFiles) + const [contentRanges, newContentRanges, reclaimedSpace] = result + + if (Settings.enablePdfCachingDark) { + // In dark mode we are doing the computation only and do not emit + // any ranges to the frontend. + } else { + outputFile.contentId = Path.basename(contentDir) + outputFile.ranges = contentRanges + } + + timings['compute-pdf-caching'] = timer.done() + stats['pdf-caching-n-ranges'] = contentRanges.length + stats['pdf-caching-total-ranges-size'] = contentRanges.reduce( + (sum, next) => sum + (next.end - next.start), + 0 + ) + stats['pdf-caching-n-new-ranges'] = newContentRanges.length + stats['pdf-caching-new-ranges-size'] = newContentRanges.reduce( + (sum, next) => sum + (next.end - next.start), + 0 + ) + stats['pdf-caching-reclaimed-space'] = reclaimedSpace + callback(null, outputFiles) + } + ) + } else { + callback(null, outputFiles) + } + }) + }, + + ensureContentDir(contentRoot, callback) { + fse.ensureDir(contentRoot, function (err) { + if (err != null) { + return callback(err) + } + fs.readdir(contentRoot, function (err, results) { + const dirs = results.sort() + const contentId = dirs.find(dir => + OutputCacheManager.BUILD_REGEX.test(dir) + ) + if (contentId) { + callback(null, Path.join(contentRoot, contentId)) + } else { + // make a content directory + OutputCacheManager.generateBuildId(function (err, contentId) { + if (err) { + return callback(err) + } + const contentDir = Path.join(contentRoot, contentId) + fse.ensureDir(contentDir, function (err) { + if (err) { + return callback(err) + } + return callback(null, contentDir) + }) + }) + } + }) + }) + }, + + archiveLogs(outputFiles, compileDir, outputDir, buildId, callback) { + if (callback == null) { + callback = function (error) {} + } + const archiveDir = Path.join( + outputDir, + OutputCacheManager.ARCHIVE_SUBDIR, + buildId + ) + logger.log({ dir: archiveDir }, 'archiving log files for project') + return fse.ensureDir(archiveDir, function (err) { + if (err != null) { + return callback(err) + } + return async.mapSeries( + outputFiles, + function (file, cb) { + const [src, dst] = Array.from([ + Path.join(compileDir, file.path), + Path.join(archiveDir, file.path), + ]) + return OutputCacheManager._checkFileIsSafe( + src, + function (err, isSafe) { + if (err != null) { + return cb(err) + } + if (!isSafe) { + return cb() + } + return OutputCacheManager._checkIfShouldArchive( + src, + function (err, shouldArchive) { + if (err != null) { + return cb(err) + } + if (!shouldArchive) { + return cb() + } + return OutputCacheManager._copyFile(src, dst, cb) + } + ) + } + ) + }, + callback + ) + }) + }, + + expireOutputFiles(cacheRoot, options, callback) { + // look in compileDir for build dirs and delete if > N or age of mod time > T + if (callback == null) { + callback = function (error) {} + } + return fs.readdir(cacheRoot, function (err, results) { + if (err != null) { + if (err.code === 'ENOENT') { + return callback(null) + } // cache directory is empty + logger.error({ err, project_id: cacheRoot }, 'error clearing cache') + return callback(err) + } + + const dirs = results.sort().reverse() + const currentTime = Date.now() + + const isExpired = function (dir, index) { + if ((options != null ? options.keep : undefined) === dir) { + return false + } + // remove any directories over the requested (non-null) limit + if ( + (options != null ? options.limit : undefined) != null && + index > options.limit + ) { + return true + } + // remove any directories over the hard limit + if (index > OutputCacheManager.CACHE_LIMIT) { + return true + } + // we can get the build time from the first part of the directory name DDDD-RRRR + // DDDD is date and RRRR is random bytes + const dirTime = parseInt( + __guard__(dir.split('-'), x => x[0]), + 16 + ) + const age = currentTime - dirTime + return age > OutputCacheManager.CACHE_AGE + } + + const toRemove = _.filter(dirs, isExpired) + + const removeDir = (dir, cb) => + fse.remove(Path.join(cacheRoot, dir), function (err, result) { + logger.log({ cache: cacheRoot, dir }, 'removed expired cache dir') + if (err != null) { + logger.error({ err, dir }, 'cache remove error') + } + return cb(err, result) + }) + return async.eachSeries( + toRemove, + (dir, cb) => removeDir(dir, cb), + callback + ) + }) + }, + + _fileIsHidden(path) { + return (path != null ? path.match(/^\.|\/\./) : undefined) != null + }, + + _checkFileIsSafe(src, callback) { + // check if we have a valid file to copy into the cache + if (callback == null) { + callback = function (error, isSafe) {} + } + return fs.stat(src, function (err, stats) { + if ((err != null ? err.code : undefined) === 'ENOENT') { + logger.warn( + { err, file: src }, + 'file has disappeared before copying to build cache' + ) + return callback(err, false) + } else if (err != null) { + // some other problem reading the file + logger.error({ err, file: src }, 'stat error for file in cache') + return callback(err, false) + } else if (!stats.isFile()) { + // other filetype - reject it + logger.warn( + { src, stat: stats }, + 'nonfile output - refusing to copy to cache' + ) + return callback(null, false) + } else { + // it's a plain file, ok to copy + return callback(null, true) + } + }) + }, + + _copyFile(src, dst, callback) { + // copy output file into the cache + return fse.copy(src, dst, function (err) { + if ((err != null ? err.code : undefined) === 'ENOENT') { + logger.warn( + { err, file: src }, + 'file has disappeared when copying to build cache' + ) + return callback(err, false) + } else if (err != null) { + logger.error({ err, src, dst }, 'copy error for file in cache') + return callback(err) + } else { + if ( + Settings.clsi != null ? Settings.clsi.optimiseInDocker : undefined + ) { + // don't run any optimisations on the pdf when they are done + // in the docker container + return callback() + } else { + // call the optimiser for the file too + return OutputFileOptimiser.optimiseFile(src, dst, callback) + } + } + }) + }, + + _checkIfShouldCopy(src, callback) { + if (callback == null) { + callback = function (err, shouldCopy) {} + } + return callback(null, !Path.basename(src).match(/^strace/)) + }, + + _checkIfShouldArchive(src, callback) { + let needle + if (callback == null) { + callback = function (err, shouldCopy) {} + } + if (Path.basename(src).match(/^strace/)) { + return callback(null, true) + } + if ( + (Settings.clsi != null ? Settings.clsi.archive_logs : undefined) && + ((needle = Path.basename(src)), + ['output.log', 'output.blg'].includes(needle)) + ) { + return callback(null, true) + } + return callback(null, false) + }, +} + +function __guard__(value, transform) { + return typeof value !== 'undefined' && value !== null + ? transform(value) + : undefined +} diff --git a/services/clsi/app/js/OutputFileFinder.js b/services/clsi/app/js/OutputFileFinder.js new file mode 100644 index 0000000000..9088215d1a --- /dev/null +++ b/services/clsi/app/js/OutputFileFinder.js @@ -0,0 +1,78 @@ +let OutputFileFinder +const Path = require('path') +const _ = require('lodash') +const { spawn } = require('child_process') +const logger = require('logger-sharelatex') + +module.exports = OutputFileFinder = { + findOutputFiles(resources, directory, callback) { + const incomingResources = new Set(resources.map(resource => resource.path)) + + OutputFileFinder._getAllFiles(directory, function (error, allFiles) { + if (allFiles == null) { + allFiles = [] + } + if (error) { + logger.err({ err: error }, 'error finding all output files') + return callback(error) + } + const outputFiles = [] + for (const file of allFiles) { + if (!incomingResources.has(file)) { + outputFiles.push({ + path: file, + type: Path.extname(file).replace(/^\./, '') || undefined, + }) + } + } + callback(null, outputFiles, allFiles) + }) + }, + + _getAllFiles(directory, callback) { + callback = _.once(callback) + // don't include clsi-specific files/directories in the output list + const EXCLUDE_DIRS = [ + '-name', + '.cache', + '-o', + '-name', + '.archive', + '-o', + '-name', + '.project-*', + ] + const args = [ + directory, + '(', + ...EXCLUDE_DIRS, + ')', + '-prune', + '-o', + '-type', + 'f', + '-print', + ] + logger.log({ args }, 'running find command') + + const proc = spawn('find', args) + let stdout = '' + proc.stdout.setEncoding('utf8').on('data', chunk => (stdout += chunk)) + proc.on('error', callback) + proc.on('close', function (code) { + if (code !== 0) { + logger.warn( + { directory, code }, + "find returned error, directory likely doesn't exist" + ) + return callback(null, []) + } + let fileList = stdout.trim().split('\n') + fileList = fileList.map(function (file) { + // Strip leading directory + return Path.relative(directory, file) + }) + callback(null, fileList) + }) + }, +} diff --git a/services/clsi/app/js/OutputFileOptimiser.js b/services/clsi/app/js/OutputFileOptimiser.js new file mode 100644 index 0000000000..979697b07c --- /dev/null +++ b/services/clsi/app/js/OutputFileOptimiser.js @@ -0,0 +1,103 @@ +/* eslint-disable + handle-callback-err, + no-return-assign, + no-undef, + no-unused-vars, + node/no-deprecated-api, +*/ +// TODO: This file was created by bulk-decaffeinate. +// Fix any style issues and re-enable lint. +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +let OutputFileOptimiser +const fs = require('fs') +const Path = require('path') +const { spawn } = require('child_process') +const logger = require('logger-sharelatex') +const Metrics = require('./Metrics') +const _ = require('lodash') + +module.exports = OutputFileOptimiser = { + optimiseFile(src, dst, callback) { + // check output file (src) and see if we can optimise it, storing + // the result in the build directory (dst) + if (callback == null) { + callback = function (error) {} + } + if (src.match(/\/output\.pdf$/)) { + return OutputFileOptimiser.checkIfPDFIsOptimised( + src, + function (err, isOptimised) { + if (err != null || isOptimised) { + return callback(null) + } + return OutputFileOptimiser.optimisePDF(src, dst, callback) + } + ) + } else { + return callback(null) + } + }, + + checkIfPDFIsOptimised(file, callback) { + const SIZE = 16 * 1024 // check the header of the pdf + const result = Buffer.alloc(SIZE) // fills with zeroes by default + return fs.open(file, 'r', function (err, fd) { + if (err != null) { + return callback(err) + } + return fs.read(fd, result, 0, SIZE, 0, (errRead, bytesRead, buffer) => + fs.close(fd, function (errClose) { + if (errRead != null) { + return callback(errRead) + } + if (typeof errReadClose !== 'undefined' && errReadClose !== null) { + return callback(errClose) + } + const isOptimised = + buffer.toString('ascii').indexOf('/Linearized 1') >= 0 + return callback(null, isOptimised) + }) + ) + }) + }, + + optimisePDF(src, dst, callback) { + if (callback == null) { + callback = function (error) {} + } + const tmpOutput = dst + '.opt' + const args = ['--linearize', '--newline-before-endstream', src, tmpOutput] + logger.log({ args }, 'running qpdf command') + + const timer = new Metrics.Timer('qpdf') + const proc = spawn('qpdf', args) + let stdout = '' + proc.stdout.setEncoding('utf8').on('data', chunk => (stdout += chunk)) + callback = _.once(callback) // avoid double call back for error and close event + proc.on('error', function (err) { + logger.warn({ err, args }, 'qpdf failed') + return callback(null) + }) // ignore the error + return proc.on('close', function (code) { + timer.done() + if (code !== 0) { + logger.warn({ code, args }, 'qpdf returned error') + return callback(null) // ignore the error + } + return fs.rename(tmpOutput, dst, function (err) { + if (err != null) { + logger.warn( + { tmpOutput, dst }, + 'failed to rename output of qpdf command' + ) + } + return callback(null) + }) + }) + }, // ignore the error +} diff --git a/services/clsi/app/js/ProjectPersistenceManager.js b/services/clsi/app/js/ProjectPersistenceManager.js new file mode 100644 index 0000000000..c4abb69b6e --- /dev/null +++ b/services/clsi/app/js/ProjectPersistenceManager.js @@ -0,0 +1,207 @@ +/* eslint-disable + camelcase, + handle-callback-err, +*/ +// TODO: This file was created by bulk-decaffeinate. +// Fix any style issues and re-enable lint. +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +let ProjectPersistenceManager +const Metrics = require('./Metrics') +const UrlCache = require('./UrlCache') +const CompileManager = require('./CompileManager') +const db = require('./db') +const dbQueue = require('./DbQueue') +const async = require('async') +const logger = require('logger-sharelatex') +const oneDay = 24 * 60 * 60 * 1000 +const Settings = require('@overleaf/settings') +const diskusage = require('diskusage') +const { callbackify } = require('util') + +async function refreshExpiryTimeout() { + const paths = [ + Settings.path.compilesDir, + Settings.path.outputDir, + Settings.path.clsiCacheDir, + ] + for (const path of paths) { + try { + const stats = await diskusage.check(path) + const lowDisk = stats.available / stats.total < 0.1 + + const lowerExpiry = ProjectPersistenceManager.EXPIRY_TIMEOUT * 0.9 + if (lowDisk && Settings.project_cache_length_ms / 2 < lowerExpiry) { + logger.warn( + { + stats, + newExpiryTimeoutInDays: (lowerExpiry / oneDay).toFixed(2), + }, + 'disk running low on space, modifying EXPIRY_TIMEOUT' + ) + ProjectPersistenceManager.EXPIRY_TIMEOUT = lowerExpiry + break + } + } catch (err) { + logger.err({ err, path }, 'error getting disk usage') + } + } +} + +module.exports = ProjectPersistenceManager = { + EXPIRY_TIMEOUT: Settings.project_cache_length_ms || oneDay * 2.5, + + promises: { + refreshExpiryTimeout, + }, + + refreshExpiryTimeout: callbackify(refreshExpiryTimeout), + markProjectAsJustAccessed(project_id, callback) { + if (callback == null) { + callback = function (error) {} + } + const timer = new Metrics.Timer('db-bump-last-accessed') + const job = cb => + db.Project.findOrCreate({ where: { project_id } }) + .spread((project, created) => + project + .update({ lastAccessed: new Date() }) + .then(() => cb()) + .error(cb) + ) + .error(cb) + dbQueue.queue.push(job, error => { + timer.done() + callback(error) + }) + }, + + clearExpiredProjects(callback) { + if (callback == null) { + callback = function (error) {} + } + return ProjectPersistenceManager._findExpiredProjectIds(function ( + error, + project_ids + ) { + if (error != null) { + return callback(error) + } + logger.log({ project_ids }, 'clearing expired projects') + const jobs = Array.from(project_ids || []).map(project_id => + ( + project_id => callback => + ProjectPersistenceManager.clearProjectFromCache( + project_id, + function (err) { + if (err != null) { + logger.error({ err, project_id }, 'error clearing project') + } + return callback() + } + ) + )(project_id) + ) + return async.series(jobs, function (error) { + if (error != null) { + return callback(error) + } + return CompileManager.clearExpiredProjects( + ProjectPersistenceManager.EXPIRY_TIMEOUT, + error => callback() + ) + }) + }) + }, // ignore any errors from deleting directories + + clearProject(project_id, user_id, callback) { + if (callback == null) { + callback = function (error) {} + } + logger.log({ project_id, user_id }, 'clearing project for user') + return CompileManager.clearProject(project_id, user_id, function (error) { + if (error != null) { + return callback(error) + } + return ProjectPersistenceManager.clearProjectFromCache( + project_id, + function (error) { + if (error != null) { + return callback(error) + } + return callback() + } + ) + }) + }, + + clearProjectFromCache(project_id, callback) { + if (callback == null) { + callback = function (error) {} + } + logger.log({ project_id }, 'clearing project from cache') + return UrlCache.clearProject(project_id, function (error) { + if (error != null) { + logger.err({ error, project_id }, 'error clearing project from cache') + return callback(error) + } + return ProjectPersistenceManager._clearProjectFromDatabase( + project_id, + function (error) { + if (error != null) { + logger.err( + { error, project_id }, + 'error clearing project from database' + ) + } + return callback(error) + } + ) + }) + }, + + _clearProjectFromDatabase(project_id, callback) { + if (callback == null) { + callback = function (error) {} + } + logger.log({ project_id }, 'clearing project from database') + const job = cb => + db.Project.destroy({ where: { project_id } }) + .then(() => cb()) + .error(cb) + return dbQueue.queue.push(job, callback) + }, + + _findExpiredProjectIds(callback) { + if (callback == null) { + callback = function (error, project_ids) {} + } + const job = function (cb) { + const keepProjectsFrom = new Date( + Date.now() - ProjectPersistenceManager.EXPIRY_TIMEOUT + ) + const q = {} + q[db.op.lt] = keepProjectsFrom + return db.Project.findAll({ where: { lastAccessed: q } }) + .then(projects => + cb( + null, + projects.map(project => project.project_id) + ) + ) + .error(cb) + } + + return dbQueue.queue.push(job, callback) + }, +} + +logger.log( + { EXPIRY_TIMEOUT: ProjectPersistenceManager.EXPIRY_TIMEOUT }, + 'project assets kept timeout' +) diff --git a/services/clsi/app/js/RequestParser.js b/services/clsi/app/js/RequestParser.js new file mode 100644 index 0000000000..04502e422c --- /dev/null +++ b/services/clsi/app/js/RequestParser.js @@ -0,0 +1,239 @@ +/* eslint-disable + handle-callback-err, + no-control-regex, + no-throw-literal, + no-unused-vars, + no-useless-escape, + valid-typeof, +*/ +// TODO: This file was created by bulk-decaffeinate. +// Fix any style issues and re-enable lint. +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * DS205: Consider reworking code to avoid use of IIFEs + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +let RequestParser +const settings = require('@overleaf/settings') + +module.exports = RequestParser = { + VALID_COMPILERS: ['pdflatex', 'latex', 'xelatex', 'lualatex'], + MAX_TIMEOUT: 600, + + parse(body, callback) { + let resource + if (callback == null) { + callback = function (error, data) {} + } + const response = {} + + if (body.compile == null) { + return callback('top level object should have a compile attribute') + } + + const { compile } = body + if (!compile.options) { + compile.options = {} + } + + try { + response.compiler = this._parseAttribute( + 'compiler', + compile.options.compiler, + { + validValues: this.VALID_COMPILERS, + default: 'pdflatex', + type: 'string', + } + ) + response.enablePdfCaching = this._parseAttribute( + 'enablePdfCaching', + compile.options.enablePdfCaching, + { + default: false, + type: 'boolean', + } + ) + response.timeout = this._parseAttribute( + 'timeout', + compile.options.timeout, + { + default: RequestParser.MAX_TIMEOUT, + type: 'number', + } + ) + response.imageName = this._parseAttribute( + 'imageName', + compile.options.imageName, + { + type: 'string', + validValues: + settings.clsi && + settings.clsi.docker && + settings.clsi.docker.allowedImages, + } + ) + response.draft = this._parseAttribute('draft', compile.options.draft, { + default: false, + type: 'boolean', + }) + response.check = this._parseAttribute('check', compile.options.check, { + type: 'string', + }) + response.flags = this._parseAttribute('flags', compile.options.flags, { + default: [], + type: 'object', + }) + if (settings.allowedCompileGroups) { + response.compileGroup = this._parseAttribute( + 'compileGroup', + compile.options.compileGroup, + { + validValues: settings.allowedCompileGroups, + default: '', + type: 'string', + } + ) + } + // The syncType specifies whether the request contains all + // resources (full) or only those resources to be updated + // in-place (incremental). + response.syncType = this._parseAttribute( + 'syncType', + compile.options.syncType, + { + validValues: ['full', 'incremental'], + type: 'string', + } + ) + + // The syncState is an identifier passed in with the request + // which has the property that it changes when any resource is + // added, deleted, moved or renamed. + // + // on syncType full the syncState identifier is passed in and + // stored + // + // on syncType incremental the syncState identifier must match + // the stored value + response.syncState = this._parseAttribute( + 'syncState', + compile.options.syncState, + { type: 'string' } + ) + + if (response.timeout > RequestParser.MAX_TIMEOUT) { + response.timeout = RequestParser.MAX_TIMEOUT + } + response.timeout = response.timeout * 1000 // milliseconds + + response.resources = (() => { + const result = [] + for (resource of Array.from(compile.resources || [])) { + result.push(this._parseResource(resource)) + } + return result + })() + + const rootResourcePath = this._parseAttribute( + 'rootResourcePath', + compile.rootResourcePath, + { + default: 'main.tex', + type: 'string', + } + ) + const originalRootResourcePath = rootResourcePath + const sanitizedRootResourcePath = + RequestParser._sanitizePath(rootResourcePath) + response.rootResourcePath = RequestParser._checkPath( + sanitizedRootResourcePath + ) + + for (resource of Array.from(response.resources)) { + if (resource.path === originalRootResourcePath) { + resource.path = sanitizedRootResourcePath + } + } + } catch (error1) { + const error = error1 + return callback(error) + } + + return callback(null, response) + }, + + _parseResource(resource) { + let modified + if (resource.path == null || typeof resource.path !== 'string') { + throw 'all resources should have a path attribute' + } + + if (resource.modified != null) { + modified = new Date(resource.modified) + if (isNaN(modified.getTime())) { + throw `resource modified date could not be understood: ${resource.modified}` + } + } + + if (resource.url == null && resource.content == null) { + throw 'all resources should have either a url or content attribute' + } + if (resource.content != null && typeof resource.content !== 'string') { + throw 'content attribute should be a string' + } + if (resource.url != null && typeof resource.url !== 'string') { + throw 'url attribute should be a string' + } + + return { + path: resource.path, + modified, + url: resource.url, + content: resource.content, + } + }, + + _parseAttribute(name, attribute, options) { + if (attribute != null) { + if (options.validValues != null) { + if (options.validValues.indexOf(attribute) === -1) { + throw `${name} attribute should be one of: ${options.validValues.join( + ', ' + )}` + } + } + if (options.type != null) { + if (typeof attribute !== options.type) { + throw `${name} attribute should be a ${options.type}` + } + } + } else { + if (options.default != null) { + return options.default + } + } + return attribute + }, + + _sanitizePath(path) { + // See http://php.net/manual/en/function.escapeshellcmd.php + return path.replace( + /[\#\&\;\`\|\*\?\~\<\>\^\(\)\[\]\{\}\$\\\x0A\xFF\x00]/g, + '' + ) + }, + + _checkPath(path) { + // check that the request does not use a relative path + for (const dir of Array.from(path.split('/'))) { + if (dir === '..') { + throw 'relative path in root resource' + } + } + return path + }, +} diff --git a/services/clsi/app/js/ResourceStateManager.js b/services/clsi/app/js/ResourceStateManager.js new file mode 100644 index 0000000000..7ae3557d51 --- /dev/null +++ b/services/clsi/app/js/ResourceStateManager.js @@ -0,0 +1,116 @@ +const Path = require('path') +const fs = require('fs') +const logger = require('logger-sharelatex') +const Errors = require('./Errors') +const SafeReader = require('./SafeReader') + +module.exports = { + // The sync state is an identifier which must match for an + // incremental update to be allowed. + // + // The initial value is passed in and stored on a full + // compile, along with the list of resources.. + // + // Subsequent incremental compiles must come with the same value - if + // not they will be rejected with a 409 Conflict response. The + // previous list of resources is returned. + // + // An incremental compile can only update existing files with new + // content. The sync state identifier must change if any docs or + // files are moved, added, deleted or renamed. + + SYNC_STATE_FILE: '.project-sync-state', + SYNC_STATE_MAX_SIZE: 128 * 1024, + + saveProjectState(state, resources, basePath, callback) { + const stateFile = Path.join(basePath, this.SYNC_STATE_FILE) + if (state == null) { + // remove the file if no state passed in + logger.log({ state, basePath }, 'clearing sync state') + fs.unlink(stateFile, function (err) { + if (err && err.code !== 'ENOENT') { + return callback(err) + } else { + return callback() + } + }) + } else { + logger.log({ state, basePath }, 'writing sync state') + const resourceList = resources.map(resource => resource.path) + fs.writeFile( + stateFile, + [...resourceList, `stateHash:${state}`].join('\n'), + callback + ) + } + }, + + checkProjectStateMatches(state, basePath, callback) { + const stateFile = Path.join(basePath, this.SYNC_STATE_FILE) + const size = this.SYNC_STATE_MAX_SIZE + SafeReader.readFile( + stateFile, + size, + 'utf8', + function (err, result, bytesRead) { + if (err) { + return callback(err) + } + if (bytesRead === size) { + logger.error( + { file: stateFile, size, bytesRead }, + 'project state file truncated' + ) + } + const array = result ? result.toString().split('\n') : [] + const adjustedLength = Math.max(array.length, 1) + const resourceList = array.slice(0, adjustedLength - 1) + const oldState = array[adjustedLength - 1] + const newState = `stateHash:${state}` + logger.log( + { state, oldState, basePath, stateMatches: newState === oldState }, + 'checking sync state' + ) + if (newState !== oldState) { + return callback( + new Errors.FilesOutOfSyncError( + 'invalid state for incremental update' + ) + ) + } else { + const resources = resourceList.map(path => ({ path })) + callback(null, resources) + } + } + ) + }, + + checkResourceFiles(resources, allFiles, basePath, callback) { + // check the paths are all relative to current directory + const containsRelativePath = resource => { + const dirs = resource.path.split('/') + return dirs.indexOf('..') !== -1 + } + if (resources.some(containsRelativePath)) { + return callback(new Error('relative path in resource file list')) + } + // check if any of the input files are not present in list of files + const seenFiles = new Set(allFiles) + const missingFiles = resources + .map(resource => resource.path) + .filter(path => !seenFiles.has(path)) + if (missingFiles.length > 0) { + logger.err( + { missingFiles, basePath, allFiles, resources }, + 'missing input files for project' + ) + return callback( + new Errors.FilesOutOfSyncError( + 'resource files missing in incremental update' + ) + ) + } else { + callback() + } + }, +} diff --git a/services/clsi/app/js/ResourceWriter.js b/services/clsi/app/js/ResourceWriter.js new file mode 100644 index 0000000000..d7cdc5027f --- /dev/null +++ b/services/clsi/app/js/ResourceWriter.js @@ -0,0 +1,354 @@ +/* eslint-disable + camelcase, + handle-callback-err, + no-return-assign, + no-unused-vars, + no-useless-escape, +*/ +// TODO: This file was created by bulk-decaffeinate. +// Fix any style issues and re-enable lint. +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +let ResourceWriter +const UrlCache = require('./UrlCache') +const Path = require('path') +const fs = require('fs') +const async = require('async') +const OutputFileFinder = require('./OutputFileFinder') +const ResourceStateManager = require('./ResourceStateManager') +const Metrics = require('./Metrics') +const logger = require('logger-sharelatex') +const settings = require('@overleaf/settings') + +const parallelFileDownloads = settings.parallelFileDownloads || 1 + +module.exports = ResourceWriter = { + syncResourcesToDisk(request, basePath, callback) { + if (callback == null) { + callback = function (error, resourceList) {} + } + if (request.syncType === 'incremental') { + logger.log( + { project_id: request.project_id, user_id: request.user_id }, + 'incremental sync' + ) + return ResourceStateManager.checkProjectStateMatches( + request.syncState, + basePath, + function (error, resourceList) { + if (error != null) { + return callback(error) + } + return ResourceWriter._removeExtraneousFiles( + resourceList, + basePath, + function (error, outputFiles, allFiles) { + if (error != null) { + return callback(error) + } + return ResourceStateManager.checkResourceFiles( + resourceList, + allFiles, + basePath, + function (error) { + if (error != null) { + return callback(error) + } + return ResourceWriter.saveIncrementalResourcesToDisk( + request.project_id, + request.resources, + basePath, + function (error) { + if (error != null) { + return callback(error) + } + return callback(null, resourceList) + } + ) + } + ) + } + ) + } + ) + } else { + logger.log( + { project_id: request.project_id, user_id: request.user_id }, + 'full sync' + ) + return this.saveAllResourcesToDisk( + request.project_id, + request.resources, + basePath, + function (error) { + if (error != null) { + return callback(error) + } + return ResourceStateManager.saveProjectState( + request.syncState, + request.resources, + basePath, + function (error) { + if (error != null) { + return callback(error) + } + return callback(null, request.resources) + } + ) + } + ) + } + }, + + saveIncrementalResourcesToDisk(project_id, resources, basePath, callback) { + if (callback == null) { + callback = function (error) {} + } + return this._createDirectory(basePath, error => { + if (error != null) { + return callback(error) + } + const jobs = Array.from(resources).map(resource => + (resource => { + return callback => + this._writeResourceToDisk(project_id, resource, basePath, callback) + })(resource) + ) + return async.parallelLimit(jobs, parallelFileDownloads, callback) + }) + }, + + saveAllResourcesToDisk(project_id, resources, basePath, callback) { + if (callback == null) { + callback = function (error) {} + } + return this._createDirectory(basePath, error => { + if (error != null) { + return callback(error) + } + return this._removeExtraneousFiles(resources, basePath, error => { + if (error != null) { + return callback(error) + } + const jobs = Array.from(resources).map(resource => + (resource => { + return callback => + this._writeResourceToDisk( + project_id, + resource, + basePath, + callback + ) + })(resource) + ) + return async.parallelLimit(jobs, parallelFileDownloads, callback) + }) + }) + }, + + _createDirectory(basePath, callback) { + if (callback == null) { + callback = function (error) {} + } + return fs.mkdir(basePath, function (err) { + if (err != null) { + if (err.code === 'EEXIST') { + return callback() + } else { + logger.log({ err, dir: basePath }, 'error creating directory') + return callback(err) + } + } else { + return callback() + } + }) + }, + + _removeExtraneousFiles(resources, basePath, _callback) { + if (_callback == null) { + _callback = function (error, outputFiles, allFiles) {} + } + const timer = new Metrics.Timer('unlink-output-files') + const callback = function (error, ...result) { + timer.done() + return _callback(error, ...Array.from(result)) + } + + return OutputFileFinder.findOutputFiles( + resources, + basePath, + function (error, outputFiles, allFiles) { + if (error != null) { + return callback(error) + } + + const jobs = [] + for (const file of Array.from(outputFiles || [])) { + ;(function (file) { + const { path } = file + let should_delete = true + if ( + path.match(/^output\./) || + path.match(/\.aux$/) || + path.match(/^cache\//) + ) { + // knitr cache + should_delete = false + } + if (path.match(/^output-.*/)) { + // Tikz cached figures (default case) + should_delete = false + } + if (path.match(/\.(pdf|dpth|md5)$/)) { + // Tikz cached figures (by extension) + should_delete = false + } + if ( + path.match(/\.(pygtex|pygstyle)$/) || + path.match(/(^|\/)_minted-[^\/]+\//) + ) { + // minted files/directory + should_delete = false + } + if ( + path.match(/\.md\.tex$/) || + path.match(/(^|\/)_markdown_[^\/]+\//) + ) { + // markdown files/directory + should_delete = false + } + if (path.match(/-eps-converted-to\.pdf$/)) { + // Epstopdf generated files + should_delete = false + } + if ( + path === 'output.pdf' || + path === 'output.dvi' || + path === 'output.log' || + path === 'output.xdv' || + path === 'output.stdout' || + path === 'output.stderr' + ) { + should_delete = true + } + if (path === 'output.tex') { + // created by TikzManager if present in output files + should_delete = true + } + if (should_delete) { + return jobs.push(callback => + ResourceWriter._deleteFileIfNotDirectory( + Path.join(basePath, path), + callback + ) + ) + } + })(file) + } + + return async.series(jobs, function (error) { + if (error != null) { + return callback(error) + } + return callback(null, outputFiles, allFiles) + }) + } + ) + }, + + _deleteFileIfNotDirectory(path, callback) { + if (callback == null) { + callback = function (error) {} + } + return fs.stat(path, function (error, stat) { + if (error != null && error.code === 'ENOENT') { + return callback() + } else if (error != null) { + logger.err( + { err: error, path }, + 'error stating file in deleteFileIfNotDirectory' + ) + return callback(error) + } else if (stat.isFile()) { + return fs.unlink(path, function (error) { + if (error != null) { + logger.err( + { err: error, path }, + 'error removing file in deleteFileIfNotDirectory' + ) + return callback(error) + } else { + return callback() + } + }) + } else { + return callback() + } + }) + }, + + _writeResourceToDisk(project_id, resource, basePath, callback) { + if (callback == null) { + callback = function (error) {} + } + return ResourceWriter.checkPath( + basePath, + resource.path, + function (error, path) { + if (error != null) { + return callback(error) + } + return fs.mkdir( + Path.dirname(path), + { recursive: true }, + function (error) { + if (error != null) { + return callback(error) + } + // TODO: Don't overwrite file if it hasn't been modified + if (resource.url != null) { + return UrlCache.downloadUrlToFile( + project_id, + resource.url, + path, + resource.modified, + function (err) { + if (err != null) { + logger.err( + { + err, + project_id, + path, + resource_url: resource.url, + modified: resource.modified, + }, + 'error downloading file for resources' + ) + Metrics.inc('download-failed') + } + return callback() + } + ) // try and continue compiling even if http resource can not be downloaded at this time + } else { + fs.writeFile(path, resource.content, callback) + } + } + ) + } + ) + }, + + checkPath(basePath, resourcePath, callback) { + const path = Path.normalize(Path.join(basePath, resourcePath)) + if (path.slice(0, basePath.length + 1) !== basePath + '/') { + return callback(new Error('resource path is outside root directory')) + } else { + return callback(null, path) + } + }, +} diff --git a/services/clsi/app/js/SafeReader.js b/services/clsi/app/js/SafeReader.js new file mode 100644 index 0000000000..760a7725b9 --- /dev/null +++ b/services/clsi/app/js/SafeReader.js @@ -0,0 +1,63 @@ +/* eslint-disable + handle-callback-err, + no-unused-vars, + node/no-deprecated-api, +*/ +// TODO: This file was created by bulk-decaffeinate. +// Fix any style issues and re-enable lint. +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +let SafeReader +const fs = require('fs') +const logger = require('logger-sharelatex') + +module.exports = SafeReader = { + // safely read up to size bytes from a file and return result as a + // string + + readFile(file, size, encoding, callback) { + if (callback == null) { + callback = function (error, result) {} + } + return fs.open(file, 'r', function (err, fd) { + if (err != null && err.code === 'ENOENT') { + return callback() + } + if (err != null) { + return callback(err) + } + + // safely return always closing the file + const callbackWithClose = (err, ...result) => + fs.close(fd, function (err1) { + if (err != null) { + return callback(err) + } + if (err1 != null) { + return callback(err1) + } + return callback(null, ...Array.from(result)) + }) + const buff = Buffer.alloc(size) // fills with zeroes by default + return fs.read( + fd, + buff, + 0, + buff.length, + 0, + function (err, bytesRead, buffer) { + if (err != null) { + return callbackWithClose(err) + } + const result = buffer.toString(encoding, 0, bytesRead) + return callbackWithClose(null, result, bytesRead) + } + ) + }) + }, +} diff --git a/services/clsi/app/js/StaticServerForbidSymlinks.js b/services/clsi/app/js/StaticServerForbidSymlinks.js new file mode 100644 index 0000000000..f810d2b8ab --- /dev/null +++ b/services/clsi/app/js/StaticServerForbidSymlinks.js @@ -0,0 +1,94 @@ +/* eslint-disable + camelcase, + no-cond-assign, + no-unused-vars, + node/no-deprecated-api, +*/ +// TODO: This file was created by bulk-decaffeinate. +// Fix any style issues and re-enable lint. +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * DS103: Rewrite code to no longer use __guard__ + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +let ForbidSymlinks +const Path = require('path') +const fs = require('fs') +const Settings = require('@overleaf/settings') +const logger = require('logger-sharelatex') +const url = require('url') + +module.exports = ForbidSymlinks = function (staticFn, root, options) { + const expressStatic = staticFn(root, options) + const basePath = Path.resolve(root) + return function (req, res, next) { + let file, project_id, result + const path = __guard__(url.parse(req.url), x => x.pathname) + // check that the path is of the form /project_id_or_name/path/to/file.log + if ((result = path.match(/^\/?([a-zA-Z0-9_-]+)\/(.*)/))) { + project_id = result[1] + file = result[2] + } else { + logger.warn({ path }, 'unrecognized file request') + return res.sendStatus(404) + } + // check that the file does not use a relative path + for (const dir of Array.from(file.split('/'))) { + if (dir === '..') { + logger.warn({ path }, 'attempt to use a relative path') + return res.sendStatus(404) + } + } + // check that the requested path is normalized + const requestedFsPath = `${basePath}/${project_id}/${file}` + if (requestedFsPath !== Path.normalize(requestedFsPath)) { + logger.error( + { path: requestedFsPath }, + 'requestedFsPath is not normalized' + ) + return res.sendStatus(404) + } + // check that the requested path is not a symlink + return fs.realpath(requestedFsPath, function (err, realFsPath) { + if (err != null) { + if (err.code === 'ENOENT') { + return res.sendStatus(404) + } else { + logger.error( + { + err, + requestedFsPath, + realFsPath, + path: req.params[0], + project_id: req.params.project_id, + }, + 'error checking file access' + ) + return res.sendStatus(500) + } + } else if (requestedFsPath !== realFsPath) { + logger.warn( + { + requestedFsPath, + realFsPath, + path: req.params[0], + project_id: req.params.project_id, + }, + 'trying to access a different file (symlink), aborting' + ) + return res.sendStatus(404) + } else { + return expressStatic(req, res, next) + } + }) + } +} + +function __guard__(value, transform) { + return typeof value !== 'undefined' && value !== null + ? transform(value) + : undefined +} diff --git a/services/clsi/app/js/TikzManager.js b/services/clsi/app/js/TikzManager.js new file mode 100644 index 0000000000..ac62ddac5a --- /dev/null +++ b/services/clsi/app/js/TikzManager.js @@ -0,0 +1,101 @@ +/* eslint-disable + handle-callback-err, + no-unused-vars, +*/ +// TODO: This file was created by bulk-decaffeinate. +// Fix any style issues and re-enable lint. +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +let TikzManager +const fs = require('fs') +const Path = require('path') +const ResourceWriter = require('./ResourceWriter') +const SafeReader = require('./SafeReader') +const logger = require('logger-sharelatex') + +// for \tikzexternalize or pstool to work the main file needs to match the +// jobname. Since we set the -jobname to output, we have to create a +// copy of the main file as 'output.tex'. + +module.exports = TikzManager = { + checkMainFile(compileDir, mainFile, resources, callback) { + // if there's already an output.tex file, we don't want to touch it + if (callback == null) { + callback = function (error, needsMainFile) {} + } + for (const resource of Array.from(resources)) { + if (resource.path === 'output.tex') { + logger.log({ compileDir, mainFile }, 'output.tex already in resources') + return callback(null, false) + } + } + // if there's no output.tex, see if we are using tikz/pgf or pstool in the main file + return ResourceWriter.checkPath( + compileDir, + mainFile, + function (error, path) { + if (error != null) { + return callback(error) + } + return SafeReader.readFile( + path, + 65536, + 'utf8', + function (error, content) { + if (error != null) { + return callback(error) + } + const usesTikzExternalize = + (content != null + ? content.indexOf('\\tikzexternalize') + : undefined) >= 0 + const usesPsTool = + (content != null ? content.indexOf('{pstool}') : undefined) >= 0 + logger.log( + { compileDir, mainFile, usesTikzExternalize, usesPsTool }, + 'checked for packages needing main file as output.tex' + ) + const needsMainFile = usesTikzExternalize || usesPsTool + return callback(null, needsMainFile) + } + ) + } + ) + }, + + injectOutputFile(compileDir, mainFile, callback) { + if (callback == null) { + callback = function (error) {} + } + return ResourceWriter.checkPath( + compileDir, + mainFile, + function (error, path) { + if (error != null) { + return callback(error) + } + return fs.readFile(path, 'utf8', function (error, content) { + if (error != null) { + return callback(error) + } + logger.log( + { compileDir, mainFile }, + 'copied file to output.tex as project uses packages which require it' + ) + // use wx flag to ensure that output file does not already exist + return fs.writeFile( + Path.join(compileDir, 'output.tex'), + content, + { flag: 'wx' }, + callback + ) + }) + } + ) + }, +} diff --git a/services/clsi/app/js/UrlCache.js b/services/clsi/app/js/UrlCache.js new file mode 100644 index 0000000000..70535b6155 --- /dev/null +++ b/services/clsi/app/js/UrlCache.js @@ -0,0 +1,281 @@ +/* eslint-disable + camelcase, + handle-callback-err, + no-return-assign, +*/ +// TODO: This file was created by bulk-decaffeinate. +// Fix any style issues and re-enable lint. +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +let UrlCache +const db = require('./db') +const dbQueue = require('./DbQueue') +const UrlFetcher = require('./UrlFetcher') +const Settings = require('@overleaf/settings') +const crypto = require('crypto') +const fs = require('fs') +const logger = require('logger-sharelatex') +const async = require('async') +const Metrics = require('./Metrics') + +module.exports = UrlCache = { + downloadUrlToFile(project_id, url, destPath, lastModified, callback) { + if (callback == null) { + callback = function (error) {} + } + return UrlCache._ensureUrlIsInCache( + project_id, + url, + lastModified, + (error, pathToCachedUrl) => { + if (error != null) { + return callback(error) + } + return fs.copyFile(pathToCachedUrl, destPath, function (error) { + if (error != null) { + logger.error( + { err: error, from: pathToCachedUrl, to: destPath }, + 'error copying file from cache' + ) + return UrlCache._clearUrlDetails(project_id, url, () => + callback(error) + ) + } else { + return callback(error) + } + }) + } + ) + }, + + clearProject(project_id, callback) { + if (callback == null) { + callback = function (error) {} + } + return UrlCache._findAllUrlsInProject(project_id, function (error, urls) { + logger.log( + { project_id, url_count: urls.length }, + 'clearing project URLs' + ) + if (error != null) { + return callback(error) + } + const jobs = Array.from(urls || []).map(url => + ( + url => callback => + UrlCache._clearUrlFromCache(project_id, url, function (error) { + if (error != null) { + logger.error( + { err: error, project_id, url }, + 'error clearing project URL' + ) + } + return callback() + }) + )(url) + ) + return async.series(jobs, callback) + }) + }, + + _ensureUrlIsInCache(project_id, url, lastModified, callback) { + if (callback == null) { + callback = function (error, pathOnDisk) {} + } + if (lastModified != null) { + // MYSQL only stores dates to an accuracy of a second but the incoming lastModified might have milliseconds. + // So round down to seconds + lastModified = new Date(Math.floor(lastModified.getTime() / 1000) * 1000) + } + return UrlCache._doesUrlNeedDownloading( + project_id, + url, + lastModified, + (error, needsDownloading) => { + if (error != null) { + return callback(error) + } + if (needsDownloading) { + logger.log({ url, lastModified }, 'downloading URL') + return UrlFetcher.pipeUrlToFileWithRetry( + url, + UrlCache._cacheFilePathForUrl(project_id, url), + error => { + if (error != null) { + return callback(error) + } + return UrlCache._updateOrCreateUrlDetails( + project_id, + url, + lastModified, + error => { + if (error != null) { + return callback(error) + } + return callback( + null, + UrlCache._cacheFilePathForUrl(project_id, url) + ) + } + ) + } + ) + } else { + logger.log({ url, lastModified }, 'URL is up to date in cache') + return callback(null, UrlCache._cacheFilePathForUrl(project_id, url)) + } + } + ) + }, + + _doesUrlNeedDownloading(project_id, url, lastModified, callback) { + if (callback == null) { + callback = function (error, needsDownloading) {} + } + if (lastModified == null) { + return callback(null, true) + } + return UrlCache._findUrlDetails( + project_id, + url, + function (error, urlDetails) { + if (error != null) { + return callback(error) + } + if ( + urlDetails == null || + urlDetails.lastModified == null || + urlDetails.lastModified.getTime() < lastModified.getTime() + ) { + return callback(null, true) + } else { + return callback(null, false) + } + } + ) + }, + + _cacheFileNameForUrl(project_id, url) { + return project_id + ':' + crypto.createHash('md5').update(url).digest('hex') + }, + + _cacheFilePathForUrl(project_id, url) { + return `${Settings.path.clsiCacheDir}/${UrlCache._cacheFileNameForUrl( + project_id, + url + )}` + }, + + _clearUrlFromCache(project_id, url, callback) { + if (callback == null) { + callback = function (error) {} + } + return UrlCache._clearUrlDetails(project_id, url, function (error) { + if (error != null) { + return callback(error) + } + return UrlCache._deleteUrlCacheFromDisk( + project_id, + url, + function (error) { + if (error != null) { + return callback(error) + } + return callback(null) + } + ) + }) + }, + + _deleteUrlCacheFromDisk(project_id, url, callback) { + if (callback == null) { + callback = function (error) {} + } + return fs.unlink( + UrlCache._cacheFilePathForUrl(project_id, url), + function (error) { + if (error != null && error.code !== 'ENOENT') { + // no error if the file isn't present + return callback(error) + } else { + return callback() + } + } + ) + }, + + _findUrlDetails(project_id, url, callback) { + if (callback == null) { + callback = function (error, urlDetails) {} + } + const timer = new Metrics.Timer('db-find-url-details') + const job = cb => + db.UrlCache.findOne({ where: { url, project_id } }) + .then(urlDetails => cb(null, urlDetails)) + .error(cb) + dbQueue.queue.push(job, (error, urlDetails) => { + timer.done() + callback(error, urlDetails) + }) + }, + + _updateOrCreateUrlDetails(project_id, url, lastModified, callback) { + if (callback == null) { + callback = function (error) {} + } + const timer = new Metrics.Timer('db-update-or-create-url-details') + const job = cb => + db.UrlCache.findOrCreate({ where: { url, project_id } }) + .spread((urlDetails, created) => + urlDetails + .update({ lastModified }) + .then(() => cb()) + .error(cb) + ) + .error(cb) + dbQueue.queue.push(job, error => { + timer.done() + callback(error) + }) + }, + + _clearUrlDetails(project_id, url, callback) { + if (callback == null) { + callback = function (error) {} + } + const timer = new Metrics.Timer('db-clear-url-details') + const job = cb => + db.UrlCache.destroy({ where: { url, project_id } }) + .then(() => cb(null)) + .error(cb) + dbQueue.queue.push(job, error => { + timer.done() + callback(error) + }) + }, + + _findAllUrlsInProject(project_id, callback) { + if (callback == null) { + callback = function (error, urls) {} + } + const timer = new Metrics.Timer('db-find-urls-in-project') + const job = cb => + db.UrlCache.findAll({ where: { project_id } }) + .then(urlEntries => + cb( + null, + urlEntries.map(entry => entry.url) + ) + ) + .error(cb) + dbQueue.queue.push(job, (err, urls) => { + timer.done() + callback(err, urls) + }) + }, +} diff --git a/services/clsi/app/js/UrlFetcher.js b/services/clsi/app/js/UrlFetcher.js new file mode 100644 index 0000000000..4d3c3d5ebe --- /dev/null +++ b/services/clsi/app/js/UrlFetcher.js @@ -0,0 +1,131 @@ +/* eslint-disable + handle-callback-err, + no-return-assign, + no-unused-vars, + node/no-deprecated-api, +*/ +// TODO: This file was created by bulk-decaffeinate. +// Fix any style issues and re-enable lint. +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +let UrlFetcher +const request = require('request').defaults({ jar: false }) +const fs = require('fs') +const logger = require('logger-sharelatex') +const settings = require('@overleaf/settings') +const URL = require('url') +const async = require('async') + +const oneMinute = 60 * 1000 + +module.exports = UrlFetcher = { + pipeUrlToFileWithRetry(url, filePath, callback) { + const doDownload = function (cb) { + UrlFetcher.pipeUrlToFile(url, filePath, cb) + } + async.retry(3, doDownload, callback) + }, + + pipeUrlToFile(url, filePath, _callback) { + if (_callback == null) { + _callback = function (error) {} + } + const callbackOnce = function (error) { + if (timeoutHandler != null) { + clearTimeout(timeoutHandler) + } + _callback(error) + return (_callback = function () {}) + } + + const u = URL.parse(url) + if ( + settings.filestoreDomainOveride && + u.host !== settings.apis.clsiPerf.host + ) { + url = `${settings.filestoreDomainOveride}${u.path}` + } + var timeoutHandler = setTimeout( + function () { + timeoutHandler = null + logger.error({ url, filePath }, 'Timed out downloading file to cache') + return callbackOnce( + new Error(`Timed out downloading file to cache ${url}`) + ) + }, + // FIXME: maybe need to close fileStream here + 3 * oneMinute + ) + + logger.log({ url, filePath }, 'started downloading url to cache') + const urlStream = request.get({ url, timeout: oneMinute }) + urlStream.pause() // stop data flowing until we are ready + + // attach handlers before setting up pipes + urlStream.on('error', function (error) { + logger.error({ err: error, url, filePath }, 'error downloading url') + return callbackOnce( + error || new Error(`Something went wrong downloading the URL ${url}`) + ) + }) + + urlStream.on('end', () => + logger.log({ url, filePath }, 'finished downloading file into cache') + ) + + return urlStream.on('response', function (res) { + if (res.statusCode >= 200 && res.statusCode < 300) { + const fileStream = fs.createWriteStream(filePath) + + // attach handlers before setting up pipes + fileStream.on('error', function (error) { + logger.error( + { err: error, url, filePath }, + 'error writing file into cache' + ) + return fs.unlink(filePath, function (err) { + if (err != null) { + logger.err({ err, filePath }, 'error deleting file from cache') + } + return callbackOnce(error) + }) + }) + + fileStream.on('finish', function () { + logger.log({ url, filePath }, 'finished writing file into cache') + return callbackOnce() + }) + + fileStream.on('pipe', () => + logger.log({ url, filePath }, 'piping into filestream') + ) + + urlStream.pipe(fileStream) + return urlStream.resume() // now we are ready to handle the data + } else { + logger.error( + { statusCode: res.statusCode, url, filePath }, + 'unexpected status code downloading url to cache' + ) + // https://nodejs.org/api/http.html#http_class_http_clientrequest + // If you add a 'response' event handler, then you must consume + // the data from the response object, either by calling + // response.read() whenever there is a 'readable' event, or by + // adding a 'data' handler, or by calling the .resume() + // method. Until the data is consumed, the 'end' event will not + // fire. Also, until the data is read it will consume memory + // that can eventually lead to a 'process out of memory' error. + urlStream.resume() // discard the data + return callbackOnce( + new Error( + `URL returned non-success status code: ${res.statusCode} ${url}` + ) + ) + } + }) + }, +} diff --git a/services/clsi/app/js/db.js b/services/clsi/app/js/db.js new file mode 100644 index 0000000000..856f1da08b --- /dev/null +++ b/services/clsi/app/js/db.js @@ -0,0 +1,67 @@ +/* eslint-disable + no-console, +*/ +// TODO: This file was created by bulk-decaffeinate. +// Fix any style issues and re-enable lint. +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const Sequelize = require('sequelize') +const Settings = require('@overleaf/settings') +const _ = require('lodash') +const logger = require('logger-sharelatex') + +const options = _.extend({ logging: false }, Settings.mysql.clsi) + +logger.log({ dbPath: Settings.mysql.clsi.storage }, 'connecting to db') + +const sequelize = new Sequelize( + Settings.mysql.clsi.database, + Settings.mysql.clsi.username, + Settings.mysql.clsi.password, + options +) + +if (Settings.mysql.clsi.dialect === 'sqlite') { + logger.log('running PRAGMA journal_mode=WAL;') + sequelize.query('PRAGMA journal_mode=WAL;') + sequelize.query('PRAGMA synchronous=OFF;') + sequelize.query('PRAGMA read_uncommitted = true;') +} + +module.exports = { + UrlCache: sequelize.define( + 'UrlCache', + { + url: Sequelize.STRING, + project_id: Sequelize.STRING, + lastModified: Sequelize.DATE, + }, + { + indexes: [{ fields: ['url', 'project_id'] }, { fields: ['project_id'] }], + } + ), + + Project: sequelize.define( + 'Project', + { + project_id: { type: Sequelize.STRING, primaryKey: true }, + lastAccessed: Sequelize.DATE, + }, + { + indexes: [{ fields: ['lastAccessed'] }], + } + ), + + op: Sequelize.Op, + + sync() { + logger.log({ dbPath: Settings.mysql.clsi.storage }, 'syncing db schema') + return sequelize + .sync() + .then(() => logger.log('db sync complete')) + .catch(err => console.log(err, 'error syncing')) + }, +} diff --git a/services/clsi/app/lib/pdfjs/FSPdfManager.js b/services/clsi/app/lib/pdfjs/FSPdfManager.js new file mode 100644 index 0000000000..692576b2ce --- /dev/null +++ b/services/clsi/app/lib/pdfjs/FSPdfManager.js @@ -0,0 +1,43 @@ +const { PDFDocument } = require('pdfjs-dist/lib/core/document') +const { LocalPdfManager } = require('pdfjs-dist/lib/core/pdf_manager') +const { MissingDataException } = require('pdfjs-dist/lib/core/core_utils') +const { FSStream } = require('./FSStream') + +class FSPdfManager extends LocalPdfManager { + constructor(docId, { fh, size, checkDeadline }) { + const nonEmptyDummyBuffer = Buffer.alloc(1, 0) + super(docId, nonEmptyDummyBuffer) + this.stream = new FSStream(fh, 0, size, null, null, checkDeadline) + this.pdfDocument = new PDFDocument(this, this.stream) + } + + async ensure(obj, prop, args) { + try { + const value = obj[prop] + if (typeof value === 'function') { + return value.apply(obj, args) + } + return value + } catch (ex) { + if (!(ex instanceof MissingDataException)) { + throw ex + } + await this.requestRange(ex.begin, ex.end) + return this.ensure(obj, prop, args) + } + } + + requestRange(begin, end) { + return this.stream.requestRange(begin, end) + } + + requestLoadedStream() {} + + onLoadedStream() {} + + terminate(reason) {} +} + +module.exports = { + FSPdfManager, +} diff --git a/services/clsi/app/lib/pdfjs/FSStream.js b/services/clsi/app/lib/pdfjs/FSStream.js new file mode 100644 index 0000000000..e3e3ac0243 --- /dev/null +++ b/services/clsi/app/lib/pdfjs/FSStream.js @@ -0,0 +1,148 @@ +const { Stream } = require('pdfjs-dist/lib/core/stream') +const { MissingDataException } = require('pdfjs-dist/lib/core/core_utils') + +const BUF_SIZE = 1024 // read from the file in 1024 byte pages + +class FSStream extends Stream { + constructor(fh, start, length, dict, cachedBytes, checkDeadline) { + const nonEmptyDummyBuffer = Buffer.alloc(1, 0) + super(nonEmptyDummyBuffer, start, length, dict) + delete this.bytes + this.fh = fh + this.checkDeadline = checkDeadline + this.cachedBytes = cachedBytes || [] + } + + get length() { + return this.end - this.start + } + + get isEmpty() { + return this.length === 0 + } + + // Manage cached reads from the file + + requestRange(begin, end) { + this.checkDeadline(`request range ${begin} - ${end}`) + // expand small ranges to read a larger amount + if (end - begin < BUF_SIZE) { + end = begin + BUF_SIZE + } + end = Math.min(end, this.length) + // keep a cache of previous reads with {begin,end,buffer} values + const result = { + begin: begin, + end: end, + buffer: Buffer.alloc(end - begin, 0), + } + this.cachedBytes.push(result) + return this.fh.read(result.buffer, 0, end - begin, begin) + } + + _ensureGetPos(pos) { + const found = this.cachedBytes.find(x => { + return x.begin <= pos && pos < x.end + }) + if (!found) { + throw new MissingDataException(pos, pos + 1) + } + return found + } + + _ensureGetRange(begin, end) { + end = Math.min(end, this.length) // BG: handle overflow case + const found = this.cachedBytes.find(x => { + return x.begin <= begin && end <= x.end + }) + if (!found) { + throw new MissingDataException(begin, end) + } + return found + } + + _readByte(found, pos) { + return found.buffer[pos - found.begin] + } + + _readBytes(found, pos, end) { + return found.buffer.subarray(pos - found.begin, end - found.begin) + } + + // handle accesses to the bytes + + ensureByte(pos) { + this._ensureGetPos(pos) // may throw a MissingDataException + } + + getByte() { + const pos = this.pos + if (this.pos >= this.end) { + return -1 + } + const found = this._ensureGetPos(pos) + return this._readByte(found, this.pos++) + } + + // BG: for a range, end is not included (see Buffer.subarray for example) + + ensureBytes(length, forceClamped = false) { + const pos = this.pos + this._ensureGetRange(pos, pos + length) + } + + getBytes(length, forceClamped = false) { + const pos = this.pos + const strEnd = this.end + + const found = this._ensureGetRange(pos, pos + length) + if (!length) { + const subarray = this._readBytes(found, pos, strEnd) + // `this.bytes` is always a `Uint8Array` here. + return forceClamped ? new Uint8ClampedArray(subarray) : subarray + } + let end = pos + length + if (end > strEnd) { + end = strEnd + } + this.pos = end + const subarray = this._readBytes(found, pos, end) + // `this.bytes` is always a `Uint8Array` here. + return forceClamped ? new Uint8ClampedArray(subarray) : subarray + } + + getByteRange() { + // BG: this isn't needed as far as I can tell + throw new Error('not implemented') + } + + reset() { + this.pos = this.start + } + + moveStart() { + this.start = this.pos + } + + makeSubStream(start, length, dict = null) { + this.checkDeadline(`make sub stream start=${start}/length=${length}`) + // BG: had to add this check for null length, it is being called with only + // the start value at one point in the xref decoding. The intent is clear + // enough + // - a null length means "to the end of the file" -- not sure how it is + // working in the existing pdfjs code without this. + if (!length) { + length = this.end - start + } + return new FSStream( + this.fh, + start, + length, + dict, + this.cachedBytes, + this.checkDeadline + ) + } +} + +module.exports = { FSStream } diff --git a/services/clsi/app/lib/pdfjs/parseXrefTable.js b/services/clsi/app/lib/pdfjs/parseXrefTable.js new file mode 100644 index 0000000000..1ecfd2397d --- /dev/null +++ b/services/clsi/app/lib/pdfjs/parseXrefTable.js @@ -0,0 +1,27 @@ +const fs = require('fs') +const { FSPdfManager } = require('./FSPdfManager') + +async function parseXrefTable(path, size, checkDeadline) { + if (size === 0) { + return [] + } + + const file = await fs.promises.open(path) + try { + const manager = new FSPdfManager(0, { fh: file, size, checkDeadline }) + + await manager.ensureDoc('checkHeader') + checkDeadline('pdfjs: after checkHeader') + await manager.ensureDoc('parseStartXRef') + checkDeadline('pdfjs: after parseStartXRef') + await manager.ensureDoc('parse') + checkDeadline('pdfjs: after parse') + return manager.pdfDocument.catalog.xref.entries + } finally { + file.close() + } +} + +module.exports = { + parseXrefTable, +} diff --git a/services/clsi/bin/.gitignore b/services/clsi/bin/.gitignore new file mode 100644 index 0000000000..e69de29bb2 diff --git a/services/clsi/bin/acceptance_test b/services/clsi/bin/acceptance_test new file mode 100644 index 0000000000..fd2e5137b5 --- /dev/null +++ b/services/clsi/bin/acceptance_test @@ -0,0 +1,4 @@ +#!/bin/bash +set -e; +MOCHA="node_modules/.bin/mocha --recursive --reporter spec --timeout 15000" +$MOCHA "$@" diff --git a/services/clsi/bin/synctex b/services/clsi/bin/synctex new file mode 100755 index 0000000000..89b8cc6988 Binary files /dev/null and b/services/clsi/bin/synctex differ diff --git a/services/clsi/buildscript.txt b/services/clsi/buildscript.txt new file mode 100644 index 0000000000..9b755dfe46 --- /dev/null +++ b/services/clsi/buildscript.txt @@ -0,0 +1,9 @@ +clsi +--data-dirs=cache,compiles,db,output +--dependencies= +--docker-repos=gcr.io/overleaf-ops +--env-add=ENABLE_PDF_CACHING="true" +--env-pass-through=TEXLIVE_IMAGE +--node-version=12.22.3 +--public-repo=True +--script-version=3.11.0 diff --git a/services/clsi/config/settings.defaults.js b/services/clsi/config/settings.defaults.js new file mode 100644 index 0000000000..e36334df1b --- /dev/null +++ b/services/clsi/config/settings.defaults.js @@ -0,0 +1,170 @@ +const Path = require('path') + +module.exports = { + // Options are passed to Sequelize. + // See http://sequelizejs.com/documentation#usage-options for details + mysql: { + clsi: { + database: 'clsi', + username: 'clsi', + dialect: 'sqlite', + storage: + process.env.SQLITE_PATH || Path.resolve(__dirname, '../db/db.sqlite'), + pool: { + max: 1, + min: 1, + }, + retry: { + max: 10, + }, + }, + }, + + compileSizeLimit: process.env.COMPILE_SIZE_LIMIT || '7mb', + + processLifespanLimitMs: + parseInt(process.env.PROCESS_LIFE_SPAN_LIMIT_MS) || 60 * 60 * 24 * 1000 * 2, + + catchErrors: process.env.CATCH_ERRORS === 'true', + + path: { + compilesDir: Path.resolve(__dirname, '../compiles'), + outputDir: Path.resolve(__dirname, '../output'), + clsiCacheDir: Path.resolve(__dirname, '../cache'), + synctexBaseDir(projectId) { + return Path.join(this.compilesDir, projectId) + }, + }, + + internal: { + clsi: { + port: 3013, + host: process.env.LISTEN_ADDRESS || 'localhost', + }, + + load_balancer_agent: { + report_load: true, + load_port: 3048, + local_port: 3049, + }, + }, + apis: { + clsi: { + url: `http://${process.env.CLSI_HOST || 'localhost'}:3013`, + }, + clsiPerf: { + host: `${process.env.CLSI_PERF_HOST || 'localhost'}:${ + process.env.CLSI_PERF_PORT || '3043' + }`, + }, + }, + + smokeTest: process.env.SMOKE_TEST || false, + project_cache_length_ms: 1000 * 60 * 60 * 24, + parallelFileDownloads: process.env.FILESTORE_PARALLEL_FILE_DOWNLOADS || 1, + parallelSqlQueryLimit: process.env.FILESTORE_PARALLEL_SQL_QUERY_LIMIT || 1, + filestoreDomainOveride: process.env.FILESTORE_DOMAIN_OVERRIDE, + texliveImageNameOveride: process.env.TEX_LIVE_IMAGE_NAME_OVERRIDE, + texliveOpenoutAny: process.env.TEXLIVE_OPENOUT_ANY, + sentry: { + dsn: process.env.SENTRY_DSN, + }, + + enablePdfCaching: process.env.ENABLE_PDF_CACHING === 'true', + enablePdfCachingDark: process.env.ENABLE_PDF_CACHING_DARK === 'true', + pdfCachingMinChunkSize: + parseInt(process.env.PDF_CACHING_MIN_CHUNK_SIZE, 10) || 1024, + pdfCachingMaxProcessingTime: + parseInt(process.env.PDF_CACHING_MAX_PROCESSING_TIME, 10) || 10 * 1000, +} + +if (process.env.ALLOWED_COMPILE_GROUPS) { + try { + module.exports.allowedCompileGroups = + process.env.ALLOWED_COMPILE_GROUPS.split(' ') + } catch (error) { + console.error(error, 'could not apply allowed compile group setting') + process.exit(1) + } +} + +if (process.env.DOCKER_RUNNER) { + let seccompProfilePath + module.exports.clsi = { + dockerRunner: process.env.DOCKER_RUNNER === 'true', + docker: { + runtime: process.env.DOCKER_RUNTIME, + image: + process.env.TEXLIVE_IMAGE || 'quay.io/sharelatex/texlive-full:2017.1', + env: { + HOME: '/tmp', + }, + socketPath: '/var/run/docker.sock', + user: process.env.TEXLIVE_IMAGE_USER || 'tex', + }, + optimiseInDocker: true, + expireProjectAfterIdleMs: 24 * 60 * 60 * 1000, + checkProjectsIntervalMs: 10 * 60 * 1000, + } + + try { + // Override individual docker settings using path-based keys, e.g.: + // compileGroupDockerConfigs = { + // priority: { 'HostConfig.CpuShares': 100 } + // beta: { 'dotted.path.here', 'value'} + // } + const compileGroupConfig = JSON.parse( + process.env.COMPILE_GROUP_DOCKER_CONFIGS || '{}' + ) + // Automatically clean up wordcount and synctex containers + const defaultCompileGroupConfig = { + wordcount: { 'HostConfig.AutoRemove': true }, + synctex: { 'HostConfig.AutoRemove': true }, + } + module.exports.clsi.docker.compileGroupConfig = Object.assign( + defaultCompileGroupConfig, + compileGroupConfig + ) + } catch (error) { + console.error(error, 'could not apply compile group docker configs') + process.exit(1) + } + + try { + seccompProfilePath = Path.resolve(__dirname, '../seccomp/clsi-profile.json') + module.exports.clsi.docker.seccomp_profile = JSON.stringify( + JSON.parse(require('fs').readFileSync(seccompProfilePath)) + ) + } catch (error) { + console.error( + error, + `could not load seccomp profile from ${seccompProfilePath}` + ) + process.exit(1) + } + + if (process.env.APPARMOR_PROFILE) { + try { + module.exports.clsi.docker.apparmor_profile = process.env.APPARMOR_PROFILE + } catch (error) { + console.error(error, 'could not apply apparmor profile setting') + process.exit(1) + } + } + + if (process.env.ALLOWED_IMAGES) { + try { + module.exports.clsi.docker.allowedImages = + process.env.ALLOWED_IMAGES.split(' ') + } catch (error) { + console.error(error, 'could not apply allowed images setting') + process.exit(1) + } + } + + module.exports.path.synctexBaseDir = () => '/compile' + + module.exports.path.sandboxedCompilesHostDir = process.env.COMPILES_HOST_DIR + + module.exports.path.synctexBinHostPath = process.env.SYNCTEX_BIN_HOST_PATH +} diff --git a/services/clsi/db/.gitignore b/services/clsi/db/.gitignore new file mode 100644 index 0000000000..d6b7ef32c8 --- /dev/null +++ b/services/clsi/db/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/services/clsi/debug b/services/clsi/debug new file mode 100755 index 0000000000..fcc371c36e --- /dev/null +++ b/services/clsi/debug @@ -0,0 +1,5 @@ +#!/bin/bash +echo "hello world" +sleep 3 +echo "awake" +/opt/synctex pdf /compile/output.pdf 1 100 200 diff --git a/services/clsi/docker-compose-config.yml b/services/clsi/docker-compose-config.yml new file mode 100644 index 0000000000..0c141eaa18 --- /dev/null +++ b/services/clsi/docker-compose-config.yml @@ -0,0 +1,34 @@ +version: "2.3" + +services: + dev: + environment: + ALLOWED_IMAGES: "quay.io/sharelatex/texlive-full:2017.1" + TEXLIVE_IMAGE: quay.io/sharelatex/texlive-full:2017.1 + TEXLIVE_IMAGE_USER: "tex" + SHARELATEX_CONFIG: /app/config/settings.defaults.js + DOCKER_RUNNER: "true" + COMPILES_HOST_DIR: $PWD/compiles + SYNCTEX_BIN_HOST_PATH: $PWD/bin/synctex + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - ./compiles:/app/compiles + - ./cache:/app/cache + - ./bin/synctex:/app/bin/synctex + + + ci: + environment: + ALLOWED_IMAGES: ${TEXLIVE_IMAGE} + TEXLIVE_IMAGE: quay.io/sharelatex/texlive-full:2017.1 + TEXLIVE_IMAGE_USER: "tex" + SHARELATEX_CONFIG: /app/config/settings.defaults.js + DOCKER_RUNNER: "true" + COMPILES_HOST_DIR: $PWD/compiles + SYNCTEX_BIN_HOST_PATH: $PWD/bin/synctex + SQLITE_PATH: /app/compiles/db.sqlite + volumes: + - /var/run/docker.sock:/var/run/docker.sock:rw + - ./compiles:/app/compiles + - ./cache:/app/cache + - ./bin/synctex:/app/bin/synctex diff --git a/services/clsi/docker-compose.ci.yml b/services/clsi/docker-compose.ci.yml new file mode 100644 index 0000000000..245059ad98 --- /dev/null +++ b/services/clsi/docker-compose.ci.yml @@ -0,0 +1,42 @@ +# This file was auto-generated, do not edit it directly. +# Instead run bin/update_build_scripts from +# https://github.com/sharelatex/sharelatex-dev-environment + +version: "2.3" + +services: + test_unit: + image: ci/$PROJECT_NAME:$BRANCH_NAME-$BUILD_NUMBER + command: npm run test:unit:_run + environment: + NODE_ENV: test + NODE_OPTIONS: "--unhandled-rejections=strict" + + + test_acceptance: + build: . + image: ci/$PROJECT_NAME:$BRANCH_NAME-$BUILD_NUMBER + extends: + file: docker-compose-config.yml + service: ci + environment: + ELASTIC_SEARCH_DSN: es:9200 + REDIS_HOST: redis + QUEUES_REDIS_HOST: redis + MONGO_HOST: mongo + POSTGRES_HOST: postgres + MOCHA_GREP: ${MOCHA_GREP} + NODE_ENV: test + NODE_OPTIONS: "--unhandled-rejections=strict" + TEXLIVE_IMAGE: + ENABLE_PDF_CACHING: "true" + command: npm run test:acceptance:_run + + + tar: + build: . + image: ci/$PROJECT_NAME:$BRANCH_NAME-$BUILD_NUMBER + volumes: + - ./:/tmp/build/ + command: tar -czf /tmp/build/build.tar.gz --exclude=build.tar.gz --exclude-vcs . + user: root diff --git a/services/clsi/docker-compose.yml b/services/clsi/docker-compose.yml new file mode 100644 index 0000000000..ee68a7c0ee --- /dev/null +++ b/services/clsi/docker-compose.yml @@ -0,0 +1,43 @@ +# This file was auto-generated, do not edit it directly. +# Instead run bin/update_build_scripts from +# https://github.com/sharelatex/sharelatex-dev-environment + +version: "2.3" + +services: + test_unit: + build: + context: . + target: base + volumes: + - .:/app + working_dir: /app + environment: + MOCHA_GREP: ${MOCHA_GREP} + NODE_ENV: test + NODE_OPTIONS: "--unhandled-rejections=strict" + command: npm run --silent test:unit + + test_acceptance: + build: + context: . + target: base + volumes: + - .:/app + working_dir: /app + extends: + file: docker-compose-config.yml + service: dev + environment: + ELASTIC_SEARCH_DSN: es:9200 + REDIS_HOST: redis + QUEUES_REDIS_HOST: redis + MONGO_HOST: mongo + POSTGRES_HOST: postgres + MOCHA_GREP: ${MOCHA_GREP} + LOG_LEVEL: ERROR + NODE_ENV: test + NODE_OPTIONS: "--unhandled-rejections=strict" + ENABLE_PDF_CACHING: "true" + command: npm run --silent test:acceptance + diff --git a/services/clsi/entrypoint.sh b/services/clsi/entrypoint.sh new file mode 100755 index 0000000000..b05a773ea1 --- /dev/null +++ b/services/clsi/entrypoint.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +docker --version >&2 + +# add the node user to the docker group on the host +DOCKER_GROUP=$(stat -c '%g' /var/run/docker.sock) +groupadd --non-unique --gid ${DOCKER_GROUP} dockeronhost +usermod -aG dockeronhost node + +# compatibility: initial volume setup +mkdir -p /app/cache && chown node:node /app/cache +mkdir -p /app/compiles && chown node:node /app/compiles +mkdir -p /app/db && chown node:node /app/db +mkdir -p /app/output && chown node:node /app/output + +# make synctex available for remount in compiles +cp /app/bin/synctex /app/bin/synctex-mount/synctex + +exec runuser -u node -- "$@" diff --git a/services/clsi/install_deps.sh b/services/clsi/install_deps.sh new file mode 100755 index 0000000000..f0cc386ff5 --- /dev/null +++ b/services/clsi/install_deps.sh @@ -0,0 +1,24 @@ +#!/bin/bash +set -ex + +apt-get update +apt-get install -y \ + apt-transport-https \ + ca-certificates \ + curl \ + gnupg \ + lsb-release + +curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg +echo \ + "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian \ + $(lsb_release -cs) stable" \ + > /etc/apt/sources.list.d/docker.list +apt-get update + +apt-get install -y \ + docker-ce-cli \ + poppler-utils \ + ghostscript \ + +rm -rf /var/lib/apt/lists/* diff --git a/services/clsi/kube.yaml b/services/clsi/kube.yaml new file mode 100644 index 0000000000..d3fb04291e --- /dev/null +++ b/services/clsi/kube.yaml @@ -0,0 +1,41 @@ +apiVersion: v1 +kind: Service +metadata: + name: clsi + namespace: default +spec: + type: LoadBalancer + ports: + - port: 80 + protocol: TCP + targetPort: 80 + selector: + run: clsi +--- +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: clsi + namespace: default +spec: + replicas: 2 + template: + metadata: + labels: + run: clsi + spec: + containers: + - name: clsi + image: gcr.io/henry-terraform-admin/clsi + imagePullPolicy: Always + readinessProbe: + httpGet: + path: status + port: 80 + periodSeconds: 5 + initialDelaySeconds: 0 + failureThreshold: 3 + successThreshold: 1 + + + diff --git a/services/clsi/nodemon.json b/services/clsi/nodemon.json new file mode 100644 index 0000000000..e3e8817d90 --- /dev/null +++ b/services/clsi/nodemon.json @@ -0,0 +1,17 @@ +{ + "ignore": [ + ".git", + "node_modules/" + ], + "verbose": true, + "legacyWatch": true, + "execMap": { + "js": "npm run start" + }, + "watch": [ + "app/js/", + "app.js", + "config/" + ], + "ext": "js" +} diff --git a/services/clsi/package-lock.json b/services/clsi/package-lock.json new file mode 100644 index 0000000000..86789cafbc --- /dev/null +++ b/services/clsi/package-lock.json @@ -0,0 +1,6775 @@ +{ + "name": "node-clsi", + "version": "0.1.4", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz", + "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==", + "dev": true + }, + "@babel/highlight": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.14.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + } + } + }, + "@eslint/eslintrc": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.2.tgz", + "integrity": "sha512-8nmGq/4ycLpIwzvhI4tNDmQztZ8sp+hI7cyG8i1nQDhkAbRzHpXPidRAHlNvCZQpJTKw5ItIpMw9RSToGF00mg==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==" + } + } + }, + "@google-cloud/common": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-2.4.0.tgz", + "integrity": "sha512-zWFjBS35eI9leAHhjfeOYlK5Plcuj/77EzstnrJIZbKgF/nkqjcQuGiMCpzCwOfPyUbz8ZaEOYgbHa759AKbjg==", + "requires": { + "@google-cloud/projectify": "^1.0.0", + "@google-cloud/promisify": "^1.0.0", + "arrify": "^2.0.0", + "duplexify": "^3.6.0", + "ent": "^2.2.0", + "extend": "^3.0.2", + "google-auth-library": "^5.5.0", + "retry-request": "^4.0.0", + "teeny-request": "^6.0.0" + }, + "dependencies": { + "google-auth-library": { + "version": "5.10.1", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-5.10.1.tgz", + "integrity": "sha512-rOlaok5vlpV9rSiUu5EpR0vVpc+PhN62oF4RyX/6++DG1VsaulAFEMlDYBLjJDDPI6OcNOCGAKy9UVB/3NIDXg==", + "requires": { + "arrify": "^2.0.0", + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "fast-text-encoding": "^1.0.0", + "gaxios": "^2.1.0", + "gcp-metadata": "^3.4.0", + "gtoken": "^4.1.0", + "jws": "^4.0.0", + "lru-cache": "^5.0.0" + } + } + } + }, + "@google-cloud/debug-agent": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/@google-cloud/debug-agent/-/debug-agent-5.1.3.tgz", + "integrity": "sha512-WbzeEz4MvPlM7DX2QBsPcWgF62u7LSQv/oMYPl0L+TddTebqjDKiVXwxpzWk61NIfcKiet3dyCbPIt3N5o8XPQ==", + "requires": { + "@google-cloud/common": "^3.0.0", + "acorn": "^8.0.0", + "coffeescript": "^2.0.0", + "console-log-level": "^1.4.0", + "extend": "^3.0.2", + "findit2": "^2.2.3", + "gcp-metadata": "^4.0.0", + "p-limit": "^3.0.1", + "semver": "^7.0.0", + "source-map": "^0.6.1", + "split": "^1.0.0" + }, + "dependencies": { + "@google-cloud/common": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-3.5.0.tgz", + "integrity": "sha512-10d7ZAvKhq47L271AqvHEd8KzJqGU45TY+rwM2Z3JHuB070FeTi7oJJd7elfrnKaEvaktw3hH2wKnRWxk/3oWQ==", + "requires": { + "@google-cloud/projectify": "^2.0.0", + "@google-cloud/promisify": "^2.0.0", + "arrify": "^2.0.1", + "duplexify": "^4.1.1", + "ent": "^2.2.0", + "extend": "^3.0.2", + "google-auth-library": "^6.1.1", + "retry-request": "^4.1.1", + "teeny-request": "^7.0.0" + } + }, + "@google-cloud/projectify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-2.0.1.tgz", + "integrity": "sha512-ZDG38U/Yy6Zr21LaR3BTiiLtpJl6RkPS/JwoRT453G+6Q1DhlV0waNf8Lfu+YVYGIIxgKnLayJRfYlFJfiI8iQ==" + }, + "@google-cloud/promisify": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-2.0.3.tgz", + "integrity": "sha512-d4VSA86eL/AFTe5xtyZX+ePUjE8dIFu2T8zmdeNBSa5/kNgXPCx/o/wbFNHAGLJdGnk1vddRuMESD9HbOC8irw==" + }, + "bignumber.js": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz", + "integrity": "sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA==" + }, + "duplexify": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.1.tgz", + "integrity": "sha512-DY3xVEmVHTv1wSzKNbwoU6nVjzI369Y6sPoqfYr0/xlx3IdX2n94xIszTcjPO8W8ZIv0Wb0PXNcjuZyT4wiICA==", + "requires": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.0" + } + }, + "gaxios": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-4.1.0.tgz", + "integrity": "sha512-vb0to8xzGnA2qcgywAjtshOKKVDf2eQhJoiL6fHhgW5tVN7wNk7egnYIO9zotfn3lQ3De1VPdf7V5/BWfCtCmg==", + "requires": { + "abort-controller": "^3.0.0", + "extend": "^3.0.2", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.3.0" + } + }, + "gcp-metadata": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.2.1.tgz", + "integrity": "sha512-tSk+REe5iq/N+K+SK1XjZJUrFPuDqGZVzCy2vocIHIGmPlTGsa8owXMJwGkrXr73NO0AzhPW4MF2DEHz7P2AVw==", + "requires": { + "gaxios": "^4.0.0", + "json-bigint": "^1.0.0" + } + }, + "google-auth-library": { + "version": "6.1.6", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.1.6.tgz", + "integrity": "sha512-Q+ZjUEvLQj/lrVHF/IQwRo6p3s8Nc44Zk/DALsN+ac3T4HY/g/3rrufkgtl+nZ1TW7DNAw5cTChdVp4apUXVgQ==", + "requires": { + "arrify": "^2.0.0", + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "fast-text-encoding": "^1.0.0", + "gaxios": "^4.0.0", + "gcp-metadata": "^4.2.0", + "gtoken": "^5.0.4", + "jws": "^4.0.0", + "lru-cache": "^6.0.0" + } + }, + "google-p12-pem": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.0.3.tgz", + "integrity": "sha512-wS0ek4ZtFx/ACKYF3JhyGe5kzH7pgiQ7J5otlumqR9psmWMYc+U9cErKlCYVYHoUaidXHdZ2xbo34kB+S+24hA==", + "requires": { + "node-forge": "^0.10.0" + } + }, + "gtoken": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.2.1.tgz", + "integrity": "sha512-OY0BfPKe3QnMsY9MzTHTSKn+Vl2l1CcLe6BwDEQj00mbbkl5nyQ/7EUREstg4fQNZ8iYE7br4JJ7TdKeDOPWmw==", + "requires": { + "gaxios": "^4.0.0", + "google-p12-pem": "^3.0.3", + "jws": "^4.0.0" + } + }, + "json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "requires": { + "bignumber.js": "^9.0.0" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "node-forge": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==" + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "teeny-request": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-7.0.1.tgz", + "integrity": "sha512-sasJmQ37klOlplL4Ia/786M5YlOcoLGQyq2TE4WHSRupbAuDaQW0PfVxV4MtdBtRJ4ngzS+1qim8zP6Zp35qCw==", + "requires": { + "http-proxy-agent": "^4.0.0", + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.1", + "stream-events": "^1.0.5", + "uuid": "^8.0.0" + } + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } + }, + "@google-cloud/logging": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/@google-cloud/logging/-/logging-7.3.0.tgz", + "integrity": "sha512-xTW1V4MKpYC0mjSugyuiyUoZ9g6A42IhrrO3z7Tt3SmAb2IRj2Gf4RLoguKKncs340ooZFXrrVN/++t2Aj5zgg==", + "requires": { + "@google-cloud/common": "^2.2.2", + "@google-cloud/paginator": "^2.0.0", + "@google-cloud/projectify": "^1.0.0", + "@google-cloud/promisify": "^1.0.0", + "@opencensus/propagation-stackdriver": "0.0.20", + "arrify": "^2.0.0", + "dot-prop": "^5.1.0", + "eventid": "^1.0.0", + "extend": "^3.0.2", + "gcp-metadata": "^3.1.0", + "google-auth-library": "^5.2.2", + "google-gax": "^1.11.0", + "is": "^3.3.0", + "on-finished": "^2.3.0", + "pumpify": "^2.0.0", + "snakecase-keys": "^3.0.0", + "stream-events": "^1.0.4", + "through2": "^3.0.0", + "type-fest": "^0.12.0" + }, + "dependencies": { + "google-auth-library": { + "version": "5.10.1", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-5.10.1.tgz", + "integrity": "sha512-rOlaok5vlpV9rSiUu5EpR0vVpc+PhN62oF4RyX/6++DG1VsaulAFEMlDYBLjJDDPI6OcNOCGAKy9UVB/3NIDXg==", + "requires": { + "arrify": "^2.0.0", + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "fast-text-encoding": "^1.0.0", + "gaxios": "^2.1.0", + "gcp-metadata": "^3.4.0", + "gtoken": "^4.1.0", + "jws": "^4.0.0", + "lru-cache": "^5.0.0" + } + }, + "type-fest": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.12.0.tgz", + "integrity": "sha512-53RyidyjvkGpnWPMF9bQgFtWp+Sl8O2Rp13VavmJgfAP9WWG6q6TkrKU8iyJdnwnfgHI6k2hTlgqH4aSdjoTbg==" + } + } + }, + "@google-cloud/logging-bunyan": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@google-cloud/logging-bunyan/-/logging-bunyan-3.0.0.tgz", + "integrity": "sha512-ZLVXEejNQ27ktGcA3S/sd7GPefp7kywbn+/KoBajdb1Syqcmtc98jhXpYQBXVtNP2065iyu77s4SBaiYFbTC5A==", + "requires": { + "@google-cloud/logging": "^7.0.0", + "google-auth-library": "^6.0.0" + } + }, + "@google-cloud/paginator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-2.0.3.tgz", + "integrity": "sha512-kp/pkb2p/p0d8/SKUu4mOq8+HGwF8NPzHWkj+VKrIPQPyMRw8deZtrO/OcSiy9C/7bpfU5Txah5ltUNfPkgEXg==", + "requires": { + "arrify": "^2.0.0", + "extend": "^3.0.2" + } + }, + "@google-cloud/profiler": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@google-cloud/profiler/-/profiler-4.1.0.tgz", + "integrity": "sha512-9e1zXRctLSUHAoAsFGwE4rS28fr0siiG+jXl5OpwTK8ZAUlxb70aosHaZGdsv8YXrYKjuiufjRZ/OXCs0XLI9g==", + "requires": { + "@google-cloud/common": "^3.0.0", + "@types/console-log-level": "^1.4.0", + "@types/semver": "^7.0.0", + "console-log-level": "^1.4.0", + "delay": "^4.0.1", + "extend": "^3.0.2", + "gcp-metadata": "^4.0.0", + "parse-duration": "^0.4.4", + "pprof": "3.0.0", + "pretty-ms": "^7.0.0", + "protobufjs": "~6.10.0", + "semver": "^7.0.0", + "teeny-request": "^7.0.0" + }, + "dependencies": { + "@google-cloud/common": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-3.5.0.tgz", + "integrity": "sha512-10d7ZAvKhq47L271AqvHEd8KzJqGU45TY+rwM2Z3JHuB070FeTi7oJJd7elfrnKaEvaktw3hH2wKnRWxk/3oWQ==", + "requires": { + "@google-cloud/projectify": "^2.0.0", + "@google-cloud/promisify": "^2.0.0", + "arrify": "^2.0.1", + "duplexify": "^4.1.1", + "ent": "^2.2.0", + "extend": "^3.0.2", + "google-auth-library": "^6.1.1", + "retry-request": "^4.1.1", + "teeny-request": "^7.0.0" + } + }, + "@google-cloud/projectify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-2.0.1.tgz", + "integrity": "sha512-ZDG38U/Yy6Zr21LaR3BTiiLtpJl6RkPS/JwoRT453G+6Q1DhlV0waNf8Lfu+YVYGIIxgKnLayJRfYlFJfiI8iQ==" + }, + "@google-cloud/promisify": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-2.0.3.tgz", + "integrity": "sha512-d4VSA86eL/AFTe5xtyZX+ePUjE8dIFu2T8zmdeNBSa5/kNgXPCx/o/wbFNHAGLJdGnk1vddRuMESD9HbOC8irw==" + }, + "@types/long": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", + "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" + }, + "@types/node": { + "version": "13.13.42", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.42.tgz", + "integrity": "sha512-g+w2QgbW7k2CWLOXzQXbO37a7v5P9ObPvYahKphdBLV5aqpbVZRhTpWCT0SMRqX1i30Aig791ZmIM2fJGL2S8A==" + }, + "bignumber.js": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz", + "integrity": "sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA==" + }, + "duplexify": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.1.tgz", + "integrity": "sha512-DY3xVEmVHTv1wSzKNbwoU6nVjzI369Y6sPoqfYr0/xlx3IdX2n94xIszTcjPO8W8ZIv0Wb0PXNcjuZyT4wiICA==", + "requires": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.0" + } + }, + "gaxios": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-4.1.0.tgz", + "integrity": "sha512-vb0to8xzGnA2qcgywAjtshOKKVDf2eQhJoiL6fHhgW5tVN7wNk7egnYIO9zotfn3lQ3De1VPdf7V5/BWfCtCmg==", + "requires": { + "abort-controller": "^3.0.0", + "extend": "^3.0.2", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.3.0" + } + }, + "gcp-metadata": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.2.1.tgz", + "integrity": "sha512-tSk+REe5iq/N+K+SK1XjZJUrFPuDqGZVzCy2vocIHIGmPlTGsa8owXMJwGkrXr73NO0AzhPW4MF2DEHz7P2AVw==", + "requires": { + "gaxios": "^4.0.0", + "json-bigint": "^1.0.0" + } + }, + "google-auth-library": { + "version": "6.1.6", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.1.6.tgz", + "integrity": "sha512-Q+ZjUEvLQj/lrVHF/IQwRo6p3s8Nc44Zk/DALsN+ac3T4HY/g/3rrufkgtl+nZ1TW7DNAw5cTChdVp4apUXVgQ==", + "requires": { + "arrify": "^2.0.0", + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "fast-text-encoding": "^1.0.0", + "gaxios": "^4.0.0", + "gcp-metadata": "^4.2.0", + "gtoken": "^5.0.4", + "jws": "^4.0.0", + "lru-cache": "^6.0.0" + } + }, + "google-p12-pem": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.0.3.tgz", + "integrity": "sha512-wS0ek4ZtFx/ACKYF3JhyGe5kzH7pgiQ7J5otlumqR9psmWMYc+U9cErKlCYVYHoUaidXHdZ2xbo34kB+S+24hA==", + "requires": { + "node-forge": "^0.10.0" + } + }, + "gtoken": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.2.1.tgz", + "integrity": "sha512-OY0BfPKe3QnMsY9MzTHTSKn+Vl2l1CcLe6BwDEQj00mbbkl5nyQ/7EUREstg4fQNZ8iYE7br4JJ7TdKeDOPWmw==", + "requires": { + "gaxios": "^4.0.0", + "google-p12-pem": "^3.0.3", + "jws": "^4.0.0" + } + }, + "json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "requires": { + "bignumber.js": "^9.0.0" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "node-forge": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==" + }, + "protobufjs": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.10.2.tgz", + "integrity": "sha512-27yj+04uF6ya9l+qfpH187aqEzfCF4+Uit0I9ZBQVqK09hk/SQzKa2MUqUpXaVa7LOFRg1TSSr3lVxGOk6c0SQ==", + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": "^13.7.0", + "long": "^4.0.0" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "teeny-request": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-7.0.1.tgz", + "integrity": "sha512-sasJmQ37klOlplL4Ia/786M5YlOcoLGQyq2TE4WHSRupbAuDaQW0PfVxV4MtdBtRJ4ngzS+1qim8zP6Zp35qCw==", + "requires": { + "http-proxy-agent": "^4.0.0", + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.1", + "stream-events": "^1.0.5", + "uuid": "^8.0.0" + } + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } + }, + "@google-cloud/projectify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-1.0.4.tgz", + "integrity": "sha512-ZdzQUN02eRsmTKfBj9FDL0KNDIFNjBn/d6tHQmA/+FImH5DO6ZV8E7FzxMgAUiVAUq41RFAkb25p1oHOZ8psfg==" + }, + "@google-cloud/promisify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-1.0.4.tgz", + "integrity": "sha512-VccZDcOql77obTnFh0TbNED/6ZbbmHDf8UMNnzO1d5g9V0Htfm4k5cllY8P1tJsRKC3zWYGRLaViiupcgVjBoQ==" + }, + "@google-cloud/trace-agent": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/@google-cloud/trace-agent/-/trace-agent-5.1.3.tgz", + "integrity": "sha512-f+5DX7n6QpDlHA+4kr81z69SLAdrlvd9T8skqCMgnYvtXx14AwzXZyzEDf3jppOYzYoqPPJv8XYiyYHHmYD0BA==", + "requires": { + "@google-cloud/common": "^3.0.0", + "@opencensus/propagation-stackdriver": "0.0.22", + "builtin-modules": "^3.0.0", + "console-log-level": "^1.4.0", + "continuation-local-storage": "^3.2.1", + "extend": "^3.0.2", + "gcp-metadata": "^4.0.0", + "google-auth-library": "^7.0.0", + "hex2dec": "^1.0.1", + "is": "^3.2.0", + "methods": "^1.1.1", + "require-in-the-middle": "^5.0.0", + "semver": "^7.0.0", + "shimmer": "^1.2.0", + "source-map-support": "^0.5.16", + "uuid": "^8.0.0" + }, + "dependencies": { + "@google-cloud/common": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-3.5.0.tgz", + "integrity": "sha512-10d7ZAvKhq47L271AqvHEd8KzJqGU45TY+rwM2Z3JHuB070FeTi7oJJd7elfrnKaEvaktw3hH2wKnRWxk/3oWQ==", + "requires": { + "@google-cloud/projectify": "^2.0.0", + "@google-cloud/promisify": "^2.0.0", + "arrify": "^2.0.1", + "duplexify": "^4.1.1", + "ent": "^2.2.0", + "extend": "^3.0.2", + "google-auth-library": "^6.1.1", + "retry-request": "^4.1.1", + "teeny-request": "^7.0.0" + }, + "dependencies": { + "google-auth-library": { + "version": "6.1.6", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.1.6.tgz", + "integrity": "sha512-Q+ZjUEvLQj/lrVHF/IQwRo6p3s8Nc44Zk/DALsN+ac3T4HY/g/3rrufkgtl+nZ1TW7DNAw5cTChdVp4apUXVgQ==", + "requires": { + "arrify": "^2.0.0", + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "fast-text-encoding": "^1.0.0", + "gaxios": "^4.0.0", + "gcp-metadata": "^4.2.0", + "gtoken": "^5.0.4", + "jws": "^4.0.0", + "lru-cache": "^6.0.0" + } + } + } + }, + "@google-cloud/projectify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-2.0.1.tgz", + "integrity": "sha512-ZDG38U/Yy6Zr21LaR3BTiiLtpJl6RkPS/JwoRT453G+6Q1DhlV0waNf8Lfu+YVYGIIxgKnLayJRfYlFJfiI8iQ==" + }, + "@google-cloud/promisify": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-2.0.3.tgz", + "integrity": "sha512-d4VSA86eL/AFTe5xtyZX+ePUjE8dIFu2T8zmdeNBSa5/kNgXPCx/o/wbFNHAGLJdGnk1vddRuMESD9HbOC8irw==" + }, + "@opencensus/core": { + "version": "0.0.22", + "resolved": "https://registry.npmjs.org/@opencensus/core/-/core-0.0.22.tgz", + "integrity": "sha512-ErazJtivjceNoOZI1bG9giQ6cWS45J4i6iPUtlp7dLNu58OLs/v+CD0FsaPCh47XgPxAI12vbBE8Ec09ViwHNA==", + "requires": { + "continuation-local-storage": "^3.2.1", + "log-driver": "^1.2.7", + "semver": "^7.0.0", + "shimmer": "^1.2.0", + "uuid": "^8.0.0" + } + }, + "@opencensus/propagation-stackdriver": { + "version": "0.0.22", + "resolved": "https://registry.npmjs.org/@opencensus/propagation-stackdriver/-/propagation-stackdriver-0.0.22.tgz", + "integrity": "sha512-eBvf/ihb1mN8Yz/ASkz8nHzuMKqygu77+VNnUeR0yEh3Nj+ykB8VVR6lK+NAFXo1Rd1cOsTmgvuXAZgDAGleQQ==", + "requires": { + "@opencensus/core": "^0.0.22", + "hex2dec": "^1.0.1", + "uuid": "^8.0.0" + } + }, + "bignumber.js": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz", + "integrity": "sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA==" + }, + "duplexify": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.1.tgz", + "integrity": "sha512-DY3xVEmVHTv1wSzKNbwoU6nVjzI369Y6sPoqfYr0/xlx3IdX2n94xIszTcjPO8W8ZIv0Wb0PXNcjuZyT4wiICA==", + "requires": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.0" + } + }, + "gaxios": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-4.1.0.tgz", + "integrity": "sha512-vb0to8xzGnA2qcgywAjtshOKKVDf2eQhJoiL6fHhgW5tVN7wNk7egnYIO9zotfn3lQ3De1VPdf7V5/BWfCtCmg==", + "requires": { + "abort-controller": "^3.0.0", + "extend": "^3.0.2", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.3.0" + } + }, + "gcp-metadata": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.2.1.tgz", + "integrity": "sha512-tSk+REe5iq/N+K+SK1XjZJUrFPuDqGZVzCy2vocIHIGmPlTGsa8owXMJwGkrXr73NO0AzhPW4MF2DEHz7P2AVw==", + "requires": { + "gaxios": "^4.0.0", + "json-bigint": "^1.0.0" + } + }, + "google-auth-library": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-7.0.2.tgz", + "integrity": "sha512-vjyNZR3pDLC0u7GHLfj+Hw9tGprrJwoMwkYGqURCXYITjCrP9HprOyxVV+KekdLgATtWGuDkQG2MTh0qpUPUgg==", + "requires": { + "arrify": "^2.0.0", + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "fast-text-encoding": "^1.0.0", + "gaxios": "^4.0.0", + "gcp-metadata": "^4.2.0", + "gtoken": "^5.0.4", + "jws": "^4.0.0", + "lru-cache": "^6.0.0" + } + }, + "google-p12-pem": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.0.3.tgz", + "integrity": "sha512-wS0ek4ZtFx/ACKYF3JhyGe5kzH7pgiQ7J5otlumqR9psmWMYc+U9cErKlCYVYHoUaidXHdZ2xbo34kB+S+24hA==", + "requires": { + "node-forge": "^0.10.0" + } + }, + "gtoken": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.2.1.tgz", + "integrity": "sha512-OY0BfPKe3QnMsY9MzTHTSKn+Vl2l1CcLe6BwDEQj00mbbkl5nyQ/7EUREstg4fQNZ8iYE7br4JJ7TdKeDOPWmw==", + "requires": { + "gaxios": "^4.0.0", + "google-p12-pem": "^3.0.3", + "jws": "^4.0.0" + } + }, + "json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "requires": { + "bignumber.js": "^9.0.0" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "node-forge": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==" + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "teeny-request": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-7.0.1.tgz", + "integrity": "sha512-sasJmQ37klOlplL4Ia/786M5YlOcoLGQyq2TE4WHSRupbAuDaQW0PfVxV4MtdBtRJ4ngzS+1qim8zP6Zp35qCw==", + "requires": { + "http-proxy-agent": "^4.0.0", + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.1", + "stream-events": "^1.0.5", + "uuid": "^8.0.0" + } + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } + }, + "@grpc/grpc-js": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.0.5.tgz", + "integrity": "sha512-Hm+xOiqAhcpT9RYM8lc15dbQD7aQurM7ZU8ulmulepiPlN7iwBXXwP3vSBUimoFoApRqz7pSIisXU8pZaCB4og==", + "requires": { + "semver": "^6.2.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "@grpc/proto-loader": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.5.5.tgz", + "integrity": "sha512-WwN9jVNdHRQoOBo9FDH7qU+mgfjPc8GygPYms3M+y3fbQLfnCe/Kv/E01t7JRgnrsOHH8euvSbed3mIalXhwqQ==", + "requires": { + "lodash.camelcase": "^4.3.0", + "protobufjs": "^6.8.6" + } + }, + "@humanwhocodes/config-array": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "dependencies": { + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@humanwhocodes/object-schema": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", + "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", + "dev": true + }, + "@opencensus/core": { + "version": "0.0.20", + "resolved": "https://registry.npmjs.org/@opencensus/core/-/core-0.0.20.tgz", + "integrity": "sha512-vqOuTd2yuMpKohp8TNNGUAPjWEGjlnGfB9Rh5e3DKqeyR94YgierNs4LbMqxKtsnwB8Dm2yoEtRuUgoe5vD9DA==", + "requires": { + "continuation-local-storage": "^3.2.1", + "log-driver": "^1.2.7", + "semver": "^6.0.0", + "shimmer": "^1.2.0", + "uuid": "^3.2.1" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "@opencensus/propagation-stackdriver": { + "version": "0.0.20", + "resolved": "https://registry.npmjs.org/@opencensus/propagation-stackdriver/-/propagation-stackdriver-0.0.20.tgz", + "integrity": "sha512-P8yuHSLtce+yb+2EZjtTVqG7DQ48laC+IuOWi3X9q78s1Gni5F9+hmbmyP6Nb61jb5BEvXQX1s2rtRI6bayUWA==", + "requires": { + "@opencensus/core": "^0.0.20", + "hex2dec": "^1.0.1", + "uuid": "^3.2.1" + } + }, + "@overleaf/metrics": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@overleaf/metrics/-/metrics-3.5.1.tgz", + "integrity": "sha512-RLHxkMF7Y3725L3QwXo9cIn2gGobsMYUGuxKxg7PVMrPTMsomHEMeG7StOxCO7ML1Z/BwB/9nsVYNrsRdAJtKg==", + "requires": { + "@google-cloud/debug-agent": "^5.1.2", + "@google-cloud/profiler": "^4.0.3", + "@google-cloud/trace-agent": "^5.1.1", + "compression": "^1.7.4", + "prom-client": "^11.1.3", + "underscore": "~1.6.0", + "yn": "^3.1.1" + } + }, + "@overleaf/o-error": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@overleaf/o-error/-/o-error-3.3.1.tgz", + "integrity": "sha512-1FRBYZO0lbJ0U+FRGZVS8ou6RhEw3e2B86WW/NbtBw554g0h5iC8ESf+juIfPMU/WDf/JDIFbg3eB/LnP2RSow==", + "requires": { + "core-js": "^3.8.3" + } + }, + "@overleaf/settings": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@overleaf/settings/-/settings-2.1.1.tgz", + "integrity": "sha512-vcJwqCGFKmQxTP/syUqCeMaSRjHmBcQgKOACR9He2uJcErg2GZPa1go+nGvszMbkElM4HfRKm/MfxvqHhoN4TQ==" + }, + "@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78=" + }, + "@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A=" + }, + "@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=", + "requires": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E=" + }, + "@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik=" + }, + "@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0=" + }, + "@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q=" + }, + "@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA=" + }, + "@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "dev": true + }, + "@sinonjs/commons": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.7.1.tgz", + "integrity": "sha512-Debi3Baff1Qu1Unc3mjJ96MgpbwTn43S1+9yJ0llWygPwDNu2aaWBD6yc9y/Z8XDRNhx7U+u2UDg2OGQXkclUQ==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.0.tgz", + "integrity": "sha512-atR1J/jRXvQAb47gfzSK8zavXy7BcpnYq21ALon0U99etu99vsir0trzIO3wpeLtW+LLVY6X7EkfVTbjGSH8Ww==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "@sinonjs/formatio": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-5.0.1.tgz", + "integrity": "sha512-KaiQ5pBf1MpS09MuA0kp6KBQt2JUOQycqVG1NZXvzeaXe5LGFqAKueIS0bw4w0P9r7KuBSVdUk5QjXsUdu2CxQ==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1", + "@sinonjs/samsam": "^5.0.2" + } + }, + "@sinonjs/samsam": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.0.3.tgz", + "integrity": "sha512-QucHkc2uMJ0pFGjJUDP3F9dq5dx8QIaqISl9QgwLOh6P9yv877uONPGXh/OH/0zmM3tW1JjuJltAZV2l7zU+uQ==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.6.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } + }, + "@sinonjs/text-encoding": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", + "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", + "dev": true + }, + "@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "dev": true, + "requires": { + "defer-to-connect": "^1.0.1" + } + }, + "@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==" + }, + "@types/console-log-level": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@types/console-log-level/-/console-log-level-1.4.0.tgz", + "integrity": "sha512-x+OscEQwcx5Biair4enH7ov9W+clcqUWaZRaxn5IkT4yNWWjRr2oiYDkY/x1uXSTVZOQ2xlbFQySaQGB+VdXGQ==" + }, + "@types/fs-extra": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.1.tgz", + "integrity": "sha512-TcUlBem321DFQzBNuz8p0CLLKp0VvF/XH9E4KHNmgwyp4E3AfgI5cjiIVZWlbfThBop2qxFIh4+LeY6hVWWZ2w==", + "requires": { + "@types/node": "*" + } + }, + "@types/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.0.tgz", + "integrity": "sha512-1w52Nyx4Gq47uuu0EVcsHBxZFJgurQ+rTKS3qMHxR1GY2T8c2AJYd6vZoZ9q1rupaDjU0yT+Jc2XTyXkjeMA+Q==" + }, + "@types/node": { + "version": "10.12.15", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.15.tgz", + "integrity": "sha1-IOhWUbYv2GZW5Xycm8dxqxVwvFk=" + }, + "@types/semver": { + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-+nVsLKlcUCeMzD2ufHEYuJ9a2ovstb6Dp52A5VsoKxDXgvE051XgHI/33I1EymwkRGQkwnA0LkhnUzituGs4EQ==" + }, + "@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "dev": true + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha1-+PLIh60Qv2f2NPAFtph/7TF5qsg=" + }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "requires": { + "event-target-shim": "^5.0.0" + } + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "acorn": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.0.5.tgz", + "integrity": "sha512-v+DieK/HJkJOpFBETDJioequtc3PfxsWMaxIdIwujtF7FEV/MAyDQLlm6/zPvr7Mix07mLh6ccVwIsloceodlg==" + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true + }, + "agent-base": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.1.tgz", + "integrity": "sha512-01q25QQDwLSsyfhrKbn8yuur+JNw0H+0Y4JiGIKd3z9aYk/w/2kxD/Upc+t2ZBBSUNff50VjPsSW2YxM8QYKVg==", + "requires": { + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "ajv": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.0.tgz", + "integrity": "sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-align": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", + "integrity": "sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==", + "dev": true, + "requires": { + "string-width": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" + }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha1-aALmJk79GMeQobDVF/DyYnvyyUo=" + }, + "are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha1-SzXClE8GKov82mZBB2A1D+nd/CE=", + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "array-includes": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz", + "integrity": "sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2", + "get-intrinsic": "^1.1.1", + "is-string": "^1.0.5" + } + }, + "array.prototype.flat": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz", + "integrity": "sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1" + }, + "dependencies": { + "has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" + }, + "is-callable": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", + "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==" + }, + "is-string": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz", + "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==" + } + } + }, + "arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==" + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true + }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true + }, + "async": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", + "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==" + }, + "async-listener": { + "version": "0.6.10", + "resolved": "https://registry.npmjs.org/async-listener/-/async-listener-0.6.10.tgz", + "integrity": "sha512-gpuo6xOyF4D5DE5WvyqZdPA3NGhiT6Qf07l7DCB0wwDEsLvDIbCr6j9S5aj5Ch96dLace5tXVzWBZkxU/c5ohw==", + "requires": { + "semver": "^5.3.0", + "shimmer": "^1.1.0" + } + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + }, + "aws4": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz", + "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==" + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "bignumber.js": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-7.2.1.tgz", + "integrity": "sha512-S4XzBk5sMB+Rcb/LNcpzXr57VRTxgAvaAEDAl1AwRx27j00hT84O6OkteE7u8UB3NuaaygCRrEpqox4uDOrbdQ==" + }, + "binary-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", + "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", + "dev": true + }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "requires": { + "file-uri-to-path": "1.0.0" + } + }, + "bintrees": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.1.tgz", + "integrity": "sha1-DmVcm5wkNeqraL9AJyJtK1WjRSQ=" + }, + "bl": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.0.3.tgz", + "integrity": "sha512-fs4G6/Hu4/EE+F75J8DuN/0IpQqNjAdC7aEQv7Qt8MHGUH7Ckv2MwTEEeN9QehD0pfIDkMI1bkHYkKy7xHyKIg==", + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + }, + "dependencies": { + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + } + } + }, + "boxen": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", + "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==", + "dev": true, + "requires": { + "ansi-align": "^3.0.0", + "camelcase": "^5.3.1", + "chalk": "^3.0.0", + "cli-boxes": "^2.2.0", + "string-width": "^4.1.0", + "term-size": "^2.1.0", + "type-fest": "^0.8.1", + "widest-line": "^3.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "builtin-modules": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz", + "integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==" + }, + "bunyan": { + "version": "1.8.15", + "resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.15.tgz", + "integrity": "sha512-0tECWShh6wUysgucJcBAoYegf3JJoZWibxdqhTm7OHPeT42qdjkZ29QCMcKwbgU1kiH+auSIasNRXMLWXafXig==", + "requires": { + "dtrace-provider": "~0.8", + "moment": "^2.19.3", + "mv": "~2", + "safe-json-stringify": "~1" + } + }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, + "cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "dev": true, + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "dependencies": { + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true + } + } + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "chai": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", + "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", + "dev": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "pathval": "^1.1.0", + "type-detect": "^4.0.5" + } + }, + "chai-as-promised": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz", + "integrity": "sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA==", + "dev": true, + "requires": { + "check-error": "^1.0.2" + } + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true + }, + "charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=" + }, + "check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true + }, + "chokidar": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", + "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.2.0" + } + }, + "chownr": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz", + "integrity": "sha1-VHJri4//TfBTxCGH6AH7RBLfFJQ=" + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "dev": true + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "wrap-ansi": "^7.0.0" + } + }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "cls-bluebird": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cls-bluebird/-/cls-bluebird-2.1.0.tgz", + "integrity": "sha1-N+8eCAqP+1XC9BZPU28ZGeeWiu4=", + "requires": { + "is-bluebird": "^1.0.2", + "shimmer": "^1.1.0" + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + }, + "coffeescript": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/coffeescript/-/coffeescript-2.5.1.tgz", + "integrity": "sha512-J2jRPX0eeFh5VKyVnoLrfVFgLZtnnmp96WQSLAS8OrLm2wtQLcnikYKe1gViJKDH7vucjuhHvBKKBP3rKcD1tQ==" + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "requires": { + "mime-db": ">= 1.43.0 < 2" + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "dependencies": { + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + } + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "dev": true, + "requires": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + } + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + }, + "console-log-level": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/console-log-level/-/console-log-level-1.4.1.tgz", + "integrity": "sha512-VZzbIORbP+PPcN/gg3DXClTLPLg5Slwd5fL2MIc+o1qZ4BXBvWyc6QxPk6T/Mkr6IVjRpoAGf32XxP3ZWMVRcQ==" + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "requires": { + "safe-buffer": "5.1.2" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "continuation-local-storage": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/continuation-local-storage/-/continuation-local-storage-3.2.1.tgz", + "integrity": "sha512-jx44cconVqkCEEyLSKWwkvUXwO561jXMa3LPjTPsm5QR22PA0/mhe33FT4Xb5y74JDvt/Cq+5lm8S8rskLv9ZA==", + "requires": { + "async-listener": "^0.6.0", + "emitter-listener": "^1.1.1" + } + }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "core-js": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.13.0.tgz", + "integrity": "sha512-iWDbiyha1M5vFwPFmQnvRv+tJzGbFAm6XimJUT0NgHYW3xZEs1SkCAcasWSVFxpI2Xb/V1DDJckq3v90+bQnog==" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=" + }, + "crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true + }, + "d64": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/d64/-/d64-1.0.0.tgz", + "integrity": "sha1-QAKofoUMv8n52XBrYPymE6MzbpA=" + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true + }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "requires": { + "type-detect": "^4.0.0" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha1-xPp8lUBKF6nD6Mp+FTcxK3NjMKw=" + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", + "dev": true + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "delay": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/delay/-/delay-4.4.1.tgz", + "integrity": "sha512-aL3AhqtfhOlT/3ai6sWXeqwnw63ATNpnUiN4HL7x9q+My5QtHlO3OIkasmug9LKzpheLdmUKGRKnYXYAS7FQkQ==" + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" + }, + "diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true + }, + "diskusage": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/diskusage/-/diskusage-1.1.3.tgz", + "integrity": "sha512-EAyaxl8hy4Ph07kzlzGTfpbZMNAAAHXSZtNEMwdlnSd1noHzvA6HsgKt4fEMSvaEXQYLSphe5rPMxN4WOj0hcQ==", + "requires": { + "es6-promise": "^4.2.5", + "nan": "^2.14.0" + } + }, + "docker-modem": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/docker-modem/-/docker-modem-2.1.1.tgz", + "integrity": "sha512-zSFwYN4AP38LJhTIOpZMjiDbAqSJbv8+u9i/Xq5XABIeTzgp83VF63epu6sVHWxe+6tfhMXqgV+sYjZWh/UzSQ==", + "requires": { + "debug": "^4.1.1", + "readable-stream": "^3.5.0", + "split-ca": "^1.0.1", + "ssh2": "^0.8.7" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "dockerode": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/dockerode/-/dockerode-3.1.0.tgz", + "integrity": "sha512-E0KknBBTlIVEvtt2XJRZ3he59u2UN8Yr1A08Sey/BKIox+WlwnJp5fL5SKyhPgNmSXgamPEuKYCJxMi31uj0Nw==", + "requires": { + "concat-stream": "~2.0.0", + "docker-modem": "^2.1.0", + "tar-fs": "~2.0.0" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "dot-prop": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.2.0.tgz", + "integrity": "sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A==", + "requires": { + "is-obj": "^2.0.0" + } + }, + "dottie": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.2.tgz", + "integrity": "sha512-fmrwR04lsniq/uSr8yikThDTrM7epXHBAAjH9TbeH3rEA8tdCO7mRzB9hdmdGyJCxF8KERo9CITcm3kGuoyMhg==" + }, + "dtrace-provider": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.8.8.tgz", + "integrity": "sha512-b7Z7cNtHPhH9EJhNNbbeqTcXB8LGFFZhq1PGgEvpeHlzd36bhbdTWoE/Ba/YguqpBSlAPKnARWhVlhunCMwfxg==", + "optional": true, + "requires": { + "nan": "^2.14.0" + } + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "emitter-listener": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/emitter-listener/-/emitter-listener-1.1.2.tgz", + "integrity": "sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ==", + "requires": { + "shimmer": "^1.2.0" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "end-of-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", + "integrity": "sha1-7SljTRm6ukY7bOa4CjchPqtx7EM=", + "requires": { + "once": "^1.4.0" + } + }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1" + } + }, + "ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=" + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.18.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.3.tgz", + "integrity": "sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "has": "^1.0.3", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.3", + "object-inspect": "^1.10.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", + "dev": true + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "eslint": { + "version": "7.30.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.30.0.tgz", + "integrity": "sha512-VLqz80i3as3NdloY44BQSJpFw534L9Oh+6zJOUaViV4JPd+DaHwutqP7tcpkW3YiXbK6s05RZl7yl7cQn+lijg==", + "dev": true, + "requires": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.2", + "@humanwhocodes/config-array": "^0.5.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + }, + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==" + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "requires": { + "glob": "^7.1.3" + } + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "eslint-config-prettier": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz", + "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==", + "dev": true + }, + "eslint-config-standard": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-16.0.3.tgz", + "integrity": "sha512-x4fmJL5hGqNJKGHSjnLdgA6U6h1YW/G2dW9fA+cyVur4SK6lyue8+UgNKWlZtUDTXvgKDD/Oa3GQjmB5kjtVvg==", + "dev": true + }, + "eslint-import-resolver-node": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", + "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "resolve": "^1.13.1" + }, + "dependencies": { + "resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "dev": true, + "requires": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + } + } + } + }, + "eslint-module-utils": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.1.tgz", + "integrity": "sha512-ZXI9B8cxAJIH4nfkhTwcRTEAnrVfobYqwjWy/QMCZ8rHkZHFjf9yO4BzpiF9kCSfNlMG54eKigISHpX0+AaT4A==", + "dev": true, + "requires": { + "debug": "^3.2.7", + "pkg-dir": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + } + } + }, + "eslint-plugin-chai-expect": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-chai-expect/-/eslint-plugin-chai-expect-2.2.0.tgz", + "integrity": "sha512-ExTJKhgeYMfY8wDj3UiZmgpMKJOUHGNHmWMlxT49JUDB1vTnw0sSNfXJSxnX+LcebyBD/gudXzjzD136WqPJrQ==", + "dev": true + }, + "eslint-plugin-chai-friendly": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-chai-friendly/-/eslint-plugin-chai-friendly-0.6.0.tgz", + "integrity": "sha512-Uvvv1gkbRGp/qfN15B0kQyQWg+oFA8buDSqrwmW3egNSk/FpqH2MjQqKOuKwmEL6w4QIQrIjDp+gg6kGGmD3oQ==", + "dev": true + }, + "eslint-plugin-es": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", + "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", + "dev": true, + "requires": { + "eslint-utils": "^2.0.0", + "regexpp": "^3.0.0" + } + }, + "eslint-plugin-import": { + "version": "2.23.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.23.4.tgz", + "integrity": "sha512-6/wP8zZRsnQFiR3iaPFgh5ImVRM1WN5NUWfTIRqwOdeiGJlBcSk82o1FEVq8yXmy4lkIzTo7YhHCIxlU/2HyEQ==", + "dev": true, + "requires": { + "array-includes": "^3.1.3", + "array.prototype.flat": "^1.2.4", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.4", + "eslint-module-utils": "^2.6.1", + "find-up": "^2.0.0", + "has": "^1.0.3", + "is-core-module": "^2.4.0", + "minimatch": "^3.0.4", + "object.values": "^1.1.3", + "pkg-up": "^2.0.0", + "read-pkg-up": "^3.0.0", + "resolve": "^1.20.0", + "tsconfig-paths": "^3.9.0" + }, + "dependencies": { + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" + }, + "is-callable": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", + "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==" + }, + "resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "dev": true, + "requires": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + } + } + } + }, + "eslint-plugin-mocha": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-8.2.0.tgz", + "integrity": "sha512-8oOR47Ejt+YJPNQzedbiklDqS1zurEaNrxXpRs+Uk4DMDPVmKNagShFeUaYsfvWP55AhI+P1non5QZAHV6K78A==", + "dev": true, + "requires": { + "eslint-utils": "^2.1.0", + "ramda": "^0.27.1" + } + }, + "eslint-plugin-node": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", + "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", + "dev": true, + "requires": { + "eslint-plugin-es": "^3.0.0", + "eslint-utils": "^2.0.0", + "ignore": "^5.1.1", + "minimatch": "^3.0.4", + "resolve": "^1.10.1", + "semver": "^6.1.0" + }, + "dependencies": { + "ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "eslint-plugin-prettier": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.2.tgz", + "integrity": "sha512-GlolCC9y3XZfv3RQfwGew7NnuFDKsfI4lbvRK+PIIo23SFH+LemGs4cKwzAaRa+Mdb+lQO/STaIayno8T5sJJA==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0" + } + }, + "eslint-plugin-promise": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-4.2.1.tgz", + "integrity": "sha512-VoM09vT7bfA7D+upt+FjeBO5eHIJQBUWki1aPvB+vbNiHS3+oGIJGIeyBtKQTME6UPXXy3vV07OL1tHd3ANuDw==", + "dev": true + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", + "dev": true + }, + "espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "requires": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" + }, + "eventid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eventid/-/eventid-1.0.0.tgz", + "integrity": "sha512-4upSDsvpxhWPsmw4fsJCp0zj8S7I0qh1lCDTmZXP8V3TtryQKDI8CgQPN+e5JakbWwzaAX3lrdp2b3KSoMSUpw==", + "requires": { + "d64": "^1.0.0", + "uuid": "^3.0.1" + } + }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha1-+LETa0Bx+9jrFAr/hYsQGewpFfo=" + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "fast-deep-equal": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz", + "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==" + }, + "fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fast-text-encoding": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.0.tgz", + "integrity": "sha512-R9bHCvweUxxwkDwhjav5vxpFvdPGlVngtqmx4pIZfSUhM/Q4NiIUHB456BAf+Q1Nwu3HEZYONtu+Rya+af4jiQ==" + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "findit2": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/findit2/-/findit2-2.2.3.tgz", + "integrity": "sha1-WKRmaX34piBc39vzlVNri9d3pfY=" + }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0" + } + }, + "flatted": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.1.tgz", + "integrity": "sha512-OMQjaErSFHmHqZe+PSidH5n8j3O0F2DdnVh8JB4j4eUQ2k6KvB0qGfrKIhapvez5JerBbmWkaLYUYWISaESoXg==", + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, + "fs-extra": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", + "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "fs-minipass": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz", + "integrity": "sha1-BsJ3IYRU7CiN93raVKA7hwKqy50=", + "requires": { + "minipass": "^2.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fsevents": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz", + "integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "gaxios": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-2.3.4.tgz", + "integrity": "sha512-US8UMj8C5pRnao3Zykc4AAVr+cffoNKRTg9Rsf2GiuZCW69vgJj38VK2PzlPuQU73FZ/nTk9/Av6/JGcE1N9vA==", + "requires": { + "abort-controller": "^3.0.0", + "extend": "^3.0.2", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.3.0" + } + }, + "gcp-metadata": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-3.5.0.tgz", + "integrity": "sha512-ZQf+DLZ5aKcRpLzYUyBS3yo3N0JSa82lNDO8rj3nMSlovLcz2riKFBsYgDzeXcv75oo5eqB2lx+B14UvPoCRnA==", + "requires": { + "gaxios": "^2.1.0", + "json-bigint": "^0.3.0" + } + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true + }, + "get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha1-OWCDLT8VdBCDQtr9OmezMsCWnfE=", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "global-dirs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.1.0.tgz", + "integrity": "sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ==", + "dev": true, + "requires": { + "ini": "1.3.7" + }, + "dependencies": { + "ini": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.7.tgz", + "integrity": "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==", + "dev": true + } + } + }, + "globals": { + "version": "13.10.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.10.0.tgz", + "integrity": "sha512-piHC3blgLGFjvOuMmWZX60f+na1lXFDhQXBf1UYp2fXPXqvEUbOhNwi6BsQ0bQishwedgnjkwv1d9zKf+MWw3g==", + "dev": true + }, + "google-auth-library": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.0.6.tgz", + "integrity": "sha512-fWYdRdg55HSJoRq9k568jJA1lrhg9i2xgfhVIMJbskUmbDpJGHsbv9l41DGhCDXM21F9Kn4kUwdysgxSYBYJUw==", + "requires": { + "arrify": "^2.0.0", + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "fast-text-encoding": "^1.0.0", + "gaxios": "^3.0.0", + "gcp-metadata": "^4.1.0", + "gtoken": "^5.0.0", + "jws": "^4.0.0", + "lru-cache": "^6.0.0" + }, + "dependencies": { + "bignumber.js": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", + "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==" + }, + "gaxios": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.1.0.tgz", + "integrity": "sha512-DDTn3KXVJJigtz+g0J3vhcfbDbKtAroSTxauWsdnP57sM5KZ3d2c/3D9RKFJ86s43hfw6WULg6TXYw/AYiBlpA==", + "requires": { + "abort-controller": "^3.0.0", + "extend": "^3.0.2", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.3.0" + } + }, + "gcp-metadata": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.1.4.tgz", + "integrity": "sha512-5J/GIH0yWt/56R3dNaNWPGQ/zXsZOddYECfJaqxFWgrZ9HC2Kvc5vl9upOgUUHKzURjAVf2N+f6tEJiojqXUuA==", + "requires": { + "gaxios": "^3.0.0", + "json-bigint": "^1.0.0" + } + }, + "google-p12-pem": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.0.2.tgz", + "integrity": "sha512-tbjzndQvSIHGBLzHnhDs3cL4RBjLbLXc2pYvGH+imGVu5b4RMAttUTdnmW2UH0t11QeBTXZ7wlXPS7hrypO/tg==", + "requires": { + "node-forge": "^0.9.0" + } + }, + "gtoken": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-5.0.3.tgz", + "integrity": "sha512-Nyd1wZCMRc2dj/mAD0LlfQLcAO06uKdpKJXvK85SGrF5+5+Bpfil9u/2aw35ltvEHjvl0h5FMKN5knEU+9JrOg==", + "requires": { + "gaxios": "^3.0.0", + "google-p12-pem": "^3.0.0", + "jws": "^4.0.0", + "mime": "^2.2.0" + } + }, + "json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "requires": { + "bignumber.js": "^9.0.0" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "mime": { + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz", + "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } + }, + "google-gax": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-1.15.3.tgz", + "integrity": "sha512-3JKJCRumNm3x2EksUTw4P1Rad43FTpqrtW9jzpf3xSMYXx+ogaqTM1vGo7VixHB4xkAyATXVIa3OcNSh8H9zsQ==", + "requires": { + "@grpc/grpc-js": "~1.0.3", + "@grpc/proto-loader": "^0.5.1", + "@types/fs-extra": "^8.0.1", + "@types/long": "^4.0.0", + "abort-controller": "^3.0.0", + "duplexify": "^3.6.0", + "google-auth-library": "^5.0.0", + "is-stream-ended": "^0.1.4", + "lodash.at": "^4.6.0", + "lodash.has": "^4.5.2", + "node-fetch": "^2.6.0", + "protobufjs": "^6.8.9", + "retry-request": "^4.0.0", + "semver": "^6.0.0", + "walkdir": "^0.4.0" + }, + "dependencies": { + "@types/node": { + "version": "13.13.15", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.15.tgz", + "integrity": "sha512-kwbcs0jySLxzLsa2nWUAGOd/s21WU1jebrEdtzhsj1D4Yps1EOuyI1Qcu+FD56dL7NRNIJtDDjcqIG22NwkgLw==" + }, + "google-auth-library": { + "version": "5.10.1", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-5.10.1.tgz", + "integrity": "sha512-rOlaok5vlpV9rSiUu5EpR0vVpc+PhN62oF4RyX/6++DG1VsaulAFEMlDYBLjJDDPI6OcNOCGAKy9UVB/3NIDXg==", + "requires": { + "arrify": "^2.0.0", + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "fast-text-encoding": "^1.0.0", + "gaxios": "^2.1.0", + "gcp-metadata": "^3.4.0", + "gtoken": "^4.1.0", + "jws": "^4.0.0", + "lru-cache": "^5.0.0" + } + }, + "protobufjs": { + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.10.1.tgz", + "integrity": "sha512-pb8kTchL+1Ceg4lFd5XUpK8PdWacbvV5SK2ULH2ebrYtl4GjJmS24m6CKME67jzV53tbJxHlnNOSqQHbTsR9JQ==", + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": "^13.7.0", + "long": "^4.0.0" + }, + "dependencies": { + "@types/long": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", + "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" + } + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "google-p12-pem": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-2.0.4.tgz", + "integrity": "sha512-S4blHBQWZRnEW44OcR7TL9WR+QCqByRvhNDZ/uuQfpxywfupikf/miba8js1jZi6ZOGv5slgSuoshCWh6EMDzg==", + "requires": { + "node-forge": "^0.9.0" + } + }, + "got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "dev": true, + "requires": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + } + }, + "graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==" + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, + "gtoken": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-4.1.4.tgz", + "integrity": "sha512-VxirzD0SWoFUo5p8RDP8Jt2AGyOmyYcT/pOUgDKJCK+iSw0TMqwrVfY37RXTNmoKwrzmDHSk0GMT9FsgVmnVSA==", + "requires": { + "gaxios": "^2.1.0", + "google-p12-pem": "^2.0.0", + "jws": "^4.0.0", + "mime": "^2.2.0" + }, + "dependencies": { + "mime": { + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz", + "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==" + } + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + }, + "har-validator": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "requires": { + "ajv": "^6.5.5", + "har-schema": "^2.0.0" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" + }, + "has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", + "dev": true + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "heapdump": { + "version": "0.3.15", + "resolved": "https://registry.npmjs.org/heapdump/-/heapdump-0.3.15.tgz", + "integrity": "sha512-n8aSFscI9r3gfhOcAECAtXFaQ1uy4QSke6bnaL+iymYZ/dWs9cqDqHM+rALfsHUwukUbxsdlECZ0pKmJdQ/4OA==", + "requires": { + "nan": "^2.13.2" + } + }, + "hex2dec": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/hex2dec/-/hex2dec-1.1.2.tgz", + "integrity": "sha512-Yu+q/XWr2fFQ11tHxPq4p4EiNkb2y+lAacJNhAdRXVfRIcDH6gi7htWFnnlIzvqHMHoWeIsfXlNAjZInpAOJDA==" + }, + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "dev": true + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "requires": { + "agent-base": "6", + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "iconv-lite": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha1-KXhx9jvlB63Pv8pxXQzQ7thOmmM=", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", + "dev": true + }, + "ignore-walk": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz", + "integrity": "sha1-qD5i59JyrA47VRqqgoMaGbafgvg=", + "requires": { + "minimatch": "^3.0.4" + } + }, + "import-fresh": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inflection": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz", + "integrity": "sha1-ogCTVlbW9fa8TcdQLhrstwMihBY=" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "is": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/is/-/is-3.3.0.tgz", + "integrity": "sha512-nW24QBoPcFGGHJGUwnfpI7Yc5CdqWNdsyHQszVE/z2pKHXzh7FZ5GWhJqSyaQ9wMkQnsTx+kAI8bHlCX4tKdbg==" + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-bigint": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.2.tgz", + "integrity": "sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA==", + "dev": true + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-bluebird": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-bluebird/-/is-bluebird-1.0.2.tgz", + "integrity": "sha1-CWQ5Bg9KpBGr7hkUOoTWpVNG1uI=" + }, + "is-boolean-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.1.tgz", + "integrity": "sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", + "dev": true + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "requires": { + "ci-info": "^2.0.0" + } + }, + "is-core-module": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.5.0.tgz", + "integrity": "sha512-TXCMSDsEHMEEZ6eCA8rwRDbLu55MRGmrctljsBX/2v1d9/GzqHOxW5c5oPSgrUt2vBFXebu9rGqckXGPWOlYpg==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-installed-globally": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz", + "integrity": "sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==", + "dev": true, + "requires": { + "global-dirs": "^2.0.1", + "is-path-inside": "^3.0.1" + } + }, + "is-negative-zero": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", + "dev": true + }, + "is-npm": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz", + "integrity": "sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-number-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.5.tgz", + "integrity": "sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw==", + "dev": true + }, + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==" + }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true + }, + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true + }, + "is-regex": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz", + "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==" + }, + "is-stream-ended": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-stream-ended/-/is-stream-ended-0.1.4.tgz", + "integrity": "sha512-xj0XPvmr7bQFTvirqnFr50o0hQIh6ZItDqloxt5aJrR4NQsYeSsyFQERYGCAzfindAcnKjINnwEEgLx4IqVzQw==" + }, + "is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "dev": true + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + }, + "json-bigint": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-0.3.0.tgz", + "integrity": "sha1-DM2RLEuCcNBfBW+9E4FLU9OCWx4=", + "requires": { + "bignumber.js": "^7.0.0" + } + }, + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", + "dev": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha1-afaofZUTq4u4/mO9sJecRI5oRmA=" + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + }, + "dependencies": { + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + } + } + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "just-extend": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.1.0.tgz", + "integrity": "sha512-ApcjaOdVTJ7y4r08xI5wIqpvwS48Q0PBG4DJROcEkH1f8MdAiNFyFxz3xoL0LWAVwjrwPYZdVHHxhRHcx/uGLA==", + "dev": true + }, + "jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "requires": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, + "keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "dev": true, + "requires": { + "json-buffer": "3.0.0" + } + }, + "latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "dev": true, + "requires": { + "package-json": "^6.3.0" + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "lockfile": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lockfile/-/lockfile-1.0.4.tgz", + "integrity": "sha1-B/gZ0lrkj4flOOZXi2lkpJgaVgk=", + "requires": { + "signal-exit": "^3.0.2" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash.at": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.at/-/lodash.at-4.6.0.tgz", + "integrity": "sha1-k83OZk8KGZTqM9181A4jr9EbD/g=" + }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true + }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", + "dev": true + }, + "lodash.has": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/lodash.has/-/lodash.has-4.5.2.tgz", + "integrity": "sha1-0Z9NwQlQWMzL4rDN9O4P5Ko3yGI=" + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", + "dev": true + }, + "log-driver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz", + "integrity": "sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==" + }, + "log-symbols": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", + "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==", + "dev": true, + "requires": { + "chalk": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "logger-sharelatex": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/logger-sharelatex/-/logger-sharelatex-2.2.0.tgz", + "integrity": "sha512-ko+OmE25XHJJCiz1R9EgwlfM7J/5olpunUfR3WcfuqOQrcUqsdBrDA2sOytngT0ViwjCR0Fh4qZVPwEWfmrvwA==", + "requires": { + "@google-cloud/logging-bunyan": "^3.0.0", + "@overleaf/o-error": "^3.0.0", + "bunyan": "^1.8.14", + "node-fetch": "^2.6.0", + "raven": "^2.6.4", + "yn": "^4.0.0" + }, + "dependencies": { + "yn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yn/-/yn-4.0.0.tgz", + "integrity": "sha512-huWiiCS4TxKc4SfgmTwW1K7JmXPPAmuXWYy4j9qjQo4+27Kni8mGhAAi1cloRWmBe2EqcLgt3IGqQoRL/MtPgg==" + } + } + }, + "long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "requires": { + "yallist": "^3.0.2" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "map-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.1.0.tgz", + "integrity": "sha512-glc9y00wgtwcDmp7GaE/0b0OnxpNJsVf3ael/An6Fe2Q51LLwN1er6sdomLRzz5h0+yMpiYLhWYF5R7HeqVd4g==" + }, + "md5": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", + "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", + "requires": { + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", + "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==" + }, + "mime-types": { + "version": "2.1.26", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", + "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", + "requires": { + "mime-db": "1.43.0" + } + }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "minipass": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz", + "integrity": "sha1-ys6+SSAiSX9law8PUeJoKp7S2Eg=", + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz", + "integrity": "sha1-3SfqYTYkPHyIBoToZyuzpF/ZthQ=", + "requires": { + "minipass": "^2.2.1" + } + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + } + }, + "mocha": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-8.4.0.tgz", + "integrity": "sha512-hJaO0mwDXmZS4ghXsvPVriOhsxQ7ofcpQdm8dE+jISUOKopitvnXFQmpRR7jd2K6VBG6E26gU3IAbXXGIbu4sQ==", + "dev": true, + "requires": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.1", + "debug": "4.3.1", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.1.6", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "4.0.0", + "log-symbols": "4.0.0", + "minimatch": "3.0.4", + "ms": "2.1.3", + "nanoid": "3.1.20", + "serialize-javascript": "5.0.1", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "which": "2.0.2", + "wide-align": "1.1.3", + "workerpool": "6.1.0", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "chokidar": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", + "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.5.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "js-yaml": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", + "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "readdirp": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", + "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "module-details-from-path": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.3.tgz", + "integrity": "sha1-EUyUlnPiqKNenTV4hSeqN7Z52is=" + }, + "moment": { + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.23.0.tgz", + "integrity": "sha1-dZ6kkayX1UusWtd2mW4qWMwbwiU=" + }, + "moment-timezone": { + "version": "0.5.28", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.28.tgz", + "integrity": "sha512-TDJkZvAyKIVWg5EtVqRzU97w0Rb0YVbfpqyjgu6GwXCAohVRqwZjf4fOzDE6p1Ch98Sro/8hQQi65WDXW5STPw==", + "requires": { + "moment": ">= 2.9.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "mv": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz", + "integrity": "sha1-rmzg1vbV4KT32JN5jQPB6pVZtqI=", + "optional": true, + "requires": { + "mkdirp": "~0.5.1", + "ncp": "~2.0.0", + "rimraf": "~2.4.0" + }, + "dependencies": { + "glob": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", + "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", + "optional": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "rimraf": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz", + "integrity": "sha1-7nEM5dk6j9uFb7Xqj/Di11k0sto=", + "optional": true, + "requires": { + "glob": "^6.0.1" + } + } + } + }, + "mysql": { + "version": "2.18.1", + "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz", + "integrity": "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==", + "requires": { + "bignumber.js": "9.0.0", + "readable-stream": "2.3.7", + "safe-buffer": "5.1.2", + "sqlstring": "2.3.1" + }, + "dependencies": { + "bignumber.js": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", + "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + } + } + }, + "nan": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==" + }, + "nanoid": { + "version": "3.1.20", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz", + "integrity": "sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "ncp": { + "version": "2.0.0", + "resolved": "http://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", + "integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=", + "optional": true + }, + "needle": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/needle/-/needle-2.2.4.tgz", + "integrity": "sha1-UZMb/4JTOxkot9HWngHxsA/9Kk4=", + "requires": { + "debug": "^2.1.2", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + }, + "nise": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/nise/-/nise-4.0.3.tgz", + "integrity": "sha512-EGlhjm7/4KvmmE6B/UFsKh7eHykRl9VH+au8dduHLCyWUO/hr7+N+WtTvDUwc9zHuM1IaIJs/0lQ6Ag1jDkQSg==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0", + "@sinonjs/fake-timers": "^6.0.0", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "path-to-regexp": "^1.7.0" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dev": true, + "requires": { + "isarray": "0.0.1" + } + } + } + }, + "node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" + }, + "node-forge": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.1.tgz", + "integrity": "sha512-G6RlQt5Sb4GMBzXvhfkeFmbqR6MzhtnT7VTHuLadjkii3rdYHNdw0m8zA4BTxVIh68FicCQ2NSUANpsqkr9jvQ==" + }, + "node-pre-gyp": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz", + "integrity": "sha512-TwWAOZb0j7e9eGaf9esRx3ZcLaE5tQ2lvYy1pb5IAaG1a2e2Kv5Lms1Y4hpj+ciXJRofIxxlt5haeQ/2ANeE0Q==", + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + }, + "nodemon": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.7.tgz", + "integrity": "sha512-XHzK69Awgnec9UzHr1kc8EomQh4sjTQ8oRf8TsGrSmHDx9/UmiGG9E/mM3BuTfNeFwdNBvrqQq/RHL0xIeyFOA==", + "dev": true, + "requires": { + "chokidar": "^3.2.2", + "debug": "^3.2.6", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.0.4", + "pstree.remy": "^1.1.7", + "semver": "^5.7.1", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.3", + "update-notifier": "^4.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "nopt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", + "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "normalize-url": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", + "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", + "dev": true + }, + "npm-bundled": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.5.tgz", + "integrity": "sha1-PBcyt7qTazoQMlrvYWRnwMy8yXk=" + }, + "npm-packlist": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.1.12.tgz", + "integrity": "sha1-Ir3i68EucspIKr1nr8UetJN3JDo=", + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha1-CKfyqL9zRgR3mp76StXMcXq7lUs=", + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "object-inspect": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", + "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "object.values": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.4.tgz", + "integrity": "sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.2" + } + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha1-hc36+uso6Gd/QW4odZK18/SepBA=", + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "dev": true + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + }, + "dependencies": { + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + } + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "dev": true, + "requires": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-duration": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/parse-duration/-/parse-duration-0.4.4.tgz", + "integrity": "sha512-KbAJuYGUhZkB9gotDiKLnZ7Z3VTacK3fgwmDdB6ZVDtJbMBT6MfLga0WJaYpPDu0mzqT0NgHtHDt5PY4l0nidg==" + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "parse-ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-2.1.0.tgz", + "integrity": "sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==" + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "pathval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", + "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", + "dev": true + }, + "pdfjs-dist": { + "version": "2.7.570", + "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-2.7.570.tgz", + "integrity": "sha512-/ZkA1FwkEOyDaq11JhMLazdwQAA0F9uwrP7h/1L9Akt9KWh1G5/tkzS+bPuUELq2s2GDFnaT+kooN/aSjT7DXQ==" + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "picomatch": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.1.tgz", + "integrity": "sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA==", + "dev": true + }, + "pify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz", + "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==" + }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + }, + "pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", + "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + }, + "pprof": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pprof/-/pprof-3.0.0.tgz", + "integrity": "sha512-uPWbAhoH/zvq1kM3/Fd/wshb4D7sLlGap8t6uCTER4aZRWqqyPYgXzpjWbT0Unn5U25pEy2VREUu27nQ9o9VPA==", + "requires": { + "bindings": "^1.2.1", + "delay": "^4.0.1", + "findit2": "^2.2.3", + "nan": "^2.14.0", + "node-pre-gyp": "^0.16.0", + "p-limit": "^3.0.0", + "pify": "^5.0.0", + "protobufjs": "~6.10.0", + "source-map": "^0.7.3", + "split": "^1.0.1" + }, + "dependencies": { + "@types/long": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", + "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==" + }, + "@types/node": { + "version": "13.13.42", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.42.tgz", + "integrity": "sha512-g+w2QgbW7k2CWLOXzQXbO37a7v5P9ObPvYahKphdBLV5aqpbVZRhTpWCT0SMRqX1i30Aig791ZmIM2fJGL2S8A==" + }, + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "requires": { + "minimist": "^1.2.5" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "needle": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-2.6.0.tgz", + "integrity": "sha512-KKYdza4heMsEfSWD7VPUIz3zX2XDwOyX2d+geb4vrERZMT5RMU6ujjaD+I5Yr54uZxQ2w6XRTAhHBbSCyovZBg==", + "requires": { + "debug": "^3.2.6", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.16.0.tgz", + "integrity": "sha512-4efGA+X/YXAHLi1hN8KaPrILULaUn2nWecFrn1k2I+99HpoyvcOGEbtcOxpDiUwPF2ZANMJDh32qwOUPenuR1g==", + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.3", + "needle": "^2.5.0", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4.4.2" + } + }, + "protobufjs": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.10.2.tgz", + "integrity": "sha512-27yj+04uF6ya9l+qfpH187aqEzfCF4+Uit0I9ZBQVqK09hk/SQzKa2MUqUpXaVa7LOFRg1TSSr3lVxGOk6c0SQ==", + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": "^13.7.0", + "long": "^4.0.0" + } + }, + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" + } + } + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "dev": true + }, + "prettier": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.2.tgz", + "integrity": "sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ==", + "dev": true + }, + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "requires": { + "fast-diff": "^1.1.2" + } + }, + "pretty-ms": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-7.0.1.tgz", + "integrity": "sha512-973driJZvxiGOQ5ONsFhOF/DtzPMOMtgC11kCpUrPGMTgqp2q/1gwzCquocrN33is0VZ5GFHXZYMM9l6h67v2Q==", + "requires": { + "parse-ms": "^2.1.0" + } + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha1-o31zL0JxtKsa0HDTVQjoKQeI/6o=" + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "prom-client": { + "version": "11.5.3", + "resolved": "https://registry.npmjs.org/prom-client/-/prom-client-11.5.3.tgz", + "integrity": "sha512-iz22FmTbtkyL2vt0MdDFY+kWof+S9UB/NACxSn2aJcewtw+EERsen0urSkZ2WrHseNdydsvcxCTAnPcSMZZv4Q==", + "requires": { + "tdigest": "^0.1.1" + } + }, + "protobufjs": { + "version": "6.8.8", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.8.8.tgz", + "integrity": "sha512-AAmHtD5pXgZfi7GMpllpO3q1Xw1OYldr+dMUlAnffGTAhqkg72WdmSY71uKBF/JuyiKs8psYbtKrhi0ASCD8qw==", + "requires": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.0", + "@types/node": "^10.1.0", + "long": "^4.0.0" + } + }, + "proxy-addr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", + "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.1" + } + }, + "psl": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.7.0.tgz", + "integrity": "sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ==" + }, + "pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-2.0.1.tgz", + "integrity": "sha512-m7KOje7jZxrmutanlkS1daj1dS6z6BgslzOXmcSEpIlCxM3VJH7lG5QLeck/6hgF6F4crFf01UtQmNsJfweTAw==", + "requires": { + "duplexify": "^4.1.1", + "inherits": "^2.0.3", + "pump": "^3.0.0" + }, + "dependencies": { + "duplexify": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.1.tgz", + "integrity": "sha512-DY3xVEmVHTv1wSzKNbwoU6nVjzI369Y6sPoqfYr0/xlx3IdX2n94xIszTcjPO8W8ZIv0Wb0PXNcjuZyT4wiICA==", + "requires": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.0" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha1-tYsBCsQMIsVldhbI0sLALHv0eew=" + }, + "pupa": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", + "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "dev": true, + "requires": { + "escape-goat": "^2.0.0" + } + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + }, + "ramda": { + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.1.tgz", + "integrity": "sha512-PgIdVpn5y5Yns8vqb8FzBUEYn98V3xcPgawAkkgj0YJ0qDsnHCiNmZYfOGMgOvoB0eWFLpYbhxUR3mxfDIMvpw==", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raven": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/raven/-/raven-2.6.4.tgz", + "integrity": "sha512-6PQdfC4+DQSFncowthLf+B6Hr0JpPsFBgTVYTAOq7tCmx/kR4SXbeawtPch20+3QfUcQDoJBLjWW1ybvZ4kXTw==", + "requires": { + "cookie": "0.3.1", + "md5": "^2.2.1", + "stack-trace": "0.0.10", + "timed-out": "4.0.1", + "uuid": "3.3.2" + }, + "dependencies": { + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" + }, + "uuid": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" + } + } + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + } + } + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha1-zZJL9SAKB1uDwYjNa54hG3/A0+0=", + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + } + } + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "read-pkg-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", + "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", + "dev": true, + "requires": { + "picomatch": "^2.0.4" + } + }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, + "registry-auth-token": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", + "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", + "dev": true, + "requires": { + "rc": "^1.2.8" + } + }, + "registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "dev": true, + "requires": { + "rc": "^1.2.8" + } + }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + } + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, + "require-in-the-middle": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-5.1.0.tgz", + "integrity": "sha512-M2rLKVupQfJ5lf9OvqFGIT+9iVLnTmjgbOmpil12hiSQNn5zJTKGPoIisETNjfK+09vP3rpm1zJajmErpr2sEQ==", + "requires": { + "debug": "^4.1.1", + "module-details-from-path": "^1.0.3", + "resolve": "^1.12.0" + }, + "dependencies": { + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "require-like": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/require-like/-/require-like-0.1.2.tgz", + "integrity": "sha1-rW8wwTvs15cBDEaK+ndcDAprR/o=", + "dev": true + }, + "resolve": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", + "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "dev": true, + "requires": { + "lowercase-keys": "^1.0.0" + } + }, + "retry-as-promised": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-3.2.0.tgz", + "integrity": "sha512-CybGs60B7oYU/qSQ6kuaFmRd9sTZ6oXSc0toqePvV74Ac6/IFZSI1ReFQmtCN+uvW1Mtqdwpvt/LGOiCBAY2Mg==", + "requires": { + "any-promise": "^1.3.0" + } + }, + "retry-request": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-4.1.1.tgz", + "integrity": "sha512-BINDzVtLI2BDukjWmjAIRZ0oglnCAkpP2vQjM3jdLhmT62h0xnQgciPwBRDAvHqpkPT2Wo1XuUyLyn6nbGrZQQ==", + "requires": { + "debug": "^4.1.1", + "through2": "^3.0.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha1-LtgVDSShbqhlHm1u8PR8QVjOejY=", + "requires": { + "glob": "^7.0.5" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=" + }, + "safe-json-stringify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/safe-json-stringify/-/safe-json-stringify-1.2.0.tgz", + "integrity": "sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==", + "optional": true + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=" + }, + "sandboxed-module": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/sandboxed-module/-/sandboxed-module-2.0.3.tgz", + "integrity": "sha1-x+VFkzm7y6KMUwPusz9ug4e/upY=", + "dev": true, + "requires": { + "require-like": "0.1.2", + "stack-trace": "0.0.9" + } + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha1-KBYjTiN4vdxOU1T6tcqold9xANk=" + }, + "semver": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", + "integrity": "sha1-fnQlb7qknHWqfHogXMInmcrIAAQ=" + }, + "semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "dev": true, + "requires": { + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, + "sequelize": { + "version": "5.21.5", + "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-5.21.5.tgz", + "integrity": "sha512-n9hR5K4uQGmBGK/Y/iqewCeSFmKVsd0TRnh0tfoLoAkmXbKC4tpeK96RhKs7d+TTMtrJlgt2TNLVBaAxEwC4iw==", + "requires": { + "bluebird": "^3.5.0", + "cls-bluebird": "^2.1.0", + "debug": "^4.1.1", + "dottie": "^2.0.0", + "inflection": "1.12.0", + "lodash": "^4.17.15", + "moment": "^2.24.0", + "moment-timezone": "^0.5.21", + "retry-as-promised": "^3.2.0", + "semver": "^6.3.0", + "sequelize-pool": "^2.3.0", + "toposort-class": "^1.0.1", + "uuid": "^3.3.3", + "validator": "^10.11.0", + "wkx": "^0.4.8" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "moment": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", + "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "sequelize-pool": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-2.3.0.tgz", + "integrity": "sha512-Ibz08vnXvkZ8LJTiUOxRcj1Ckdn7qafNZ2t59jYHMX1VIebTAOYefWdRYFt6z6+hy52WGthAHAoLc9hvk3onqA==" + }, + "serialize-javascript": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", + "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "shimmer": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.0.tgz", + "integrity": "sha1-+Wb3VVeJdj502IQRk2haXnhzZmU=" + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" + }, + "sinon": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.0.1.tgz", + "integrity": "sha512-iTTyiQo5T94jrOx7X7QLBZyucUJ2WvL9J13+96HMfm2CGoJYbIPqRfl6wgNcqmzk0DI28jeGx5bUTXizkrqBmg==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0", + "@sinonjs/fake-timers": "^6.0.0", + "@sinonjs/formatio": "^5.0.1", + "@sinonjs/samsam": "^5.0.3", + "diff": "^4.0.2", + "nise": "^4.0.1", + "supports-color": "^7.1.0" + }, + "dependencies": { + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true + } + } + }, + "snakecase-keys": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/snakecase-keys/-/snakecase-keys-3.2.0.tgz", + "integrity": "sha512-WTJ0NhCH/37J+PU3fuz0x5b6TvtWQChTcKPOndWoUy0pteKOe0hrHMzSRsJOWSIP48EQkzUEsgQPmrG3W8pFNQ==", + "requires": { + "map-obj": "^4.0.0", + "to-snake-case": "^1.0.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.9.tgz", + "integrity": "sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ==", + "dev": true + }, + "split": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "requires": { + "through": "2" + } + }, + "split-ca": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split-ca/-/split-ca-1.0.1.tgz", + "integrity": "sha1-bIOv82kvphJW4M0ZfgXp3hV2kaY=" + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "sqlite3": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-4.1.1.tgz", + "integrity": "sha512-CvT5XY+MWnn0HkbwVKJAyWEMfzpAPwnTiB3TobA5Mri44SrTovmmh499NPQP+gatkeOipqPlBLel7rn4E/PCQg==", + "requires": { + "nan": "^2.12.1", + "node-pre-gyp": "^0.11.0", + "request": "^2.87.0" + } + }, + "sqlstring": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", + "integrity": "sha1-R1OT/56RR5rqYtyvDKPRSYOn+0A=" + }, + "ssh2": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/ssh2/-/ssh2-0.8.8.tgz", + "integrity": "sha512-egJVQkf3sbjECTY6rCeg8rgV/fab6S/7E5kpYqHT3Fe/YpfJbLYeA1qTcB2d+LRUUAjqKi7rlbfWkaP66YdpAQ==", + "requires": { + "ssh2-streams": "~0.4.9" + } + }, + "ssh2-streams": { + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/ssh2-streams/-/ssh2-streams-0.4.9.tgz", + "integrity": "sha512-glMQKeYKuA+rLaH16fJC3nZMV1BWklbxuYCR4C5/LlBSf2yaoNRpPU7Ul702xsi5nvYjIx9XDkKBJwrBjkDynw==", + "requires": { + "asn1": "~0.2.0", + "bcrypt-pbkdf": "^1.0.2", + "streamsearch": "~0.1.2" + } + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "stack-trace": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.9.tgz", + "integrity": "sha1-qPbq7KkGdMMz58Q5U/J1tFFRBpU=", + "dev": true + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "stream-events": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz", + "integrity": "sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==", + "requires": { + "stubs": "^3.0.0" + } + }, + "stream-shift": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", + "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=" + }, + "streamsearch": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", + "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=" + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string.prototype.trimend": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + }, + "stubs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz", + "integrity": "sha1-6NK6H6nJBXAwPAMLaQD31fiavls=" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "table": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", + "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", + "dev": true, + "requires": { + "ajv": "^8.0.1", + "lodash.clonedeep": "^4.5.0", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.6.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.1.tgz", + "integrity": "sha512-42VLtQUOLefAvKFAQIxIZDaThq6om/PrfP0CYk3/vn+y4BMNkKnbli8ON2QCiHov4KkzOSJ/xSoBJdayiiYvVQ==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + } + } + }, + "tar": { + "version": "4.4.8", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz", + "integrity": "sha1-sZ7sP94qluZGZt+f20DFyhvDdH0=", + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" + } + }, + "tar-fs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.0.0.tgz", + "integrity": "sha512-vaY0obB6Om/fso8a8vakQBzwholQ7v5+uy+tF3Ozvxv1KNezmVQAiWtcNmMHFSFPqL3dJA8ha6gdtFbfX9mcxA==", + "requires": { + "chownr": "^1.1.1", + "mkdirp": "^0.5.1", + "pump": "^3.0.0", + "tar-stream": "^2.0.0" + } + }, + "tar-stream": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.2.tgz", + "integrity": "sha512-UaF6FoJ32WqALZGOIAApXx+OdxhekNMChu6axLJR85zMMjXKWFGjbIRe+J6P4UnRGg9rAwWvbTT0oI7hD/Un7Q==", + "requires": { + "bl": "^4.0.1", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "tdigest": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/tdigest/-/tdigest-0.1.1.tgz", + "integrity": "sha1-Ljyyw56kSeVdHmzZEReszKRYgCE=", + "requires": { + "bintrees": "1.0.1" + } + }, + "teeny-request": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-6.0.3.tgz", + "integrity": "sha512-TZG/dfd2r6yeji19es1cUIwAlVD8y+/svB1kAC2Y0bjEyysrfbO8EZvJBRwIE6WkwmUoB7uvWLwTIhJbMXZ1Dw==", + "requires": { + "http-proxy-agent": "^4.0.0", + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.2.0", + "stream-events": "^1.0.5", + "uuid": "^7.0.0" + }, + "dependencies": { + "uuid": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz", + "integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==" + } + } + }, + "term-size": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.1.tgz", + "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==", + "dev": true + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "through2": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", + "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", + "requires": { + "readable-stream": "2 || 3" + } + }, + "timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=" + }, + "timekeeper": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/timekeeper/-/timekeeper-2.2.0.tgz", + "integrity": "sha512-W3AmPTJWZkRwu+iSNxPIsLZ2ByADsOLbbLxe46UJyWj3mlYLlwucKiq+/dPm0l9wTzqoF3/2PH0AGFCebjq23A==", + "dev": true + }, + "to-no-case": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/to-no-case/-/to-no-case-1.0.2.tgz", + "integrity": "sha1-xyKQcWTvaxeBMsjmmTAhLRtKoWo=" + }, + "to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "to-snake-case": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-snake-case/-/to-snake-case-1.0.0.tgz", + "integrity": "sha1-znRpE4l5RgGah+Yu366upMYIq4w=", + "requires": { + "to-space-case": "^1.0.0" + } + }, + "to-space-case": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-space-case/-/to-space-case-1.0.0.tgz", + "integrity": "sha1-sFLar7Gysp3HcM6gFj5ewOvJ/Bc=", + "requires": { + "to-no-case": "^1.0.0" + } + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + }, + "toposort-class": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz", + "integrity": "sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg=" + }, + "touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "requires": { + "nopt": "~1.0.10" + }, + "dependencies": { + "nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "dev": true, + "requires": { + "abbrev": "1" + } + } + } + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "tsconfig-paths": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.10.1.tgz", + "integrity": "sha512-rETidPDgCpltxF7MjBZlAFPUHv5aHH2MymyPvh+vEyWAED4Eb/WeMbsnD/JDr4OKPOA1TssDHgIcpTN5Kh0p6Q==", + "dev": true, + "requires": { + "json5": "^2.2.0", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + } + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "unbox-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", + "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + }, + "dependencies": { + "has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "dev": true + } + } + }, + "undefsafe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.3.tgz", + "integrity": "sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A==", + "dev": true, + "requires": { + "debug": "^2.2.0" + } + }, + "underscore": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", + "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=" + }, + "unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "requires": { + "crypto-random-string": "^2.0.0" + } + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "update-notifier": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.3.tgz", + "integrity": "sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A==", + "dev": true, + "requires": { + "boxen": "^4.2.0", + "chalk": "^3.0.0", + "configstore": "^5.0.1", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.3.1", + "is-npm": "^4.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.0.0", + "pupa": "^2.0.1", + "semver-diff": "^3.1.1", + "xdg-basedir": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha1-lMVA4f93KVbiKZUHwBCupsiDjrA=", + "requires": { + "punycode": "^2.1.0" + } + }, + "url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "dev": true, + "requires": { + "prepend-http": "^2.0.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "uuid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", + "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==" + }, + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "v8-profiler-node8": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/v8-profiler-node8/-/v8-profiler-node8-6.1.1.tgz", + "integrity": "sha512-mKS7TXRRYi70hvbv5c1tk9AbuqNrtbLc+jFLlsZ2TpaC1l5lWryBlDLZKJ1JP6hjSbMEjW1ucjWLSaKsaPnGXg==", + "requires": { + "nan": "^2.14.0", + "node-pre-gyp": "^0.13.0" + }, + "dependencies": { + "node-pre-gyp": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.13.0.tgz", + "integrity": "sha512-Md1D3xnEne8b/HGVQkZZwV27WUi1ZRuZBij24TNaZwUPU3ZAFtvT6xxJGaUVillfmMKnn5oD1HoGsp2Ftik7SQ==", + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + } + } + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "validator": { + "version": "10.11.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-10.11.0.tgz", + "integrity": "sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw==" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "walkdir": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/walkdir/-/walkdir-0.4.1.tgz", + "integrity": "sha512-3eBwRyEln6E1MSzcxcVpQIhRG8Q1jLvEqRmCZqS3dsfXEDR/AhOF4d+jHg1qvDCpYaVRZjENPQyrVxAkQqxPgQ==" + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha1-rgdOa9wMFKQx6ATmJFScYzsABFc=", + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dev": true, + "requires": { + "string-width": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, + "wkx": { + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/wkx/-/wkx-0.4.8.tgz", + "integrity": "sha512-ikPXMM9IR/gy/LwiOSqWlSL3X/J5uk9EO2hHNRXS41eTLXaUFEVw9fn/593jW/tE5tedNg8YjT5HkCa4FqQZyQ==", + "requires": { + "@types/node": "*" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "workerpool": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.0.tgz", + "integrity": "sha512-toV7q9rWNYha963Pl/qyeZ6wG+3nnsyvolaNUS8+R5Wtw6qJPTxIlOP1ZSvcGhEJw+l3HMMmtiNo9Gl61G4GVg==", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "wrench": { + "version": "1.5.9", + "resolved": "https://registry.npmjs.org/wrench/-/wrench-1.5.9.tgz", + "integrity": "sha1-QRaRxjqbJTGxcAJnJ5veyiOyFCo=" + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "dev": true + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yallist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", + "integrity": "sha1-tLBJ4xS+VF486AIjbWzSLNkcPek=" + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true + }, + "yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "requires": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "dependencies": { + "camelcase": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", + "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", + "dev": true + } + } + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==" + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" + } + } +} diff --git a/services/clsi/package.json b/services/clsi/package.json new file mode 100644 index 0000000000..0b2b011d49 --- /dev/null +++ b/services/clsi/package.json @@ -0,0 +1,67 @@ +{ + "name": "node-clsi", + "description": "A Node.js implementation of the CLSI LaTeX web-API", + "version": "0.1.4", + "repository": { + "type": "git", + "url": "https://github.com/sharelatex/clsi-sharelatex.git" + }, + "scripts": { + "start": "node $NODE_APP_OPTIONS app.js", + "test:acceptance:_run": "mocha --recursive --reporter spec --timeout 15000 --exit $@ test/acceptance/js", + "test:acceptance": "npm run test:acceptance:_run -- --grep=$MOCHA_GREP", + "test:unit:_run": "mocha --recursive --reporter spec $@ test/unit/js", + "test:unit": "npm run test:unit:_run -- --grep=$MOCHA_GREP", + "nodemon": "nodemon --config nodemon.json", + "lint": "eslint --max-warnings 0 --format unix .", + "format": "prettier --list-different $PWD/'**/*.js'", + "format:fix": "prettier --write $PWD/'**/*.js'", + "lint:fix": "eslint --fix ." + }, + "author": "James Allen ", + "dependencies": { + "@overleaf/metrics": "^3.5.1", + "@overleaf/o-error": "^3.3.1", + "@overleaf/settings": "^2.1.1", + "async": "3.2.0", + "body-parser": "^1.19.0", + "bunyan": "^1.8.15", + "diskusage": "^1.1.3", + "dockerode": "^3.1.0", + "express": "^4.17.1", + "fs-extra": "^10.0.0", + "heapdump": "^0.3.15", + "lockfile": "^1.0.4", + "lodash": "^4.17.21", + "logger-sharelatex": "^2.2.0", + "mysql": "^2.18.1", + "p-limit": "^3.1.0", + "pdfjs-dist": "^2.7.570", + "request": "^2.88.2", + "send": "^0.17.1", + "sequelize": "^5.21.5", + "sqlite3": "^4.1.1", + "v8-profiler-node8": "^6.1.1", + "wrench": "~1.5.9" + }, + "devDependencies": { + "chai": "^4.2.0", + "chai-as-promised": "^7.1.1", + "eslint": "^7.21.0", + "eslint-config-prettier": "^8.1.0", + "eslint-config-standard": "^16.0.2", + "eslint-plugin-chai-expect": "^2.2.0", + "eslint-plugin-chai-friendly": "^0.6.0", + "eslint-plugin-import": "^2.22.1", + "eslint-plugin-mocha": "^8.0.0", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-prettier": "^3.1.2", + "eslint-plugin-promise": "^4.2.1", + "mocha": "^8.3.2", + "nodemon": "^2.0.7", + "prettier": "^2.2.1", + "sandboxed-module": "^2.0.3", + "sinon": "~9.0.1", + "timekeeper": "2.2.0" + } +} diff --git a/services/clsi/patch-texlive-dockerfile b/services/clsi/patch-texlive-dockerfile new file mode 100644 index 0000000000..61cb796414 --- /dev/null +++ b/services/clsi/patch-texlive-dockerfile @@ -0,0 +1,3 @@ +FROM quay.io/sharelatex/texlive-full:2017.1 + +# RUN usermod -u 1001 tex diff --git a/services/clsi/scripts/demo-pdfjs-Xref.js b/services/clsi/scripts/demo-pdfjs-Xref.js new file mode 100644 index 0000000000..86be134ef5 --- /dev/null +++ b/services/clsi/scripts/demo-pdfjs-Xref.js @@ -0,0 +1,12 @@ +const fs = require('fs') +const { parseXrefTable } = require('../app/lib/pdfjs/parseXrefTable') + +const pdfPath = process.argv[2] + +async function main() { + const size = (await fs.promises.stat(pdfPath)).size + const xRefEntries = await parseXrefTable(pdfPath, size) + console.log('Xref entries', xRefEntries) +} + +main().catch(console.error) diff --git a/services/clsi/seccomp/clsi-profile.json b/services/clsi/seccomp/clsi-profile.json new file mode 100644 index 0000000000..e7e9dd010b --- /dev/null +++ b/services/clsi/seccomp/clsi-profile.json @@ -0,0 +1,836 @@ +{ + "defaultAction": "SCMP_ACT_ERRNO", + "architectures": [ + "SCMP_ARCH_X86_64", + "SCMP_ARCH_X86", + "SCMP_ARCH_X32" + ], + "syscalls": [ + { + "name": "access", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "arch_prctl", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "brk", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "chdir", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "chmod", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "clock_getres", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "clock_gettime", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "clock_nanosleep", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "clone", + "action": "SCMP_ACT_ALLOW", + "args": [ + { + "index": 0, + "value": 2080505856, + "valueTwo": 0, + "op": "SCMP_CMP_MASKED_EQ" + } + ] + }, + { + "name": "close", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "copy_file_range", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "creat", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "dup", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "dup2", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "dup3", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "execve", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "execveat", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "exit", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "exit_group", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "faccessat", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "fadvise64", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "fadvise64_64", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "fallocate", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "fchdir", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "fchmod", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "fchmodat", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "fcntl", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "fcntl64", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "fdatasync", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "fork", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "fstat", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "fstat64", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "fstatat64", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "fstatfs", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "fstatfs64", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "fsync", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "ftruncate", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "ftruncate64", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "futex", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "futimesat", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "getcpu", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "getcwd", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "getdents", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "getdents64", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "getegid", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "getegid32", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "geteuid", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "geteuid32", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "getgid", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "getgid32", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "getgroups", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "getgroups32", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "getpgid", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "getpgrp", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "getpid", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "getppid", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "getpriority", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "getresgid", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "getresgid32", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "getresuid", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "getresuid32", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "getrlimit", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "get_robust_list", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "getrusage", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "getsid", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "gettid", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "getuid", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "getuid32", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "ioctl", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "kill", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "_llseek", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "lseek", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "lstat", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "lstat64", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "madvise", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "mkdir", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "mkdirat", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "mmap", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "mmap2", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "mprotect", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "mremap", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "munmap", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "newfstatat", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "open", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "openat", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "pause", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "pipe", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "pipe2", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "prctl", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "pread64", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "preadv", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "prlimit64", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "pwrite64", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "pwritev", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "read", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "readlink", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "readlinkat", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "readv", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "rename", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "renameat", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "renameat2", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "restart_syscall", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "rmdir", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "rt_sigaction", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "rt_sigpending", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "rt_sigprocmask", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "rt_sigqueueinfo", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "rt_sigreturn", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "rt_sigsuspend", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "rt_sigtimedwait", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "rt_tgsigqueueinfo", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "sched_getaffinity", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "sched_getparam", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "sched_get_priority_max", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "sched_get_priority_min", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "sched_getscheduler", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "sched_rr_get_interval", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "sched_yield", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "sendfile", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "sendfile64", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "setgroups", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "setgroups32", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "set_robust_list", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "set_tid_address", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "sigaltstack", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "stat", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "stat64", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "statfs", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "statfs64", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "sync", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "sync_file_range", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "syncfs", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "sysinfo", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "tgkill", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "timer_create", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "timer_delete", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "timer_getoverrun", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "timer_gettime", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "timer_settime", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "times", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "tkill", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "truncate", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "truncate64", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "umask", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "uname", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "unlink", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "unlinkat", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "utime", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "utimensat", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "utimes", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "vfork", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "vhangup", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "wait4", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "waitid", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "write", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "writev", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "pread", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "setgid", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "setuid", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "capget", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "capset", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "fchown", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, + { + "name": "gettimeofday", + "action": "SCMP_ACT_ALLOW", + "args": [] + }, { + "name": "epoll_pwait", + "action": "SCMP_ACT_ALLOW", + "args": [] + } + ] +} \ No newline at end of file diff --git a/services/clsi/src/synctex.c b/services/clsi/src/synctex.c new file mode 100644 index 0000000000..5267f81f9c --- /dev/null +++ b/services/clsi/src/synctex.c @@ -0,0 +1,66 @@ +#include +#include +#include +#include + +#include "synctex/synctex_parser.h" + + +void print_usage() { + fprintf (stderr, "Usage: synctex code \n"); + fprintf (stderr, " synctex pdf \n"); +} + +int main(int argc, char *argv[], char *envp[]) { + synctex_scanner_t scanner; + + if (argc < 6 || (strcmp(argv[1], "code") != 0 && strcmp(argv[1], "pdf") != 0)) { + print_usage(); + return EXIT_FAILURE; + } + + const char* direction = argv[1]; + const char* synctex_file = argv[2]; + + scanner = synctex_scanner_new_with_output_file(synctex_file, NULL, 1); + + if(!(scanner = synctex_scanner_parse(scanner))) { + fprintf (stderr, "Could not parse output file\n"); + return EXIT_FAILURE; + } + + if (strcmp(direction, "code") == 0) { + const char* name = argv[3]; + int line = atoi(argv[4]); + int column = atoi(argv[5]); + + if(synctex_display_query(scanner, name, line, column) > 0) { + synctex_node_t node; + while((node = synctex_next_result(scanner))) { + int page = synctex_node_page(node); + float h = synctex_node_box_visible_h(node); + float v = synctex_node_box_visible_v(node); + float width = synctex_node_box_visible_width(node); + float height = synctex_node_box_visible_height(node); + printf ("NODE\t%d\t%.2f\t%.2f\t%.2f\t%.2f\n", page, h, v, width, height); + } + } + } else if (strcmp(direction, "pdf") == 0) { + int page = atoi(argv[3]); + float h = atof(argv[4]); + float v = atof(argv[5]); + + if(synctex_edit_query(scanner, page, h, v) > 0) { + synctex_node_t node; + while((node = synctex_next_result(scanner))) { + int tag = synctex_node_tag(node); + const char* name = synctex_scanner_get_name(scanner, tag); + int line = synctex_node_line(node); + int column = synctex_node_column(node); + printf ("NODE\t%s\t%d\t%d\n", name, line, column); + } + } + } + + return 0; +} \ No newline at end of file diff --git a/services/clsi/src/synctex/synctex_parser.c b/services/clsi/src/synctex/synctex_parser.c new file mode 100644 index 0000000000..0d3de08b48 --- /dev/null +++ b/services/clsi/src/synctex/synctex_parser.c @@ -0,0 +1,4249 @@ +/* +Copyright (c) 2008, 2009, 2010 , 2011 jerome DOT laurens AT u-bourgogne DOT fr + +This file is part of the SyncTeX package. + +Latest Revision: Tue Jun 14 08:23:30 UTC 2011 + +Version: 1.16 + +See synctex_parser_readme.txt for more details + +License: +-------- +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 + +Except as contained in this notice, the name of the copyright holder +shall not be used in advertising or otherwise to promote the sale, +use or other dealings in this Software without prior written +authorization from the copyright holder. + +Acknowledgments: +---------------- +The author received useful remarks from the pdfTeX developers, especially Hahn The Thanh, +and significant help from XeTeX developer Jonathan Kew + +Nota Bene: +---------- +If you include or use a significant part of the synctex package into a software, +I would appreciate to be listed as contributor and see "SyncTeX" highlighted. + +Version 1 +Thu Jun 19 09:39:21 UTC 2008 + +*/ + +/* We assume that high level application like pdf viewers will want + * to embed this code as is. We assume that they also have locale.h and setlocale. + * For other tools such as TeXLive tools, you must define SYNCTEX_USE_LOCAL_HEADER, + * when building. You also have to create and customize synctex_parser_local.h to fit your system. + * In particular, the HAVE_LOCALE_H and HAVE_SETLOCALE macros should be properly defined. + * With this design, you should not need to edit this file. */ + +# if defined(SYNCTEX_USE_LOCAL_HEADER) +# include "synctex_parser_local.h" +# else +# define HAVE_LOCALE_H 1 +# define HAVE_SETLOCALE 1 +# if defined(_MSC_VER) +# define SYNCTEX_INLINE __inline +# else +# define SYNCTEX_INLINE inline +# endif +# endif + +#include +#include +#include +#include +#include + +#if defined(HAVE_LOCALE_H) +#include +#endif + +/* The data is organized in a graph with multiple entries. + * The root object is a scanner, it is created with the contents on a synctex file. + * Each leaf of the tree is a synctex_node_t object. + * There are 3 subtrees, two of them sharing the same leaves. + * The first tree is the list of input records, where input file names are associated with tags. + * The second tree is the box tree as given by TeX when shipping pages out. + * First level objects are sheets, containing boxes, glues, kerns... + * The third tree allows to browse leaves according to tag and line. + */ + +#include "synctex_parser.h" +#include "synctex_parser_utils.h" + +/* These are the possible extensions of the synctex file */ +const char * synctex_suffix = ".synctex"; +const char * synctex_suffix_gz = ".gz"; + +/* each synctex node has a class */ +typedef struct __synctex_class_t _synctex_class_t; +typedef _synctex_class_t * synctex_class_t; + + +/* synctex_node_t is a pointer to a node + * _synctex_node is the target of the synctex_node_t pointer + * It is a pseudo object oriented program. + * class is a pointer to the class object the node belongs to. + * implementation is meant to contain the private data of the node + * basically, there are 2 kinds of information: navigation information and + * synctex information. Both will depend on the type of the node, + * thus different nodes will have different private data. + * There is no inheritancy overhead. + */ +typedef union _synctex_info_t { + int INT; + char * PTR; +} synctex_info_t; + +struct _synctex_node { + synctex_class_t class; + synctex_info_t * implementation; +}; + +/* Each node of the tree, except the scanner itself belongs to a class. + * The class object is just a struct declaring the owning scanner + * This is a pointer to the scanner as root of the tree. + * The type is used to identify the kind of node. + * The class declares pointers to a creator and a destructor method. + * The log and display fields are used to log and display the node. + * display will also display the child, sibling and parent sibling. + * parent, child and sibling are used to navigate the tree, + * from TeX box hierarchy point of view. + * The friend field points to a method which allows to navigate from friend to friend. + * A friend is a node with very close tag and line numbers. + * Finally, the info field point to a method giving the private node info offset. + */ + +typedef synctex_node_t *(*_synctex_node_getter_t)(synctex_node_t); +typedef synctex_info_t *(*_synctex_info_getter_t)(synctex_node_t); + +struct __synctex_class_t { + synctex_scanner_t scanner; + int type; + synctex_node_t (*new)(synctex_scanner_t scanner); + void (*free)(synctex_node_t); + void (*log)(synctex_node_t); + void (*display)(synctex_node_t); + _synctex_node_getter_t parent; + _synctex_node_getter_t child; + _synctex_node_getter_t sibling; + _synctex_node_getter_t friend; + _synctex_node_getter_t next_box; + _synctex_info_getter_t info; +}; + +# ifdef SYNCTEX_NOTHING +# pragma mark - +# pragma mark Abstract OBJECTS and METHODS +# endif + +/* These macros are shortcuts + * This macro checks if a message can be sent. + */ +# define SYNCTEX_CAN_PERFORM(NODE,SELECTOR)\ + (NULL!=((((NODE)->class))->SELECTOR)) + +/* This macro is some kind of objc_msg_send. + * It takes care of sending the proper message if possible. + */ +# define SYNCTEX_MSG_SEND(NODE,SELECTOR) if (NODE && SYNCTEX_CAN_PERFORM(NODE,SELECTOR)) {\ + (*((((NODE)->class))->SELECTOR))(NODE);\ + } + +/* read only safe getter + */ +# define SYNCTEX_GET(NODE,SELECTOR)((NODE && SYNCTEX_CAN_PERFORM(NODE,SELECTOR))?SYNCTEX_GETTER(NODE,SELECTOR)[0]:(NULL)) + +/* read/write getter + */ +# define SYNCTEX_GETTER(NODE,SELECTOR)\ + ((synctex_node_t *)((*((((NODE)->class))->SELECTOR))(NODE))) + +# define SYNCTEX_FREE(NODE) SYNCTEX_MSG_SEND(NODE,free); + +/* Parent getter and setter + */ +# define SYNCTEX_PARENT(NODE) SYNCTEX_GET(NODE,parent) +# define SYNCTEX_SET_PARENT(NODE,NEW_PARENT) if (NODE && NEW_PARENT && SYNCTEX_CAN_PERFORM(NODE,parent)){\ + SYNCTEX_GETTER(NODE,parent)[0]=NEW_PARENT;\ + } + +/* Child getter and setter + */ +# define SYNCTEX_CHILD(NODE) SYNCTEX_GET(NODE,child) +# define SYNCTEX_SET_CHILD(NODE,NEW_CHILD) if (NODE && NEW_CHILD){\ + SYNCTEX_GETTER(NODE,child)[0]=NEW_CHILD;\ + SYNCTEX_GETTER(NEW_CHILD,parent)[0]=NODE;\ + } + +/* Sibling getter and setter + */ +# define SYNCTEX_SIBLING(NODE) SYNCTEX_GET(NODE,sibling) +# define SYNCTEX_SET_SIBLING(NODE,NEW_SIBLING) if (NODE && NEW_SIBLING) {\ + SYNCTEX_GETTER(NODE,sibling)[0]=NEW_SIBLING;\ + if (SYNCTEX_CAN_PERFORM(NEW_SIBLING,parent) && SYNCTEX_CAN_PERFORM(NODE,parent)) {\ + SYNCTEX_GETTER(NEW_SIBLING,parent)[0]=SYNCTEX_GETTER(NODE,parent)[0];\ + }\ + } +/* Friend getter and setter. A friend is a kern, math, glue or void box node which tag and line numbers are similar. + * This is a first filter on the nodes that avoids testing all of them. + * Friends are used mainly in forward synchronization aka from source to output. + */ +# define SYNCTEX_FRIEND(NODE) SYNCTEX_GET(NODE,friend) +# define SYNCTEX_SET_FRIEND(NODE,NEW_FRIEND) if (NODE && NEW_FRIEND){\ + SYNCTEX_GETTER(NODE,friend)[0]=NEW_FRIEND;\ + } + +/* Next box getter and setter. The box tree can be traversed from one horizontal box to the other. + * Navigation starts with the deeper boxes. + */ +# define SYNCTEX_NEXT_HORIZ_BOX(NODE) SYNCTEX_GET(NODE,next_box) +# define SYNCTEX_SET_NEXT_HORIZ_BOX(NODE,NEXT_BOX) if (NODE && NEXT_BOX){\ + SYNCTEX_GETTER(NODE,next_box)[0]=NEXT_BOX;\ + } + +void _synctex_free_node(synctex_node_t node); +void _synctex_free_leaf(synctex_node_t node); + +/* A node is meant to own its child and sibling. + * It is not owned by its parent, unless it is its first child. + * This destructor is for all nodes with children. + */ +void _synctex_free_node(synctex_node_t node) { + if (node) { + (*((node->class)->sibling))(node); + SYNCTEX_FREE(SYNCTEX_SIBLING(node)); + SYNCTEX_FREE(SYNCTEX_CHILD(node)); + free(node); + } + return; +} + +/* A node is meant to own its child and sibling. + * It is not owned by its parent, unless it is its first child. + * This destructor is for nodes with no child. + */ +void _synctex_free_leaf(synctex_node_t node) { + if (node) { + SYNCTEX_FREE(SYNCTEX_SIBLING(node)); + free(node); + } + return; +} +# ifdef __SYNCTEX_WORK__ +# include "/usr/include/zlib.h" +# else +# include +# endif + +/* The synctex scanner is the root object. + * Is is initialized with the contents of a text file or a gzipped file. + * The buffer_? are first used to parse the text. + */ +struct __synctex_scanner_t { + gzFile file; /* The (possibly compressed) file */ + char * buffer_cur; /* current location in the buffer */ + char * buffer_start; /* start of the buffer */ + char * buffer_end; /* end of the buffer */ + char * output_fmt; /* dvi or pdf, not yet used */ + char * output; /* the output name used to create the scanner */ + char * synctex; /* the .synctex or .synctex.gz name used to create the scanner */ + int version; /* 1, not yet used */ + struct { + unsigned has_parsed:1; /* Whether the scanner has parsed its underlying synctex file. */ + unsigned reserved:sizeof(unsigned)-1; /* alignment */ + } flags; + int pre_magnification; /* magnification from the synctex preamble */ + int pre_unit; /* unit from the synctex preamble */ + int pre_x_offset; /* X offste from the synctex preamble */ + int pre_y_offset; /* Y offset from the synctex preamble */ + int count; /* Number of records, from the synctex postamble */ + float unit; /* real unit, from synctex preamble or post scriptum */ + float x_offset; /* X offset, from synctex preamble or post scriptum */ + float y_offset; /* Y Offset, from synctex preamble or post scriptum */ + synctex_node_t sheet; /* The first sheet node, its siblings are the other sheet nodes */ + synctex_node_t input; /* The first input node, its siblings are the other input nodes */ + int number_of_lists; /* The number of friend lists */ + synctex_node_t * lists_of_friends;/* The friend lists */ + _synctex_class_t class[synctex_node_number_of_types]; /* The classes of the nodes of the scanner */ +}; + +/* SYNCTEX_CUR, SYNCTEX_START and SYNCTEX_END are convenient shortcuts + */ +# define SYNCTEX_CUR (scanner->buffer_cur) +# define SYNCTEX_START (scanner->buffer_start) +# define SYNCTEX_END (scanner->buffer_end) + +# ifdef SYNCTEX_NOTHING +# pragma mark - +# pragma mark OBJECTS, their creators and destructors. +# endif + +/* Here, we define the indices for the different informations. + * They are used to declare the size of the implementation. + * For example, if one object uses SYNCTEX_HORIZ_IDX is its size, + * then its info will contain a tag, line, column, horiz but no width nor height nor depth + */ + +/* The sheet is a first level node. + * It has no parent (the parent is the scanner itself) + * Its sibling points to another sheet. + * Its child points to its first child, in general a box. + * A sheet node contains only one synctex information: the page. + * This is the 1 based page index as given by TeX. + */ +/* The next macros are used to access the node info + * SYNCTEX_INFO(node) points to the first synctex integer or pointer data of node + * SYNCTEX_INFO(node)[index] is the information at index + * for example, the page of a sheet is stored in SYNCTEX_INFO(sheet)[SYNCTEX_PAGE_IDX] + */ +# define SYNCTEX_INFO(NODE) ((*((((NODE)->class))->info))(NODE)) +# define SYNCTEX_PAGE_IDX 0 +# define SYNCTEX_PAGE(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_PAGE_IDX].INT + +/* This macro defines implementation offsets + * It is only used for pointer values + */ +# define SYNCTEX_MAKE_GET(SYNCTEX_GETTER,OFFSET)\ +synctex_node_t * SYNCTEX_GETTER (synctex_node_t node);\ +synctex_node_t * SYNCTEX_GETTER (synctex_node_t node) {\ + return node?(synctex_node_t *)((&((node)->implementation))+OFFSET):NULL;\ +} +SYNCTEX_MAKE_GET(_synctex_implementation_0,0) +SYNCTEX_MAKE_GET(_synctex_implementation_1,1) +SYNCTEX_MAKE_GET(_synctex_implementation_2,2) +SYNCTEX_MAKE_GET(_synctex_implementation_3,3) +SYNCTEX_MAKE_GET(_synctex_implementation_4,4) +SYNCTEX_MAKE_GET(_synctex_implementation_5,5) + +typedef struct { + synctex_class_t class; + synctex_info_t implementation[3+SYNCTEX_PAGE_IDX+1];/* child, sibling, next box, + * SYNCTEX_PAGE_IDX */ +} synctex_sheet_t; + +synctex_node_t _synctex_new_sheet(synctex_scanner_t scanner); +void _synctex_display_sheet(synctex_node_t sheet); +void _synctex_log_sheet(synctex_node_t sheet); + +static _synctex_class_t synctex_class_sheet = { + NULL, /* No scanner yet */ + synctex_node_type_sheet, /* Node type */ + &_synctex_new_sheet, /* creator */ + &_synctex_free_node, /* destructor */ + &_synctex_log_sheet, /* log */ + &_synctex_display_sheet, /* display */ + NULL, /* No parent */ + &_synctex_implementation_0, /* child */ + &_synctex_implementation_1, /* sibling */ + NULL, /* No friend */ + &_synctex_implementation_2, /* Next box */ + (_synctex_info_getter_t)&_synctex_implementation_3 /* info */ +}; + +/* sheet node creator */ +synctex_node_t _synctex_new_sheet(synctex_scanner_t scanner) { + synctex_node_t node = _synctex_malloc(sizeof(synctex_sheet_t)); + if (node) { + node->class = scanner?scanner->class+synctex_node_type_sheet:(synctex_class_t)&synctex_class_sheet; + } + return node; +} + +/* A box node contains navigation and synctex information + * There are different kind of boxes. + * Only horizontal boxes are treated differently because of their visible size. + */ +# define SYNCTEX_TAG_IDX 0 +# define SYNCTEX_LINE_IDX (SYNCTEX_TAG_IDX+1) +# define SYNCTEX_COLUMN_IDX (SYNCTEX_LINE_IDX+1) +# define SYNCTEX_HORIZ_IDX (SYNCTEX_COLUMN_IDX+1) +# define SYNCTEX_VERT_IDX (SYNCTEX_HORIZ_IDX+1) +# define SYNCTEX_WIDTH_IDX (SYNCTEX_VERT_IDX+1) +# define SYNCTEX_HEIGHT_IDX (SYNCTEX_WIDTH_IDX+1) +# define SYNCTEX_DEPTH_IDX (SYNCTEX_HEIGHT_IDX+1) +/* the corresponding info accessors */ +# define SYNCTEX_TAG(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_TAG_IDX].INT +# define SYNCTEX_LINE(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_LINE_IDX].INT +# define SYNCTEX_COLUMN(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_COLUMN_IDX].INT +# define SYNCTEX_HORIZ(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_HORIZ_IDX].INT +# define SYNCTEX_VERT(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_VERT_IDX].INT +# define SYNCTEX_WIDTH(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_WIDTH_IDX].INT +# define SYNCTEX_HEIGHT(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_HEIGHT_IDX].INT +# define SYNCTEX_DEPTH(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_DEPTH_IDX].INT +# define SYNCTEX_ABS_WIDTH(NODE) ((SYNCTEX_WIDTH(NODE)>0?SYNCTEX_WIDTH(NODE):-SYNCTEX_WIDTH(NODE))) +# define SYNCTEX_ABS_HEIGHT(NODE) ((SYNCTEX_HEIGHT(NODE)>0?SYNCTEX_HEIGHT(NODE):-SYNCTEX_HEIGHT(NODE))) +# define SYNCTEX_ABS_DEPTH(NODE) ((SYNCTEX_DEPTH(NODE)>0?SYNCTEX_DEPTH(NODE):-SYNCTEX_DEPTH(NODE))) + +typedef struct { + synctex_class_t class; + synctex_info_t implementation[5+SYNCTEX_DEPTH_IDX+1]; /* parent,child,sibling,friend,next box, + * SYNCTEX_TAG,SYNCTEX_LINE,SYNCTEX_COLUMN, + * SYNCTEX_HORIZ,SYNCTEX_VERT,SYNCTEX_WIDTH,SYNCTEX_HEIGHT,SYNCTEX_DEPTH */ +} synctex_vert_box_node_t; + +synctex_node_t _synctex_new_vbox(synctex_scanner_t scanner); +void _synctex_log_box(synctex_node_t sheet); +void _synctex_display_vbox(synctex_node_t node); + +/* These are static class objects, each scanner will make a copy of them and setup the scanner field. + */ +static _synctex_class_t synctex_class_vbox = { + NULL, /* No scanner yet */ + synctex_node_type_vbox, /* Node type */ + &_synctex_new_vbox, /* creator */ + &_synctex_free_node, /* destructor */ + &_synctex_log_box, /* log */ + &_synctex_display_vbox, /* display */ + &_synctex_implementation_0, /* parent */ + &_synctex_implementation_1, /* child */ + &_synctex_implementation_2, /* sibling */ + &_synctex_implementation_3, /* friend */ + &_synctex_implementation_4, /* next box */ + (_synctex_info_getter_t)&_synctex_implementation_5 +}; + +/* vertical box node creator */ +synctex_node_t _synctex_new_vbox(synctex_scanner_t scanner) { + synctex_node_t node = _synctex_malloc(sizeof(synctex_vert_box_node_t)); + if (node) { + node->class = scanner?scanner->class+synctex_node_type_vbox:(synctex_class_t)&synctex_class_vbox; + } + return node; +} + +# define SYNCTEX_HORIZ_V_IDX (SYNCTEX_DEPTH_IDX+1) +# define SYNCTEX_VERT_V_IDX (SYNCTEX_HORIZ_V_IDX+1) +# define SYNCTEX_WIDTH_V_IDX (SYNCTEX_VERT_V_IDX+1) +# define SYNCTEX_HEIGHT_V_IDX (SYNCTEX_WIDTH_V_IDX+1) +# define SYNCTEX_DEPTH_V_IDX (SYNCTEX_HEIGHT_V_IDX+1) +/* the corresponding info accessors */ +# define SYNCTEX_HORIZ_V(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_HORIZ_V_IDX].INT +# define SYNCTEX_VERT_V(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_VERT_V_IDX].INT +# define SYNCTEX_WIDTH_V(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_WIDTH_V_IDX].INT +# define SYNCTEX_HEIGHT_V(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_HEIGHT_V_IDX].INT +# define SYNCTEX_DEPTH_V(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_DEPTH_V_IDX].INT +# define SYNCTEX_ABS_WIDTH_V(NODE) ((SYNCTEX_WIDTH_V(NODE)>0?SYNCTEX_WIDTH_V(NODE):-SYNCTEX_WIDTH_V(NODE))) +# define SYNCTEX_ABS_HEIGHT_V(NODE) ((SYNCTEX_HEIGHT_V(NODE)>0?SYNCTEX_HEIGHT_V(NODE):-SYNCTEX_HEIGHT_V(NODE))) +# define SYNCTEX_ABS_DEPTH_V(NODE) ((SYNCTEX_DEPTH_V(NODE)>0?SYNCTEX_DEPTH_V(NODE):-SYNCTEX_DEPTH_V(NODE))) + +/* Horizontal boxes must contain visible size, because 0 width does not mean emptiness */ +typedef struct { + synctex_class_t class; + synctex_info_t implementation[5+SYNCTEX_DEPTH_V_IDX+1]; /*parent,child,sibling,friend,next box, + * SYNCTEX_TAG,SYNCTEX_LINE,SYNCTEX_COLUMN, + * SYNCTEX_HORIZ,SYNCTEX_VERT,SYNCTEX_WIDTH,SYNCTEX_HEIGHT,SYNCTEX_DEPTH, + * SYNCTEX_HORIZ_V,SYNCTEX_VERT_V,SYNCTEX_WIDTH_V,SYNCTEX_HEIGHT_V,SYNCTEX_DEPTH_V*/ +} synctex_horiz_box_node_t; + +synctex_node_t _synctex_new_hbox(synctex_scanner_t scanner); +void _synctex_display_hbox(synctex_node_t node); +void _synctex_log_horiz_box(synctex_node_t sheet); + + +static _synctex_class_t synctex_class_hbox = { + NULL, /* No scanner yet */ + synctex_node_type_hbox, /* Node type */ + &_synctex_new_hbox, /* creator */ + &_synctex_free_node, /* destructor */ + &_synctex_log_horiz_box, /* log */ + &_synctex_display_hbox, /* display */ + &_synctex_implementation_0, /* parent */ + &_synctex_implementation_1, /* child */ + &_synctex_implementation_2, /* sibling */ + &_synctex_implementation_3, /* friend */ + &_synctex_implementation_4, /* next box */ + (_synctex_info_getter_t)&_synctex_implementation_5 +}; + +/* horizontal box node creator */ +synctex_node_t _synctex_new_hbox(synctex_scanner_t scanner) { + synctex_node_t node = _synctex_malloc(sizeof(synctex_horiz_box_node_t)); + if (node) { + node->class = scanner?scanner->class+synctex_node_type_hbox:(synctex_class_t)&synctex_class_hbox; + } + return node; +} + +/* This void box node implementation is either horizontal or vertical + * It does not contain a child field. + */ +typedef struct { + synctex_class_t class; + synctex_info_t implementation[3+SYNCTEX_DEPTH_IDX+1]; /* parent,sibling,friend, + * SYNCTEX_TAG,SYNCTEX_LINE,SYNCTEX_COLUMN, + * SYNCTEX_HORIZ,SYNCTEX_VERT,SYNCTEX_WIDTH,SYNCTEX_HEIGHT,SYNCTEX_DEPTH*/ +} synctex_void_box_node_t; + +synctex_node_t _synctex_new_void_vbox(synctex_scanner_t scanner); +void _synctex_log_void_box(synctex_node_t sheet); +void _synctex_display_void_vbox(synctex_node_t node); + +static _synctex_class_t synctex_class_void_vbox = { + NULL, /* No scanner yet */ + synctex_node_type_void_vbox,/* Node type */ + &_synctex_new_void_vbox, /* creator */ + &_synctex_free_node, /* destructor */ + &_synctex_log_void_box, /* log */ + &_synctex_display_void_vbox,/* display */ + &_synctex_implementation_0, /* parent */ + NULL, /* No child */ + &_synctex_implementation_1, /* sibling */ + &_synctex_implementation_2, /* friend */ + NULL, /* No next box */ + (_synctex_info_getter_t)&_synctex_implementation_3 +}; + +/* vertical void box node creator */ +synctex_node_t _synctex_new_void_vbox(synctex_scanner_t scanner) { + synctex_node_t node = _synctex_malloc(sizeof(synctex_void_box_node_t)); + if (node) { + node->class = scanner?scanner->class+synctex_node_type_void_vbox:(synctex_class_t)&synctex_class_void_vbox; + } + return node; +} + +synctex_node_t _synctex_new_void_hbox(synctex_scanner_t scanner); +void _synctex_display_void_hbox(synctex_node_t node); + +static _synctex_class_t synctex_class_void_hbox = { + NULL, /* No scanner yet */ + synctex_node_type_void_hbox,/* Node type */ + &_synctex_new_void_hbox, /* creator */ + &_synctex_free_node, /* destructor */ + &_synctex_log_void_box, /* log */ + &_synctex_display_void_hbox,/* display */ + &_synctex_implementation_0, /* parent */ + NULL, /* No child */ + &_synctex_implementation_1, /* sibling */ + &_synctex_implementation_2, /* friend */ + NULL, /* No next box */ + (_synctex_info_getter_t)&_synctex_implementation_3 +}; + +/* horizontal void box node creator */ +synctex_node_t _synctex_new_void_hbox(synctex_scanner_t scanner) { + synctex_node_t node = _synctex_malloc(sizeof(synctex_void_box_node_t)); + if (node) { + node->class = scanner?scanner->class+synctex_node_type_void_hbox:(synctex_class_t)&synctex_class_void_hbox; + } + return node; +} + +/* The medium nodes correspond to kern, glue, penalty and math nodes. */ +typedef struct { + synctex_class_t class; + synctex_info_t implementation[3+SYNCTEX_WIDTH_IDX+1]; /* parent,sibling,friend, + * SYNCTEX_TAG,SYNCTEX_LINE,SYNCTEX_COLUMN, + * SYNCTEX_HORIZ,SYNCTEX_VERT,SYNCTEX_WIDTH */ +} synctex_medium_node_t; + +#define SYNCTEX_IS_BOX(NODE)\ + ((NODE->class->type == synctex_node_type_vbox)\ + || (NODE->class->type == synctex_node_type_void_vbox)\ + || (NODE->class->type == synctex_node_type_hbox)\ + || (NODE->class->type == synctex_node_type_void_hbox)) + +#define SYNCTEX_HAS_CHILDREN(NODE) (NODE && SYNCTEX_CHILD(NODE)) + +void _synctex_log_medium_node(synctex_node_t node); + +/* math node creator */ +synctex_node_t _synctex_new_math(synctex_scanner_t scanner); +void _synctex_display_math(synctex_node_t node); + +static _synctex_class_t synctex_class_math = { + NULL, /* No scanner yet */ + synctex_node_type_math, /* Node type */ + &_synctex_new_math, /* creator */ + &_synctex_free_leaf, /* destructor */ + &_synctex_log_medium_node, /* log */ + &_synctex_display_math, /* display */ + &_synctex_implementation_0, /* parent */ + NULL, /* No child */ + &_synctex_implementation_1, /* sibling */ + &_synctex_implementation_2, /* friend */ + NULL, /* No next box */ + (_synctex_info_getter_t)&_synctex_implementation_3 +}; + +synctex_node_t _synctex_new_math(synctex_scanner_t scanner) { + synctex_node_t node = _synctex_malloc(sizeof(synctex_medium_node_t)); + if (node) { + node->class = scanner?scanner->class+synctex_node_type_math:(synctex_class_t)&synctex_class_math; + } + return node; +} + +/* kern node creator */ +synctex_node_t _synctex_new_kern(synctex_scanner_t scanner); +void _synctex_display_kern(synctex_node_t node); + +static _synctex_class_t synctex_class_kern = { + NULL, /* No scanner yet */ + synctex_node_type_kern, /* Node type */ + &_synctex_new_kern, /* creator */ + &_synctex_free_leaf, /* destructor */ + &_synctex_log_medium_node, /* log */ + &_synctex_display_kern, /* display */ + &_synctex_implementation_0, /* parent */ + NULL, /* No child */ + &_synctex_implementation_1, /* sibling */ + &_synctex_implementation_2, /* friend */ + NULL, /* No next box */ + (_synctex_info_getter_t)&_synctex_implementation_3 +}; + +synctex_node_t _synctex_new_kern(synctex_scanner_t scanner) { + synctex_node_t node = _synctex_malloc(sizeof(synctex_medium_node_t)); + if (node) { + node->class = scanner?scanner->class+synctex_node_type_kern:(synctex_class_t)&synctex_class_kern; + } + return node; +} + +/* The small nodes correspond to glue and boundary nodes. */ +typedef struct { + synctex_class_t class; + synctex_info_t implementation[3+SYNCTEX_VERT_IDX+1]; /* parent,sibling,friend, + * SYNCTEX_TAG,SYNCTEX_LINE,SYNCTEX_COLUMN, + * SYNCTEX_HORIZ,SYNCTEX_VERT */ +} synctex_small_node_t; + +void _synctex_log_small_node(synctex_node_t node); +/* glue node creator */ +synctex_node_t _synctex_new_glue(synctex_scanner_t scanner); +void _synctex_display_glue(synctex_node_t node); + +static _synctex_class_t synctex_class_glue = { + NULL, /* No scanner yet */ + synctex_node_type_glue, /* Node type */ + &_synctex_new_glue, /* creator */ + &_synctex_free_leaf, /* destructor */ + &_synctex_log_medium_node, /* log */ + &_synctex_display_glue, /* display */ + &_synctex_implementation_0, /* parent */ + NULL, /* No child */ + &_synctex_implementation_1, /* sibling */ + &_synctex_implementation_2, /* friend */ + NULL, /* No next box */ + (_synctex_info_getter_t)&_synctex_implementation_3 +}; +synctex_node_t _synctex_new_glue(synctex_scanner_t scanner) { + synctex_node_t node = _synctex_malloc(sizeof(synctex_medium_node_t)); + if (node) { + node->class = scanner?scanner->class+synctex_node_type_glue:(synctex_class_t)&synctex_class_glue; + } + return node; +} + +/* boundary node creator */ +synctex_node_t _synctex_new_boundary(synctex_scanner_t scanner); +void _synctex_display_boundary(synctex_node_t node); + +static _synctex_class_t synctex_class_boundary = { + NULL, /* No scanner yet */ + synctex_node_type_boundary, /* Node type */ + &_synctex_new_boundary, /* creator */ + &_synctex_free_leaf, /* destructor */ + &_synctex_log_small_node, /* log */ + &_synctex_display_boundary, /* display */ + &_synctex_implementation_0, /* parent */ + NULL, /* No child */ + &_synctex_implementation_1, /* sibling */ + &_synctex_implementation_2, /* friend */ + NULL, /* No next box */ + (_synctex_info_getter_t)&_synctex_implementation_3 +}; + +synctex_node_t _synctex_new_boundary(synctex_scanner_t scanner) { + synctex_node_t node = _synctex_malloc(sizeof(synctex_small_node_t)); + if (node) { + node->class = scanner?scanner->class+synctex_node_type_boundary:(synctex_class_t)&synctex_class_boundary; + } + return node; +} + +# define SYNCTEX_NAME_IDX (SYNCTEX_TAG_IDX+1) +# define SYNCTEX_NAME(NODE) SYNCTEX_INFO(NODE)[SYNCTEX_NAME_IDX].PTR + +/* Input nodes only know about their sibling, which is another input node. + * The synctex information is the SYNCTEX_TAG and SYNCTEX_NAME*/ +typedef struct { + synctex_class_t class; + synctex_info_t implementation[1+SYNCTEX_NAME_IDX+1]; /* sibling, + * SYNCTEX_TAG,SYNCTEX_NAME */ +} synctex_input_t; + +synctex_node_t _synctex_new_input(synctex_scanner_t scanner); +void _synctex_free_input(synctex_node_t node); +void _synctex_display_input(synctex_node_t node); +void _synctex_log_input(synctex_node_t sheet); + +static _synctex_class_t synctex_class_input = { + NULL, /* No scanner yet */ + synctex_node_type_input, /* Node type */ + &_synctex_new_input, /* creator */ + &_synctex_free_input, /* destructor */ + &_synctex_log_input, /* log */ + &_synctex_display_input, /* display */ + NULL, /* No parent */ + NULL, /* No child */ + &_synctex_implementation_0, /* sibling */ + NULL, /* No friend */ + NULL, /* No next box */ + (_synctex_info_getter_t)&_synctex_implementation_1 +}; + +synctex_node_t _synctex_new_input(synctex_scanner_t scanner) { + synctex_node_t node = _synctex_malloc(sizeof(synctex_input_t)); + if (node) { + node->class = scanner?scanner->class+synctex_node_type_input:(synctex_class_t)&synctex_class_input; + } + return node; +} +void _synctex_free_input(synctex_node_t node){ + if (node) { + SYNCTEX_FREE(SYNCTEX_SIBLING(node)); + free(SYNCTEX_NAME(node)); + free(node); + } +} +# ifdef SYNCTEX_NOTHING +# pragma mark - +# pragma mark Navigation +# endif +synctex_node_t synctex_node_parent(synctex_node_t node) +{ + return SYNCTEX_PARENT(node); +} +synctex_node_t synctex_node_sheet(synctex_node_t node) +{ + while(node && node->class->type != synctex_node_type_sheet) { + node = SYNCTEX_PARENT(node); + } + /* exit the while loop either when node is NULL or node is a sheet */ + return node; +} +synctex_node_t synctex_node_child(synctex_node_t node) +{ + return SYNCTEX_CHILD(node); +} +synctex_node_t synctex_node_sibling(synctex_node_t node) +{ + return SYNCTEX_SIBLING(node); +} +synctex_node_t synctex_node_next(synctex_node_t node) { + if (SYNCTEX_CHILD(node)) { + return SYNCTEX_CHILD(node); + } +sibling: + if (SYNCTEX_SIBLING(node)) { + return SYNCTEX_SIBLING(node); + } + if ((node = SYNCTEX_PARENT(node))) { + if (node->class->type == synctex_node_type_sheet) {/* EXC_BAD_ACCESS? */ + return NULL; + } + goto sibling; + } + return NULL; +} +# ifdef SYNCTEX_NOTHING +# pragma mark - +# pragma mark CLASS +# endif + +/* Public node accessor: the type */ +synctex_node_type_t synctex_node_type(synctex_node_t node) { + if (node) { + return (((node)->class))->type; + } + return synctex_node_type_error; +} + +/* Public node accessor: the human readable type */ +const char * synctex_node_isa(synctex_node_t node) { +static const char * isa[synctex_node_number_of_types] = + {"Not a node","input","sheet","vbox","void vbox","hbox","void hbox","kern","glue","math","boundary"}; + return isa[synctex_node_type(node)]; +} + +# ifdef SYNCTEX_NOTHING +# pragma mark - +# pragma mark SYNCTEX_LOG +# endif + +# define SYNCTEX_LOG(NODE) SYNCTEX_MSG_SEND(NODE,log) + +/* Public node logger */ +void synctex_node_log(synctex_node_t node) { + SYNCTEX_LOG(node); +} + +# define SYNCTEX_DISPLAY(NODE) SYNCTEX_MSG_SEND(NODE,display) + +void synctex_node_display(synctex_node_t node) { + SYNCTEX_DISPLAY(node); +} + +void _synctex_display_input(synctex_node_t node) { + printf("....Input:%i:%s\n", + SYNCTEX_TAG(node), + SYNCTEX_NAME(node)); + SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node)); +} + +void _synctex_log_sheet(synctex_node_t sheet) { + if (sheet) { + printf("%s:%i\n",synctex_node_isa(sheet),SYNCTEX_PAGE(sheet)); + printf("SELF:%p",(void *)sheet); + printf(" SYNCTEX_PARENT:%p",(void *)SYNCTEX_PARENT(sheet)); + printf(" SYNCTEX_CHILD:%p",(void *)SYNCTEX_CHILD(sheet)); + printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(sheet)); + printf(" SYNCTEX_FRIEND:%p\n",(void *)SYNCTEX_FRIEND(sheet)); + } +} + +void _synctex_log_small_node(synctex_node_t node) { + printf("%s:%i,%i:%i,%i\n", + synctex_node_isa(node), + SYNCTEX_TAG(node), + SYNCTEX_LINE(node), + SYNCTEX_HORIZ(node), + SYNCTEX_VERT(node)); + printf("SELF:%p",(void *)node); + printf(" SYNCTEX_PARENT:%p",(void *)SYNCTEX_PARENT(node)); + printf(" SYNCTEX_CHILD:%p",(void *)SYNCTEX_CHILD(node)); + printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(node)); + printf(" SYNCTEX_FRIEND:%p\n",(void *)SYNCTEX_FRIEND(node)); +} + +void _synctex_log_medium_node(synctex_node_t node) { + printf("%s:%i,%i:%i,%i:%i\n", + synctex_node_isa(node), + SYNCTEX_TAG(node), + SYNCTEX_LINE(node), + SYNCTEX_HORIZ(node), + SYNCTEX_VERT(node), + SYNCTEX_WIDTH(node)); + printf("SELF:%p",(void *)node); + printf(" SYNCTEX_PARENT:%p",(void *)SYNCTEX_PARENT(node)); + printf(" SYNCTEX_CHILD:%p",(void *)SYNCTEX_CHILD(node)); + printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(node)); + printf(" SYNCTEX_FRIEND:%p\n",(void *)SYNCTEX_FRIEND(node)); +} + +void _synctex_log_void_box(synctex_node_t node) { + printf("%s",synctex_node_isa(node)); + printf(":%i",SYNCTEX_TAG(node)); + printf(",%i",SYNCTEX_LINE(node)); + printf(",%i",0); + printf(":%i",SYNCTEX_HORIZ(node)); + printf(",%i",SYNCTEX_VERT(node)); + printf(":%i",SYNCTEX_WIDTH(node)); + printf(",%i",SYNCTEX_HEIGHT(node)); + printf(",%i",SYNCTEX_DEPTH(node)); + printf("\nSELF:%p",(void *)node); + printf(" SYNCTEX_PARENT:%p",(void *)SYNCTEX_PARENT(node)); + printf(" SYNCTEX_CHILD:%p",(void *)SYNCTEX_CHILD(node)); + printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(node)); + printf(" SYNCTEX_FRIEND:%p\n",(void *)SYNCTEX_FRIEND(node)); +} + +void _synctex_log_box(synctex_node_t node) { + printf("%s",synctex_node_isa(node)); + printf(":%i",SYNCTEX_TAG(node)); + printf(",%i",SYNCTEX_LINE(node)); + printf(",%i",0); + printf(":%i",SYNCTEX_HORIZ(node)); + printf(",%i",SYNCTEX_VERT(node)); + printf(":%i",SYNCTEX_WIDTH(node)); + printf(",%i",SYNCTEX_HEIGHT(node)); + printf(",%i",SYNCTEX_DEPTH(node)); + printf("\nSELF:%p",(void *)node); + printf(" SYNCTEX_PARENT:%p",(void *)SYNCTEX_PARENT(node)); + printf(" SYNCTEX_CHILD:%p",(void *)SYNCTEX_CHILD(node)); + printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(node)); + printf(" SYNCTEX_FRIEND:%p\n",(void *)SYNCTEX_FRIEND(node)); +} + +void _synctex_log_horiz_box(synctex_node_t node) { + printf("%s",synctex_node_isa(node)); + printf(":%i",SYNCTEX_TAG(node)); + printf(",%i",SYNCTEX_LINE(node)); + printf(",%i",0); + printf(":%i",SYNCTEX_HORIZ(node)); + printf(",%i",SYNCTEX_VERT(node)); + printf(":%i",SYNCTEX_WIDTH(node)); + printf(",%i",SYNCTEX_HEIGHT(node)); + printf(",%i",SYNCTEX_DEPTH(node)); + printf("/%i",SYNCTEX_HORIZ_V(node)); + printf(",%i",SYNCTEX_VERT_V(node)); + printf(":%i",SYNCTEX_WIDTH_V(node)); + printf(",%i",SYNCTEX_HEIGHT_V(node)); + printf(",%i",SYNCTEX_DEPTH_V(node)); + printf("\nSELF:%p",(void *)node); + printf(" SYNCTEX_PARENT:%p",(void *)SYNCTEX_PARENT(node)); + printf(" SYNCTEX_CHILD:%p",(void *)SYNCTEX_CHILD(node)); + printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(node)); + printf(" SYNCTEX_FRIEND:%p\n",(void *)SYNCTEX_FRIEND(node)); +} + +void _synctex_log_input(synctex_node_t node) { + printf("%s",synctex_node_isa(node)); + printf(":%i",SYNCTEX_TAG(node)); + printf(",%s",SYNCTEX_NAME(node)); + printf(" SYNCTEX_SIBLING:%p",(void *)SYNCTEX_SIBLING(node)); +} + +void _synctex_display_sheet(synctex_node_t sheet) { + if (sheet) { + printf("....{%i\n",SYNCTEX_PAGE(sheet)); + SYNCTEX_DISPLAY(SYNCTEX_CHILD(sheet)); + printf("....}\n"); + SYNCTEX_DISPLAY(SYNCTEX_SIBLING(sheet)); + } +} + +void _synctex_display_vbox(synctex_node_t node) { + printf("....[%i,%i:%i,%i:%i,%i,%i\n", + SYNCTEX_TAG(node), + SYNCTEX_LINE(node), + SYNCTEX_HORIZ(node), + SYNCTEX_VERT(node), + SYNCTEX_WIDTH(node), + SYNCTEX_HEIGHT(node), + SYNCTEX_DEPTH(node)); + SYNCTEX_DISPLAY(SYNCTEX_CHILD(node)); + printf("....]\n"); + SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node)); +} + +void _synctex_display_hbox(synctex_node_t node) { + printf("....(%i,%i:%i,%i:%i,%i,%i\n", + SYNCTEX_TAG(node), + SYNCTEX_LINE(node), + SYNCTEX_HORIZ(node), + SYNCTEX_VERT(node), + SYNCTEX_WIDTH(node), + SYNCTEX_HEIGHT(node), + SYNCTEX_DEPTH(node)); + SYNCTEX_DISPLAY(SYNCTEX_CHILD(node)); + printf("....)\n"); + SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node)); +} + +void _synctex_display_void_vbox(synctex_node_t node) { + printf("....v%i,%i;%i,%i:%i,%i,%i\n", + SYNCTEX_TAG(node), + SYNCTEX_LINE(node), + SYNCTEX_HORIZ(node), + SYNCTEX_VERT(node), + SYNCTEX_WIDTH(node), + SYNCTEX_HEIGHT(node), + SYNCTEX_DEPTH(node)); + SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node)); +} + +void _synctex_display_void_hbox(synctex_node_t node) { + printf("....h%i,%i:%i,%i:%i,%i,%i\n", + SYNCTEX_TAG(node), + SYNCTEX_LINE(node), + SYNCTEX_HORIZ(node), + SYNCTEX_VERT(node), + SYNCTEX_WIDTH(node), + SYNCTEX_HEIGHT(node), + SYNCTEX_DEPTH(node)); + SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node)); +} + +void _synctex_display_glue(synctex_node_t node) { + printf("....glue:%i,%i:%i,%i\n", + SYNCTEX_TAG(node), + SYNCTEX_LINE(node), + SYNCTEX_HORIZ(node), + SYNCTEX_VERT(node)); + SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node)); +} + +void _synctex_display_math(synctex_node_t node) { + printf("....math:%i,%i:%i,%i\n", + SYNCTEX_TAG(node), + SYNCTEX_LINE(node), + SYNCTEX_HORIZ(node), + SYNCTEX_VERT(node)); + SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node)); +} + +void _synctex_display_kern(synctex_node_t node) { + printf("....kern:%i,%i:%i,%i:%i\n", + SYNCTEX_TAG(node), + SYNCTEX_LINE(node), + SYNCTEX_HORIZ(node), + SYNCTEX_VERT(node), + SYNCTEX_WIDTH(node)); + SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node)); +} + +void _synctex_display_boundary(synctex_node_t node) { + printf("....boundary:%i,%i:%i,%i\n", + SYNCTEX_TAG(node), + SYNCTEX_LINE(node), + SYNCTEX_HORIZ(node), + SYNCTEX_VERT(node)); + SYNCTEX_DISPLAY(SYNCTEX_SIBLING(node)); +} + +# ifdef SYNCTEX_NOTHING +# pragma mark - +# pragma mark SCANNER +# endif + +/* Here are gathered all the possible status that the next scanning functions will return. + * All these functions return a status, and pass their result through pointers. + * Negative values correspond to errors. + * The management of the buffer is causing some significant overhead. + * Every function that may access the buffer returns a status related to the buffer and file state. + * status >= SYNCTEX_STATUS_OK means the function worked as expected + * status < SYNCTEX_STATUS_OK means the function did not work as expected + * status == SYNCTEX_STATUS_NOT_OK means the function did not work as expected but there is still some material to parse. + * status == SYNCTEX_STATUS_EOF means the function did not work as expected and there is no more material. + * statusfile) + +/* Actually, the minimum buffer size is driven by integer and float parsing. + * 0.123456789e123 + */ +# define SYNCTEX_BUFFER_MIN_SIZE 16 +# define SYNCTEX_BUFFER_SIZE 32768 + +# ifdef SYNCTEX_NOTHING +# pragma mark - +# pragma mark Prototypes +# endif +void _synctex_log_void_box(synctex_node_t node); +void _synctex_log_box(synctex_node_t node); +void _synctex_log_horiz_box(synctex_node_t node); +void _synctex_log_input(synctex_node_t node); +synctex_status_t _synctex_buffer_get_available_size(synctex_scanner_t scanner, size_t * size_ptr); +synctex_status_t _synctex_next_line(synctex_scanner_t scanner); +synctex_status_t _synctex_match_string(synctex_scanner_t scanner, const char * the_string); +synctex_status_t _synctex_decode_int(synctex_scanner_t scanner, int* value_ref); +synctex_status_t _synctex_decode_string(synctex_scanner_t scanner, char ** value_ref); +synctex_status_t _synctex_scan_input(synctex_scanner_t scanner); +synctex_status_t _synctex_scan_preamble(synctex_scanner_t scanner); +synctex_status_t _synctex_scan_float_and_dimension(synctex_scanner_t scanner, float * value_ref); +synctex_status_t _synctex_scan_post_scriptum(synctex_scanner_t scanner); +int _synctex_scan_postamble(synctex_scanner_t scanner); +synctex_status_t _synctex_setup_visible_box(synctex_node_t box); +synctex_status_t _synctex_horiz_box_setup_visible(synctex_node_t node,int h, int v); +synctex_status_t _synctex_scan_sheet(synctex_scanner_t scanner, synctex_node_t parent); +synctex_status_t _synctex_scan_nested_sheet(synctex_scanner_t scanner); +synctex_status_t _synctex_scan_content(synctex_scanner_t scanner); +int synctex_scanner_pre_x_offset(synctex_scanner_t scanner); +int synctex_scanner_pre_y_offset(synctex_scanner_t scanner); +const char * synctex_scanner_get_output_fmt(synctex_scanner_t scanner); +int _synctex_node_is_box(synctex_node_t node); +int _synctex_bail(void); + +/* Try to ensure that the buffer contains at least size bytes. + * Passing a huge size argument means the whole buffer length. + * Passing a null size argument means return the available buffer length, without reading the file. + * In that case, the return status is always SYNCTEX_STATUS_OK unless the given scanner is NULL, + * in which case, SYNCTEX_STATUS_BAD_ARGUMENT is returned. + * The value returned in size_ptr is the number of bytes now available in the buffer. + * This is a nonnegative integer, it may take the value 0. + * It is the responsibility of the caller to test whether this size is conforming to its needs. + * Negative values may return in case of error, actually + * when there was an error reading the synctex file. */ +synctex_status_t _synctex_buffer_get_available_size(synctex_scanner_t scanner, size_t * size_ptr) { + size_t available = 0; + if (NULL == scanner || NULL == size_ptr) { + return SYNCTEX_STATUS_BAD_ARGUMENT; + } +# define size (* size_ptr) + if (size>SYNCTEX_BUFFER_SIZE){ + size = SYNCTEX_BUFFER_SIZE; + } + available = SYNCTEX_END - SYNCTEX_CUR; /* available is the number of unparsed chars in the buffer */ + if (size<=available) { + /* There are already sufficiently many characters in the buffer */ + size = available; + return SYNCTEX_STATUS_OK; + } + if (SYNCTEX_FILE) { + /* Copy the remaining part of the buffer to the beginning, + * then read the next part of the file */ + int already_read = 0; + if (available) { + memmove(SYNCTEX_START, SYNCTEX_CUR, available); + } + SYNCTEX_CUR = SYNCTEX_START + available; /* the next character after the move, will change. */ + /* Fill the buffer up to its end */ + already_read = gzread(SYNCTEX_FILE,(void *)SYNCTEX_CUR,SYNCTEX_BUFFER_SIZE - available); + if (already_read>0) { + /* We assume that 0already_read) { + /* There is a possible error in reading the file */ + int errnum = 0; + const char * error_string = gzerror(SYNCTEX_FILE, &errnum); + if (Z_ERRNO == errnum) { + /* There is an error in zlib caused by the file system */ + _synctex_error("gzread error from the file system (%i)",errno); + return SYNCTEX_STATUS_ERROR; + } else if (errnum) { + _synctex_error("gzread error (%i:%i,%s)",already_read,errnum,error_string); + return SYNCTEX_STATUS_ERROR; + } + } + /* Nothing was read, we are at the end of the file. */ + gzclose(SYNCTEX_FILE); + SYNCTEX_FILE = NULL; + SYNCTEX_END = SYNCTEX_CUR; + SYNCTEX_CUR = SYNCTEX_START; + * SYNCTEX_END = '\0';/* Terminate the string properly.*/ + size = SYNCTEX_END - SYNCTEX_CUR; + return SYNCTEX_STATUS_EOF; /* there might be a bit of text left */ + } + /* We cannot enlarge the buffer because the end of the file was reached. */ + size = available; + return SYNCTEX_STATUS_EOF; +# undef size +} + +/* Used when parsing the synctex file. + * Advance to the next character starting a line. + * Actually, only '\n' is recognized as end of line marker. + * On normal completion, the returned value is the number of unparsed characters available in the buffer. + * In general, it is a positive value, 0 meaning that the end of file was reached. + * -1 is returned in case of error, actually because there was an error while feeding the buffer. + * When the function returns with no error, SYNCTEX_CUR points to the first character of the next line, if any. + * J. Laurens: Sat May 10 07:52:31 UTC 2008 + */ +synctex_status_t _synctex_next_line(synctex_scanner_t scanner) { + synctex_status_t status = SYNCTEX_STATUS_OK; + size_t available = 0; + if (NULL == scanner) { + return SYNCTEX_STATUS_BAD_ARGUMENT; + } +infinite_loop: + while(SYNCTEX_CUR=remaining_len) { + /* The buffer is sufficiently big to hold the expected number of characters. */ + if (strncmp((char *)SYNCTEX_CUR,the_string,remaining_len)) { + return SYNCTEX_STATUS_NOT_OK; + } +return_OK: + /* Advance SYNCTEX_CUR to the next character after the_string. */ + SYNCTEX_CUR += remaining_len; + return SYNCTEX_STATUS_OK; + } else if (strncmp((char *)SYNCTEX_CUR,the_string,available)) { + /* No need to goo further, this is not the expected string in the buffer. */ + return SYNCTEX_STATUS_NOT_OK; + } else if (SYNCTEX_FILE) { + /* The buffer was too small to contain remaining_len characters. + * We have to cut the string into pieces. */ + z_off_t offset = 0L; + /* the first part of the string is found, advance the_string to the next untested character. */ + the_string += available; + /* update the remaining length and the parsed length. */ + remaining_len -= available; + tested_len += available; + SYNCTEX_CUR += available; /* We validate the tested characters. */ + if (0 == remaining_len) { + /* Nothing left to test, we have found the given string, we return the length. */ + return tested_len; + } + /* We also have to record the current state of the file cursor because + * if the_string does not match, all this should be a totally blank operation, + * for which the file and buffer states should not be modified at all. + * In fact, the states of the buffer before and after this function are in general different + * but they are totally equivalent as long as the values of the buffer before SYNCTEX_CUR + * can be safely discarded. */ + offset = gztell(SYNCTEX_FILE); + /* offset now corresponds to the first character of the file that was not buffered. */ + available = SYNCTEX_CUR - SYNCTEX_START; /* available can be used as temporary placeholder. */ + /* available now corresponds to the number of chars that where already buffered and + * that match the head of the_string. If in fine the_string does not match, all these chars must be recovered + * because the buffer contents is completely replaced by _synctex_buffer_get_available_size. + * They were buffered from offset-len location in the file. */ + offset -= available; +more_characters: + /* There is still some work to be done, so read another bunch of file. + * This is the second call to _synctex_buffer_get_available_size, + * which means that the actual contents of the buffer will be discarded. + * We will definitely have to recover the previous state in case we do not find the expected string. */ + available = remaining_len; + status = _synctex_buffer_get_available_size(scanner,&available); + if (statusptr) { + SYNCTEX_CUR = end; + if (value_ref) { + * value_ref = result; + } + return SYNCTEX_STATUS_OK;/* Successfully scanned an int */ + } + return SYNCTEX_STATUS_NOT_OK;/* Could not scan an int */ +} + +/* The purpose of this function is to read a string. + * A string is an array of characters from the current parser location + * and before the next '\n' character. + * If a string was properly decoded, it is returned in value_ref and + * the cursor points to the new line marker. + * The returned string was alloced on the heap, the caller is the owner and + * is responsible to free it in due time. + * If no string is parsed, * value_ref is undefined. + * The maximum length of a string that a scanner can decode is platform dependent, namely UINT_MAX. + * If you just want to blindly parse the file up to the end of the current line, + * use _synctex_next_line instead. + * On return, the scanner cursor is unchanged if a string could not be scanned or + * points to the terminating '\n' character otherwise. As a consequence, + * _synctex_next_line is necessary after. + * If either scanner or value_ref is NULL, it is considered as an error and + * SYNCTEX_STATUS_BAD_ARGUMENT is returned. + */ +synctex_status_t _synctex_decode_string(synctex_scanner_t scanner, char ** value_ref) { + char * end = NULL; + size_t current_size = 0; + size_t new_size = 0; + size_t len = 0;/* The number of bytes to copy */ + size_t available = 0; + synctex_status_t status = 0; + if (NULL == scanner || NULL == value_ref) { + return SYNCTEX_STATUS_BAD_ARGUMENT; + } + /* The buffer must at least contain one character: the '\n' end of line marker */ + if (SYNCTEX_CUR>=SYNCTEX_END) { + available = 1; + status = _synctex_buffer_get_available_size(scanner,&available); + if (status < 0) { + return status; + } + if (0 == available) { + return SYNCTEX_STATUS_EOF; + } + } + /* Now we are sure that there is at least one available character, either because + * SYNCTEX_CUR was already < SYNCTEX_END, or because the buffer has been properly filled. */ + /* end will point to the next unparsed '\n' character in the file, when mapped to the buffer. */ + end = SYNCTEX_CUR; + * value_ref = NULL;/* Initialize, it will be realloc'ed */ + /* We scan all the characters up to the next '\n' */ +next_character: + if (endUINT_MAX-len-1) { + /* But we have reached the limit: we do not have current_size+len+1>UINT_MAX. + * We return the missing amount of memory. + * This will never occur in practice. */ + return UINT_MAX-len-1 - current_size; + } + new_size = current_size+len; + /* We have current_size+len+1<=UINT_MAX + * or equivalently new_sizeUINT_MAX-len-1) { + /* We have reached the limit. */ + _synctex_error("limit reached (missing %i).",current_size-(UINT_MAX-len-1)); + return SYNCTEX_STATUS_ERROR; + } + new_size = current_size+len; + if ((* value_ref = realloc(* value_ref,new_size+1)) != NULL) { + if (memcpy((*value_ref)+current_size,SYNCTEX_CUR,len)) { + (* value_ref)[new_size]='\0'; /* Terminate the string */ + SYNCTEX_CUR = SYNCTEX_END;/* Advance the cursor to the end of the bufer */ + return SYNCTEX_STATUS_OK; + } + free(* value_ref); + * value_ref = NULL; + _synctex_error("could not copy memory (2)."); + return SYNCTEX_STATUS_ERROR; + } + /* Huge memory problem */ + _synctex_error("could not allocate memory (2)."); + return SYNCTEX_STATUS_ERROR; + } +} + +/* Used when parsing the synctex file. + * Read an Input record. + */ +synctex_status_t _synctex_scan_input(synctex_scanner_t scanner) { + synctex_status_t status = 0; + size_t available = 0; + synctex_node_t input = NULL; + if (NULL == scanner) { + return SYNCTEX_STATUS_BAD_ARGUMENT; + } + status = _synctex_match_string(scanner,"Input:"); + if (statusinput); + scanner->input = input; + return _synctex_next_line(scanner);/* read the line termination character, if any */ + /* Now, set up the path */ +} + +typedef synctex_status_t (*synctex_decoder_t)(synctex_scanner_t,void *); + +synctex_status_t _synctex_scan_named(synctex_scanner_t scanner,const char * name,void * value_ref,synctex_decoder_t decoder); + +/* Used when parsing the synctex file. + * Read one of the settings. + * On normal completion, returns SYNCTEX_STATUS_OK. + * On error, returns SYNCTEX_STATUS_ERROR. + * Both arguments must not be NULL. + * On return, the scanner points to the next character after the decoded object whatever it is. + * It is the responsibility of the caller to prepare the scanner for the next line. + */ +synctex_status_t _synctex_scan_named(synctex_scanner_t scanner,const char * name,void * value_ref,synctex_decoder_t decoder) { + synctex_status_t status = 0; + if (NULL == scanner || NULL == name || NULL == value_ref || NULL == decoder) { + return SYNCTEX_STATUS_BAD_ARGUMENT; + } +not_found: + status = _synctex_match_string(scanner,name); + if (statusversion),(synctex_decoder_t)&_synctex_decode_int); + if (statusoutput_fmt),(synctex_decoder_t)&_synctex_decode_string); + if (statuspre_magnification),(synctex_decoder_t)&_synctex_decode_int); + if (statuspre_unit),(synctex_decoder_t)&_synctex_decode_int); + if (statuspre_x_offset),(synctex_decoder_t)&_synctex_decode_int); + if (statuspre_y_offset),(synctex_decoder_t)&_synctex_decode_int); + if (status= SYNCTEX_STATUS_OK) { + f *= 72.27f*65536; + } else if (status= SYNCTEX_STATUS_OK) { + f *= 72.27f*65536/2.54f; + } else if (status<0) { + goto report_unit_error; + } else if ((status = _synctex_match_string(scanner,"mm")) >= SYNCTEX_STATUS_OK) { + f *= 72.27f*65536/25.4f; + } else if (status<0) { + goto report_unit_error; + } else if ((status = _synctex_match_string(scanner,"pt")) >= SYNCTEX_STATUS_OK) { + f *= 65536.0f; + } else if (status<0) { + goto report_unit_error; + } else if ((status = _synctex_match_string(scanner,"bp")) >= SYNCTEX_STATUS_OK) { + f *= 72.27f/72*65536.0f; + } else if (status<0) { + goto report_unit_error; + } else if ((status = _synctex_match_string(scanner,"pc")) >= SYNCTEX_STATUS_OK) { + f *= 12.0*65536.0f; + } else if (status<0) { + goto report_unit_error; + } else if ((status = _synctex_match_string(scanner,"sp")) >= SYNCTEX_STATUS_OK) { + f *= 1.0f; + } else if (status<0) { + goto report_unit_error; + } else if ((status = _synctex_match_string(scanner,"dd")) >= SYNCTEX_STATUS_OK) { + f *= 1238.0f/1157*65536.0f; + } else if (status<0) { + goto report_unit_error; + } else if ((status = _synctex_match_string(scanner,"cc")) >= SYNCTEX_STATUS_OK) { + f *= 14856.0f/1157*65536; + } else if (status<0) { + goto report_unit_error; + } else if ((status = _synctex_match_string(scanner,"nd")) >= SYNCTEX_STATUS_OK) { + f *= 685.0f/642*65536; + } else if (status<0) { + goto report_unit_error; + } else if ((status = _synctex_match_string(scanner,"nc")) >= SYNCTEX_STATUS_OK) { + f *= 1370.0f/107*65536; + } else if (status<0) { + goto report_unit_error; + } + *value_ref = f; + return SYNCTEX_STATUS_OK; +} + +/* parse the post scriptum + * SYNCTEX_STATUS_OK is returned on completion + * a negative error is returned otherwise */ +synctex_status_t _synctex_scan_post_scriptum(synctex_scanner_t scanner) { + synctex_status_t status = 0; + char * endptr = NULL; +#ifdef HAVE_SETLOCALE + char * loc = setlocale(LC_NUMERIC, NULL); +#endif + if (NULL == scanner) { + return SYNCTEX_STATUS_BAD_ARGUMENT; + } + /* Scan the file until a post scriptum line is found */ +post_scriptum_not_found: + status = _synctex_match_string(scanner,"Post scriptum:"); + if (statusunit = strtod(SYNCTEX_CUR,&endptr); +#ifdef HAVE_SETLOCALE + setlocale(LC_NUMERIC, loc); +#endif + if (endptr == SYNCTEX_CUR) { + _synctex_error("bad magnification in the post scriptum, a float was expected."); + return SYNCTEX_STATUS_ERROR; + } + if (scanner->unit<=0) { + _synctex_error("bad magnification in the post scriptum, a positive float was expected."); + return SYNCTEX_STATUS_ERROR; + } + SYNCTEX_CUR = endptr; + goto next_line; + } + if (statusx_offset)); + if (statusy_offset)); + if (statuscount),(synctex_decoder_t)&_synctex_decode_int); + if (status < SYNCTEX_STATUS_EOF) { + return status; /* forward the error */ + } else if (status < SYNCTEX_STATUS_OK) { /* No Count record found */ + status = _synctex_next_line(scanner); /* Advance one more line */ + if (statusclass->type) { + case synctex_node_type_hbox: + if (SYNCTEX_INFO(box) != NULL) { + SYNCTEX_HORIZ_V(box) = SYNCTEX_HORIZ(box); + SYNCTEX_VERT_V(box) = SYNCTEX_VERT(box); + SYNCTEX_WIDTH_V(box) = SYNCTEX_WIDTH(box); + SYNCTEX_HEIGHT_V(box) = SYNCTEX_HEIGHT(box); + SYNCTEX_DEPTH_V(box) = SYNCTEX_DEPTH(box); + return SYNCTEX_STATUS_OK; + } + return SYNCTEX_STATUS_ERROR; + } + } + return SYNCTEX_STATUS_BAD_ARGUMENT; +} + +/* This method is sent to an horizontal box to setup the visible size + * Some box have 0 width but do contain text material. + * With this method, one can enlarge the box to contain the given point (h,v). + */ +synctex_status_t _synctex_horiz_box_setup_visible(synctex_node_t node,int h, int v) { +# ifdef __DARWIN_UNIX03 +# pragma unused(v) +# endif + int itsBtm, itsTop; + if (NULL == node || node->class->type != synctex_node_type_hbox) { + return SYNCTEX_STATUS_BAD_ARGUMENT; + } + if (SYNCTEX_WIDTH_V(node)<0) { + itsBtm = SYNCTEX_HORIZ_V(node); + itsTop = SYNCTEX_HORIZ_V(node)-SYNCTEX_WIDTH_V(node); + if (hitsTop) { + SYNCTEX_WIDTH_V(node) = SYNCTEX_HORIZ_V(node) - h; + } + } else { + itsBtm = SYNCTEX_HORIZ_V(node); + itsTop = SYNCTEX_HORIZ_V(node)+SYNCTEX_WIDTH_V(node); + if (hitsTop) { + SYNCTEX_WIDTH_V(node) = h - SYNCTEX_HORIZ_V(node); + } + } + return SYNCTEX_STATUS_OK; +} + +/* Here are the control characters that strat each line of the synctex output file. + * Their values define the meaning of the line. + */ +# define SYNCTEX_CHAR_BEGIN_SHEET '{' +# define SYNCTEX_CHAR_END_SHEET '}' +# define SYNCTEX_CHAR_BEGIN_VBOX '[' +# define SYNCTEX_CHAR_END_VBOX ']' +# define SYNCTEX_CHAR_BEGIN_HBOX '(' +# define SYNCTEX_CHAR_END_HBOX ')' +# define SYNCTEX_CHAR_ANCHOR '!' +# define SYNCTEX_CHAR_VOID_VBOX 'v' +# define SYNCTEX_CHAR_VOID_HBOX 'h' +# define SYNCTEX_CHAR_KERN 'k' +# define SYNCTEX_CHAR_GLUE 'g' +# define SYNCTEX_CHAR_MATH '$' +# define SYNCTEX_CHAR_BOUNDARY 'x' + +# define SYNCTEX_RETURN(STATUS) return STATUS; + +/* Used when parsing the synctex file. A '{' character has just been parsed. + * The purpose is to gobble everything until the closing '}'. + * Actually only one nesting depth has been observed when using the clip option + * of \includegraphics option. Here we use arbitrary level of depth. + */ +synctex_status_t _synctex_scan_nested_sheet(synctex_scanner_t scanner) { + unsigned int depth = 0; +deeper: + ++depth; + if (_synctex_next_line(scanner)0) { + goto scan_next_line; + } else { + SYNCTEX_RETURN(SYNCTEX_STATUS_OK); + } + } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_BEGIN_SHEET) { + ++SYNCTEX_CUR; + goto deeper; + + } else if (_synctex_next_line(scanner)class->type != synctex_node_type_sheet + || _synctex_next_line(scanner)0){ + _synctex_error("Uncomplete sheet(0)"); + SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); + } else { + goto prepare_loop; + } + } + _synctex_bail(); +/* The child loop means that we go do one level, when we just created a box node, + * the next node created is a child of this box. */ +child_loop: + if (SYNCTEX_CURclass->type == synctex_node_type_vbox) { + #define SYNCTEX_UPDATE_BOX_FRIEND(NODE)\ + friend_index = ((SYNCTEX_INFO(NODE))[SYNCTEX_TAG_IDX].INT+(SYNCTEX_INFO(NODE))[SYNCTEX_LINE_IDX].INT)%(scanner->number_of_lists);\ + SYNCTEX_SET_FRIEND(NODE,(scanner->lists_of_friends)[friend_index]);\ + (scanner->lists_of_friends)[friend_index] = NODE; + if (NULL == SYNCTEX_CHILD(parent)) { + /* only void boxes are friends */ + SYNCTEX_UPDATE_BOX_FRIEND(parent); + } + child = parent; + parent = SYNCTEX_PARENT(child); + } else { + _synctex_error("Unexpected end of vbox, ignored."); + } + if (_synctex_next_line(scanner)class->type == synctex_node_type_hbox) { + if (NULL == child) { + /* Only boxes with no children are friends, + * boxes with children are indirectly friends through one of their descendants. */ + SYNCTEX_UPDATE_BOX_FRIEND(parent); + } + /* setting the next horizontal box at the end ensures that a child is recorded before any of its ancestors. */ + SYNCTEX_SET_NEXT_HORIZ_BOX(box,parent); + box = parent; + child = parent; + parent = SYNCTEX_PARENT(child); + } else { + _synctex_error("Unexpected enf of hbox, ignored."); + } + if (_synctex_next_line(scanner)number_of_lists);\ + SYNCTEX_SET_FRIEND(NODE,(scanner->lists_of_friends)[friend_index]);\ + (scanner->lists_of_friends)[friend_index] = NODE; + SYNCTEX_UPDATE_FRIEND(child); + goto sibling_loop; + } else { + _synctex_error("Can't create vbox record."); + SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); + } + } else if (*SYNCTEX_CUR == SYNCTEX_CHAR_VOID_HBOX) { + ++SYNCTEX_CUR; + if (NULL != (child = _synctex_new_void_hbox(scanner)) + && NULL != (info = SYNCTEX_INFO(child))) { + if (SYNCTEX_DECODE_FAILED(SYNCTEX_TAG_IDX) + || SYNCTEX_DECODE_FAILED(SYNCTEX_LINE_IDX) + || SYNCTEX_DECODE_FAILED(SYNCTEX_HORIZ_IDX) + || SYNCTEX_DECODE_FAILED(SYNCTEX_VERT_IDX) + || SYNCTEX_DECODE_FAILED(SYNCTEX_WIDTH_IDX) + || SYNCTEX_DECODE_FAILED(SYNCTEX_HEIGHT_IDX) + || SYNCTEX_DECODE_FAILED(SYNCTEX_DEPTH_IDX) + || _synctex_next_line(scanner)0){ + _synctex_error("Uncomplete sheet(0)"); + SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); + } else { + goto child_loop; + } + } + _synctex_bail(); +/* The vertical loop means that we are on the same level, for example when we just ended a box. + * If a node is created now, it will be a sibling of the current node, sharing the same parent. */ +sibling_loop: + if (SYNCTEX_CUR0){ + goto sibling_loop; + } else { + _synctex_error("Uncomplete sheet(2)"); + SYNCTEX_RETURN(SYNCTEX_STATUS_ERROR); + } + } +# undef SYNCTEX_DECODE_FAILED +} + +/* Used when parsing the synctex file + */ +synctex_status_t _synctex_scan_content(synctex_scanner_t scanner) { + synctex_node_t sheet = NULL; + synctex_status_t status = 0; + if (NULL == scanner) { + return SYNCTEX_STATUS_BAD_ARGUMENT; + } + /* set up the lists of friends */ + if (NULL == scanner->lists_of_friends) { + scanner->number_of_lists = 1024; + scanner->lists_of_friends = (synctex_node_t *)_synctex_malloc(scanner->number_of_lists*sizeof(synctex_node_t)); + if (NULL == scanner->lists_of_friends) { + _synctex_error("malloc:2"); + return SYNCTEX_STATUS_ERROR; + } + } + /* Find where this section starts */ +content_not_found: + status = _synctex_match_string(scanner,"Content:"); + if (statussheet); + scanner->sheet = sheet; + sheet = NULL; + /* Now read the list of Inputs between 2 sheets. */ + do { + status = _synctex_scan_input(scanner); + if (status= SYNCTEX_STATUS_OK); + goto next_sheet; +} + +int _synctex_open(const char * output, const char * build_directory, char ** synctex_name_ref, gzFile * file_ref, synctex_bool_t add_quotes, synctex_io_mode_t * io_modeRef); + +/* Where the synctex scanner is created. */ +synctex_scanner_t synctex_scanner_new_with_output_file(const char * output, const char * build_directory, int parse) { + gzFile file = NULL; + char * synctex = NULL; + synctex_scanner_t scanner = NULL; + synctex_io_mode_t io_mode = 0; + /* Here we assume that int are smaller than void * */ + if (sizeof(int)>sizeof(void*)) { + _synctex_error("INTERNAL INCONSISTENCY: int's are unexpectedly bigger than pointers, bailing out."); + return NULL; + } + /* We ensure that SYNCTEX_BUFFER_SIZE < UINT_MAX, I don't know if it makes sense... */ + if (SYNCTEX_BUFFER_SIZE >= UINT_MAX) { + _synctex_error("SyncTeX BUG: Internal inconsistency, bad SYNCTEX_BUFFER_SIZE (1)"); + return NULL; + } + /* for integers: */ + if (SYNCTEX_BUFFER_SIZE < SYNCTEX_BUFFER_MIN_SIZE) { + _synctex_error("SyncTeX BUG: Internal inconsistency, bad SYNCTEX_BUFFER_SIZE (2)"); + return NULL; + } + /* now open the synctex file */ + if (_synctex_open(output,build_directory,&synctex,&file,synctex_ADD_QUOTES,&io_mode) || !file) { + if (_synctex_open(output,build_directory,&synctex,&file,synctex_DONT_ADD_QUOTES,&io_mode) || !file) { + return NULL; + } + } + scanner = (synctex_scanner_t)_synctex_malloc(sizeof(_synctex_scanner_t)); + if (NULL == scanner) { + _synctex_error("SyncTeX: malloc problem"); + free(synctex); + gzclose(file); + return NULL; + } + /* make a private copy of output for the scanner */ + if (NULL == (scanner->output = (char *)malloc(strlen(output)+1))){ + _synctex_error("! synctex_scanner_new_with_output_file: Memory problem (2), scanner's output is not reliable."); + } else if (scanner->output != strcpy(scanner->output,output)) { + _synctex_error("! synctex_scanner_new_with_output_file: Copy problem, scanner's output is not reliable."); + } + scanner->synctex = synctex;/* Now the scanner owns synctex */ + SYNCTEX_FILE = file; + return parse? synctex_scanner_parse(scanner):scanner; +} + +int __synctex_open(const char * output, char ** synctex_name_ref, gzFile * file_ref, synctex_bool_t add_quotes, synctex_io_mode_t * io_mode_ref); + +/* This functions opens the file at the "output" given location. + * It manages the problem of quoted filenames that appear with pdftex and filenames containing the space character. + * In TeXLive 2008, the synctex file created with pdftex did contain unexpected quotes. + * This function will remove them if possible. + * All the reference arguments will take a value on return. They must be non NULL. + * 0 on success, non 0 on error. */ +int __synctex_open(const char * output, char ** synctex_name_ref, gzFile * file_ref, synctex_bool_t add_quotes, synctex_io_mode_t * io_mode_ref) { + if (synctex_name_ref && file_ref && io_mode_ref) { + /* 1 local variables that uses dynamic memory */ + char * synctex_name = NULL; + gzFile the_file = NULL; + char * quoteless_synctex_name = NULL; + size_t size = 0; + synctex_io_mode_t io_mode = *io_mode_ref; + const char * mode = _synctex_get_io_mode_name(io_mode); + /* now create the synctex file name */ + size = strlen(output)+strlen(synctex_suffix)+strlen(synctex_suffix_gz)+1; + synctex_name = (char *)malloc(size); + if (NULL == synctex_name) { + _synctex_error("! __synctex_open: Memory problem (1)\n"); + return 1; + } + /* we have reserved for synctex enough memory to copy output (including its 2 eventual quotes), both suffices, + * including the terminating character. size is free now. */ + if (synctex_name != strcpy(synctex_name,output)) { + _synctex_error("! __synctex_open: Copy problem\n"); +return_on_error: + free(synctex_name); + free(quoteless_synctex_name); + return 2; + } + /* remove the last path extension if any */ + _synctex_strip_last_path_extension(synctex_name); + if (!strlen(synctex_name)) { + goto return_on_error; + } + /* now insert quotes. */ + if (add_quotes) { + char * quoted = NULL; + if (_synctex_copy_with_quoting_last_path_component(synctex_name,"ed,size) || (NULL == quoted)) { + /* There was an error or quoting does not make sense: */ + goto return_on_error; + } + quoteless_synctex_name = synctex_name; + synctex_name = quoted; + } + /* Now add to synctex_name the first path extension. */ + if (synctex_name != strcat(synctex_name,synctex_suffix)){ + _synctex_error("! __synctex_open: Concatenation problem (can't add suffix '%s')\n",synctex_suffix); + goto return_on_error; + } + /* Add to quoteless_synctex_name as well, if relevant. */ + if (quoteless_synctex_name && (quoteless_synctex_name != strcat(quoteless_synctex_name,synctex_suffix))){ + free(quoteless_synctex_name); + quoteless_synctex_name = NULL; + } + if (NULL == (the_file = gzopen(synctex_name,mode))) { + /* Could not open this file */ + if (errno != ENOENT) { + /* The file does exist, this is a lower level error, I can't do anything. */ + _synctex_error("SyncTeX: could not open %s, error %i\n",synctex_name,errno); + goto return_on_error; + } + /* Apparently, there is no uncompressed synctex file. Try the compressed version */ + if (synctex_name != strcat(synctex_name,synctex_suffix_gz)){ + _synctex_error("! __synctex_open: Concatenation problem (can't add suffix '%s')\n",synctex_suffix_gz); + goto return_on_error; + } + io_mode |= synctex_io_gz_mask; + mode = _synctex_get_io_mode_name(io_mode); /* the file is a compressed and is a binary file, this caused errors on Windows */ + /* Add the suffix to the quoteless_synctex_name as well. */ + if (quoteless_synctex_name && (quoteless_synctex_name != strcat(quoteless_synctex_name,synctex_suffix_gz))){ + free(quoteless_synctex_name); + quoteless_synctex_name = NULL; + } + if (NULL == (the_file = gzopen(synctex_name,mode))) { + /* Could not open this file */ + if (errno != ENOENT) { + /* The file does exist, this is a lower level error, I can't do anything. */ + _synctex_error("SyncTeX: could not open %s, error %i\n",synctex_name,errno); + } + goto return_on_error; + } + } + /* At this point, the file is properly open. + * If we are in the add_quotes mode, we change the file name by removing the quotes. */ + if (quoteless_synctex_name) { + gzclose(the_file); + if (rename(synctex_name,quoteless_synctex_name)) { + _synctex_error("SyncTeX: could not rename %s to %s, error %i\n",synctex_name,quoteless_synctex_name,errno); + /* We could not rename, reopen the file with the quoted name. */ + if (NULL == (the_file = gzopen(synctex_name,mode))) { + /* No luck, could not re open this file, something has happened meanwhile */ + if (errno != ENOENT) { + /* The file does not exist any more, it has certainly be removed somehow + * this is a lower level error, I can't do anything. */ + _synctex_error("SyncTeX: could not open again %s, error %i\n",synctex_name,errno); + } + goto return_on_error; + } + } else { + /* The file has been successfully renamed */ + if (NULL == (the_file = gzopen(quoteless_synctex_name,mode))) { + /* Could not open this file */ + if (errno != ENOENT) { + /* The file does exist, this is a lower level error, I can't do anything. */ + _synctex_error("SyncTeX: could not open renamed %s, error %i\n",quoteless_synctex_name,errno); + } + goto return_on_error; + } + /* The quote free file name should replace the old one:*/ + free(synctex_name); + synctex_name = quoteless_synctex_name; + quoteless_synctex_name = NULL; + } + } + /* The operation is successfull, return the arguments by value. */ + * file_ref = the_file; + * io_mode_ref = io_mode; + * synctex_name_ref = synctex_name; + return 0; + } + return 3; /* Bad parameter. */ +} + +/* Opens the ouput file, taking into account the eventual build_directory. + * 0 on success, non 0 on error. */ +int _synctex_open(const char * output, const char * build_directory, char ** synctex_name_ref, gzFile * file_ref, synctex_bool_t add_quotes, synctex_io_mode_t * io_mode_ref) { +# define synctex_name (*synctex_name_ref) +# define the_file (*file_ref) + int result = __synctex_open(output,synctex_name_ref,file_ref,add_quotes,io_mode_ref); + if ((result || !*file_ref) && build_directory && strlen(build_directory)) { + char * build_output; + const char *lpc; + size_t size; + synctex_bool_t is_absolute; + build_output = NULL; + lpc = _synctex_last_path_component(output); + size = strlen(build_directory)+strlen(lpc)+2; /* One for the '/' and one for the '\0'. */ + is_absolute = _synctex_path_is_absolute(build_directory); + if (!is_absolute) { + size += strlen(output); + } + if ((build_output = (char *)malloc(size))) { + if (is_absolute) { + build_output[0] = '\0'; + } else { + if (build_output != strcpy(build_output,output)) { + return -4; + } + build_output[lpc-output]='\0'; + } + if (build_output == strcat(build_output,build_directory)) { + /* Append a path separator if necessary. */ + if (!SYNCTEX_IS_PATH_SEPARATOR(build_output[strlen(build_directory)-1])) { + if (build_output != strcat(build_output,"/")) { + return -2; + } + } + /* Append the last path component of the output. */ + if (build_output != strcat(build_output,lpc)) { + return -3; + } + return __synctex_open(build_output,synctex_name_ref,file_ref,add_quotes,io_mode_ref); + } + } + return -1; + } + return result; +# undef synctex_name +# undef the_file +} + +/* The scanner destructor + */ +void synctex_scanner_free(synctex_scanner_t scanner) { + if (NULL == scanner) { + return; + } + if (SYNCTEX_FILE) { + gzclose(SYNCTEX_FILE); + SYNCTEX_FILE = NULL; + } + SYNCTEX_FREE(scanner->sheet); + SYNCTEX_FREE(scanner->input); + free(SYNCTEX_START); + free(scanner->output_fmt); + free(scanner->output); + free(scanner->synctex); + free(scanner->lists_of_friends); + free(scanner); +} + +/* Where the synctex scanner parses the contents of the file. */ +synctex_scanner_t synctex_scanner_parse(synctex_scanner_t scanner) { + synctex_status_t status = 0; + if (!scanner || scanner->flags.has_parsed) { + return scanner; + } + scanner->flags.has_parsed=1; + scanner->pre_magnification = 1000; + scanner->pre_unit = 8192; + scanner->pre_x_offset = scanner->pre_y_offset = 578; + /* initialize the offset with a fake unprobable value, + * If there is a post scriptum section, this value will be overriden by the real life value */ + scanner->x_offset = scanner->y_offset = 6.027e23f; + scanner->class[synctex_node_type_sheet] = synctex_class_sheet; + scanner->class[synctex_node_type_input] = synctex_class_input; + (scanner->class[synctex_node_type_input]).scanner = scanner; + (scanner->class[synctex_node_type_sheet]).scanner = scanner; + scanner->class[synctex_node_type_vbox] = synctex_class_vbox; + (scanner->class[synctex_node_type_vbox]).scanner = scanner; + scanner->class[synctex_node_type_void_vbox] = synctex_class_void_vbox; + (scanner->class[synctex_node_type_void_vbox]).scanner = scanner; + scanner->class[synctex_node_type_hbox] = synctex_class_hbox; + (scanner->class[synctex_node_type_hbox]).scanner = scanner; + scanner->class[synctex_node_type_void_hbox] = synctex_class_void_hbox; + (scanner->class[synctex_node_type_void_hbox]).scanner = scanner; + scanner->class[synctex_node_type_kern] = synctex_class_kern; + (scanner->class[synctex_node_type_kern]).scanner = scanner; + scanner->class[synctex_node_type_glue] = synctex_class_glue; + (scanner->class[synctex_node_type_glue]).scanner = scanner; + scanner->class[synctex_node_type_math] = synctex_class_math; + (scanner->class[synctex_node_type_math]).scanner = scanner; + scanner->class[synctex_node_type_boundary] = synctex_class_boundary; + (scanner->class[synctex_node_type_boundary]).scanner = scanner; + SYNCTEX_START = (char *)malloc(SYNCTEX_BUFFER_SIZE+1); /* one more character for null termination */ + if (NULL == SYNCTEX_START) { + _synctex_error("SyncTeX: malloc error"); + synctex_scanner_free(scanner); + return NULL; + } + SYNCTEX_END = SYNCTEX_START+SYNCTEX_BUFFER_SIZE; + /* SYNCTEX_END always points to a null terminating character. + * Maybe there is another null terminating character between SYNCTEX_CUR and SYNCTEX_END-1. + * At least, we are sure that SYNCTEX_CUR points to a string covering a valid part of the memory. */ + *SYNCTEX_END = '\0'; + SYNCTEX_CUR = SYNCTEX_END; + status = _synctex_scan_preamble(scanner); + if (statuspre_unit)/65536 pt = (scanner->pre_unit)/65781.76 bp + * 1 pt = 65536 sp */ + if (scanner->pre_unit<=0) { + scanner->pre_unit = 8192; + } + if (scanner->pre_magnification<=0) { + scanner->pre_magnification = 1000; + } + if (scanner->unit <= 0) { + /* no post magnification */ + scanner->unit = scanner->pre_unit / 65781.76;/* 65781.76 or 65536.0*/ + } else { + /* post magnification */ + scanner->unit *= scanner->pre_unit / 65781.76; + } + scanner->unit *= scanner->pre_magnification / 1000.0; + if (scanner->x_offset > 6e23) { + /* no post offset */ + scanner->x_offset = scanner->pre_x_offset * (scanner->pre_unit / 65781.76); + scanner->y_offset = scanner->pre_y_offset * (scanner->pre_unit / 65781.76); + } else { + /* post offset */ + scanner->x_offset /= 65781.76f; + scanner->y_offset /= 65781.76f; + } + return scanner; + #undef SYNCTEX_FILE +} + +/* Scanner accessors. + */ +int synctex_scanner_pre_x_offset(synctex_scanner_t scanner){ + return scanner?scanner->pre_x_offset:0; +} +int synctex_scanner_pre_y_offset(synctex_scanner_t scanner){ + return scanner?scanner->pre_y_offset:0; +} +int synctex_scanner_x_offset(synctex_scanner_t scanner){ + return scanner?scanner->x_offset:0; +} +int synctex_scanner_y_offset(synctex_scanner_t scanner){ + return scanner?scanner->y_offset:0; +} +float synctex_scanner_magnification(synctex_scanner_t scanner){ + return scanner?scanner->unit:1; +} +void synctex_scanner_display(synctex_scanner_t scanner) { + if (NULL == scanner) { + return; + } + printf("The scanner:\noutput:%s\noutput_fmt:%s\nversion:%i\n",scanner->output,scanner->output_fmt,scanner->version); + printf("pre_unit:%i\nx_offset:%i\ny_offset:%i\n",scanner->pre_unit,scanner->pre_x_offset,scanner->pre_y_offset); + printf("count:%i\npost_magnification:%f\npost_x_offset:%f\npost_y_offset:%f\n", + scanner->count,scanner->unit,scanner->x_offset,scanner->y_offset); + printf("The input:\n"); + SYNCTEX_DISPLAY(scanner->input); + if (scanner->count<1000) { + printf("The sheets:\n"); + SYNCTEX_DISPLAY(scanner->sheet); + printf("The friends:\n"); + if (scanner->lists_of_friends) { + int i = scanner->number_of_lists; + synctex_node_t node; + while(i--) { + printf("Friend index:%i\n",i); + node = (scanner->lists_of_friends)[i]; + while(node) { + printf("%s:%i,%i\n", + synctex_node_isa(node), + SYNCTEX_TAG(node), + SYNCTEX_LINE(node) + ); + node = SYNCTEX_FRIEND(node); + } + } + } + } else { + printf("SyncTeX Warning: Too many objects\n"); + } +} +/* Public*/ +const char * synctex_scanner_get_name(synctex_scanner_t scanner,int tag) { + synctex_node_t input = NULL; + if (NULL == scanner) { + return NULL; + } + input = scanner->input; + do { + if (tag == SYNCTEX_TAG(input)) { + return (SYNCTEX_NAME(input)); + } + } while((input = SYNCTEX_SIBLING(input)) != NULL); + return NULL; +} + +int _synctex_scanner_get_tag(synctex_scanner_t scanner,const char * name); +int _synctex_scanner_get_tag(synctex_scanner_t scanner,const char * name) { + synctex_node_t input = NULL; + if (NULL == scanner) { + return 0; + } + input = scanner->input; + do { + if (_synctex_is_equivalent_file_name(name,(SYNCTEX_NAME(input)))) { + return SYNCTEX_TAG(input); + } + } while((input = SYNCTEX_SIBLING(input)) != NULL); + return 0; +} + +int synctex_scanner_get_tag(synctex_scanner_t scanner,const char * name) { + size_t char_index = strlen(name); + if ((scanner = synctex_scanner_parse(scanner)) && (0 < char_index)) { + /* the name is not void */ + char_index -= 1; + if (!SYNCTEX_IS_PATH_SEPARATOR(name[char_index])) { + /* the last character of name is not a path separator */ + int result = _synctex_scanner_get_tag(scanner,name); + if (result) { + return result; + } else { + /* the given name was not the one known by TeX + * try a name relative to the enclosing directory of the scanner->output file */ + const char * relative = name; + const char * ptr = scanner->output; + while((strlen(relative) > 0) && (strlen(ptr) > 0) && (*relative == *ptr)) + { + relative += 1; + ptr += 1; + } + /* Find the last path separator before relative */ + while(relative > name) { + if (SYNCTEX_IS_PATH_SEPARATOR(*(relative-1))) { + break; + } + relative -= 1; + } + if ((relative > name) && (result = _synctex_scanner_get_tag(scanner,relative))) { + return result; + } + if (SYNCTEX_IS_PATH_SEPARATOR(name[0])) { + /* No tag found for the given absolute name, + * Try each relative path starting from the shortest one */ + while(0input:NULL; +} +const char * synctex_scanner_get_output_fmt(synctex_scanner_t scanner) { + return NULL != scanner && scanner->output_fmt?scanner->output_fmt:""; +} +const char * synctex_scanner_get_output(synctex_scanner_t scanner) { + return NULL != scanner && scanner->output?scanner->output:""; +} +const char * synctex_scanner_get_synctex(synctex_scanner_t scanner) { + return NULL != scanner && scanner->synctex?scanner->synctex:""; +} +# ifdef SYNCTEX_NOTHING +# pragma mark - +# pragma mark Public node attributes +# endif +int synctex_node_h(synctex_node_t node){ + if (!node) { + return 0; + } + return SYNCTEX_HORIZ(node); +} +int synctex_node_v(synctex_node_t node){ + if (!node) { + return 0; + } + return SYNCTEX_VERT(node); +} +int synctex_node_width(synctex_node_t node){ + if (!node) { + return 0; + } + return SYNCTEX_WIDTH(node); +} +int synctex_node_box_h(synctex_node_t node){ + if (!node) { + return 0; + } + if (SYNCTEX_IS_BOX(node)) { +result: + return SYNCTEX_HORIZ(node); + } + if ((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) { + goto result; + } + return 0; +} +int synctex_node_box_v(synctex_node_t node){ + if (!node) { + return 0; + } + if (SYNCTEX_IS_BOX(node)) { +result: + return SYNCTEX_VERT(node); + } + if ((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) { + goto result; + } + return 0; +} +int synctex_node_box_width(synctex_node_t node){ + if (!node) { + return 0; + } + if (SYNCTEX_IS_BOX(node)) { +result: + return SYNCTEX_WIDTH(node); + } + if ((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) { + goto result; + } + return 0; +} +int synctex_node_box_height(synctex_node_t node){ + if (!node) { + return 0; + } + if (SYNCTEX_IS_BOX(node)) { +result: + return SYNCTEX_HEIGHT(node); + } + if ((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) { + goto result; + } + return 0; +} +int synctex_node_box_depth(synctex_node_t node){ + if (!node) { + return 0; + } + if (SYNCTEX_IS_BOX(node)) { +result: + return SYNCTEX_DEPTH(node); + } + if ((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) { + goto result; + } + return 0; +} +# ifdef SYNCTEX_NOTHING +# pragma mark - +# pragma mark Public node visible attributes +# endif +float synctex_node_visible_h(synctex_node_t node){ + if (!node) { + return 0; + } + return SYNCTEX_HORIZ(node)*node->class->scanner->unit+node->class->scanner->x_offset; +} +float synctex_node_visible_v(synctex_node_t node){ + if (!node) { + return 0; + } + return SYNCTEX_VERT(node)*node->class->scanner->unit+node->class->scanner->y_offset; +} +float synctex_node_visible_width(synctex_node_t node){ + if (!node) { + return 0; + } + return SYNCTEX_WIDTH(node)*node->class->scanner->unit; +} +float synctex_node_box_visible_h(synctex_node_t node){ + if (!node) { + return 0; + } + switch(node->class->type) { + case synctex_node_type_vbox: + case synctex_node_type_void_vbox: + case synctex_node_type_void_hbox: + return SYNCTEX_HORIZ(node)*node->class->scanner->unit+node->class->scanner->x_offset; + case synctex_node_type_hbox: +result: + return SYNCTEX_HORIZ_V(node)*node->class->scanner->unit+node->class->scanner->x_offset; + } + if ((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) { + goto result; + } + return 0; +} +float synctex_node_box_visible_v(synctex_node_t node){ + if (!node) { + return 0; + } + switch(node->class->type) { + case synctex_node_type_vbox: + case synctex_node_type_void_vbox: + case synctex_node_type_void_hbox: + return SYNCTEX_VERT(node)*node->class->scanner->unit+node->class->scanner->y_offset; + case synctex_node_type_hbox: +result: + return SYNCTEX_VERT_V(node)*node->class->scanner->unit+node->class->scanner->y_offset; + } + if ((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) { + goto result; + } + return 0; +} +float synctex_node_box_visible_width(synctex_node_t node){ + if (!node) { + return 0; + } + switch(node->class->type) { + case synctex_node_type_vbox: + case synctex_node_type_void_vbox: + case synctex_node_type_void_hbox: + return SYNCTEX_WIDTH(node)*node->class->scanner->unit; + case synctex_node_type_hbox: +result: + return SYNCTEX_WIDTH_V(node)*node->class->scanner->unit; + } + if ((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) { + goto result; + } + return 0; +} +float synctex_node_box_visible_height(synctex_node_t node){ + if (!node) { + return 0; + } + switch(node->class->type) { + case synctex_node_type_vbox: + case synctex_node_type_void_vbox: + case synctex_node_type_void_hbox: + return SYNCTEX_HEIGHT(node)*node->class->scanner->unit; + case synctex_node_type_hbox: +result: + return SYNCTEX_HEIGHT_V(node)*node->class->scanner->unit; + } + if ((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) { + goto result; + } + return 0; +} +float synctex_node_box_visible_depth(synctex_node_t node){ + if (!node) { + return 0; + } + switch(node->class->type) { + case synctex_node_type_vbox: + case synctex_node_type_void_vbox: + case synctex_node_type_void_hbox: + return SYNCTEX_DEPTH(node)*node->class->scanner->unit; + case synctex_node_type_hbox: +result: + return SYNCTEX_DEPTH_V(node)*node->class->scanner->unit; + } + if ((node = SYNCTEX_PARENT(node)) && (node->class->type != synctex_node_type_sheet)) { + goto result; + } + return 0; +} +# ifdef SYNCTEX_NOTHING +# pragma mark - +# pragma mark Other public node attributes +# endif + +int synctex_node_page(synctex_node_t node){ + synctex_node_t parent = NULL; + if (!node) { + return -1; + } + parent = SYNCTEX_PARENT(node); + while(parent) { + node = parent; + parent = SYNCTEX_PARENT(node); + } + if (node->class->type == synctex_node_type_sheet) { + return SYNCTEX_PAGE(node); + } + return -1; +} +int synctex_node_tag(synctex_node_t node) { + return node?SYNCTEX_TAG(node):-1; +} +int synctex_node_line(synctex_node_t node) { + return node?SYNCTEX_LINE(node):-1; +} +int synctex_node_column(synctex_node_t node) { +# ifdef __DARWIN_UNIX03 +# pragma unused(node) +# endif + return -1; +} +# ifdef SYNCTEX_NOTHING +# pragma mark - +# pragma mark Sheet +# endif + +synctex_node_t synctex_sheet_content(synctex_scanner_t scanner,int page) { + if (scanner) { + synctex_node_t sheet = scanner->sheet; + while(sheet) { + if (page == SYNCTEX_PAGE(sheet)) { + return SYNCTEX_CHILD(sheet); + } + sheet = SYNCTEX_SIBLING(sheet); + } + } + return NULL; +} + +# ifdef SYNCTEX_NOTHING +# pragma mark - +# pragma mark Query +# endif + +int synctex_display_query(synctex_scanner_t scanner,const char * name,int line,int column) { +# ifdef __DARWIN_UNIX03 +# pragma unused(column) +# endif + int tag = synctex_scanner_get_tag(scanner,name); + size_t size = 0; + int friend_index = 0; + int max_line = 0; + synctex_node_t node = NULL; + if (tag == 0) { + printf("SyncTeX Warning: No tag for %s\n",name); + return -1; + } + free(SYNCTEX_START); + SYNCTEX_CUR = SYNCTEX_END = SYNCTEX_START = NULL; + max_line = line < INT_MAX-scanner->number_of_lists ? line+scanner->number_of_lists:INT_MAX; + while(linenumber_of_lists); + if ((node = (scanner->lists_of_friends)[friend_index])) { + do { + if ((synctex_node_type(node)>=synctex_node_type_boundary) + && (tag == SYNCTEX_TAG(node)) + && (line == SYNCTEX_LINE(node))) { + if (SYNCTEX_CUR == SYNCTEX_END) { + size += 16; + SYNCTEX_END = realloc(SYNCTEX_START,size*sizeof(synctex_node_t *)); + SYNCTEX_CUR += SYNCTEX_END - SYNCTEX_START; + SYNCTEX_START = SYNCTEX_END; + SYNCTEX_END = SYNCTEX_START + size*sizeof(synctex_node_t *); + } + *(synctex_node_t *)SYNCTEX_CUR = node; + SYNCTEX_CUR += sizeof(synctex_node_t); + } + } while((node = SYNCTEX_FRIEND(node))); + if (SYNCTEX_START == NULL) { + /* We did not find any matching boundary, retry with glue or kern */ + node = (scanner->lists_of_friends)[friend_index];/* no need to test it again, already done */ + do { + if ((synctex_node_type(node)>=synctex_node_type_kern) + && (tag == SYNCTEX_TAG(node)) + && (line == SYNCTEX_LINE(node))) { + if (SYNCTEX_CUR == SYNCTEX_END) { + size += 16; + SYNCTEX_END = realloc(SYNCTEX_START,size*sizeof(synctex_node_t *)); + SYNCTEX_CUR += SYNCTEX_END - SYNCTEX_START; + SYNCTEX_START = SYNCTEX_END; + SYNCTEX_END = SYNCTEX_START + size*sizeof(synctex_node_t *); + } + *(synctex_node_t *)SYNCTEX_CUR = node; + SYNCTEX_CUR += sizeof(synctex_node_t); + } + } while((node = SYNCTEX_FRIEND(node))); + if (SYNCTEX_START == NULL) { + /* We did not find any matching glue or kern, retry with boxes */ + node = (scanner->lists_of_friends)[friend_index];/* no need to test it again, already done */ + do { + if ((tag == SYNCTEX_TAG(node)) + && (line == SYNCTEX_LINE(node))) { + if (SYNCTEX_CUR == SYNCTEX_END) { + size += 16; + SYNCTEX_END = realloc(SYNCTEX_START,size*sizeof(synctex_node_t *)); + SYNCTEX_CUR += SYNCTEX_END - SYNCTEX_START; + SYNCTEX_START = SYNCTEX_END; + SYNCTEX_END = SYNCTEX_START + size*sizeof(synctex_node_t *); + } + *(synctex_node_t *)SYNCTEX_CUR = node; + SYNCTEX_CUR += sizeof(synctex_node_t); + } + } while((node = SYNCTEX_FRIEND(node))); + } + } + SYNCTEX_END = SYNCTEX_CUR; + /* Now reverse the order to have nodes in display order, and keep just a few nodes */ + if ((SYNCTEX_START) && (SYNCTEX_END)) + { + synctex_node_t * start_ref = (synctex_node_t *)SYNCTEX_START; + synctex_node_t * end_ref = (synctex_node_t *)SYNCTEX_END; + end_ref -= 1; + while(start_ref < end_ref) { + node = *start_ref; + *start_ref = *end_ref; + *end_ref = node; + start_ref += 1; + end_ref -= 1; + } + /* Basically, we keep the first node for each parent. + * More precisely, we keep only nodes that are not descendants of + * their predecessor's parent. */ + start_ref = (synctex_node_t *)SYNCTEX_START; + end_ref = (synctex_node_t *)SYNCTEX_START; + next_end: + end_ref += 1; /* we allways have start_ref<= end_ref*/ + if (end_ref < (synctex_node_t *)SYNCTEX_END) { + node = *end_ref; + while((node = SYNCTEX_PARENT(node))) { + if (SYNCTEX_PARENT(*start_ref) == node) { + goto next_end; + } + } + start_ref += 1; + *start_ref = *end_ref; + goto next_end; + } + start_ref += 1; + SYNCTEX_END = (char *)start_ref; + SYNCTEX_CUR = NULL;// added on behalf of Jose Alliste + return (SYNCTEX_END-SYNCTEX_START)/sizeof(synctex_node_t);// added on behalf Jan Sundermeyer + } + SYNCTEX_CUR = NULL; + // return (SYNCTEX_END-SYNCTEX_START)/sizeof(synctex_node_t); removed on behalf Jan Sundermeyer + } +# if defined(__SYNCTEX_STRONG_DISPLAY_QUERY__) + break; +# else + ++line; +# endif + } + return 0; +} + +synctex_node_t synctex_next_result(synctex_scanner_t scanner) { + if (NULL == SYNCTEX_CUR) { + SYNCTEX_CUR = SYNCTEX_START; + } else { + SYNCTEX_CUR+=sizeof(synctex_node_t); + } + if (SYNCTEX_CUR= scanner->unit) {/* scanner->unit must be >0 */ + return 0; + } + /* Convert the given point to scanner integer coordinates */ + hitPoint.h = (h-scanner->x_offset)/scanner->unit; + hitPoint.v = (v-scanner->y_offset)/scanner->unit; + /* We will store in the scanner's buffer the result of the query. */ + free(SYNCTEX_START); + SYNCTEX_START = SYNCTEX_END = SYNCTEX_CUR = NULL; + /* Find the proper sheet */ + sheet = scanner->sheet; + while((sheet) && SYNCTEX_PAGE(sheet) != page) { + sheet = SYNCTEX_SIBLING(sheet); + } + if (NULL == sheet) { + return -1; + } + /* Now sheet points to the sheet node with proper page number */ + /* Here is how we work: + * At first we do not consider the visible box dimensions. This will cover the most frequent cases. + * Then we try with the visible box dimensions. + * We try to find a non void box containing the hit point. + * We browse all the horizontal boxes until we find one containing the hit point. */ + if ((node = SYNCTEX_NEXT_HORIZ_BOX(sheet))) { + do { + if (_synctex_point_in_box(hitPoint,node,synctex_YES)) { + /* Maybe the hitPoint belongs to a contained vertical box. */ +end: + /* This trick is for catching overlapping boxes */ + if ((other_node = SYNCTEX_NEXT_HORIZ_BOX(node))) { + do { + if (_synctex_point_in_box(hitPoint,other_node,synctex_YES)) { + node = _synctex_smallest_container(other_node,node); + } + } while((other_node = SYNCTEX_NEXT_HORIZ_BOX(other_node))); + } + /* node is the smallest horizontal box that contains hitPoint. */ + if ((bestContainer = _synctex_eq_deepest_container(hitPoint,node,synctex_YES))) { + node = bestContainer; + } + _synctex_eq_get_closest_children_in_box(hitPoint,node,&bestNodes,&bestDistances,synctex_YES); + if (bestNodes.right && bestNodes.left) { + if ((SYNCTEX_TAG(bestNodes.right)!=SYNCTEX_TAG(bestNodes.left)) + || (SYNCTEX_LINE(bestNodes.right)!=SYNCTEX_LINE(bestNodes.left)) + || (SYNCTEX_COLUMN(bestNodes.right)!=SYNCTEX_COLUMN(bestNodes.left))) { + if ((SYNCTEX_START = malloc(2*sizeof(synctex_node_t)))) { + if (bestDistances.left>bestDistances.right) { + ((synctex_node_t *)SYNCTEX_START)[0] = bestNodes.right; + ((synctex_node_t *)SYNCTEX_START)[1] = bestNodes.left; + } else { + ((synctex_node_t *)SYNCTEX_START)[0] = bestNodes.left; + ((synctex_node_t *)SYNCTEX_START)[1] = bestNodes.right; + } + SYNCTEX_END = SYNCTEX_START + 2*sizeof(synctex_node_t); + SYNCTEX_CUR = NULL; + return (SYNCTEX_END-SYNCTEX_START)/sizeof(synctex_node_t); + } + return SYNCTEX_STATUS_ERROR; + } + /* both nodes have the same input coordinates + * We choose the one closest to the hit point */ + if (bestDistances.left>bestDistances.right) { + bestNodes.left = bestNodes.right; + } + bestNodes.right = NULL; + } else if (bestNodes.right) { + bestNodes.left = bestNodes.right; + } else if (!bestNodes.left){ + bestNodes.left = node; + } + if ((SYNCTEX_START = malloc(sizeof(synctex_node_t)))) { + * (synctex_node_t *)SYNCTEX_START = bestNodes.left; + SYNCTEX_END = SYNCTEX_START + sizeof(synctex_node_t); + SYNCTEX_CUR = NULL; + return (SYNCTEX_END-SYNCTEX_START)/sizeof(synctex_node_t); + } + return SYNCTEX_STATUS_ERROR; + } + } while ((node = SYNCTEX_NEXT_HORIZ_BOX(node))); + /* All the horizontal boxes have been tested, + * None of them contains the hit point. + */ + } + /* We are not lucky */ + if ((node = SYNCTEX_CHILD(sheet))) { + goto end; + } + return 0; +} + +# ifdef SYNCTEX_NOTHING +# pragma mark - +# pragma mark Utilities +# endif + +int _synctex_bail(void) { + _synctex_error("SyncTeX ERROR\n"); + return -1; +} +/* Rougly speaking, this is: + * node's h coordinate - hitPoint's h coordinate. + * If node is to the right of the hit point, then this distance is positive, + * if node is to the left of the hit point, this distance is negative.*/ +int _synctex_point_h_distance(synctex_point_t hitPoint, synctex_node_t node, synctex_bool_t visible); +int _synctex_point_h_distance(synctex_point_t hitPoint, synctex_node_t node, synctex_bool_t visible) { + if (node) { + int min,med,max; + switch(node->class->type) { + /* The distance between a point and a box is special. + * It is not the euclidian distance, nor something similar. + * We have to take into account the particular layout, + * and the box hierarchy. + * Given a box, there are 9 regions delimited by the lines of the edges of the box. + * The origin being at the top left corner of the page, + * we also give names to the vertices of the box. + * + * 1 | 2 | 3 + * ---A---B---> + * 4 | 5 | 6 + * ---C---D---> + * 7 | 8 | 9 + * v v + */ + case synctex_node_type_hbox: + /* getting the box bounds, taking into account negative width, height and depth. */ + min = visible?SYNCTEX_HORIZ_V(node):SYNCTEX_HORIZ(node); + max = min + (visible?SYNCTEX_ABS_WIDTH_V(node):SYNCTEX_ABS_WIDTH(node)); + /* We allways have min <= max */ + if (hitPoint.h 0 */ + } else if (hitPoint.h>max) { + return max - hitPoint.h; /* regions 3+6+9, result is < 0 */ + } else { + return 0; /* regions 2+5+8, inside the box, except for vertical coordinates */ + } + break; + case synctex_node_type_vbox: + case synctex_node_type_void_vbox: + case synctex_node_type_void_hbox: + /* getting the box bounds, taking into account negative width, height and depth. + * For these boxes, no visible dimension available */ + min = SYNCTEX_HORIZ(node); + max = min + SYNCTEX_ABS_WIDTH(node); + /* We allways have min <= max */ + if (hitPoint.h 0 */ + } else if (hitPoint.h>max) { + return max - hitPoint.h; /* regions 3+6+9, result is < 0 */ + } else { + return 0; /* regions 2+5+8, inside the box, except for vertical coordinates */ + } + break; + case synctex_node_type_kern: + /* IMPORTANT NOTICE: the location of the kern is recorded AFTER the move. + * The distance to the kern is very special, + * in general, there is no text material in the kern, + * this is why we compute the offset relative to the closest edge of the kern.*/ + max = SYNCTEX_WIDTH(node); + if (max<0) { + min = SYNCTEX_HORIZ(node); + max = min - max; + } else { + min = -max; + max = SYNCTEX_HORIZ(node); + min += max; + } + med = (min+max)/2; + /* positive kern: '.' means text, '>' means kern offset + * ............. + * min>>>>med>>>>max + * ............... + * negative kern: '.' means text, '<' means kern offset + * ............................ + * min<<<max) { + return max - hitPoint.h - 1; /* same kind of penalty */ + } else if (hitPoint.h>med) { + /* do things like if the node had 0 width and was placed at the max edge + 1*/ + return max - hitPoint.h + 1; /* positive, the kern is to the right of the hitPoint */ + } else { + return min - hitPoint.h - 1; /* negative, the kern is to the left of the hitPoint */ + } + case synctex_node_type_glue: + case synctex_node_type_math: + return SYNCTEX_HORIZ(node) - hitPoint.h; + } + } + return INT_MAX;/* We always assume that the node is faraway to the right*/ +} +/* Rougly speaking, this is: + * node's v coordinate - hitPoint's v coordinate. + * If node is at the top of the hit point, then this distance is positive, + * if node is at the bottom of the hit point, this distance is negative.*/ +int _synctex_point_v_distance(synctex_point_t hitPoint, synctex_node_t node,synctex_bool_t visible); +int _synctex_point_v_distance(synctex_point_t hitPoint, synctex_node_t node,synctex_bool_t visible) { +# ifdef __DARWIN_UNIX03 +# pragma unused(visible) +# endif + if (node) { + int min,max; + switch(node->class->type) { + /* The distance between a point and a box is special. + * It is not the euclidian distance, nor something similar. + * We have to take into account the particular layout, + * and the box hierarchy. + * Given a box, there are 9 regions delimited by the lines of the edges of the box. + * The origin being at the top left corner of the page, + * we also give names to the vertices of the box. + * + * 1 | 2 | 3 + * ---A---B---> + * 4 | 5 | 6 + * ---C---D---> + * 7 | 8 | 9 + * v v + */ + case synctex_node_type_hbox: + /* getting the box bounds, taking into account negative width, height and depth. */ + min = SYNCTEX_VERT_V(node); + max = min + SYNCTEX_ABS_DEPTH_V(node); + min -= SYNCTEX_ABS_HEIGHT_V(node); + /* We allways have min <= max */ + if (hitPoint.v 0 */ + } else if (hitPoint.v>max) { + return max - hitPoint.v; /* regions 7+8+9, result is < 0 */ + } else { + return 0; /* regions 4.5.6, inside the box, except for horizontal coordinates */ + } + break; + case synctex_node_type_vbox: + case synctex_node_type_void_vbox: + case synctex_node_type_void_hbox: + /* getting the box bounds, taking into account negative width, height and depth. */ + min = SYNCTEX_VERT(node); + max = min + SYNCTEX_ABS_DEPTH(node); + min -= SYNCTEX_ABS_HEIGHT(node); + /* We allways have min <= max */ + if (hitPoint.v 0 */ + } else if (hitPoint.v>max) { + return max - hitPoint.v; /* regions 7+8+9, result is < 0 */ + } else { + return 0; /* regions 4.5.6, inside the box, except for horizontal coordinates */ + } + break; + case synctex_node_type_kern: + case synctex_node_type_glue: + case synctex_node_type_math: + return SYNCTEX_VERT(node) - hitPoint.v; + } + } + return INT_MAX;/* We always assume that the node is faraway to the top*/ +} + +SYNCTEX_INLINE static synctex_node_t _synctex_smallest_container(synctex_node_t node, synctex_node_t other_node) { + float height, other_height; + if (SYNCTEX_ABS_WIDTH(node)SYNCTEX_ABS_WIDTH(other_node)) { + return other_node; + } + height = SYNCTEX_ABS_DEPTH(node) + SYNCTEX_ABS_HEIGHT(node); + other_height = SYNCTEX_ABS_DEPTH(other_node) + SYNCTEX_ABS_HEIGHT(other_node); + if (heightother_height) { + return other_node; + } + return node; +} + +synctex_bool_t _synctex_point_in_box(synctex_point_t hitPoint, synctex_node_t node, synctex_bool_t visible) { + if (node) { + if (0 == _synctex_point_h_distance(hitPoint,node,visible) + && 0 == _synctex_point_v_distance(hitPoint,node,visible)) { + return synctex_YES; + } + } + return synctex_NO; +} + +int _synctex_node_distance_to_point(synctex_point_t hitPoint, synctex_node_t node, synctex_bool_t visible) { +# ifdef __DARWIN_UNIX03 +# pragma unused(visible) +# endif + int result = INT_MAX; /* when the distance is meaning less (sheet, input...) */ + if (node) { + int minH,maxH,minV,maxV; + switch(node->class->type) { + /* The distance between a point and a box is special. + * It is not the euclidian distance, nor something similar. + * We have to take into account the particular layout, + * and the box hierarchy. + * Given a box, there are 9 regions delimited by the lines of the edges of the box. + * The origin being at the top left corner of the page, + * we also give names to the vertices of the box. + * + * 1 | 2 | 3 + * ---A---B---> + * 4 | 5 | 6 + * ---C---D---> + * 7 | 8 | 9 + * v v + * In each region, there is a different formula. + * In the end we have a continuous distance which may not be a mathematical distance but who cares. */ + case synctex_node_type_vbox: + case synctex_node_type_void_vbox: + case synctex_node_type_hbox: + case synctex_node_type_void_hbox: + /* getting the box bounds, taking into account negative widths. */ + minH = SYNCTEX_HORIZ(node); + maxH = minH + SYNCTEX_ABS_WIDTH(node); + minV = SYNCTEX_VERT(node); + maxV = minV + SYNCTEX_ABS_DEPTH(node); + minV -= SYNCTEX_ABS_HEIGHT(node); + /* In what region is the point hitPoint=(H,V) ? */ + if (hitPoint.vminV) { + result = hitPoint.v - minV + minH - hitPoint.h; + } else { + result = minV - hitPoint.v + minH - hitPoint.h; + } + } else if (hitPoint.h>maxH) { + if (hitPoint.v>minV) { + result = hitPoint.v - minV + hitPoint.h - maxH; + } else { + result = minV - hitPoint.v + hitPoint.h - maxH; + } + } else if (hitPoint.v>minV) { + result = hitPoint.v - minV; + } else { + result = minV - hitPoint.v; + } + break; + case synctex_node_type_glue: + case synctex_node_type_math: + minH = SYNCTEX_HORIZ(node); + minV = SYNCTEX_VERT(node); + if (hitPoint.hminV) { + result = hitPoint.v - minV + minH - hitPoint.h; + } else { + result = minV - hitPoint.v + minH - hitPoint.h; + } + } else if (hitPoint.v>minV) { + result = hitPoint.v - minV + hitPoint.h - minH; + } else { + result = minV - hitPoint.v + hitPoint.h - minH; + } + break; + } + } + return result; +} + +static synctex_node_t _synctex_eq_deepest_container(synctex_point_t hitPoint,synctex_node_t node, synctex_bool_t visible) { + if (node) { + synctex_node_t result = NULL; + synctex_node_t child = NULL; + switch(node->class->type) { + case synctex_node_type_vbox: + case synctex_node_type_hbox: + /* test the deep nodes first */ + if ((child = SYNCTEX_CHILD(node))) { + do { + if ((result = _synctex_eq_deepest_container(hitPoint,child,visible))) { + return result; + } + } while((child = SYNCTEX_SIBLING(child))); + } + /* is the hit point inside the box? */ + if (_synctex_point_in_box(hitPoint,node,visible)) { + /* for vboxes we try to use some node inside. + * Walk through the list of siblings until we find the closest one. + * Only consider siblings with children. */ + if ((node->class->type == synctex_node_type_vbox) && (child = SYNCTEX_CHILD(node))) { + int bestDistance = INT_MAX; + do { + if (SYNCTEX_CHILD(child)) { + int distance = _synctex_node_distance_to_point(hitPoint,child,visible); + if (distance < bestDistance) { + bestDistance = distance; + node = child; + } + } + } while((child = SYNCTEX_SIBLING(child))); + } + return node; + } + } + } + return NULL; +} + +/* Compares the locations of the hitPoint with the locations of the various nodes contained in the box. + * As it is an horizontal box, we only compare horizontal coordinates. */ +SYNCTEX_INLINE static int __synctex_eq_get_closest_children_in_hbox(synctex_point_t hitPoint, synctex_node_t node, synctex_node_set_t* bestNodesRef,synctex_distances_t* bestDistancesRef, synctex_bool_t visible); +SYNCTEX_INLINE static int __synctex_eq_get_closest_children_in_hbox(synctex_point_t hitPoint, synctex_node_t node, synctex_node_set_t* bestNodesRef,synctex_distances_t* bestDistancesRef, synctex_bool_t visible) { + int result = 0; + if ((node = SYNCTEX_CHILD(node))) { + do { + int off7 = _synctex_point_h_distance(hitPoint,node,visible); + if (off7 > 0) { + /* node is to the right of the hit point. + * We compare node and the previously recorded one, through the recorded distance. + * If the nodes have the same tag, prefer the one with the smallest line number, + * if the nodes also have the same line number, prefer the one with the smallest column. */ + if (bestDistancesRef->right > off7) { + bestDistancesRef->right = off7; + bestNodesRef->right = node; + result |= SYNCTEX_MASK_RIGHT; + } else if (bestDistancesRef->right == off7 && bestNodesRef->right) { + if (SYNCTEX_TAG(bestNodesRef->right) == SYNCTEX_TAG(node) + && (SYNCTEX_LINE(bestNodesRef->right) > SYNCTEX_LINE(node) + || (SYNCTEX_LINE(bestNodesRef->right) == SYNCTEX_LINE(node) + && SYNCTEX_COLUMN(bestNodesRef->right) > SYNCTEX_COLUMN(node)))) { + bestNodesRef->right = node; + result |= SYNCTEX_MASK_RIGHT; + } + } + } else if (off7 == 0) { + /* hitPoint is inside node. */ + bestDistancesRef->left = bestDistancesRef->right = 0; + bestNodesRef->left = node; + bestNodesRef->right = NULL; + result |= SYNCTEX_MASK_LEFT; + } else { /* here off7 < 0, hitPoint is to the right of node */ + off7 = -off7; + if (bestDistancesRef->left > off7) { + bestDistancesRef->left = off7; + bestNodesRef->left = node; + result |= SYNCTEX_MASK_LEFT; + } else if (bestDistancesRef->left == off7 && bestNodesRef->left) { + if (SYNCTEX_TAG(bestNodesRef->left) == SYNCTEX_TAG(node) + && (SYNCTEX_LINE(bestNodesRef->left) > SYNCTEX_LINE(node) + || (SYNCTEX_LINE(bestNodesRef->left) == SYNCTEX_LINE(node) + && SYNCTEX_COLUMN(bestNodesRef->left) > SYNCTEX_COLUMN(node)))) { + bestNodesRef->left = node; + result |= SYNCTEX_MASK_LEFT; + } + } + } + } while((node = SYNCTEX_SIBLING(node))); + if (result & SYNCTEX_MASK_LEFT) { + /* the left node is new, try to narrow the result */ + if ((node = _synctex_eq_deepest_container(hitPoint,bestNodesRef->left,visible))) { + bestNodesRef->left = node; + } + if ((node = _synctex_eq_closest_child(hitPoint,bestNodesRef->left,visible))) { + bestNodesRef->left = node; + } + } + if (result & SYNCTEX_MASK_RIGHT) { + /* the right node is new, try to narrow the result */ + if ((node = _synctex_eq_deepest_container(hitPoint,bestNodesRef->right,visible))) { + bestNodesRef->right = node; + } + if ((node = _synctex_eq_closest_child(hitPoint,bestNodesRef->right,visible))) { + bestNodesRef->right = node; + } + } + } + return result; +} +SYNCTEX_INLINE static int __synctex_eq_get_closest_children_in_vbox(synctex_point_t hitPoint, synctex_node_t node, synctex_node_set_t* bestNodesRef,synctex_distances_t* bestDistancesRef,synctex_bool_t visible); +SYNCTEX_INLINE static int __synctex_eq_get_closest_children_in_vbox(synctex_point_t hitPoint, synctex_node_t node, synctex_node_set_t* bestNodesRef,synctex_distances_t* bestDistancesRef,synctex_bool_t visible) { + int result = 0; + if ((node = SYNCTEX_CHILD(node))) { + do { + int off7 = _synctex_point_v_distance(hitPoint,node,visible);/* this is what makes the difference with the h version above */ + if (off7 > 0) { + /* node is to the top of the hit point (below because TeX is oriented from top to bottom. + * We compare node and the previously recorded one, through the recorded distance. + * If the nodes have the same tag, prefer the one with the smallest line number, + * if the nodes also have the same line number, prefer the one with the smallest column. */ + if (bestDistancesRef->right > off7) { + bestDistancesRef->right = off7; + bestNodesRef->right = node; + result |= SYNCTEX_MASK_RIGHT; + } else if (bestDistancesRef->right == off7 && bestNodesRef->right) { + if (SYNCTEX_TAG(bestNodesRef->right) == SYNCTEX_TAG(node) + && (SYNCTEX_LINE(bestNodesRef->right) > SYNCTEX_LINE(node) + || (SYNCTEX_LINE(bestNodesRef->right) == SYNCTEX_LINE(node) + && SYNCTEX_COLUMN(bestNodesRef->right) > SYNCTEX_COLUMN(node)))) { + bestNodesRef->right = node; + result |= SYNCTEX_MASK_RIGHT; + } + } + } else if (off7 == 0) { + bestDistancesRef->left = bestDistancesRef->right = 0; + bestNodesRef->left = node; + bestNodesRef->right = NULL; + result |= SYNCTEX_MASK_LEFT; + } else { /* here off7 < 0 */ + off7 = -off7; + if (bestDistancesRef->left > off7) { + bestDistancesRef->left = off7; + bestNodesRef->left = node; + result |= SYNCTEX_MASK_LEFT; + } else if (bestDistancesRef->left == off7 && bestNodesRef->left) { + if (SYNCTEX_TAG(bestNodesRef->left) == SYNCTEX_TAG(node) + && (SYNCTEX_LINE(bestNodesRef->left) > SYNCTEX_LINE(node) + || (SYNCTEX_LINE(bestNodesRef->left) == SYNCTEX_LINE(node) + && SYNCTEX_COLUMN(bestNodesRef->left) > SYNCTEX_COLUMN(node)))) { + bestNodesRef->left = node; + result |= SYNCTEX_MASK_LEFT; + } + } + } + } while((node = SYNCTEX_SIBLING(node))); + if (result & SYNCTEX_MASK_LEFT) { + /* the left node is new, try to narrow the result */ + if ((node = _synctex_eq_deepest_container(hitPoint,bestNodesRef->left,visible))) { + bestNodesRef->left = node; + } + if ((node = _synctex_eq_closest_child(hitPoint,bestNodesRef->left,visible))) { + bestNodesRef->left = node; + } + } + if (result & SYNCTEX_MASK_RIGHT) { + /* the right node is new, try to narrow the result */ + if ((node = _synctex_eq_deepest_container(hitPoint,bestNodesRef->right,visible))) { + bestNodesRef->right = node; + } + if ((node = _synctex_eq_closest_child(hitPoint,bestNodesRef->right,visible))) { + bestNodesRef->right = node; + } + } + } + return result; +} +SYNCTEX_INLINE static int _synctex_eq_get_closest_children_in_box(synctex_point_t hitPoint, synctex_node_t node, synctex_node_set_t* bestNodesRef,synctex_distances_t* bestDistancesRef,synctex_bool_t visible) { + if (node) { + switch(node->class->type) { + case synctex_node_type_hbox: + return __synctex_eq_get_closest_children_in_hbox(hitPoint, node, bestNodesRef, bestDistancesRef,visible); + case synctex_node_type_vbox: + return __synctex_eq_get_closest_children_in_vbox(hitPoint, node, bestNodesRef, bestDistancesRef,visible); + } + } + return 0; +} + +SYNCTEX_INLINE static synctex_node_t __synctex_eq_closest_child(synctex_point_t hitPoint, synctex_node_t node,int* distanceRef, synctex_bool_t visible); +SYNCTEX_INLINE static synctex_node_t __synctex_eq_closest_child(synctex_point_t hitPoint, synctex_node_t node,int* distanceRef, synctex_bool_t visible) { + synctex_node_t best_node = NULL; + if ((node = SYNCTEX_CHILD(node))) { + do { + int distance = _synctex_node_distance_to_point(hitPoint,node,visible); + synctex_node_t candidate = NULL; + if (distance<=*distanceRef) { + *distanceRef = distance; + best_node = node; + } + switch(node->class->type) { + case synctex_node_type_vbox: + case synctex_node_type_hbox: + if ((candidate = __synctex_eq_closest_child(hitPoint,node,distanceRef,visible))) { + best_node = candidate; + } + } + } while((node = SYNCTEX_SIBLING(node))); + } + return best_node; +} +SYNCTEX_INLINE static synctex_node_t _synctex_eq_closest_child(synctex_point_t hitPoint,synctex_node_t node, synctex_bool_t visible) { + if (node) { + switch(node->class->type) { + case synctex_node_type_hbox: + case synctex_node_type_vbox: + { + int best_distance = INT_MAX; + synctex_node_t best_node = __synctex_eq_closest_child(hitPoint,node,&best_distance,visible); + if ((best_node)) { + synctex_node_t child = NULL; + switch(best_node->class->type) { + case synctex_node_type_vbox: + case synctex_node_type_hbox: + if ((child = SYNCTEX_CHILD(best_node))) { + best_distance = _synctex_node_distance_to_point(hitPoint,child,visible); + while((child = SYNCTEX_SIBLING(child))) { + int distance = _synctex_node_distance_to_point(hitPoint,child,visible); + if (distance<=best_distance) { + best_distance = distance; + best_node = child; + } + } + } + } + } + return best_node; + } + } + } + return NULL; +} + +# ifdef SYNCTEX_NOTHING +# pragma mark - +# pragma mark Updater +# endif + +typedef int (*synctex_fprintf_t)(void *, const char * , ...); /* print formatted to either FILE * or gzFile */ + +# define SYNCTEX_BITS_PER_BYTE 8 + +struct __synctex_updater_t { + void *file; /* the foo.synctex or foo.synctex.gz I/O identifier */ + synctex_fprintf_t fprintf; /* either fprintf or gzprintf */ + int length; /* the number of chars appended */ + struct _flags { + unsigned int no_gz:1; /* Whether zlib is used or not */ + unsigned int reserved:SYNCTEX_BITS_PER_BYTE*sizeof(int)-1; /* Align */ + } flags; +}; +# define SYNCTEX_FILE updater->file +# define SYNCTEX_NO_GZ ((updater->flags).no_gz) +# define SYNCTEX_fprintf (*(updater->fprintf)) + +synctex_updater_t synctex_updater_new_with_output_file(const char * output, const char * build_directory) { + synctex_updater_t updater = NULL; + char * synctex = NULL; + synctex_io_mode_t io_mode = 0; + const char * mode = NULL; + /* prepare the updater, the memory is the only one dynamically allocated */ + updater = (synctex_updater_t)_synctex_malloc(sizeof(synctex_updater_t)); + if (NULL == updater) { + _synctex_error("! synctex_updater_new_with_file: malloc problem"); + return NULL; + } + if (_synctex_open(output,build_directory,&synctex,&SYNCTEX_FILE,synctex_ADD_QUOTES,&io_mode) + && _synctex_open(output,build_directory,&synctex,&SYNCTEX_FILE,synctex_DONT_ADD_QUOTES,&io_mode)) { +return_on_error: + free(updater); + updater = NULL; + return NULL; + } + /* OK, the file exists, we close it and reopen it with the correct mode. + * The receiver is now the owner of the "synctex" variable. */ + gzclose(SYNCTEX_FILE); + SYNCTEX_FILE = NULL; + SYNCTEX_NO_GZ = (io_mode&synctex_io_gz_mask)?synctex_NO:synctex_YES; + mode = _synctex_get_io_mode_name(io_mode|synctex_io_append_mask);/* either "a" or "ab", depending on the file extension */ + if (SYNCTEX_NO_GZ) { + if (NULL == (SYNCTEX_FILE = (void *)fopen(synctex,mode))) { +no_write_error: + _synctex_error("! synctex_updater_new_with_file: Can't append to %s",synctex); + free(synctex); + goto return_on_error; + } + updater->fprintf = (synctex_fprintf_t)(&fprintf); + } else { + if (NULL == (SYNCTEX_FILE = (void *)gzopen(synctex,mode))) { + goto no_write_error; + } + updater->fprintf = (synctex_fprintf_t)(&gzprintf); + } + printf("SyncTeX: updating %s...",synctex); + free(synctex); + return updater; +} + + +void synctex_updater_append_magnification(synctex_updater_t updater, char * magnification){ + if (NULL==updater) { + return; + } + if (magnification && strlen(magnification)) { + updater->length += SYNCTEX_fprintf(SYNCTEX_FILE,"Magnification:%s\n",magnification); + } +} + +void synctex_updater_append_x_offset(synctex_updater_t updater, char * x_offset){ + if (NULL==updater) { + return; + } + if (x_offset && strlen(x_offset)) { + updater->length += SYNCTEX_fprintf(SYNCTEX_FILE,"X Offset:%s\n",x_offset); + } +} + +void synctex_updater_append_y_offset(synctex_updater_t updater, char * y_offset){ + if (NULL==updater) { + return; + } + if (y_offset && strlen(y_offset)) { + updater->length += SYNCTEX_fprintf(SYNCTEX_FILE,"Y Offset:%s\n",y_offset); + } +} + +void synctex_updater_free(synctex_updater_t updater){ + if (NULL==updater) { + return; + } + if (updater->length>0) { + SYNCTEX_fprintf(SYNCTEX_FILE,"!%i\n",updater->length); + } + if (SYNCTEX_NO_GZ) { + fclose((FILE *)SYNCTEX_FILE); + } else { + gzclose((gzFile)SYNCTEX_FILE); + } + free(updater); + printf("... done.\n"); + return; +} diff --git a/services/clsi/src/synctex/synctex_parser.h b/services/clsi/src/synctex/synctex_parser.h new file mode 100644 index 0000000000..4aca41501e --- /dev/null +++ b/services/clsi/src/synctex/synctex_parser.h @@ -0,0 +1,346 @@ +/* +Copyright (c) 2008, 2009, 2010 , 2011 jerome DOT laurens AT u-bourgogne DOT fr + +This file is part of the SyncTeX package. + +Latest Revision: Tue Jun 14 08:23:30 UTC 2011 + +Version: 1.16 + +See synctex_parser_readme.txt for more details + +License: +-------- +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 + +Except as contained in this notice, the name of the copyright holder +shall not be used in advertising or otherwise to promote the sale, +use or other dealings in this Software without prior written +authorization from the copyright holder. + +Acknowledgments: +---------------- +The author received useful remarks from the pdfTeX developers, especially Hahn The Thanh, +and significant help from XeTeX developer Jonathan Kew + +Nota Bene: +---------- +If you include or use a significant part of the synctex package into a software, +I would appreciate to be listed as contributor and see "SyncTeX" highlighted. + +Version 1 +Thu Jun 19 09:39:21 UTC 2008 + +*/ + +#ifndef __SYNCTEX_PARSER__ +# define __SYNCTEX_PARSER__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* synctex_node_t is the type for all synctex nodes. + * The synctex file is parsed into a tree of nodes, either sheet, boxes, math nodes... */ +typedef struct _synctex_node * synctex_node_t; + +/* The main synctex object is a scanner + * Its implementation is considered private. + * The basic workflow is + * - create a "synctex scanner" with the contents of a file + * - perform actions on that scanner like display or edit queries + * - free the scanner when the work is done + */ +typedef struct __synctex_scanner_t _synctex_scanner_t; +typedef _synctex_scanner_t * synctex_scanner_t; + +/* This is the designated method to create a new synctex scanner object. + * output is the pdf/dvi/xdv file associated to the synctex file. + * If necessary, it can be the tex file that originated the synctex file + * but this might cause problems if the \jobname has a custom value. + * Despite this method can accept a relative path in practice, + * you should only pass a full path name. + * The path should be encoded by the underlying file system, + * assuming that it is based on 8 bits characters, including UTF8, + * not 16 bits nor 32 bits. + * The last file extension is removed and replaced by the proper extension. + * Then the private method _synctex_scanner_new_with_contents_of_file is called. + * NULL is returned in case of an error or non existent file. + * Once you have a scanner, use the synctex_display_query and synctex_edit_query below. + * The new "build_directory" argument is available since version 1.5. + * It is the directory where all the auxiliary stuff is created. + * Sometimes, the synctex output file and the pdf, dvi or xdv files are not created in the same directory. + * This is the case in MikTeX (I will include this into TeX Live). + * This directory path can be nil, it will be ignored then. + * It can be either absolute or relative to the directory of the output pdf (dvi or xdv) file. + * If no synctex file is found in the same directory as the output file, then we try to find one in the build directory. + * Please note that this new "build_directory" is provided as a convenient argument but should not be used. + * In fact, this is implempented as a work around of a bug in MikTeX where the synctex file does not follow the pdf file. + * The new "parse" argument is available since version 1.5. In general, use 1. + * Use 0 only if you do not want to parse the content but just check the existence. + */ +synctex_scanner_t synctex_scanner_new_with_output_file(const char * output, const char * build_directory, int parse); + +/* This is the designated method to delete a synctex scanner object. + * Frees all the memory, you must call it when you are finished with the scanner. + */ +void synctex_scanner_free(synctex_scanner_t scanner); + +/* Send this message to force the scanner to parse the contents of the synctex output file. + * Nothing is performed if the file was already parsed. + * In each query below, this message is sent, but if you need to access information more directly, + * you must be sure that the parsing did occur. + * Usage: + * if((my_scanner = synctex_scanner_parse(my_scanner))) { + * continue with my_scanner... + * } else { + * there was a problem + * } + */ +synctex_scanner_t synctex_scanner_parse(synctex_scanner_t scanner); + +/* The main entry points. + * Given the file name, a line and a column number, synctex_display_query returns the number of nodes + * satisfying the contrain. Use code like + * + * if(synctex_display_query(scanner,name,line,column)>0) { + * synctex_node_t node; + * while((node = synctex_next_result(scanner))) { + * // do something with node + * ... + * } + * } + * + * For example, one can + * - highlight each resulting node in the output, using synctex_node_h and synctex_node_v + * - highlight all the rectangles enclosing those nodes, using synctex_box_... functions + * - highlight just the character using that information + * + * Given the page and the position in the page, synctex_edit_query returns the number of nodes + * satisfying the contrain. Use code like + * + * if(synctex_edit_query(scanner,page,h,v)>0) { + * synctex_node_t node; + * while(node = synctex_next_result(scanner)) { + * // do something with node + * ... + * } + * } + * + * For example, one can + * - highlight each resulting line in the input, + * - highlight just the character using that information + * + * page is 1 based + * h and v are coordinates in 72 dpi unit, relative to the top left corner of the page. + * If you make a new query, the result of the previous one is discarded. + * If one of this function returns a non positive integer, + * it means that an error occurred. + * + * Both methods are conservative, in the sense that matching is weak. + * If the exact column number is not found, there will be an answer with the whole line. + * + * Sumatra-PDF, Skim, iTeXMac2 and Texworks are examples of open source software that use this library. + * You can browse their code for a concrete implementation. + */ +int synctex_display_query(synctex_scanner_t scanner,const char * name,int line,int column); +int synctex_edit_query(synctex_scanner_t scanner,int page,float h,float v); +synctex_node_t synctex_next_result(synctex_scanner_t scanner); + +/* Display all the information contained in the scanner object. + * If the records are too numerous, only the first ones are displayed. + * This is mainly for informatinal purpose to help developers. + */ +void synctex_scanner_display(synctex_scanner_t scanner); + +/* The x and y offset of the origin in TeX coordinates. The magnification + These are used by pdf viewers that want to display the real box size. + For example, getting the horizontal coordinates of a node would require + synctex_node_box_h(node)*synctex_scanner_magnification(scanner)+synctex_scanner_x_offset(scanner) + Getting its TeX width would simply require + synctex_node_box_width(node)*synctex_scanner_magnification(scanner) + but direct methods are available for that below. + */ +int synctex_scanner_x_offset(synctex_scanner_t scanner); +int synctex_scanner_y_offset(synctex_scanner_t scanner); +float synctex_scanner_magnification(synctex_scanner_t scanner); + +/* Managing the input file names. + * Given a tag, synctex_scanner_get_name will return the corresponding file name. + * Conversely, given a file name, synctex_scanner_get_tag will retur, the corresponding tag. + * The file name must be the very same as understood by TeX. + * For example, if you \input myDir/foo.tex, the file name is myDir/foo.tex. + * No automatic path expansion is performed. + * Finally, synctex_scanner_input is the first input node of the scanner. + * To browse all the input node, use a loop like + * + * if((input_node = synctex_scanner_input(scanner))){ + * do { + * blah + * } while((input_node=synctex_node_sibling(input_node))); + * } + * + * The output is the name that was used to create the scanner. + * The synctex is the real name of the synctex file, + * it was obtained from output by setting the proper file extension. + */ +const char * synctex_scanner_get_name(synctex_scanner_t scanner,int tag); +int synctex_scanner_get_tag(synctex_scanner_t scanner,const char * name); +synctex_node_t synctex_scanner_input(synctex_scanner_t scanner); +const char * synctex_scanner_get_output(synctex_scanner_t scanner); +const char * synctex_scanner_get_synctex(synctex_scanner_t scanner); + +/* Browsing the nodes + * parent, child and sibling are standard names for tree nodes. + * The parent is one level higher, the child is one level deeper, + * and the sibling is at the same level. + * The sheet of a node is the first ancestor, it is of type sheet. + * A node and its sibling have the same parent. + * A node is the parent of its child. + * A node is either the child of its parent, + * or belongs to the sibling chain of its parent's child. + * The next node is either the child, the sibling or the parent's sibling, + * unless the parent is a sheet. + * This allows to navigate through all the nodes of a given sheet node: + * + * synctex_node_t node = sheet; + * while((node = synctex_node_next(node))) { + * // do something with node + * } + * + * With synctex_sheet_content, you can retrieve the sheet node given the page. + * The page is 1 based, according to TeX standards. + * Conversely synctex_node_sheet allows to retrieve the sheet containing a given node. + */ +synctex_node_t synctex_node_parent(synctex_node_t node); +synctex_node_t synctex_node_sheet(synctex_node_t node); +synctex_node_t synctex_node_child(synctex_node_t node); +synctex_node_t synctex_node_sibling(synctex_node_t node); +synctex_node_t synctex_node_next(synctex_node_t node); +synctex_node_t synctex_sheet_content(synctex_scanner_t scanner,int page); + +/* These are the types of the synctex nodes */ +typedef enum { + synctex_node_type_error = 0, + synctex_node_type_input, + synctex_node_type_sheet, + synctex_node_type_vbox, + synctex_node_type_void_vbox, + synctex_node_type_hbox, + synctex_node_type_void_hbox, + synctex_node_type_kern, + synctex_node_type_glue, + synctex_node_type_math, + synctex_node_type_boundary, + synctex_node_number_of_types +} synctex_node_type_t; + +/* synctex_node_type gives the type of a given node, + * synctex_node_isa gives the same information as a human readable text. */ +synctex_node_type_t synctex_node_type(synctex_node_t node); +const char * synctex_node_isa(synctex_node_t node); + +/* This is primarily used for debugging purpose. + * The second one logs information for the node and recursively displays information for its next node */ +void synctex_node_log(synctex_node_t node); +void synctex_node_display(synctex_node_t node); + +/* Given a node, access to its tag, line and column. + * The line and column numbers are 1 based. + * The latter is not yet fully supported in TeX, the default implementation returns 0 which means the whole line. + * When the tag is known, the scanner of the node will give the corresponding file name. + * When the tag is known, the scanner of the node will give the name. + */ +int synctex_node_tag(synctex_node_t node); +int synctex_node_line(synctex_node_t node); +int synctex_node_column(synctex_node_t node); + +/* This is the page where the node appears. + * This is a 1 based index as given by TeX. + */ +int synctex_node_page(synctex_node_t node); + +/* For quite all nodes, horizontal, vertical coordinates, and width. + * These are expressed in TeX small points coordinates, with origin at the top left corner. + */ +int synctex_node_h(synctex_node_t node); +int synctex_node_v(synctex_node_t node); +int synctex_node_width(synctex_node_t node); + +/* For all nodes, dimensions of the enclosing box. + * These are expressed in TeX small points coordinates, with origin at the top left corner. + * A box is enclosing itself. + */ +int synctex_node_box_h(synctex_node_t node); +int synctex_node_box_v(synctex_node_t node); +int synctex_node_box_width(synctex_node_t node); +int synctex_node_box_height(synctex_node_t node); +int synctex_node_box_depth(synctex_node_t node); + +/* For quite all nodes, horizontal, vertical coordinates, and width. + * The visible dimensions are bigger than real ones to compensate 0 width boxes + * that do contain nodes. + * These are expressed in page coordinates, with origin at the top left corner. + * A box is enclosing itself. + */ +float synctex_node_visible_h(synctex_node_t node); +float synctex_node_visible_v(synctex_node_t node); +float synctex_node_visible_width(synctex_node_t node); +/* For all nodes, visible dimensions of the enclosing box. + * A box is enclosing itself. + * The visible dimensions are bigger than real ones to compensate 0 width boxes + * that do contain nodes. + */ +float synctex_node_box_visible_h(synctex_node_t node); +float synctex_node_box_visible_v(synctex_node_t node); +float synctex_node_box_visible_width(synctex_node_t node); +float synctex_node_box_visible_height(synctex_node_t node); +float synctex_node_box_visible_depth(synctex_node_t node); + +/* The main synctex updater object. + * This object is used to append information to the synctex file. + * Its implementation is considered private. + * It is used by the synctex command line tool to take into account modifications + * that could occur while postprocessing files by dvipdf like filters. + */ +typedef struct __synctex_updater_t _synctex_updater_t; +typedef _synctex_updater_t * synctex_updater_t; + +/* Designated initializer. + * Once you are done with your whole job, + * free the updater */ +synctex_updater_t synctex_updater_new_with_output_file(const char * output, const char * directory); + +/* Use the next functions to append records to the synctex file, + * no consistency tests made on the arguments */ +void synctex_updater_append_magnification(synctex_updater_t updater, char * magnification); +void synctex_updater_append_x_offset(synctex_updater_t updater, char * x_offset); +void synctex_updater_append_y_offset(synctex_updater_t updater, char * y_offset); + +/* You MUST free the updater, once everything is properly appended */ +void synctex_updater_free(synctex_updater_t updater); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/services/clsi/src/synctex/synctex_parser_local.h b/services/clsi/src/synctex/synctex_parser_local.h new file mode 100644 index 0000000000..6573b2638a --- /dev/null +++ b/services/clsi/src/synctex/synctex_parser_local.h @@ -0,0 +1,45 @@ +/* +Copyright (c) 2008, 2009, 2010 , 2011 jerome DOT laurens AT u-bourgogne DOT fr + +This file is part of the SyncTeX package. + +Latest Revision: Tue Jun 14 08:23:30 UTC 2011 + +Version: 1.16 + +See synctex_parser_readme.txt for more details + +License: +-------- +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 + +Except as contained in this notice, the name of the copyright holder +shall not be used in advertising or otherwise to promote the sale, +use or other dealings in this Software without prior written +authorization from the copyright holder. + +*/ + +/* This local header file is for TEXLIVE, use your own header to fit your system */ +# include /* for inline && HAVE_xxx */ +/* No inlining for synctex tool in texlive. */ +# define SYNCTEX_INLINE diff --git a/services/clsi/src/synctex/synctex_parser_readme.txt b/services/clsi/src/synctex/synctex_parser_readme.txt new file mode 100644 index 0000000000..ebc06bb7bd --- /dev/null +++ b/services/clsi/src/synctex/synctex_parser_readme.txt @@ -0,0 +1,141 @@ +This file is part of the SyncTeX package. + +The Synchronization TeXnology named SyncTeX is a new feature +of recent TeX engines designed by Jerome Laurens. +It allows to synchronize between input and output, which means to +navigate from the source document to the typeset material and vice versa. +More informations on http://itexmac2.sourceforge.net/SyncTeX.html + +This package is mainly for developers, it mainly contains the following files: + +synctex_parser_readme.txt +synctex_parser_version.txt +synctex_parser_utils.c +synctex_parser_utils.h +synctex_parser_local.h +synctex_parser.h +synctex_parser.c + +The file you are reading contains more informations about the SyncTeX parser history. + +In order to support SyncTeX in a viewer, it is sufficient to include +in the source the files synctex_parser.h and synctex_parser.c. +The synctex parser usage is described in synctex_parser.h header file. + +The other files are used by tex engines or by the synctex command line utility: + +ChangeLog +README.txt +am +man1 +man5 +synctex-common.h +synctex-convert.sh +synctex-e-mem.ch0 +synctex-e-mem.ch1 +synctex-e-rec.ch0 +synctex-e-rec.ch1 +synctex-etex.h +synctex-mem.ch0 +synctex-mem.ch1 +synctex-mem.ch2 +synctex-pdf-rec.ch2 +synctex-pdftex.h +synctex-rec.ch0 +synctex-rec.ch1 +synctex-rec.ch2 +synctex-tex.h +synctex-xe-mem.ch2 +synctex-xe-rec.ch2 +synctex-xe-rec.ch3 +synctex-xetex.h +synctex.c +synctex.defines +synctex.h +synctex_main.c +tests + + +Version: +-------- +This is version 1, which refers to the synctex output file format. +The files are identified by a build number. +In order to help developers to automatically manage the version and build numbers +and download the parser only when necessary, the synctex_parser.version +is an ASCII text file just containing the current version and build numbers. + +History: +-------- +1.1: Thu Jul 17 09:28:13 UTC 2008 +- First official version available in TeXLive 2008 DVD. + Unfortunately, the backwards synchronization is not working properly mainly for ConTeXt users, see below. +1.2: Tue Sep 2 10:28:32 UTC 2008 +- Correction for ConTeXt support in the edit query. + The previous method was assuming that TeX boxes do not overlap, + which is reasonable for LaTeX but not for ConTeXt. + This assumption is no longer considered. +1.3: Fri Sep 5 09:39:57 UTC 2008 +- Local variable "read" renamed to "already_read" to avoid conflicts. +- "inline" compiler directive renamed to "SYNCTEX_INLINE" for code support and maintenance +- _synctex_error cannot be inlined due to variable arguments (thanks Christiaan Hofman) +- Correction in the display query, extra boundary nodes are used for a more precise forwards synchronization +1.4: Fri Sep 12 08:12:34 UTC 2008 +- For an unknown reason, the previous version was not the real 1.3 (as used in iTeXMac2 build 747). + As a consequence, a crash was observed. +- Some typos are fixed. +1.6: Mon Nov 3 20:20:02 UTC 2008 +- The bug that prevented synchronization with compressed files on windows has been fixed. +- New interface to allow system specific customization. +- Note that some APIs have changed. +1.8: Mer 8 jul 2009 11:32:38 UTC +Note that version 1.7 was delivered privately. +- bug fix: synctex was causing a memory leak in pdftex and xetex, thus some processing speed degradation +- bug fix: the synctex command line tool was broken when updating a .synctex file +- enhancement: better accuracy of the synchronization process +- enhancement: the pdf output file and the associated .synctex file no longer need to live in the same directory. + The new -d option of the synctex command line tool manages this situation. + This is handy when using something like tex -output-directory=DIR ... +1.9: Wed Nov 4 11:52:35 UTC 2009 +- Various typo fixed +- OutputDebugString replaced by OutputDebugStringA to deliberately disable unicode preprocessing +- New conditional created because OutputDebugStringA is only available since Windows 2K professional +1.10: Sun Jan 10 10:12:32 UTC 2010 +- Bug fix in synctex_parser.c to solve a synchronization problem with amsmath's gather environment. + Concerns the synctex tool. +1.11: Sun Jan 17 09:12:31 UTC 2010 +- Bug fix in synctex_parser.c, function synctex_node_box_visible_v: 'x' replaced by 'y'. + Only 3rd party tools are concerned. +1.12: Mon Jul 19 21:52:10 UTC 2010 +- Bug fix in synctex_parser.c, function __synctex_open: the io_mode was modified even in case of a non zero return, +causing a void .synctex.gz file to be created even if it was not expected. Reported by Marek Kasik concerning a bug on evince. +1.13: Fri Mar 11 07:39:12 UTC 2011 +- Bug fix in synctex_parser.c, better synchronization as suggested by Jan Sundermeyer (near line 3388). +- Stronger code design in synctex_parser_utils.c, function _synctex_get_name (really neutral behavior). + Only 3rd party tools are concerned. +1.14: Fri Apr 15 19:10:57 UTC 2011 +- taking output_directory into account +- Replaced FOPEN_WBIN_MODE by FOPEN_W_MODE when opening the text version of the .synctex file. +- Merging with LuaTeX's version of synctex.c +1.15: Fri Jun 10 14:10:17 UTC 2011 +This concerns the synctex command line tool and 3rd party developers. +TeX and friends are not concerned by these changes. +- Bug fixed in _synctex_get_io_mode_name, sometimes the wrong mode was returned +- Support for LuaTeX convention of './' file prefixing +1.16: Tue Jun 14 08:23:30 UTC 2011 +This concerns the synctex command line tool and 3rd party developers. +TeX and friends are not concerned by these changes. +- Better forward search (thanks Jose Alliste) +- Support for LuaTeX convention of './' file prefixing now for everyone, not only for Windows + +Acknowledgments: +---------------- +The author received useful remarks from the pdfTeX developers, especially Hahn The Thanh, +and significant help from XeTeX developer Jonathan Kew + +Nota Bene: +---------- +If you include or use a significant part of the synctex package into a software, +I would appreciate to be listed as contributor and see "SyncTeX" highlighted. + +Copyright (c) 2008-2011 jerome DOT laurens AT u-bourgogne DOT fr + diff --git a/services/clsi/src/synctex/synctex_parser_utils.c b/services/clsi/src/synctex/synctex_parser_utils.c new file mode 100644 index 0000000000..569f7e96ca --- /dev/null +++ b/services/clsi/src/synctex/synctex_parser_utils.c @@ -0,0 +1,479 @@ +/* +Copyright (c) 2008, 2009, 2010 , 2011 jerome DOT laurens AT u-bourgogne DOT fr + +This file is part of the SyncTeX package. + +Latest Revision: Tue Jun 14 08:23:30 UTC 2011 + +Version: 1.16 + +See synctex_parser_readme.txt for more details + +License: +-------- +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 + +Except as contained in this notice, the name of the copyright holder +shall not be used in advertising or otherwise to promote the sale, +use or other dealings in this Software without prior written +authorization from the copyright holder. + +*/ + +/* In this file, we find all the functions that may depend on the operating system. */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#if defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) || defined(__WINDOWS__) +#define SYNCTEX_WINDOWS 1 +#endif + +#ifdef _WIN32_WINNT_WINXP +#define SYNCTEX_RECENT_WINDOWS 1 +#endif + +#ifdef SYNCTEX_WINDOWS +#include +#endif + +void *_synctex_malloc(size_t size) { + void * ptr = malloc(size); + if(ptr) { +/* There used to be a switch to use bzero because it is more secure. JL */ + memset(ptr,0, size); + } + return (void *)ptr; +} + +int _synctex_error(const char * reason,...) { + va_list arg; + int result; + va_start (arg, reason); +# ifdef SYNCTEX_RECENT_WINDOWS + {/* This code is contributed by William Blum. + As it does not work on some older computers, + the _WIN32 conditional here is replaced with a SYNCTEX_RECENT_WINDOWS one. + According to http://msdn.microsoft.com/en-us/library/aa363362(VS.85).aspx + Minimum supported client Windows 2000 Professional + Minimum supported server Windows 2000 Server + People running Windows 2K standard edition will not have OutputDebugStringA. + JL.*/ + char *buff; + size_t len; + OutputDebugStringA("SyncTeX ERROR: "); + len = _vscprintf(reason, arg) + 1; + buff = (char*)malloc( len * sizeof(char) ); + result = vsprintf(buff, reason, arg) +strlen("SyncTeX ERROR: "); + OutputDebugStringA(buff); + OutputDebugStringA("\n"); + free(buff); + } +# else + result = fprintf(stderr,"SyncTeX ERROR: "); + result += vfprintf(stderr, reason, arg); + result += fprintf(stderr,"\n"); +# endif + va_end (arg); + return result; +} + +/* strip the last extension of the given string, this string is modified! */ +void _synctex_strip_last_path_extension(char * string) { + if(NULL != string){ + char * last_component = NULL; + char * last_extension = NULL; + char * next = NULL; + /* first we find the last path component */ + if(NULL == (last_component = strstr(string,"/"))){ + last_component = string; + } else { + ++last_component; + while((next = strstr(last_component,"/"))){ + last_component = next+1; + } + } +# ifdef SYNCTEX_WINDOWS + /* On Windows, the '\' is also a path separator. */ + while((next = strstr(last_component,"\\"))){ + last_component = next+1; + } +# endif + /* then we find the last path extension */ + if((last_extension = strstr(last_component,"."))){ + ++last_extension; + while((next = strstr(last_extension,"."))){ + last_extension = next+1; + } + --last_extension;/* back to the "." */ + if(last_extension>last_component){/* filter out paths like ....my/dir/.hidden"*/ + last_extension[0] = '\0'; + } + } + } +} + +const char * synctex_ignore_leading_dot_slash(const char * name) +{ + while(SYNCTEX_IS_DOT(*name) && SYNCTEX_IS_PATH_SEPARATOR(name[1])) { + name += 2; + while (SYNCTEX_IS_PATH_SEPARATOR(*name)) { + ++name; + } + } + return name; +} + +/* Compare two file names, windows is sometimes case insensitive... */ +synctex_bool_t _synctex_is_equivalent_file_name(const char *lhs, const char *rhs) { + /* Remove the leading regex '(\./+)*' in both rhs and lhs */ + lhs = synctex_ignore_leading_dot_slash(lhs); + rhs = synctex_ignore_leading_dot_slash(rhs); +# if SYNCTEX_WINDOWS + /* On Windows, filename should be compared case insensitive. + * The characters '/' and '\' are both valid path separators. + * There will be a very serious problem concerning UTF8 because + * not all the characters must be toupper... + * I would like to have URL's instead of filenames. */ +next_character: + if(SYNCTEX_IS_PATH_SEPARATOR(*lhs)) {/* lhs points to a path separator */ + if(!SYNCTEX_IS_PATH_SEPARATOR(*rhs)) {/* but not rhs */ + return synctex_NO; + } + } else if(SYNCTEX_IS_PATH_SEPARATOR(*rhs)) {/* rhs points to a path separator but not lhs */ + return synctex_NO; + } else if(toupper(*lhs) != toupper(*rhs)){/* uppercase do not match */ + return synctex_NO; + } else if (!*lhs) {/* lhs is at the end of the string */ + return *rhs ? synctex_NO : synctex_YES; + } else if(!*rhs) {/* rhs is at the end of the string but not lhs */ + return synctex_NO; + } + ++lhs; + ++rhs; + goto next_character; +# else + return 0 == strcmp(lhs,rhs)?synctex_YES:synctex_NO; +# endif +} + +synctex_bool_t _synctex_path_is_absolute(const char * name) { + if(!strlen(name)) { + return synctex_NO; + } +# if SYNCTEX_WINDOWS + if(strlen(name)>2) { + return (name[1]==':' && SYNCTEX_IS_PATH_SEPARATOR(name[2]))?synctex_YES:synctex_NO; + } + return synctex_NO; +# else + return SYNCTEX_IS_PATH_SEPARATOR(name[0])?synctex_YES:synctex_NO; +# endif +} + +/* We do not take care of UTF-8 */ +const char * _synctex_last_path_component(const char * name) { + const char * c = name+strlen(name); + if(c>name) { + if(!SYNCTEX_IS_PATH_SEPARATOR(*c)) { + do { + --c; + if(SYNCTEX_IS_PATH_SEPARATOR(*c)) { + return c+1; + } + } while(c>name); + } + return c;/* the last path component is the void string*/ + } + return c; +} + +int _synctex_copy_with_quoting_last_path_component(const char * src, char ** dest_ref, size_t size) { + const char * lpc; + if(src && dest_ref) { +# define dest (*dest_ref) + dest = NULL; /* Default behavior: no change and sucess. */ + lpc = _synctex_last_path_component(src); + if(strlen(lpc)) { + if(strchr(lpc,' ') && lpc[0]!='"' && lpc[strlen(lpc)-1]!='"') { + /* We are in the situation where adding the quotes is allowed. */ + /* Time to add the quotes. */ + /* Consistency test: we must have dest+size>dest+strlen(dest)+2 + * or equivalently: strlen(dest)+20) { + char * result = NULL; + ++size; + /* Create the memory storage */ + if(NULL!=(result = (char *)malloc(size))) { + char * dest = result; + va_start (arg, first); + temp = first; + do { + if((size = strlen(temp))>0) { + /* There is something to merge */ + if(dest != strncpy(dest,temp,size)) { + _synctex_error("! _synctex_merge_strings: Copy problem"); + free(result); + result = NULL; + return NULL; + } + dest += size; + } + } while( (temp = va_arg(arg, const char *)) != NULL); + va_end(arg); + dest[0]='\0';/* Terminate the merged string */ + return result; + } + _synctex_error("! _synctex_merge_strings: Memory problem"); + return NULL; + } + return NULL; +} + +/* The purpose of _synctex_get_name is to find the name of the synctex file. + * There is a list of possible filenames from which we return the most recent one and try to remove all the others. + * With two runs of pdftex or xetex we are sure the the synctex file is really the most appropriate. + */ +int _synctex_get_name(const char * output, const char * build_directory, char ** synctex_name_ref, synctex_io_mode_t * io_mode_ref) +{ + if(output && synctex_name_ref && io_mode_ref) { + /* If output is already absolute, we just have to manage the quotes and the compress mode */ + size_t size = 0; + char * synctex_name = NULL; + synctex_io_mode_t io_mode = *io_mode_ref; + const char * base_name = _synctex_last_path_component(output); /* do not free, output is the owner. base name of output*/ + /* Do we have a real base name ? */ + if(strlen(base_name)>0) { + /* Yes, we do. */ + const char * temp = NULL; + char * core_name = NULL; /* base name of output without path extension. */ + char * dir_name = NULL; /* dir name of output */ + char * quoted_core_name = NULL; + char * basic_name = NULL; + char * gz_name = NULL; + char * quoted_name = NULL; + char * quoted_gz_name = NULL; + char * build_name = NULL; + char * build_gz_name = NULL; + char * build_quoted_name = NULL; + char * build_quoted_gz_name = NULL; + struct stat buf; + time_t the_time = 0; + /* Create core_name: let temp point to the dot before the path extension of base_name; + * We start form the \0 terminating character and scan the string upward until we find a dot. + * The leading dot is not accepted. */ + if((temp = strrchr(base_name,'.')) && (size = temp - base_name)>0) { + /* There is a dot and it is not at the leading position */ + if(NULL == (core_name = (char *)malloc(size+1))) { + _synctex_error("! _synctex_get_name: Memory problem 1"); + return -1; + } + if(core_name != strncpy(core_name,base_name,size)) { + _synctex_error("! _synctex_get_name: Copy problem 1"); + free(core_name); + dir_name = NULL; + return -2; + } + core_name[size] = '\0'; + } else { + /* There is no path extension, + * Just make a copy of base_name */ + core_name = _synctex_merge_strings(base_name); + } + /* core_name is properly set up, owned by "self". */ + /* creating dir_name. */ + size = strlen(output)-strlen(base_name); + if(size>0) { + /* output contains more than one path component */ + if(NULL == (dir_name = (char *)malloc(size+1))) { + _synctex_error("! _synctex_get_name: Memory problem"); + free(core_name); + dir_name = NULL; + return -1; + } + if(dir_name != strncpy(dir_name,output,size)) { + _synctex_error("! _synctex_get_name: Copy problem"); + free(dir_name); + dir_name = NULL; + free(core_name); + dir_name = NULL; + return -2; + } + dir_name[size] = '\0'; + } + /* dir_name is properly set up. It ends with a path separator, if non void. */ + /* creating quoted_core_name. */ + if(strchr(core_name,' ')) { + quoted_core_name = _synctex_merge_strings("\"",core_name,"\""); + } + /* quoted_core_name is properly set up. */ + if(dir_name &&strlen(dir_name)>0) { + basic_name = _synctex_merge_strings(dir_name,core_name,synctex_suffix,NULL); + if(quoted_core_name && strlen(quoted_core_name)>0) { + quoted_name = _synctex_merge_strings(dir_name,quoted_core_name,synctex_suffix,NULL); + } + } else { + basic_name = _synctex_merge_strings(core_name,synctex_suffix,NULL); + if(quoted_core_name && strlen(quoted_core_name)>0) { + quoted_name = _synctex_merge_strings(quoted_core_name,synctex_suffix,NULL); + } + } + if(!_synctex_path_is_absolute(output) && build_directory && (size = strlen(build_directory))) { + temp = build_directory + size - 1; + if(_synctex_path_is_absolute(temp)) { + build_name = _synctex_merge_strings(build_directory,basic_name,NULL); + if(quoted_core_name && strlen(quoted_core_name)>0) { + build_quoted_name = _synctex_merge_strings(build_directory,quoted_name,NULL); + } + } else { + build_name = _synctex_merge_strings(build_directory,"/",basic_name,NULL); + if(quoted_core_name && strlen(quoted_core_name)>0) { + build_quoted_name = _synctex_merge_strings(build_directory,"/",quoted_name,NULL); + } + } + } + if(basic_name) { + gz_name = _synctex_merge_strings(basic_name,synctex_suffix_gz,NULL); + } + if(quoted_name) { + quoted_gz_name = _synctex_merge_strings(quoted_name,synctex_suffix_gz,NULL); + } + if(build_name) { + build_gz_name = _synctex_merge_strings(build_name,synctex_suffix_gz,NULL); + } + if(build_quoted_name) { + build_quoted_gz_name = _synctex_merge_strings(build_quoted_name,synctex_suffix_gz,NULL); + } + /* All the others names are properly set up... */ + /* retain the most recently modified file */ +# define TEST(FILENAME,COMPRESS_MODE) \ + if(FILENAME) {\ + if (stat(FILENAME, &buf)) { \ + free(FILENAME);\ + FILENAME = NULL;\ + } else if (buf.st_mtime>the_time) { \ + the_time=buf.st_mtime; \ + synctex_name = FILENAME; \ + if (COMPRESS_MODE) { \ + io_mode |= synctex_io_gz_mask; \ + } else { \ + io_mode &= ~synctex_io_gz_mask; \ + } \ + } \ + } + TEST(basic_name,synctex_DONT_COMPRESS); + TEST(gz_name,synctex_COMPRESS); + TEST(quoted_name,synctex_DONT_COMPRESS); + TEST(quoted_gz_name,synctex_COMPRESS); + TEST(build_name,synctex_DONT_COMPRESS); + TEST(build_gz_name,synctex_COMPRESS); + TEST(build_quoted_name,synctex_DONT_COMPRESS); + TEST(build_quoted_gz_name,synctex_COMPRESS); +# undef TEST + /* Free all the intermediate filenames, except the one that will be used as returned value. */ +# define CLEAN_AND_REMOVE(FILENAME) \ + if(FILENAME && (FILENAME!=synctex_name)) {\ + remove(FILENAME);\ + printf("synctex tool info: %s removed\n",FILENAME);\ + free(FILENAME);\ + FILENAME = NULL;\ + } + CLEAN_AND_REMOVE(basic_name); + CLEAN_AND_REMOVE(gz_name); + CLEAN_AND_REMOVE(quoted_name); + CLEAN_AND_REMOVE(quoted_gz_name); + CLEAN_AND_REMOVE(build_name); + CLEAN_AND_REMOVE(build_gz_name); + CLEAN_AND_REMOVE(build_quoted_name); + CLEAN_AND_REMOVE(build_quoted_gz_name); +# undef CLEAN_AND_REMOVE + /* set up the returned values */ + * synctex_name_ref = synctex_name; + * io_mode_ref = io_mode; + return 0; + } + return -1;/* bad argument */ + } + return -2; +} + +const char * _synctex_get_io_mode_name(synctex_io_mode_t io_mode) { + static const char * synctex_io_modes[4] = {"r","rb","a","ab"}; + unsigned index = ((io_mode & synctex_io_gz_mask)?1:0) + ((io_mode & synctex_io_append_mask)?2:0);// bug pointed out by Jose Alliste + return synctex_io_modes[index]; +} diff --git a/services/clsi/src/synctex/synctex_parser_utils.h b/services/clsi/src/synctex/synctex_parser_utils.h new file mode 100644 index 0000000000..e67f8f56ed --- /dev/null +++ b/services/clsi/src/synctex/synctex_parser_utils.h @@ -0,0 +1,141 @@ +/* +Copyright (c) 2008, 2009, 2010, 2011 jerome DOT laurens AT u-bourgogne DOT fr + +This file is part of the SyncTeX package. + +Latest Revision: Tue Jun 14 08:23:30 UTC 2011 + +Version: 1.16 + +See synctex_parser_readme.txt for more details + +License: +-------- +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 + +Except as contained in this notice, the name of the copyright holder +shall not be used in advertising or otherwise to promote the sale, +use or other dealings in this Software without prior written +authorization from the copyright holder. + +*/ + +/* The utilities declared here are subject to conditional implementation. + * All the operating system special stuff goes here. + * The problem mainly comes from file name management: path separator, encoding... + */ + +# define synctex_bool_t int +# define synctex_YES -1 +# define synctex_ADD_QUOTES -1 +# define synctex_COMPRESS -1 +# define synctex_NO 0 +# define synctex_DONT_ADD_QUOTES 0 +# define synctex_DONT_COMPRESS 0 + +#ifndef __SYNCTEX_PARSER_UTILS__ +# define __SYNCTEX_PARSER_UTILS__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +# if _WIN32 +# define SYNCTEX_IS_PATH_SEPARATOR(c) ('/' == c || '\\' == c) +# else +# define SYNCTEX_IS_PATH_SEPARATOR(c) ('/' == c) +# endif + +# if _WIN32 +# define SYNCTEX_IS_DOT(c) ('.' == c) +# else +# define SYNCTEX_IS_DOT(c) ('.' == c) +# endif + +/* This custom malloc functions initializes to 0 the newly allocated memory. + * There is no bzero function on windows. */ +void *_synctex_malloc(size_t size); + +/* This is used to log some informational message to the standard error stream. + * On Windows, the stderr stream is not exposed and another method is used. + * The return value is the number of characters printed. */ +int _synctex_error(const char * reason,...); + +/* strip the last extension of the given string, this string is modified! + * This function depends on the OS because the path separator may differ. + * This should be discussed more precisely. */ +void _synctex_strip_last_path_extension(char * string); + +/* Compare two file names, windows is sometimes case insensitive... + * The given strings may differ stricto sensu, but represent the same file name. + * It might not be the real way of doing things. + * The return value is an undefined non 0 value when the two file names are equivalent. + * It is 0 otherwise. */ +synctex_bool_t _synctex_is_equivalent_file_name(const char *lhs, const char *rhs); + +/* Description forthcoming.*/ +synctex_bool_t _synctex_path_is_absolute(const char * name); + +/* Description forthcoming...*/ +const char * _synctex_last_path_component(const char * name); + +/* If the core of the last path component of src is not already enclosed with double quotes ('"') + * and contains a space character (' '), then a new buffer is created, the src is copied and quotes are added. + * In all other cases, no destination buffer is created and the src is not copied. + * 0 on success, which means no error, something non 0 means error, mainly due to memory allocation failure, or bad parameter. + * This is used to fix a bug in the first version of pdftex with synctex (1.40.9) for which names with spaces + * were not managed in a standard way. + * On success, the caller owns the buffer pointed to by dest_ref (is any) and + * is responsible of freeing the memory when done. + * The size argument is the size of the src buffer. On return the dest_ref points to a buffer sized size+2.*/ +int _synctex_copy_with_quoting_last_path_component(const char * src, char ** dest_ref, size_t size); + +/* These are the possible extensions of the synctex file */ +extern const char * synctex_suffix; +extern const char * synctex_suffix_gz; + +typedef unsigned int synctex_io_mode_t; + +typedef enum { + synctex_io_append_mask = 1, + synctex_io_gz_mask = synctex_io_append_mask<<1 +} synctex_io_mode_masks_t; + +typedef enum { + synctex_compress_mode_none = 0, + synctex_compress_mode_gz = 1 +} synctex_compress_mode_t; + +int _synctex_get_name(const char * output, const char * build_directory, char ** synctex_name_ref, synctex_io_mode_t * io_mode_ref); + +/* returns the correct mode required by fopen and gzopen from the given io_mode */ +const char * _synctex_get_io_mode_name(synctex_io_mode_t io_mode); + +const char * synctex_ignore_leading_dot_slash(const char * name); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/services/clsi/src/synctex/synctex_parser_version.txt b/services/clsi/src/synctex/synctex_parser_version.txt new file mode 100644 index 0000000000..03ff897167 --- /dev/null +++ b/services/clsi/src/synctex/synctex_parser_version.txt @@ -0,0 +1 @@ +1.16 \ No newline at end of file diff --git a/services/clsi/synctex.profile b/services/clsi/synctex.profile new file mode 100644 index 0000000000..577a901921 --- /dev/null +++ b/services/clsi/synctex.profile @@ -0,0 +1,34 @@ +include /etc/firejail/disable-common.inc +include /etc/firejail/disable-devel.inc +# include /etc/firejail/disable-mgmt.inc ## removed in 0.9.40 +# include /etc/firejail/disable-secret.inc ## removed in 0.9.40 + +read-only /bin +blacklist /boot +blacklist /dev +read-only /etc +blacklist /home # blacklisted for synctex +read-only /lib +read-only /lib64 +blacklist /media +blacklist /mnt +blacklist /opt +blacklist /root +read-only /run +blacklist /sbin +blacklist /selinux +blacklist /src +blacklist /sys +read-only /usr + +caps.drop all +noroot +nogroups +net none +private-tmp +private-dev +shell none +seccomp +nonewprivs + + diff --git a/services/clsi/test/acceptance/fixtures/examples/asymptote/main.tex b/services/clsi/test/acceptance/fixtures/examples/asymptote/main.tex new file mode 100644 index 0000000000..910cef5bf1 --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/asymptote/main.tex @@ -0,0 +1,117 @@ +\documentclass[12pt]{article} + +% Use this form to include EPS (latex) or PDF (pdflatex) files: +\usepackage{asymptote} + +% Use this form with latex or pdflatex to include inline LaTeX code by default: +%\usepackage[inline]{asymptote} + +% Use this form with latex or pdflatex to create PDF attachments by default: +%\usepackage[attach]{asymptote} + +% Enable this line to support the attach option: +%\usepackage[dvips]{attachfile2} + +\begin{document} + +% Optional subdirectory for asy files (no spaces): +\def\asydir{} + +\begin{asydef} +// Global Asymptote definitions can be put here. +import three; +usepackage("bm"); +texpreamble("\def\V#1{\bm{#1}}"); +// One can globally override the default toolbar settings here: +// settings.toolbar=true; +\end{asydef} + +Here is a venn diagram produced with Asymptote, drawn to width 4cm: + +\def\A{A} +\def\B{\V{B}} + +%\begin{figure} +\begin{center} +\begin{asy} +size(4cm,0); +pen colour1=red; +pen colour2=green; + +pair z0=(0,0); +pair z1=(-1,0); +pair z2=(1,0); +real r=1.5; +path c1=circle(z1,r); +path c2=circle(z2,r); +fill(c1,colour1); +fill(c2,colour2); + +picture intersection=new picture; +fill(intersection,c1,colour1+colour2); +clip(intersection,c2); + +add(intersection); + +draw(c1); +draw(c2); + +//draw("$\A$",box,z1); // Requires [inline] package option. +//draw(Label("$\B$","$B$"),box,z2); // Requires [inline] package option. +draw("$A$",box,z1); +draw("$\V{B}$",box,z2); + +pair z=(0,-2); +real m=3; +margin BigMargin=Margin(0,m*dot(unit(z1-z),unit(z0-z))); + +draw(Label("$A\cap B$",0),conj(z)--z0,Arrow,BigMargin); +draw(Label("$A\cup B$",0),z--z0,Arrow,BigMargin); +draw(z--z1,Arrow,Margin(0,m)); +draw(z--z2,Arrow,Margin(0,m)); + +shipout(bbox(0.25cm)); +\end{asy} +%\caption{Venn diagram}\label{venn} +\end{center} +%\end{figure} + +Each graph is drawn in its own environment. One can specify the width +and height to \LaTeX\ explicitly. This 3D example can be viewed +interactively either with Adobe Reader or Asymptote's fast OpenGL-based +renderer. To support {\tt latexmk}, 3D figures should specify +\verb+inline=true+. It is sometimes desirable to embed 3D files as annotated +attachments; this requires the \verb+attach=true+ option as well as the +\verb+attachfile2+ \LaTeX\ package. +\begin{center} +\begin{asy}[height=4cm,inline=true,attach=false,viewportwidth=\linewidth] +currentprojection=orthographic(5,4,2); +draw(unitcube,blue); +label("$V-E+F=2$",(0,1,0.5),3Y,blue+fontsize(17pt)); +\end{asy} +\end{center} + +One can also scale the figure to the full line width: +\begin{center} +\begin{asy}[width=\the\linewidth,inline=true] +pair z0=(0,0); +pair z1=(2,0); +pair z2=(5,0); +pair zf=z1+0.75*(z2-z1); + +draw(z1--z2); +dot(z1,red+0.15cm); +dot(z2,darkgreen+0.3cm); +label("$m$",z1,1.2N,red); +label("$M$",z2,1.5N,darkgreen); +label("$\hat{\ }$",zf,0.2*S,fontsize(24pt)+blue); + +pair s=-0.2*I; +draw("$x$",z0+s--z1+s,N,red,Arrows,Bars,PenMargins); +s=-0.5*I; +draw("$\bar{x}$",z0+s--zf+s,blue,Arrows,Bars,PenMargins); +s=-0.95*I; +draw("$X$",z0+s--z2+s,darkgreen,Arrows,Bars,PenMargins); +\end{asy} +\end{center} +\end{document} diff --git a/services/clsi/test/acceptance/fixtures/examples/asymptote/output.pdf b/services/clsi/test/acceptance/fixtures/examples/asymptote/output.pdf new file mode 100644 index 0000000000..e8fdde8465 Binary files /dev/null and b/services/clsi/test/acceptance/fixtures/examples/asymptote/output.pdf differ diff --git a/services/clsi/test/acceptance/fixtures/examples/biber_bibliography/bibliography.bib b/services/clsi/test/acceptance/fixtures/examples/biber_bibliography/bibliography.bib new file mode 100644 index 0000000000..5e796e057f --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/biber_bibliography/bibliography.bib @@ -0,0 +1,9 @@ +@book{DouglasAdams, + title={The Hitchhiker's Guide to the Galaxy}, + author={Adams, Douglas}, + isbn={9781417642595}, + url={http://books.google.com/books?id=W-xMPgAACAAJ}, + year={1995}, + publisher={San Val} +} + diff --git a/services/clsi/test/acceptance/fixtures/examples/biber_bibliography/main.tex b/services/clsi/test/acceptance/fixtures/examples/biber_bibliography/main.tex new file mode 100644 index 0000000000..2f032d653f --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/biber_bibliography/main.tex @@ -0,0 +1,12 @@ +\documentclass{article} + +\usepackage[backend=biber]{biblatex} +\addbibresource{bibliography.bib} + +\begin{document} + +The meaning of life, the universe and everything is 42 \cite{DouglasAdams} + +\printbibliography + +\end{document} diff --git a/services/clsi/test/acceptance/fixtures/examples/biber_bibliography/output.bbl b/services/clsi/test/acceptance/fixtures/examples/biber_bibliography/output.bbl new file mode 100644 index 0000000000..48e803b7fb --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/biber_bibliography/output.bbl @@ -0,0 +1,48 @@ +% $ biblatex auxiliary file $ +% $ biblatex version 1.5 $ +% $ biber version 0.9.3 $ +% Do not modify the above lines! +% +% This is an auxiliary file used by the 'biblatex' package. +% This file may safely be deleted. It will be recreated by +% biber or bibtex as required. +% +\begingroup +\makeatletter +\@ifundefined{ver@biblatex.sty} + {\@latex@error + {Missing 'biblatex' package} + {The bibliography requires the 'biblatex' package.} + \aftergroup\endinput} + {} +\endgroup + + +\refsection{0} + \entry{DouglasAdams}{book}{} + \name{labelname}{1}{}{% + {{}{Adams}{A\bibinitperiod}{Douglas}{D\bibinitperiod}{}{}{}{}}% + } + \name{author}{1}{}{% + {{}{Adams}{A\bibinitperiod}{Douglas}{D\bibinitperiod}{}{}{}{}}% + } + \list{publisher}{1}{% + {San Val}% + } + \strng{namehash}{AD1} + \strng{fullhash}{AD1} + \field{sortinit}{A} + \field{isbn}{9781417642595} + \field{title}{The Hitchhiker's Guide to the Galaxy} + \field{year}{1995} + \verb{url} + \verb http://books.google.com/books?id=W-xMPgAACAAJ + \endverb + \endentry + + \lossort + \endlossort + +\endrefsection +\endinput + diff --git a/services/clsi/test/acceptance/fixtures/examples/biber_bibliography/output.pdf b/services/clsi/test/acceptance/fixtures/examples/biber_bibliography/output.pdf new file mode 100644 index 0000000000..cf7a1c2400 Binary files /dev/null and b/services/clsi/test/acceptance/fixtures/examples/biber_bibliography/output.pdf differ diff --git a/services/clsi/test/acceptance/fixtures/examples/biber_bibliography/output.run.xml b/services/clsi/test/acceptance/fixtures/examples/biber_bibliography/output.run.xml new file mode 100644 index 0000000000..4d8dc9463b --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/biber_bibliography/output.run.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + +]> + + + latex + + output.bcf + + + output.bbl + + + blx-compat.def + biblatex.def + numeric.bbx + standard.bbx + numeric.cbx + biblatex.cfg + english.lbx + + + + biber + + biber + output + + + output.bcf + + + output.bbl + + + output.bbl + + + output.bcf + + + bibliography.bib + + + diff --git a/services/clsi/test/acceptance/fixtures/examples/epstopdf/image-eps-converted-to.pdf b/services/clsi/test/acceptance/fixtures/examples/epstopdf/image-eps-converted-to.pdf new file mode 100644 index 0000000000..7b92690ce1 Binary files /dev/null and b/services/clsi/test/acceptance/fixtures/examples/epstopdf/image-eps-converted-to.pdf differ diff --git a/services/clsi/test/acceptance/fixtures/examples/epstopdf/image.eps b/services/clsi/test/acceptance/fixtures/examples/epstopdf/image.eps new file mode 100644 index 0000000000..fb131b9c36 --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/epstopdf/image.eps @@ -0,0 +1,6673 @@ +%!PS-Adobe-3.0 EPSF-1.2 +%%BoundingBox: 0 0 432 268 +%%HiResBoundingBox: 0 0 432 268 +%%Creator: (Wolfram Mathematica 8.0 for Linux x86 (64-bit) (February 23, 2011)) +%%CreationDate: (Monday, October 8, 2012)(15:03:46) +%%Title: Clipboard +%%DocumentNeededResources: font Times-Roman +%%DocumentSuppliedResources: font Times-Roman-MISO +%%+ font Mathematica2 +%%+ font Mathematica1 +%%DocumentNeededFonts: Times-Roman +%%DocumentSuppliedFonts: Times-Roman-MISO +%%+ Mathematica2 +%%+ Mathematica1 +%%DocumentFonts: Times-Roman +%%+ Times-Roman-MISO +%%+ Mathematica2 +%%+ Mathematica1 +%%EndComments +/p{gsave}bind def +/P{grestore}bind def +/g{setgray}bind def +/r{setrgbcolor}bind def +/k{setcmykcolor}bind def +/w{setlinewidth}bind def +/np{newpath}bind def +/m{moveto}bind def +/Mr{rmoveto}bind def +/Mx{currentpoint exch pop moveto}bind def +/My{currentpoint pop exch moveto}bind def +/X{0 rmoveto}bind def +/Y{0 exch rmoveto}bind def +/N{currentpoint 3 -1 roll show moveto}bind def +/L{lineto}bind def +/rL{rlineto}bind def +/C{curveto}bind def +/cp{closepath}bind def +/F{eofill}bind def +/f{fill}bind def +/s{stroke}bind def +/S{show}bind def +/tri{p 9 6 roll r 6 4 roll m 4 2 roll L L cp F P}bind def +/Msf{findfont exch scalefont[1 0 0 -1 0 0]makefont setfont}bind def +1 -1 scale 0 -267.698 translate +-35.28 -2.88 translate +[1 0 0 1 0 0 ] concat +1 w +0 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit + +%%MathematicaCell +%Cell[BoxData[ +% GraphicsBox[{{}, {}, +% {GrayLevel[0], LineBox[CompressedData[" +%1:eJw113dcTf8fB/B7697q7tW0KSoJWRnp/ba3rCR7kxmSzKy+KFlFvqSMjB++ +%ESqKrlVEKJoy2nvv3S/O+5x/7uPce8/n83m/nu+zeq7cOmeNBofDqeVyOH8+ +%2a0l/9EWydgK9V7d4EmZe47Cm8LwOycM2X1fGDzdYkfqz3L1024exbOfBoC3 +%r26ui2c5/R4EpUfSFFnDytWX/v2z/Q9yO+VvM84uo/8Hg9/5EpPBp8vUJbP/ +%fBMCXy8fN5GPKqPjn4DGhdnXo/JK1cKUG86jheEwxHn2wDHnSmm8Z7DcMeyV +%7+hStfni069rzZ7D73FreM8KSmj8KKiZGhB1z6dEHdRxdMqNl+C31zh+u20J +%zfcK1nC8d2oVFqsH/93egLor7NzkU0zzvwWPY/98uDG6WP2m1qxjhmhwtBjk +%dye/iNbzDkRHH6e5ny1Sz/k74XvY7J513WxUEa0vFhJ+vlgTkFOoztzzZ8AP +%YDckMqHAu5DWGwf9rDutaBhWqN72Z3nOn2DLwfSeGb8LaP2fobqXp8v54wVq +%RiMedJ1rPhpaFVA98XBvmqp6Y1q+evLfCRIgKtrukO+hfKovAa4/0ex0wDxf +%/We2xae/wuWhSVqYkEf1foM7E+x2fnPLU/8tJ+Ub9MHHQYN75FH9iZCe2ui9 +%4F2uuvuf5XRLghFBj47Yb8mlPJLAyiiZ11kvV71u7Z8tGcxC4sIeROZQPikQ +%nNGyS29ljvrPaLrBKXB/zgzOGJ0cyisVnGs38MYEZ6vr/gxXmwpxOW67tedl +%U35pMMcjofO/jVlq278DfoegKVuPNQVkUZ7f4RpHXT5wfJb67/I80mF2ZJu1 +%cWEm5fsDHKa6JZd5Z6o/xf3ZfoDBO+2sPYMyKe+fYGHW3z0pOUOt93eBv+DB +%/IdHm/ZkUP6/4Mi8AfcqumWo/w63+DfofvIPWuzxmzwy4HDdvBtr4n5RPRng +%XyQ/26D8RT4ZMPzRQcuhjj+pvgxocL11Ky/gB3llQtVuy7W2OelUbyYkKzUb +%upink18mhO8U4sXN36n+LKgLm1j3X0gaeWaB1zML89G1qZRHFmim+1ksHZ5K +%vtlgedzAUmNvCuWTDQ3HXh8c/iKZvLPBRX+wU01bEuWVA6+K352eiUnknwMT +%axKOmR9KpPxywHbtC6ejr75RP+RCoPeYCnfuN8ozF3oOWGKVjV+pP3LBe7L5 +%piz3BMo3Dxx73Vu6Niqe+iUPxjkazH/X8IXyzoM+e25rp+74TP2TD+LzNpol +%pXGUfz4kRp4W8dZ9pH7KhytWwuBOv2PJowD+O3xdbDv/PXkUQOigqX62cTHk +%UQAmpw6MmzEmmjwKID7AsmxD6BvyKAQn433ymWavyaMQ9Dj2C8ZeekkehfD2 +%tIXdFv0o8iiCLxaLbU3qItRn/noUgeSth6vXt3DyKAKT2d+7fgx+Qh7FUOYz +%5qzF8RDyKAazMPW0oKj75FEMtptcBlWtu0UeJTCxx4K8oZKr5FEChh625dcX +%+ZBHCdxdculc2bQ95FEK/jDse0aTGzAepXDat36zh6EPMB6lEOMyLXttSyAw +%HmXw0vl9VIrLLWA8yiDsQt/zKyvuA+NRBjv2/d43+GkIMB7lUHT/5ubmpifA +%eJTD2mtGW4vgKTAe5fB4Z5evQccigfGoAOVTaPVLiAKmngqY/6hX1yGyV8D4 +%VEBui2yWT9hrYOqrAGPprh6ey94C41UBT9Mc+z4XxABTbwVYR3y/ZB36Dhi/ +%Crh4w3aAYmUsMPVXgmNgbMYq+UdgPCvBzrn8foY6jvKohF1ulbIi58/A+FbC +%qfuxDgGKeMqnEmpM34d7FscD410J2DMwyigmgfKqgsnmb18fvPYVGP8qyP+i +%eXn3/m+UXxVk1g8+OnVhIjDnZxWU1nmvz7FOojyroIeBPsdSPxmY/qiCWTF9 +%JVibTPlWwzDfRG2DpBRg+qUaTjQei30Zmkp5V8O1LS5aQ/zSgOmfanAvvXnN +%fvd3yr8a7G59+7JjcTow/VQNMr7DyVn4gzxq4Oo/D/X5vX+SRw30CbVN8hT+ +%Io8aWFESNqam4hd51MCExLtuY1J/k0cN3LLSbRmxPIM8asBzeCet0MQM8qiB +%xasjHkZMySSPWoiyEMg7qTPJoxby2zPkrUOyyKMWLhklHVp0L4s8aiFlYNjQ +%vr2yyaMWTljpGO/5N5s8asG5x7V9qMghjzp4963x2KkTOeRRB5EuJi12Grnk +%UQeF/fc1B+3NJY+O/4+32L6lNpc86mCRzYR5UVvzyKMO9DZbrbtYlEce9WA1 +%w8COvzafPOoh3SfIODcznzzqwe12cr91SwvIox5SRvB2uKYXkEc98DhqF6lj +%IXnUw9beZyJtUgrJowFsrQ6d0ZpfRB4NYHrH/+TapCLyaIAuOL1mtn0xeTTA +%GuPw70VJxeTRABNkzUUqhxLyaACvueemlaeWkEcDOFnuMly9qJQ8GsFlgFfM +%gV+l5NEI+U+NetquLCOPRngeGBIYmFdGHo2wcvfdxR82lpNHI5zRh4MnK8vJ +%oxG4C3e46NhUkEcTNMd1Tw5wryCPJpi5wunA1TcV5NEEPv2vtpRoVwJzvWyC +%hNniq7emV5JHE+j1eBv69GwleTTBucifASNTKsmjGQ6uu2yt37WKPJph027d +%liWrqsijGZZWO1vp3K0ij2ZIWrG+uVtlFXk0w5uBsu6Bw6vJoxnEvr7uFw5W +%k0cLZAa39qx4X00eLdCw/9iod4oa8miBzg+mjuIvqiGPFni9sK/u26Aa8miB +%Al/97Y1lNeTRAv945ufdGFFLHi3Qpbvry89Ha8mjFbJ6eHq7xdeSRyu4t5vZ +%X+9SRx6t8HFCVbC9Ux15tMJJ19DlHmF15NEKBUP6rQJePXm0wrlbvnoec+rJ +%ow2GN6beXXKtnjzaIEQ7Qvmhop482mD5z+vvorGBPNrApmT4yTlnG8ijDfQq +%YhoOZjWQRxsIRxUOnz2kkTzaoelrk27YP43k0Q6orNB8m9ZIHu2w1HNA0X7L +%JvJoB0Mb7tisQ03k0Q4nnwiKeSlN5NEOrolmkc/6NZMHB0+MWM0dc6SZ6uFg +%7LMxG3Z/byYfDm6x7mLnOqiF6uOg79Tpd829WsiLgzNttkwMz2mBv+Wu5eC3 +%2QNna0Mr+XFw67ivTf0vtdL1gYPJni0OpnWt5MlBz/itIby5bZQHB1sbMyRR +%D9vIl4Mng7Y/Wydrp3w4+GOPlMvf2k7eHDwaGWJx6ks75cXF5DI/5+OGHGT8 +%ueh/JmX++ykcZPLj4nHJw1On9nKQ6QcujnPtZ5PxHweZPLmYMH6oV0QGB5n+ +%4OL7L1PajHW5yOTLRRvp2tM9J3OR6RcuvjN3mfxkHxeZvLnIyX8mKwzhItM/ +%XLR7Glv1NJ+LTP5c3Ou/b/LgbhrI9BMXh4UZzZ9nr4EMhwbKe4SeMfXWQMZD +%A9/FH4OwaA1kPDRwxL86ri1tGsh4aGBk9AfkjtBExkMDd7rFhH/boYlM/2ng +%4ATDJ1seaCLj0THvBndRdrEmMh4a2Du8LXiYOQ8ZDw18dd4yfPs6HjIeGmia +%1DnC7xYPGQ8NtN/c//GDPB4yHho4LPTEwxhTPjIeGhj4wmluhRMfGQ9NLJ7n +%mGv8H588NHHZ7mzu/ko+eWjij+WDrPjWWuShiUM9n54O3a9FHproO9Y5/0m0 +%FnloomCt/IGmTJs8NHG00ZFz9x21yUMTM0cbX4i9qU0empi9YeGrzdXa5KGJ +%Xvo9TS+P1SEPTaxVVV3c76NDHprYMNZ2uixPhzx4+NEnJXbXSAF58DBb97z7 +%xzMC8uBh2zLR5oGFAvLg4QHhp+f3xgnJg4cRws6zVl8VkgcPraICnnu0C8mD +%h14jQjcPXyEiDx7GpEws8owWkQcPV1zemBzdT0wePFzjsF5Hx09MHjzUuXtS +%5ceTkAcPJzs6TQ/YKSEPHgZO/xLhXCQhDz4mdptgumiVlDz4uPCrVpRPhpQ8 +%+HjQZoT/uZUy8uBjr415hx8UysiDj6tc5vYeOUpOHny89DlzY8RROXnw8YP4 +%2ODrCXLy6Dh+bFe1XS8FefCx3n/ZZ4tdCvLg45ul2VYv4xXkwccGvW3hdwco +%yYOPe54UTHjkqyQPLbzbdNf7AkdFHlrIUWPfEBcVeXT0kUty5/FVKvLQQr7R +%zaMz9uqSR0dfRW7eoKfUIw8tdO/WLXFihB55aGGd1ZKK9W765KGF41+08r7P +%NSAPLTzbeGeVaIEheWihmb5sW85FI/LQwtHDQspjbDuThxbqTQ8JHBXclTy0 +%8NGVKzfH2fUkD208suB8pPknQ/LQxrkbyiR29/TIQxtTp7aeKF+rSx7aOOrC +%4WEXL6nIQxsrrU5OsNVSkYc2Opd6f15yTkke2rhlkNmQe4OV5NFxXpgZWaZm +%sx7a+CT3WZoikPXQxvCAL9Y/VrIe2vhc5jRvuaWCPDr2HbF5eaucPHQwNt7k +%dUGHN+Ohg8szu38bf1dOHjroOoNTnO0hJw8dNLh9xX/Wajl56ODH7Zn+AyfI +%yUMHHS8WbhlqJicPHayrWcPvLpEjc//UwWNdgnq45cvIQwc1LfudCQmXkYcO +%9p/le+K+p4w8dNBUEuTfbbmMPHTQwS6g5JO1jDx00LKqzOSEQkYeAlyvv2CP +%WSl7fgjwXtXzlkMf2PNDgJ2Gvm1w/p+UPAQIid39v5+QkocAz37gLb2+UUoe +%AnQ03/Xp3kwpeQhwEH93Yf4gKXkIULVkY9dRhlLyEODI1Z+X+LdJyEOAe0VR +%B6pyJeQhwJeuv+v6f5aQhwBX5R4QTA2XkIcQ+00ct2nwNQl5CHFSXO2vn14S +%8hCi/y/dk2N3SchDiI0ub9bbr5KQhxCD7zSaSmdJyEOIptmFtStGS8hDiP8z +%vvlmmoWEPIRosnSx6K2RhDyEuDVm966XOhLyEGL/5o2FoxvY65UQy276/BhW +%ICYPIVb0vOMXlComDyH+1+p95UismDxE+LzfgvNxEWLyEKEgPUCx976YPEQY +%O2uA8mSAmDxEGCbuv6X5jJg8RLguUKV8e0RMHiKcK3jUNcdVTB4i9JiQmDp/ +%g5g8Ova33QgwXComDxFW/HvZ1XyOmDxE+H2cfOGRiWLyEOHPuV0/m4wSk4cI +%Rw4yGS4cKCYPMb7rbJ08qLeYPMQoWBQ86XInMXmI0eHZiU0oF5OHGL3HDbja +%U0tMHmI06GPUbNMiIg8xrkz1MThdJSIPMYYeLQs1KBSRhxiN6nPOJv5m7x9i +%PHTWI/p1sog8xHhsAudK1icReYjx48pae6uO+w3jIcbS10cy7j8XkYcY7beN +%z5j/REQeErzdq+Rh3/si8pDgogMWm0yDROQhQcPN9tEz/EXkIcFrpVMXXfYV +%kYcE3Ve7L5Z6i8hDgvsWHku//cfhr4cET9WPX7n6gIg8JPhTc/GC8btE5CFB +%jwdPJkzscGQ8JDgqLkTo5CQiDwka3NnW9f5KEXlIMLXx8TtpRx8wHlI0Gfrg +%/ml7EXlIMfRmulV/OxF5SHH1ovT9RZNF5CHFSdue178eKyIPKb5clnwkzIb1 +%6LhObBxhGT2M9ZCiw+ry96UDWQ8pfnXPnzDQgvWQ4qgVQi/P3qyHFH3vnX/R +%2p31kOJQ3dTo451YDykG8swCzfVYDynumvhQniVjPWR4e2LdqYdC1kOGd/wm +%p/ryWQ8Z1h+OifHmsB4yDGyy5V5uFpKHDAsXqVIj64TkIcOf+d2tKyuF5CHD +%AylXDEeUCslDhpv2nfjtWyAkDxmeOjjzCDdHSB4yPGuVevvgbyF5yHDv1AVN +%inQhecjwtYk793GykDzk2NX8Ysuar0KqR46iVP5Q889C8pFj3kuDSS2xQqpP +%joYDWuf/ihaSlxxf+PUoi38lpHrleOOkdvjXF0Lyk6Pa521i1jMh1S/Hx+1G +%CZww9vlMjm2Lp6RZPmLzkGNBj/bY9cFCZN5nOu476/YWP7zL5iNHq7DgG1q3 +%2ec3OVaevW3qdIPNS47lccqA1EAhPT/IMZ0/ycTen81PjsZDV+/4eVFI/SDH +%6c5vmredZ/OU48iN7p7Kc0LqDzl6XXU2Up9i85Xjhv5Nuq5eQuoXOQb5BPUb +%cZzNW47TJA8rtDyE1D9yjPfwP/T7EJu/HOf17rv69QEh9ZMcz7Xoj324l/VQ +%YJ5Gb7M7bqyHAuHBsCF3d7IeCkx4fu126HbWQ4G2ZxsHfdzKeijQftr1psJN +%rIcCM8y/LFFuYD0UaB0SrTt+HeuhwHqfrF0HVrMeCtTvMz3z1QrWQ4FCboNS +%uox9flZgnx4tUSsXsx4KfHuv2kvtyHoocMWXDVEmDqyHAo2CTZeem8d6KNBj +%qnO99hzWQ4EH7B9P9LBjPRToGHFHXziD9VBgb4d9tRemsh4KvHz1XTeLyayH +%Ant8CV8XM4H1UOCMkVYjncaxHgpcN6abg2oM69FR75Tvs97ash4KxM3JbXtt +%WA8Fpr25fWXkSNZDidf1lpa3W7MeSuzbuVfEx6GshxI3Ogi0AwazHko85/Xo +%k6sV66FE25/LdtoPYD2U6PZsQdJIS9ZDiQOv6Bv0sWA9lCi4yNtoYM56KHFl +%U6yt1JT1UOJUt4hRot6shxI3KOSPJMashxLN93vl6PVkPZTY/L6+xLg766HE +%IapVUuuurEfHfHe+JNh1Zj2UOCWiJGyzEeuhxBXVRulnDFgPJf7PetaiZ3qs +%R8f+4bSwPBXroURV1to4QyXrocQj/V2WzJKzHkq8O2DNvpNS1kOJfcIUNz+J +%WQ8lFojPfFWKWA8lBqgn9VoiYD1UKHTg6t/XZj1UOPfEleh2Puuhwp+xr7Y7 +%8FgPFcZ3VWs+0WA9On4/cmO2Lpf1UGFfYd85u9vZ90cV3ihKm5/VKiAPFdrc +%mxNm1yIgDxXqn71l/KpJQB4qPFUxy2FYo4A8VDhoZoDmw3oBeagwwSZpgGWd +%gDxU6HqWj8E1AvJQ4dV1Rw8PrhaQhwp/VxQufV4pII+O96i4M7mTKwTkoUK/ +%DTv6p5UJyEOFlY+G/LOpVEAeKtxxcYAbr0RAHh3vJZHL1gQWCchDhbc1upWP +%7nhfZjxUqO57Lfp3voA8VLjxznOlR56APFR474X0i2WugDxUuDpzSmJatoA8 +%dPHMBqeU41kC/D+QSguY +% "]]}, +% {GrayLevel[0], LineBox[CompressedData[" +%1:eJw113dczfsfB/BzTvPMzoispGGEzJtrv98qZFzRtSJZyYpCXDKvkK3749rE +%jcxKSEY5lAZpUlFJpb3XaY9fnPfn+0+P+n7P5/N5v57v8/30MV7lZr+Gx+Fw +%VFwO5+dPdg3+Y5N4+KVq5W79wOm5nofA0/+3/IGu7PdzEN594CYdqFY+73u4 +%bN7z6/Cs6XVygozdvwX6g/qU18VWKS9f+nndg0fWhkbCzVX0fCCk7Bv4qFZe +%pSyf9/MvwdBjiWr0ndBK+vxT6BD6xJg4VioF6X7ukwShMKbG1HA1p5LGewHZ +%++0H7btVoTR3PBOhGhQGO2rTps+3raDxX4P+DdstzWXlyltdn073ewOhltbC +%ZWfKab63kL88dvbVUeXK0b+uSEiV5ReeTy2j+d/B1ee6G5bvLFNGqgZ1zRAF +%O5xbi+t7ldF6YuBqovuk2eGlSvtfE8ZCg8fgHNflpbS+9xAbPnuZE7dUmev5 +%c8APwLkqCRD6ldB6P0LyuaUuJ2xKlFt+Ls89Hqwnx71NKCim9SdA2Lp9JzKP +%FCvVGkmg52Y18uHAYqonCYKa3nNmxBYpbX9NkAzXJAc2PlhXRPUlwy3jzsI4 +%3SLlz9kcz6RA5tkn7hF3C6neT2CYE3l5l22h8lc56Z8gZmfeAlVRAdX/GdxP +%PHIY712gNPq5nL6pUGIc6jhlQAHlkQq/dwwM1YvKV651+XmlQdEq8YQbq/Mp +%n3TQ+K3kdQM3X/lzNP3AdEjs7GfW7cYPyusLRINQ0jTph7Lh53CqL3Aq4suQ +%S5l5lN9XUOVmFPJ25Skn/xowA/zPXTQf2j2P8syA50NHfen+JFf5a3mHM6Fk +%pgKi7HIp3yxQZedNtizPUcZ//HllQYjzNff1R3Mo728wKLf4nINZjrLbrwVm +%w8fBR5b3P/Cd8s+GaTsvhotCs5W/hnP8Dk5X27ttrPhGHjkw0WnO10mm36ie +%HFgd86Jn4OIs8smBsOJpIT6nMqm+HDjyg38t+20GeeXCbW2vRc9UX6neXPC2 +%2u/FM/9KfrnA3eSv/W7pF6o/Dza+Oe7deiqdPPOg7MDX9TeUaZRHHvydM2hj +%YnUq+f6AKzGlzm7GqZTPD5iXYM7bN+8zef+AJ2KTqsoDnyivfPhkG+SQEpRC +%/vlwPim0b7/sZMovH2xsj1/OFyZTPxRAwve5vbnjkijPAugR4NA8LC6B+qMA +%rlVsSZ9lGk/5FsK9U3H3eZ5x1C+FIGlW/uuZ+J7yLuwab8GecNNY6p8iGO9+ +%4EzhjmjKvwgcbTSuPIt9R/1UBDGWv3lb9owkj2Lw06yb4r3uLXkUQ7NjBkdv +%k5I8iqFu3o8HI7XDyKMYcFl/j9arz8mjBB79+8a1bUQIeZTAyqiAxNa3weRR +%Am8MF036cuMheZRCt1PtYX7Pbyt9fnmUwoDjh5J/O3eNPEohzF0ybo3DGfIo +%A6ltcsLzU0vJowwKl/+5aPPxo6D2KINhTwt+t553GdQe5ZAoVsaeHn0L1B7l +%0G3btXHHpj4AtUc51C31i9g/LBjUHhVQNfNA46vwp6D2qADz/unbP9o9B7VH +%BdhscL75Kf8VqD0q4UyNM7zYqwS1RyW0FS7vcffkW1B7VEJvQWa3MY6RoPao +%gjEF5+18LaJA7VEFpx/vbjvOiQG1RxV8Xvjmo0NqLKg9qkF6LNBP+eAD1VMN +%a68EO1sd+ghqn2qwG7Dkej+nBKqvGvz17Zf0MkwCtVc1bPg2vL1EmEz1VsPY +%1QLfqNZkUPtVQ+VX5Qf/8hSqvwYMBla+cMn+BGrPGuAG7p1skfyZ8qiByg+T +%fpS9SwW1bw2sjO5Xe/tFGuVTA6/GTHA7F5QOau8aMJlqZ+3l/4XyqoXIurm3 +%V1//Cmr/Whi4fyLf5UIG5VcL1teK3Lz/yQT197MWjF2PZoeczKI8a+HJvVnv +%dY99A3V/1MLmiKySE0eyKd866FXzunrm4e+g7pc6GBXTuf+SVQ7lXQfc2kWB +%+pE5oO6fOrjbvqZ4ik0u5d/1/O4B3lrRudRPdRDwMbl9v20eedRDbIXy7am4 +%PPKoh8yLgZZWdj/Iox7e7L5w6+anH+RRD2aen4fdXJxPHvVQ5j55vEd2PnnU +%g2dzg26+cwF51EPtjUdT+OUF5KECYWhP5+JtheShAvel//O93lZIHl33VU4h +%zYeLyEMFE6Lt+hpJi8lDBa17/+gluVJMHioY1So/8W5ACXk0QIjDswKbJyXk +%0QBr37y56Iul5NEAW+L8xsQllJJHA7xvaX4Wv6yMPBogvnlQw7OKMvJoAGXd +%UdHefeXk0QivfDJmWEoryKMRhnlJL3z+r4I8GiHgjPNchzGV5NEI/w4LPZH+ +%oZI8GmGUym6X3Yoq8mgEh2aVLKKhijyaYE5q1jKT6dXk0QQlw8w+LztbTR5N +%IE57eXFUTjV5NMEGvVozT4sa8miCfO302fN315BHE3zof8Ip4n0NeTTB5rTT +%VyJ61JJHM3B2Xk+yX1dLHs2QluP7ZF9XX6o9mqGh3qvZll9HHs1gpJ138fGS +%OvJohhGpbSvCH9aRRzMknvxTd3NnHXm0AHSGXky0ryePFhgzufVOhn89ebTA +%FIXlf0da60H9vmwBB72ipsa5KvJogVjf7lLjOyryaIFkc9tGfoeKPFrBcOti +%8aMFDeTRCrevX3GxCGwgj1boF5dvtFmnkTxaISfwndOBlY3k0QomRgY/Noc1 +%kkcrHHlwr8aiRxN5tEF+5KrEDI8m8mgDX/25591TmsijDXQ0C3PLRzSTRxtE +%X4j0W+nTTB5t0DvJ1zClupk82mBZvHTxNPsW8mgD/rT3CyKftpBHOzxtfHd/ +%aY9W8miHovSG97y9reTRDkGizVMS81rJox3mbDuT/nZGG3m0w4qNx4wKgtvI +%ox0875Q9ntm7nTw6IPjI56aWw+3k0QFXt3OOltW0k0cHuKnyAu2Xd5BHBwQd +%uh5mkNBBHh0wanODxazJneTRAaNzd5xvDeokj04oWeJZcEnGQbVHJ7wr2nRE +%PJuDao9O+G+tcdRcbw6qPTqhbrGv65ZIDqo9OkF/4PUH2zhcVHt0wgl/XbcN +%k7lIxw8UJI05u2gvF9X1cBCl9scwnItqHw6aTkgy+62Di+r6OFh4PmCbFfJQ +%7cXBD/d77v3Li4e/ynXhYNbMBSPjY3io9uOg2bkZWavEGqh+P3DQ4KzK64/5 +%Gqj25ODMx3O27L+qgeo8OCjteBpiXqiBal8O8rYlr5w+UhPV+XAQ7jcpyvZq +%otqbg8YbRm0e+1ET1XlxUf/FX74j+2ih2p+Lnat6DO3cpEX5cfFl8FiLgLda +%qO4HLh4VGQ9ebqBNeXLxRVzfxQPctFHdH1z8ZJQ01uK9NuXLRV9pypgL/XVQ +%3S9dOXlM2Hf0kA7lzcVlwvVLpIU6qO4fLjYt9xi3c6Yu5c9FLc+P2U3Buqju +%Jy7+I9g47mofPnnwcNhL311hx/nkwcPoDudTfm188uBhvJ5BwPGtAvLg4d8O +%UWbPywXkwUOx8/LprzYKUd1/PBxfHFflXyUkDx6+CVq3a+guEXnw8O7Cjffu +%6orJg4cbfWIL4q6LyYOHt5Pfz5AF9SYPHnb7LBoSy+1DHjwMM3QOaV3chzx4 +%GGR6rLdhSB/y0MC/0/Iza7obkocGZk8JsRXuNyQPDVz1oXTUkkpD8tBANIve +%2telL3lo4Pht33pvKOpLHhp4v8+2qhEeRuShgTcW/jN/rE4/8tDAThPrP244 +%9iMPDZQs3DHHLqwfeWjg14FBwQJzY/LQQM9v376Y3jEmDw08qLI/vWKSCXlo +%otuIJIlzowl5aOLIwRn+O8pNyaPr/iGRbdX8/uShiQZZ3+dO6DGIPDTxYWd8 +%jCKjJ3loYknACkHIoO7koYmPex61bXymTx6aOH5MmMAxWUEemijWd/3DaKiC +%PDTR8L1NYa+HcvLQxChweatvIycPTVyy0ju6tlxGHpr4+ftTU/xPRh5aGP17 +%4m7jlTLy0MIBPoOzjg2UkYcWLo25u1G7XkoeWniJJ+x5LUpKHlo4u1D/wror +%UvLQwo+9dwYleEjJQwtv3g84NXWelDy0MP+CXbTbCCl5aGFa6qvF9TIpeWhh +%k7zVtVeZHnlooXsfk+jqED3y0EJN/81nZYf0yEMba819Xcct0CMPbXwdHjWF +%a65HHtoY9Ubv3ymdEvLQRp6Z7+176RLy0MaRL+6M7PtYQh7aaOx83Hn9aQl5 +%aGNV+czgTa4S8tDGluKpjzVnS8hDGz1qb+jqW0jIQxtNjZdpe+pJyKNrfQOu +%pPSvE5OHNmrsSQpsSxeThzb2EY/dXRYuJg8dLHGqds+7JSYPHdTP0f6ccFJM +%Hjro8yfY+G8Xk4cOLg/33Dx/uZg8dNBb9iQ2aYaYPHTQSDJimNRSTB466G/S +%mqpjLCYPHTTfGaJ5VywmDx107N1rZ2WLiDx0cGSywcfEYhF56GD47/XdbNNF +%5KGDzQ+99s+OFpGHLmbrTHzyKUREHrpYzdsd8e22iDx0cfSGqMmrzovIQxeH +%9c7hO3iLyEMXX05J7/F6p4g8dLG5V8m8UxtE5KGLi55effDOUYTq/VMXvxqp +%+jrYichDF2M8suNmW4nIQxc5OS79L1qKyEMX2wyyD04wF5GHLh75Ni1wmKGI +%PHQxooeBdJtMRB58/LtgtCNPW0QefMy//1dxVouQPPgYv2b31tau96nag4+v +%XgSecCoQkgcfl5ekGWhkCsmDj896xRgXJgnJg4+Dd52M1IoRkgcfT1gIuCvC +%heTBx3spQcl1T4TkwcdvB9Ymvr4vJA8+2rqeLgq7KSQPPl6/sci++qKQPARo +%5yX0/NNHSB4CXLpte1WRt5A8BHhO5BR2b7+QPAT4tv2R34W/hOQhwDcnF395 +%7Mb2DwFqu64c27iW7R8CDDgy+tnqFULyEODU0szHzYuF5CHA0nqN5KfzhOQh +%wPXNrYfPzxSShwCXcS1DL1sLyUOAbgdbPkVMFJKHAEuMv6tEY4TkIURJdIVo +%13AheQgx2DsmX9OceQix0Op+aJAJ8+iqqxjSPfswDyFO/2qdv6o78xCi6Vfj +%UBcp8xDioI8Hg70FzEOIs2dGit9pMg8hjjBJutirU0AeQuzu1/j2RLOAPLpy +%0fJw6V4vIA8h5o/au+ZFpYA8RJhitX7dthIBeYhwT8PVy9PyBeQhQutX872G +%f2f7uQgnjHs/aEQG289FuNEsbfTUVAF5iNDC/4iPe5KAPET4wcZD+1GcgDxE +%6DVP8kQjRkAeInx18bnTxggBeYhQ3zH0ZmG4gDxEqMed+JvHCwF5iNCy4mu/ +%biEC8hChysMuOPqRgDzEaFw9euvxhwLyEOPShA6bFXcF5CHGPtutA6fdEpCH +%GJ10Ok5MvCEgj6733mj9xdZXBeQhRpdHdpccLgrIQ4yTps4u3X9OQB5iHLiE +%0/+pj4A8xJguWu/SdJJ5iDFlgK/FzGPMo+s9G9Gt495h5iFGf4HLgx4HmYcE +%b1yO/ufcPuYhweDq0j2Gu5mHBL+9rjj55C/mIcFdaXXOCz2YhwR3xjsO0trC +%PCRYse+k6s0m5iFBt14Bhkc3MA8JDrsksF26lnlIcHPGWfPxzsxDgsbufZ+a +%rWQeEuSb/q+ppxPzkGBBt57+PZcyDwmKeesHmy1mHnq4qseQK+MWMA893JOn +%cXixPfPQw5PWAScP2jEPPbxzQFUQMpt56OH7IXOSamcwDz18azD56LjpzEMP +%df13NR+1YR56qCzjD86bwjz08EuMz1MbYB56aJt57a+gicxDD+tdtf82Hc88 +%9DDZ82xf39+ZhxT3h5z+x9SS1SPFpcX3W4JGMR8pxqc8gqkjWH1STH3s0TvP +%gnlJ0fSDzcIjQ1i9UozrnDxplDnzk6JzxSyrwgGsfik6ZZ22v2nGPKXoenXo +%59UmLA8pZo9qX2jRT0DnGSnaD18wqMOQ5SPFT52Gw1J7M28pHtedavekJ8tL +%irEjxuZeNBDQ/w9SfL3uqMehbiw/Kc77WuC4Q8H6QYobrrQI3GQsTynOsLm4 +%c5Me6w8pHtq1ymarmOUrxYhYTYO9QtYvUsw38Lx9is/yluKQXe9e+umw/pHi +%rPMh+W+0WP5SNJ46uyNPg/WTFDO+WFQJeMxDhqtj/XljOcxDhhkV3kUbOth5 +%RIaH95Q5/td1HlF7yPBskEonp4WdT2RoLbr+p0kznzxk6PV41sv1jXzykGFm +%wZX1z1R88pBh9/DWYzr1fPKQYa0lRC6r5ZOHDDfYTk57Xs2n75sMeZYPAntU +%8clDht3qvYP3VPDJQ4Z7jYOHFnbti2oPGbbt8Hr5ZymfPGRoar9hX1Qxnzxk +%2KNuz/cJRXzykKEiup/LswI+eciwMbNshmU+nzy66onIcnyexycPGRY6KEWQ +%yycPGTqvtDr64TufPGRd++W6IodsPnl0Pe+4Pqk8i08eMrx+uWz6oUw+echQ +%33SWX98Mdh6U4z1RfHb4Fz55yFFof7f7inTmIceTcycaaacxDznGrYvTfPSZ +%echxzb31lss+MQ85BuS2TpekMA85Jtne3hSRxDzkODzlwlLPROYhx/xdlncs +%E5hH13p8EuPqPjIPOe6LmjE+JI55yHGuR3CO5wfmIcd0T9v/Wb1nHnLsNcRv +%oSSWechxXuTV4qxo5iHHPSr90YFRzKPr+VkNd7zeMQ854qL+q5dEMg85rm41 +%0bWMYB5y5G7b1iF/yzzkeG7B/rJaJfPoWp972j9pr5mHHHdecVgWFs485Cg7 +%fbrzVhjzkGPaC9l2n1fMQ4HXE9eH73vJPBRoNUU0x+0F81Dg6CVyyernzEOB +%X6sbZQ6hzEOBKxx5bfOeMQ8F7iqT1c4OYR4KfPhxnfGsp8yj69z3tDhx5hPm +%ocC+kdut/njMPBTIvdB9rX0w81DgmS9xdQ6PmIcCqw6dPLc6iHko0GtC761u +%gcxDgTNqHhzeG8A8FLjK23n86YfMQ4ELx0zk3HzAPLrGFy6c8ew+81DgvLuu +%ofH3mIcC1xTuVRXeZR4KNLvnNIB3l3kocOe3yQeN7jCPrvWIXGPBn3ko8Nje +%KcNX3mYeCjRasrvl0C3mocDl/LOj7vsxD31U8aOPp/zHx/8Dq98lgg== +% "]]}, +% {GrayLevel[0], LineBox[CompressedData[" +%1:eJw92XVYVNvXwPGhmWKKDhEMbEUM1Ktrid3YCihiKxa2qIAoBnaDioqg2Ipd +%iIFSiiAlId3dHe/8nLXf+ec+4zDnnL0++3tm5rlmyzfPWaXM4XCKVTic//2X +%PbQjVt3cYFYdulf78aRs1+3g/sXs10Yue34Ivlu9ilpRXRX6potX6ew3p6D3 +%mIPB81Kq6PULcCLT8uSYz1WhV3z/PeDzLT+b7vfY31+HuqG1aZyzVaFls//3 +%L/6w03WFS8Ju9v5AMHs28NatZVWhvOSALaN5QbCxuKlu5WR2vHtw9IJdTI9B +%VaG9HU5/qe/1ENLfKIen67HjP4Zpa0yFxp2VoYHydycHPIX7g7qt3xhTSecL +%hulPXSKe+1WGWv17PIfsgLEJRRsq6fwv4Ph7nrbhf5WhX+t7yc/wEj41GBkO +%4lfS9byGjdHN0aNTK0LnKE4Ih78b3xp5r4Ku7y04mTSt67e7IjTb9X8HfAfn +%qnfacSdV0PV+gKqCRz9zdCpCXf53eVtCYAVf9jMor5yu/yPsteqMdHheHqrQ +%+ASeE0MylDzLaT2f4Exd3RV/2/LQyf9O8Bly7xvs72taTuv7DEFfs/Y9LC8L +%/d/Z5KcEbtZSf+MPZbTeryAJG3d0t3dZ6L/lJH+F/FuvdvxYVEbrD4PBwxY3 +%yyzKQk3/dzldvoGp46os2/pSmsc3cJDdtNj5tTR0zer/Pb5D65m2Bu+zpTSf +%cICEdKubjqWh/zua9uNwcNjeZdT1/qU0rwiYe0IWeaq1JLThf4erj4CUA15n +%N0SW0PwiIWxa4f1xl0tCx/w7YBSYHjlkpLyqhOYZBQ4TT4z4OLgk9N/leUXD +%U6zf6sgpofn+gKRLQzM5McWhP3/8ewDf763D8avFNO+f0PbXeKXGuuJQnX8X +%GAPqNjONXYYV0/xjIM7JqiFWpTj03+EcfkGBXmhit7gi8oiFoea/nddeL6L1 +%xEJiqvYdX+ci8omFlFNZbh+ti2h9seD+ZKJ7sloRecXBDY/pq9N+F9J64+CY +%hQ8/+UYh+cWBe9SQ/z5vKKT1/4bvzt+KL44oJM/fwD9oc9tZvZDm8RsuRK8d +%1iu+gHzjgXMoKiPxRgHNJx6W+IU/2r2hgLzjYYX/8yz+iAKaVwKExV/tf0Kt +%gPwTYM3Er5eUf+fT/BLA5dZI8fLr+bQfEsFpc9cL79bn0zwTwbjlV1nHsHza +%H4mQvN5NNkoln+abBEe2XJ239Fce7ZckaIjUXbXvah7NOwlS2/5YHFqTR/sn +%GVotM57vs8qj+SfDHu1xHWs7c2k/JYNd9439JkXnkscfaEvj6Usu55LHH2j0 +%MkqOXp5LHn/A13995p4BueTxB56knjxq0JJDHilwf6nG5wffcsgjBRYdsftt +%cTaHPFLgs9vTyEsOOeSRCvYf9h4rtMgJPfPPIxU0jvNVR9dmk0cqSIzUc90+ +%ZpNHGvwYtS324bFs8kgD2xubT36fl00eaVBQ9X1/smk2eaSDU6uKb0JJFnmk +%Q0+uWuOHl1nkkQ53annfrnpkkcdfUDq+bZXTtCzy+AtN+3+46OtmkcdfaNlj +%cufG50zyyICzi7UHpCzIJI8M8I/aYZRcmkEeGZAuWWr52yODPDJB9PSkNFAn +%gzwywW30om5T7/8lj0wYZlh0+euYv+SRBWbFaR0Yn07ryYLgbNNLm9ekk08W +%TEm6vdK9NY3WlwXlPw3/XDydRl5ZcG7bss0e3dJovVlw1K/oVP/XqeSXBd+G +%PJ4cPTWV1p8NxVMKbC0zUsgzG1JOO0494pJC88iGiPx7NrdUU8g3Gy6Kxzje +%vvyH5pMN6a1DL13q84e8s0HT0UAyISSZ5pUDw/bsX58/K5n8cyBsQ6bvvJwk +%ml8OOK5v331mexL1mQOcHxDwQz2J5pkDHaOFWaE+ibQ/cmDtfjO/q30Sab65 +%cMBlgWzShwTaL7mwdUzLk6QZCTTvXNihrZ3aLzOe9k8ubN7/Jsp5SzzNPxf0 +%cnydzynF037KheHdIq9uOPebPPJgdYKpBXT7TR55cClx4tqE53HkkQf+eht/ +%TB0fRx55oPJSctAnIZY88uDswgHWL1bGkkceCPaa2B8u/kUeeTBw29fBNZq/ +%yCMfbv1NO2vTK4Y88iEvob/n6kk/ySMfVreUCKtW/SCPfNCf/eQU/1A0eeTD +%3uhlBma3osgjH8oadgmuh0aSRwHIek/vofQ3gjwKAB1GDMpqDiePArDy3cs7 +%oxtOHgWgE/9+/73B38mjAAbqlZU+nvmNPAogWtnSqff6MPIohNJC7Y/WXl/J +%oxCiFoS/HHTzC3kUgsEj9ef+7z6TRyGI+L0CTiZ8Io9CODOieOGZ9FDyKISc +%Xe5/F2t9JI8i6Dzq0aMJP5BHEfxYfyqqzuUdeRTB+T32vLRbb8ijCIKsH327 +%HfeKPIrAvjN+XDfOS/IogvXBJqKSAc/Jowhix63hdtgHk0cxOP83dMgXyRPy +%KAbPoaf7DVv7gDyK4b8dU5/afAwij2JY/evarHeSQPIohlvzB00dsOomeRSD +%o/vxzqz1vuRRArsTZaVzNM6RRwl8nvJshfYUL/IogafF2fnCn+voflkCHwev +%0zgVtQUUHiWwMtHiid64I6DwKIG6D0fX+krPg8KjFP7Embw9e+wKKDxKYdPQ +%8eMfKvmDwqMU5t6o5Ol+DgSFRykkcDpDAw7cBYVHKchOtK6WTHgICo9SeDKA +%Z/pK9SkoPMpAd+noUVGFwaDwKINIx7KNrtHPQeFRBpaW81ISnr4EhUcZpGWU +%ds649BoUHmWQ9KjT5sL+t6DwKIO+r3q1c1a9B4VHGTzLyf4weWYIKDzK4Rtu +%MRpoHQoKj3IYZZf3adnZT6DwKIe/qycen3LkMyg8yqFL1igfbbcvoPAoBxU/ +%G+G77V9B4SF//ip+KW4IA4VHBbgOM88UrvwGCo8KmOXzNPazw3dQeFTAgfqw +%9PL54aDwqICffYpCvGdFkEcFfM/ZZL17SiR5VMDxSV8Tt46PIo9KaEjs8mgG +%RJNHJej8mvV8+qgf5FEJu0KMcvyG/ySPSpjvn198dkgMeVRC+fvY86qDf5FH +%JVzYaFAxQD+WPKqgclvtm02XY2k9VTAtN6mbnl4c+VRB7dlrZXqX42h9VTB0 +%4fusgXq/yasKmhcmX313+Tf8W+7qKjgU+2D8Lv148quCHqoLQ375xoPi/iA/ +%vn1/tzFGCeRZBUPumZ9W9UugeVTBjA+LDfRME8m3ClaHR5697p9I86mCbDuz +%Oyu7J5F3FaTd/V1+PiiJ5lUNE23umRX0SSb/ajhuONbmiPx7jGJ+1eCghIa+ +%g//QfqgG3xNPHgte/6F5VkP4l+3hBaNSaH9Uw9NUx3Fln1JovtXwsNqzfMfE +%VNov8ufvT2k6/EileVfD/KcvLh6ck0b7pxoM9Mr366ek0fyr4aeT3ZZWx3Ta +%T9VQHBI1aW5hOnnUgFr40sdKm/+SRw28nhxwR6nxL3nUwKrOX3FH3DPIowaK +%DI/lzdLMJI8aWBIWl3jgbCbtvxq4Mi8x6I4wizxqYNyJn2qX52SRRw3EHxUM +%iricRR7y4wVd0xz5N4s8aiBn9Phbf82zyaMGVKpGiB+szSaPGkh92f3Yg8fZ +%5FEDvMXqFcV12eRRC5xxO1rmjMohj1r4e33qT65nDnnUwtnYX5dqInLIoxbm +%LbpiqinOJY9aGKqnKVi8MJc8aqFQ8mtp4fVc8qgFu6v+V98V5JJHLaRr3Twe +%PSCPPGrB4m3IQY1deeRRCy3LNqqvD80jj1pQ43HaLDXzyUN+PXfjK6xn55NH +%HTgdWbLK7ko+edSBpvY9i4jcfPKog3737p850L+APOrgS5vw0rZdBeRRB/7O +%2c+DPheQRx0E1AgdtQSF5FEHPl39e6csKCSPOkj/o4Qp/oXkUQfz/Fc/E5UX +%kkcd3LbS+3DRuog86kB0eELEskNF5FEHPd1X9F0SW0QedRAvOvr9rXExedRD +%2LvqyCXrismjHjbN21jR81UxedTDt4DYpctUSsijHsww7VyYbQl51EPkWusd +%ftdLyKMeYkK6C26WlZBHPdiEZvatGVlKHvWwIXj7voPHSsmjHob0DN22608p +%edRD/rzaO18tysijHjr87p5evKuMPOoh/rvznOnhZeTRABt87ilt0isnjwb4 +%41I+qHZNOXk0gJnJjx0Rb8rJowEe1RzrVcStII8GaN88qmKRfQV5NED+144/ +%Ux9VkEcDTOAZzdzWWUEeDfC8JHWj6pxK8miA99WDs7MDK8mjAQ7ZbpCNaKok +%jwYI/FRlGNejijwaADr2rI2ZVUUeDXBqit7Quj1V5NEIz5qrtNYEVpFHI1zx +%+vAzPKaKPBrhq75j8IHmKvJohIvaSeUruleTRyNYmxuZuc6qJo9GKFvNmRDq +%Wk0ejTAxqb3PpDvV5NEI+guqVIrjqsmjEZRTalzT26vJoxHMqkdpN/euIY9G +%2P22Z8qwBTXk0QidX3LLP3nWkEcTcLtnmxx+UkMeTbDQ4eqU1ek15NEEM/c5 +%V5zm1pJHE3iPW8ipH1ZLHk1g+ZRvfnJlLXk0gavLI32Hc7Xk0QQ8aC3a8KmW +%Pj+bIKET1j+vqCWPJlCa9PLGCJM68miCQwYTZqpOryOPJtBqfSZrknem8GiC +%GXYux0bcryOPJkgZ3e/E55Q68mgG7V+/9m3g1pNHM9TxdtusH1FPHs0Q5587 +%JmhdPXk0w6TdoweNvlJPHs2w+/Sjbs1R9eTRDKbJzq86WuvJoxlcZLOU5/Rv +%II9mUNpbujhnaQN5NMPZiMaAkDMN5NEMWZMHL6j40kAezZAU8mPIKvk+Ung0 +%Q2FHjptJr0byaIGVPXtv7WnfSB4tMMVr5FuXU43k0QL9HhWNNZY7KzxaYETl +%S2N+QyN5tMDYqEvR0/o0kUcLvBo/7savpU3k0QIbe8R+DDvfRB4t0PfdzB6N +%EU3k0QI7Fm5o9OpoIo8WCLFYOF8/Q4oKjxaIfXJO716pFBUeLaD5JF40q1mK +%Co8WkG36XifUkKHCoxVarG0PpWvLUOHRChmaHZN/mstQ4dEKCw+Z7Pw5SIYK +%j1b45N1rS9EYGSo8WsFhsINJlxkyVHi0wpqVnGtb7WWo8GiFQ5udshPWyVDh +%0QptGxdtddgtQ4VHK1SEZ5nUHpahwqMVat2dBPcuylDh0QqOlrsa9gTKUOEh +%//vpD6rXPZehwqMN7IOXzHX9IkOFRxvYuukdvhYnQ4VHG2SmvHEpzJKhwqMN +%rH4ccJxYJUOFRxv0O9/o+aNThgqPNjgwrO7ZZpE2KjzaYGHiEu3hptqo8GiD +%8+laa7oO1EaFRxu8v1jxujtoo8KjDUz6en6ZOUubPNogfH/ieD9HbfJoAyja +%0SLdok0ebVAx8uqpJx7a5NEO626UqK09q00e7VBuUpc46ZY2ebTDD2fJ7kXP +%tcmjHQb7LjA4FqZNHu1wYULt4cJEbfJoh9l/zu7dXqhNHu2g17Ww26BmbfJo +%h2U3eF15fB3yaAdlw/fnzU10yEP+3MZnxcqBOuTRDk3LqnwSx+qQRzvMeZw4 +%fc88HfLogEQ3t6Xz1uiQRwcsueMhXemqQx4dMNxNsvjxSR3y6ICSEaeDevvr +%kEcHWOxy6Z33Qoc8OqBVvfJBSoQOeXTA/uH3tsn+6pBHB+ztlr/0WLUOeXRA +%26WGmxPUdcmjA5Tm9soZY6RLHh3gZDq2+PAgXfLogFmrHs/Qm6hLHh1gddNA +%udFelzw64YptnorJVl3y6IQ+1UOWXTuqSx6dsPH4VgOXG7rk0QkhLuU9/F7p +%kkcnpFefi+kVo0senaAzwfqdYYEueXSC2q4wvmOHLnl0wpi/Wp56enrk0Qmn +%BY5lYwbpkYf8+ZGlvIQpeuTRCcsObXuXukKPPDpBd9vgCkc3PfLg4L4bhfdd +%fPVoPRz8kHxCvf2FHvlwMPY294xxnB6tj4NuEw8e+16uR14cNEy2tdTh69N6 +%Odir4Ty3vZc++XEw7WTKxzuT9Gn9HDR+YN2larU+eXIwtCxGWH1Yn+bBwQil +%P88ig/RR8XuGg9OcvVLXRurTfDiof23AqOJSffLmYPLNgPEzRQY0Lw4K04Xd +%Aq0MUPH9gYOcZuONnYsMaH4cDBKHa69wN6D9wMFxyz28iu8Y0Dw5uGLtg+sn +%fhnQ/uDgn54R8TubDWi+HDzQ2NF6s7sh7RcOWnIe2JrONqR5c1DdL+Zoi5sh +%7R8Obgy4u6zbY0OaPwffzEk79iPDkPYTB20M1B8ki43IQwknfM4Zaz3eiDyU +%8HAT72L8biPyUEL19xdFux8bkYcSbsxtHPktz4g8lLDzmajFxMiYPJQwymRD +%6WtbY/JQwqS5QeXcQ8bkoYRio/jMzmfG5KGED8x9z0xKNSYPJZzqeMSgvs6Y +%elPCaxNmDBe2GZOHEo7fYdTVqMCYPJTQPnZyq/NdY/JQwkpf9Z+bRxqTh/z9 +%vMC0l1eMyEMJhzyueFUXb0geSsiPFJ01b2YeSmh0vXfJTWPmoYQyk6FqxtP1 +%yUMJ7XY9Vg47qUceSng0+kLj8Fxd8lDC0dkvSmymsZ7lr7tVeZwMY/cnJWyo +%35//aLoOeShh1/aYyxOztclDGTt8Bl1K+//7rzKqOz/MaeqtTR7K2Ffz0Zf6 +%VPb5qIy/3+/9r/Ac+3xRxm6hya2/bdnnpTKGe7wWWGizzxtltKn3GV6eJiUP +%ZdQN6xfWFiQlD2V0KDJKu7RLSh7KOMki3mX6VCl5KOOOlgwDblcpeSjj9skD +%T65pkpCHMp5eobPVNF5CHsp4Yu2CublPJOQhX1+QqdGDUxLyUMZXt4/b9N0s +%IQ9l1MozzbKdLSEPZSzh+quVDpGQhzLe7TjSu8hAQh7y+Ri+knTjSMhDvl7t +%tEzfQjF5KKOSUso6vVgxeShjd+eFPrffislDGfd/abUyDhSThzL2i6vftOW0 +%mDxUcIy7hZ/PXjF5qGBj4rTxXmvF5KGCz6fbv7VcICYPFZxpO7DywHgxeahg +%c8VNHXcrMXmo4M//bjiKuonJQwVbu8WsHCkTk4cKtvCvDstWEZOHChbVP1Dq +%XSIiDxW0sbkzY9dPEXmooJnOw1sfgkXkoYJ8lWnd4i+JyEMF7bc0xETuE5GH +%Cm6/8PTjiRUi8lDB9NERyWrTROShgufn3JwxzEpEHipo+XLsXB1jEXmo4M0Y +%8UM/NRF5qOCms35XvlVqkYcKBjtZHz2YqkUeKqjT8Wzat29a5KGCNeu7jrwd +%rEUeKmg4++bkTj8t8lDBBKt7L7K8tchDBeFQ7dzRu7XIQxWnDgmMEa/WIg9V +%jPT2rbadp0UeqvjNs2O/yjgt8lDFDM/T3C6DtchDFc8Ihx/yMdMiD1XUv3Gj +%p6tEizxU0a7s/In3SlrkoYondYLHz6oRkocq2jxetnxsrpA8VNGZa831ShCS +%h/x1/dm3TL8LyUMVh/f7O0PtjZA8VNEqqN9ly/tC8lDFiVHCF8+uCclDFR3a +%ElN3nhaShyre6Ts02sNTSB6qaB2f6xmzQ0geqhhq+Mhr8ToheaiiZnjnDosl +%QvJQxcMfDacMnC0kD1W8cWe01dYJQvJQxc04e2PFCCF5yOc5v9zjzgAheaji +%f86LOk53E5KHKo4Xhbk80xeShxq+//7KkaclJA813DvtcffjKkLyUMPO1LGb +%xzQLyEMNh8ycsbd7pYA81FBzafC4ofkC8lDDZTqLTm9NE5CHGpZ83dUtM05A +%Hmo4OfI+uEQIyEMNt3vUDx0UKiAPNfRatq639JWAPNRw4+s6E9NHAvJQw1yl +%J5NnBwrIQw1/Lr3RHnhVQB5quDXe84b5eQF5qOH333bdQrwF5KGGK/8ILT08 +%BeShhhseZoU4ugrIQw1jq9+kLdsqIA81NNo91v3QegF5qOGLVhXJ9+UC8pDP +%79jYwB72AvJQw69P6sJuzRWQhxo+5R+fNma6gDzUcMfb/a4N4wXkoYZ/Ays6 +%I0cLyEMdDVTjo94ME5CHOoYtGZjyaaCAPNSxxwZeeVYv5qGOylayRV3MmYc6 +%Kk3bULDNiHmo49PDe3pkaTMPdczUNLBbo8U81LFzrOC8iibzUMcgt4jVL5WY +%hzqeqNRxcW/lk4c6JmXMVXes55OHOu6rThsxr5JPHur4M2BM45JiPnmo4xKx +%uoVrLp881DEw6q7347988lDHN00bDjQm88lDHR1XPmmx/c0nD3UM2TGr5f0P +%Pnmo41uLfPPR4XzyUMf3XScm/vjMJw91HL0xw3jzBz55qOOaWbUt3V/zyUMd +%v0wzby8P5pOHOvZ0con48pBPHvJ5Tc4/8zCITx4aOL0gyuz2LT55aKBHbdzG +%h3588tBAFeWOO999+OShgYPuDl1Xdp5PHhq4T999TI/TfPLQwAdrLSY7e/PJ +%QwMbi5ZqhnjxyUMDV6dzLc0P8MlDAys7V/c6u49PHhqobpPqJN7NPDSwn8Y5 +%U79tzEMDNV+knB+6mXloYEfTy81/1zMPDYztkht/ZjXz0MDD4Sufzl7OPDRQ +%X9u0xWQp89DANYMMZzcuZh4amOxU/Tp9PvPQwL4R9f4/ZzMPDez9dtLh6BnM +%QwOPTg6I+z2FeWigmv3EcQUTmIcGcvu7RKjaMA8NLDFvshw4hnlo4NZjQZdW +%jmQemphpvsY7YBjz0MQV6v0elg9mHppoNeveoLEDmYcmzk0/GHijL/PQxEXh +%uhyNXsxDfrzpAR57ujMPTUzqca9fXVfmoYmhb2o/7DZhHppoPO+JqaYh89DE +%6w45//nrMg9NvBf6MBNkzEMTF98Z3a9UxDw08THf8JafgHloom5tSuICLp9+ +%f8rPd6StzEideWhi3TqxZrEy89BED8f5Az508shDEwNd327wbeORhybqhF2f +%tq+ZRx7y9RmE9Hdu4JGHJg7Jq3uyrJZHHpo4zcZCd0kVjzw0ce/X+Sucynnk +%IZ+v8fwZziU88tDESouOcrdCHnlw0aBvbqRvHo88uHi83XTju2weeXBxwfTq +%1twMHnlwcbLm9q/SdB55cDHt5rlBU1N45MFFvp2T9+EkHnlw8dQmA6/oeB55 +%cDH8nN4unTgeeXAx0/Ne56oYHnlw8cql5SEfo3nkwcVjmya3GkfyyIOLXX0m +%9T3wnUceXGzWbU8s/cojDy6WdB8w3+Ezjzy4+GDw+te/P/LIg4vWx9OCZ33g +%kQcX3wgmmce/ZR5c1N8cKXR4zTy4GCBy8C5+wTy4uK1gw4V9z5gHF98GCLrq +%PWUeXOzhHVf48hHz4OKQ08eP2D1gHlzc3vKsWfUe8+Bi28bAvy/uMA8epsVX +%aq8NZB487Mrv9sbsFvPg4f2tKh8zbzAPHkbFb7UN9GMePMzQnvZjw1XmwUO9 +%BVuPjfJlHjx0nucUL7zMPHj4ouBeVP4F5sFD4cQTsz+dYx48PLX4euutM8yD +%hzu52hVHTjEP+XUc0lbfdoJ58NDnQr27kzfz4GGu/lWzeUeZBw9DHk57PP0w +%8+BhdPnpBZMPMQ8eFo7JmjDFk3nwcNecFS0zPJgHD7+nxzfNd2Me8jnv1lJe +%vo958HDgJf3D21yZBw9t1+isOrabefBQypEW+O9kHjycXTN04aftzIOHomsj +%qrK2Mg8+ui0xDldzYR7y+9Cd8V0HbmYefAy4UHnJfiPzkN8nNrhPOuHMPOT3 +%sbbi+Z/WMQ8+frC/kdO0hnnw8b86s19Wq5mH/L543/zPtpXMg4/L591seLmc +%efAx92fuxbZlzIOPYpHD3YmOzIOPEVM6Us4vYR58FF1WM8y3Zx58XNX+NNPa +%jnnw8XifAMGZRcyDjxMnqF8pWcA8+HhS2WP2lPnMQ35fvJJ69f5c5sHH4RyL +%3lpzmAcf0xd9qdlhyzz4eFWUbJY9k3nwceDjZp+ZM5gHH826aPf+NI158NGg +%aM9Iq6nMQ/658tYp+v5k5iFAs0dzw7tNYh4C1Lh3a5P/BOYhQLcOpzVm45mH +%ALd0fNALsGEeApxun7Cl91jmIcC7pTJRMDAPATrH2W3+bwzzEGBS6C7zqP+Y +%hwA3+ElLFo9iHgL8o5TBqRjBPOTfe0uyfQ9ZMw8BxvYP5pkMZx4C7GNjFfZ6 +%KPMQoP9Tw/L5Q5iH/Hvfw8fRDYOZhwBfF6X4+FoyDwEO2NeUPGYQ8xDgs9zZ +%WDCAeQhwtNeGfWf7Mw8BRs8O7j6mH/MQoM+kdQ3lfZiHAPe47hx4ozfzEKD9 +%1GPFc3sxD/n36h7h/XgWzEOAPz73bP3cg3kIMSanydWtO/MQ4sUTGVUjuzEP +%IX7RXb6t1Yx5CLFS1yL3Q1fmIUT3wDfOB0yZh/x30/4818ldmIcQh5760CYy +%YR5CPPSpMyPNiHkI0XLryJV3DZmHEBOnJq3bZcA8hPj2L+f1ZH3mIcSI+Dgv +%Iz3mIcQFrqHSah3mIUTrETFvw7WZhxB7Buzz8JcxDyHOzR9lsF/KPITYlqGe +%YCdhHkKc/t3+ywgx85DPozM92FDEPIR4xpQf2S5kHvLX7wXeyhEwDyEunryU +%E8VnHkI8V9hd/TmPeQgxuM/PD35c5iH/3edxcI23JvPQwhGnFlvs0WAe8t/5 +%9SZX1qkzDy2M9HB+YqfGPOS/s9+VBc1UZR5aaF615MJ4Feahhd57M9tHKTMP +%Law+btIyRIl5aKGL2oIRgzjMQwvPLVxr2a+TSx5aqFbb9rpPB5c8tDCxxapv +%33YueWhh6YjlZv3auOShhYVHuv4a2MolDy3c7jkwf0gLlzy08EzQMruRzVzy +%0EK35W6fbJq45KGFuW0DNKc3cslDC78Vx6QtbOCShxYKVk1atFL+uavw0MJ3 +%JywOba3jkocWFl+J6eJZyyUP+Xq9hxy8UMMlDy0cr+kfcqeaSx5a+OitrOhd +%FZc8tLDPz+9r4iq55CFC3cSka0UVXPIQYR/D1c5K8ucKDxHOv6xhZ1TOJQ8R +%ThumNmF4GZc8RPh+bMvcefLvDQoPEc749DhnawmXPESo4pq8/1wxlzxE2COm +%0fFFEZc8RLindO/VpELmIcIt3OdzWwuYhwgLB9w50bWAeYjQr8T29cR85iG/ +%3guD52zOYx4i/Har+bNPLvMQ4X2Tl9Zfc5iHCO0GaAytzGYeIqySFv0yzmYe +%Imzt+Nx3Wpb8e9M/DxF6fGtw35vJPER40v7gvocZzEOEO9y2xGX8ZR4ilIQc +%PSL9yzxEuOqS7bpJ6cxDhJrfbdfuT2MeIowcYnTlRSrzEOPie38sylNoPWpi +%HDql++yeKcxHjJMD9qx3+sNV/L4SiTFj9PrVfsnMS4zCLocbUpNovQZiHJQb +%9Uk/ifmJsf/GH6sXJdL6u4lxn3FXb58E5ilG28lvrFPjaR4DxGjS093TJJ75 +%yq/vcOVJp9+0X63FCHc44XfimLcYI3vN61keS/OyEaPHU9fbVrHMX4x/0qe4 +%7/tF85suRpedvZ98i2H7QYwOa5MniWNongvFeHez5lr7n2x/iFG6qSwj6AfN +%10mMu33E3vXRXPr/M2LcmfLOcXw0zdtZjKFFtyaej2L7R4xTQxKm5kXS/HeI +%Uav+cvbQSLafxDjs774DRyPIw0OMF6dKPNPD2f4So9L7oNGDwsnDW4xL736x +%PvydPE6LUfy08EP6N/K4IMa9nQNdhnxj+0+Mzlofu58II4/rYoz1v7Qr/yvb +%j2Lsod3zGH4lj7tiNL/qtfXqF7Y/xVgbURTR+Jk8notxTop9+bzP7P4hn2fR +%nsPPPpFHiBi9v8ycLfnE9q8Yx7ROt3YJJY9wMdpMKNz7+yPbz2J8bRmYN/gj +%ecSJ8Zn3tbGXQtj+FqOeS6R58wfySJfP67j7tSUf2H4Xo07WyxVf3pNHgRjD +%v3Gn9XrP9r8Y59343n7qHXlUiTH54CnlhresBzHyup8/svQtebSIceIky6jw +%N6wPCfImunEGv2F9SHB5w+kF116zPiT4yajIU/M160OCI3RTi7a/Yn1I8P6B +%rvNyXrI+JHhmXvDbWS9ZHxLcmnd7QOgL1ocEN2+z2j/gBetDgpUOlrIbz1kf +%EhRJTs8TP2d9SHD6l/SOA89YHxLM1vXIqwtmfUjQRFY+Ym0w60OCQ66V6aY/ +%ZX3Ir0fXPmX2U9aHBK8Orov+/oT1IcGVfNmm0U9YHxJU7Xzj+OIx60OC5Q+l +%yX0fsz4k6DRo95/AR+x+KsFeTU+bTR6xPiRombYs+vJD1ocEfU+UBkgfsj4k +%aBqy/NnJB6wPCe538+XzHrA+JDiH093/8H3Wh/z6ZitPUr3P+pA/r3dw8rzH +%+pBghVvIcqV7rA8Jrg3r2ONxl/UhwdATlQ2cu6wPCRZPNz1+IIj1IcHMEVwP +%5SDWhwTx5gMrrzusDwmm3+NlaNxhfUiwR9rXTO/brA8J7ozO6SW6zfqQ4MJ+ +%M36dD2R9SHCFZuZ4g0DWhwSl16q8bgSwPiTodUWrqEcA60OC9kX3vz68xfqQ +%yH9PRlUNucX6kOAMfdd+If6sDwk6SAP6TfQnjwIJTvjoZhZ7k/UhwbFGz/Xt +%brI+JBhXku6fd4P1Id9PE/c1b77B+pBgxrQ67bbrrA8pug2fa3f0OutDik/s +%dq7Quc76kOLMhcEzA/xYH1I8YCrbaenH+pCiclBYbug11ocUc0x9fs26xvqQ +%4rqI/g8yr7I+pNhRa6W+5SrrQ37+RWeclK6yPqTo02XbwPNXWB9SvGp+jtvj +%CutDig8Ww7nXvqwPKR4/kxs71Zf1IcXYniYLM3xYH1IcvXhb3VYf1of89cu9 +%MjR8WB9SBM/lln6XWR9StN07c7bVZdaHFIc2+a2JvMT6kGJJxeHJyy6xPqS4 +%I8o2o/Ei60OKl/PcY09fZH1IsV4y06zXRdaH/HifNJs/XWB9SDFyx9M3dhdY +%H/J5j7C2rTvP+pDiO9kjvdPnWR9SXPGr5mDv86wPKf52F+K3c6wPKQq2meg6 +%nWN9SHHMqoCX7WdZH1LMU3Oec+Us60OKTpsLXYafZX1IcXF08qLEM6wPKe50 +%SF+77QzrQ4oG5zdNlp5hfcjnYf94TvBp1ocU9z27mmZ7mvUhxe4xfl2rT7E+ +%pNimOePz2VOsD7m/Wr+8wadYH3JfTumwhJOsDykeGzR0z86TrA8pJrmHb9I/ +%yfqQ4vh5zRbvT7A+pFho88pu6QnWhxS//ne9WukE60OKfbgD228fZ31IMfPS +%lZCpx1kfUvQYc+ZXpTfrQ4YXu3wruODN+pDhbmn/8yO9WR8y/HZhQlvWMdaH +%DMdm7j5/5BjrQ4ZvRjvYDTjG+pDhzqcLkhOPsj5kqPLMInX/UdaHDCP9Hkzs +%eZT1IcOS1idhMUdYHzJU35aXt+sI60OGsn6qaHaE9SHDISk7rKIPsz5k2K1o +%ydYdh1kfMpxnOrzG9DDrQ4ZDBeP+RHmxPmRoXmG/facX60O+fjX1ueZerA8Z +%+k7Xt4s5xPqQYbD5r7+uh1gfMrwQvJHb6xDrQ4b97cVWiQdZHzIcPmvBE8+D +%rA8Z3r/829jyIOtDhjru+ksyPVkfMsxcN8zllCfrQz7Pvu8jRnuyPmR4t8fg +%JeUHWB/yeW1sWuB3gPUhw6kfg/rNOMD6kKGueVpnuwfrQ4bTnxkrPfFgfchw +%WlwNd5kH60OG1qXyu4wH60OGASPqm766sz5kuMP53eqd7qwPGbo+K2ro5c76 +%kGGb106zdDfWh3z+41f7nHZjfchQeewUu3FurA8Zbnru4dq4n/Uhwz/n3oc9 +%2M/6kOHxVe+PLNvP+pCh1bCJ3jr7WR8yTHjbMjl6H+tDhhmZCYke+1gfMvy1 +%wSV/2D7Wh3y/nMsYV76X9SHDo9OOBwfsZX3I3/986F27vawP+d/r6CyU7mV9 +%aGNE04ukSFcu/h+i+QLA +% "]]}, +% {GrayLevel[0], LineBox[CompressedData[" +%1:eJw113lczNsbB/BpmmavZokkW7cI19ZybZfOI5VoVymKJCJbiVC3ouxLJJWI +%uOLey00JP1uYuAiFlLQo2hftm/b6DXOe7z+9pu/M+Z7n8z5zzjM6a3yXrmMy +%GIxOJQbjx1+8Ul26/o4JaJf9oZG8qCxoP7EvejblzHx8HU3Kp3Tv3KfSLrs/ +%5kC9w/0EYvLPcO7Gt230/hUSCL43zWPaZOfO/riukUvnfW4OX9lG359MLp2e +%4fRVr03W4PDjP6nkOLep5s+GVvr5O8R/ZtyTlXdaZfz8RL/5/HvkN9fQC5rB +%rXS8B0R9W1JLxsJW2ST3k886Jz4i3df91u0UtNLxn5CuwPe3dXNbZFfkn85P +%TCdX6xcp551roc97SsaeXSA7sKZFZvTz+o+cu2fBNpjcQp//nGw94u32sqJZ +%9l/nRPkTXpBj6y1fGm5vpvPJIAe1JiYnMZtlS38+8BVJ3xWvPzOqic7vNXmX +%EvnwjU6TrCzox4BviOGo0dt9UhvpfLPIRH1zkfaCRtm2H9Pze0vYlebXKrIb +%6PzfkfS0E4bpqxtkCo1sovf0TMejlnpaTzYxStlZk763Xmb58wEfiEWWzrh2 +%UT2t7wMZ+76vYOaf32Q/nuZ+Moes+8e++ILBN1pvLulmDSpNe1Yn+1lOfi7J +%2q+kW7C0jtb/kahbvitKrqiVjf0xnTF55G7pwekXd9TSPPLIxOEub9JUamXr +%vX9cn8iI7SY3hWdqaD75ZJnBKub+iTWyH6NpJOeTzZuAO/FhNc2rgESvbe6u +%saqWff8xXGcBufAx51FuSRXNr5DYvXROH+ZXJTP5OWARmRzfp7qDWUXzLCLW +%He4uddGVsp/TO/CZBCzmBH3Sr6T5FpOh/7UEZD2skL3N+nEVE6dLHZ6DNhU0 +%7xIyI377/ZCyctmwnxP8QtiJLrGTAspp/l/I4/P321R45bKfw7l/JfY7Pe5r +%XyijHqVkzICdT4JBGa2nlFyws3TUfllKfUpJsdLhEqZbKa2vlPS/D9zlWPqV +%epURrdyQ2z6Cr7TeMtKt22sTP/ML9Ssjq13q/FevKaH1l5M7ET3VshPF1LOc +%kDuSwZK0zzSPcjLX0C00qK6I+lYQ3U3SeDfNIppPBdGPdB78xaKQeleQw8KO +%x3sCCmhelWTqNqdxm6/mU/9K4mhePz4z7xPNr5K4f+v9PMj+RNdDFel6wdRM +%nJ1H86wi1zh3H52OZoNifVSR624L1xgks0GRbzXZ8i79iyyDDYr1Uk36NijX +%TStjgyLvamL6yND/VC8bFOunhlxcJ/izUMoBRf41JInt/og3lQOK9VRDLryI +%mDDVggMKj1rSvuLwQkMPDig8asn1lPDrWrs5oPCoJbuW/6vaFskBhUct0Q4X +%cFKvcUDhUUfMohOuOT3jgMKjjqiP6tSsLeKAwqOOpAdUqy1r54DC4xvRyOmX +%3RZwIfKnxzfya5ZdbKcuFxQe38jbm0kfpfO4oPCoJ5n9jp1jnbig8Kgn+5M4 +%9fzNXFB41JNAPe7Bin1cUHg0kKIzyeHR8VxQeDSQB8Xx18ff5oLCo4Esn9v6 +%9NIbLig8GoljSnrGYBkXFB6NJOiwh/eMHi71aCRXhwseWol41KOJbMn0Zi3S +%51GPJpImWOM8zIRHPZqIzW1OZoYTj3o0k4TR0+4s38SjHs3kaKnV8PQwHvVo +%JiwDHw+lOB71aCFWMIM1NplH62khUS9reRrPedSnhVgbGJ//XMij9bUQVePI +%wh3NPOrVQiKs1OrqWHxabwt54B+UPmUkn/q1kFcjWx1Np/Np/a3EyPjRhwlm +%fOrZSlK5r5vyXfk0j1bCuFbW5rCFT31bSalhsvf5MD7Np5W0rPhNIymGT71b +%SXH1dM2Qa3yaVxvxbw3J037Mp/5thPVCemR3Np/m10ZeXnTNiKngg+L72Ubu +%elZxt37n0zzbSO7iPZUqPAFdH21EZ6bqTXttAc23nZjbs7udpgroemknc097 +%zFcnApp3O3kxm1+xw15A1087+T1jUVCkp4Dm305m/hK/aqm/gK6ndhJ0+qHa +%w3AB9eggy2sdZ72NElCPDtJQlKsTdllAPToIz1qq/y5VQD06CPu37G1P0gXU +%o4McKw2fZ/FeQD06SEZtZLRXiYB6dJCjG7duEdULqEcnCf3rz9k23QLq0UkK +%HErbR6gIqUcn+Tt+dukmsZB6dJKsC8b3zEYLqUcn6XltrHt5opB6dJI6rvX6 +%UCMh9fhOVmUM+uTNF1KP7yQyqOvBP4uE1OM7ebvdM6zNXkg9vhPd3P2bUpcL +%qcd38m6q/5QyTyH1+E469l2Yvd9HSD26SB37zalYPyH16CLrJ++ql+4SUo8u +%EqezIHgwWEg9ukiQC+uEY7iQenSRoqilT6SHhNSji+zZ4Fv7+zEh9egmH9Sm +%2r0/IaQe3US3503em1NC6tFNJp2McjOIFlKPbjLayrKOGSukHt3k5DdG3IIz +%QurRTbQttkqb5K8VHt0E3L5bCeKE1KOH7LnrnHNOfl/h0UP+47jMuxSLHj1E +%dbxgkXYMevSQvcabWBqn0aOHzDDfueB4JHr0kD7fuqDDEejRS3Z1nq/jH0WP +%XmJw+Z3WiIPo0UtsjmnF3AsT0v2yl7wemPBLQzB69JJTUu20tF3o0UsKTQaL +%J/mjRx/JC1N78Ptm9Ogjz6Z5CLrXoUcfMbw4RcvLAz36yGpXJdtwV/ToI9yC +%m87uDujRR9JWbwvrWIwe/eTS+3y2gyl69JMvo6bl75yLHv3Ex+PTk42G6NFP +%vubv/NNwMnr0E795re45OujRT9gr8sfba6FHPzENeTGYJEKPAfIhKHKoiYMe +%A2TNeda/2kMC6jFAjpjxcmZ+F1CPATL54f63CxoF1GOA/JUOdxdUCqjHAPFe +%/+z4/M8C6jFIApqjOUY5AuoxSMIuGSye8FpAPQZJV9XacaPk32+FxyDpfMxa +%NeyegHoMkqf3v/2nkYz71SCJPrabMe4q7ldDJDUmjGt4HverIeIoOKu+7DTu +%V0Pk1OQRJYeO4n41RPr3Maa+DsP9aojcC7YyHBWI+9UQmfXilvp+P9yvGDBB +%i1U7uB7rYUD7pkTdUx64fzHAMMi9ZI4L1seASZ4uen22uJ8x4KXppLAPFgL4 +%Wa43A/ROTD3z0gT3NwbUloqO58wU0P2BAQEaVqo903C/Y0BC2JK7s/QxDwbY +%JwiXxY7F/U8+fuHBa6ojMB8G9J4rq7oswv2QATc812gv5WFeSlAyh9czion7 +%oxLMspycxOrj0/yUABqjVTkdeH4pQaL5yJLxjXyapxI0vp/DW12N55kSJI3R +%s7n7lU/zVYIp1e6dEwvxfFMCW/u7pXdy+DRvJQh+ZfjOPQvPOyXYslY8oPOS +%T/NXgm0HC58y0vH8U4KeUCLpesCnHky4t/d4GP8OnodMmLUuzW9mMp96MCGx +%57ZO8D94PjLBOfn60+LLfOrBhJXR622WXsDzkgm/ivcwq8/wqQcTtG1SNkdE +%4fnJhNa7anE2EXzqwYSooazB8YfxPGXCwemZK4ftw/6ACQsjR87QCuVTDyY8 +%VdeuNw7EfoEJSapm1T47+NRDGeIfx7Ym+2L/oAy/eV2yUd2EHspwYkdeQag3 +%eiiDkW6OWGUNeihDjdGXlxdXoocyjH2X3WazHD2U4Y1txr9qzuihDJ8fP3lW +%YY8eyuA/+GHtG2v0UAb192eVn1uihzIE2M43yjZDD2X41M1PagD0YIF63PhC +%7fnowYJXGr7PV8xBDxa8WP5r/7+/oQcL7G61HxUaogcLtoYdbv9jGnqwYPtS +%k4yByejBgojzR8Mi9NGDBcPZA+ZT9NCDBQZeB1IKx6EHCz5/U74YOxo9WLCs +%rt3McyR6sKDu2j3vOZrowYKKPz6+HquBHirQo9PDlIrRQwUCnM9HaaihhwoE +%dwY80BGghwq8rPaYO4+LHiqwt1LNxksFPVQg+6lgZCwTPVRgR88vbz8O8aiH +%ChBPVcexA9i/qkBJlaZbQC+PesjvP9FOyuviUQ8V2FXtc9q0k0c9VODwHKWZ +%D9qw32XDgb73z+e2YH/NBqXogIEXjdj/sqE0EhLc63nUgw2XN6Sf7K/FfpgN +%1rKBwqvV2I+zIS2WMcG1Evtj+Xhz42KGl/OoBxt87w0zK/6K/TIbTB24XddL +%sH9nQ9jhb9Xhn3nUgw3m1o4Fa+T9tsKDDR990q4syedRDzZ0ufZdn5eH/T4H +%1mjV+M3M5VEPDri0n1SZ/YFHPTjwNeBxKrznUQ8OJIZYDjq8xd8HHAi0LXyz +%MZNHPTiw+9n220df86gHB1zvORWnZqAHByygmXx9gR4cyDArDBz2HD04kKSf +%luvwDD04cPNzqUtMOnrI75cHZ355gh5cuKW82Xv6Y/Tgwh33tcUH0tCDC5wl +%3ZnlD9CDC8Yfnn02v48eXJCcDhtMvoseXHC9IRga/T/04ELyQG9M1G0ePT+5 +%ULv5oonqLfTgQlTK/7wjbqIHF/bYjd8iTUEPLixq+scj4QZ6cCEwM9FrWhJ6 +%yOfj98Du+XX04EHXaaWkVdfQgwftgWNeD/6NHjzY57t7deJf6MGDzQWMYuur +%6MEDr4sZ4r5E9OCBVbzm8OTL6MGDML249+v+RA8ehLfpOOlcQg8eHKpLaitL +%QA8e6OU97//rAnrwYHLMQnO/8+jBAzuN2Ffz49GDD51Z043Uz6EHH4pWm9hV +%xqEHH2xcSooen0EPPviOq4qMj0UPPvz++Oyp4Bj04EOL+Pkjz2j04ANv7Mnz +%S06jBx/e39qvNysKPfhwNXFzoP4p9ODDwI2cbdqR6MGH7sTqPZKT6MGHhfXb +%U4Qn0IMPnBmH7vIj0EMAq41/1RMeRw95H+HsrSk6hh7yvm3oYq/mUfQQwOxr +%Goa6R9BDAAvVHhobHEYPAUStdHY0PYQeAvC3t/BadhA95H3Rp7YNWw6ghwDq +%0z1WHNqPHvK+4tIo3Sv70EMAWrmRr/8LRw/550e/elgVhh5CMPUKuCAIQw8h +%KJtHjTHaix5CmB5XHr5yD3oIoWMo6tvRUPSQ/66asD7vQQh6CKH1jmpCQzB6 +%yPve/KHfdYLRQwgjuLVrXf9ADyE070v5cCoIPYTAE1otfxuIHvLXHZJPgkD0 +%EELgUNYU693oIYSWRP+CE7vQQxWKwtR4H3eihyo8d24pH7kTPVTB0WNayNoA +%9FCFsoHWTyk70EMV3EadujOwHT1UITmj09lmO3qowqHbK9IT/NFDFe6daE5s +%24YeqpB9vcHccht6qAIj2/fART/0UAWf6kSVHl/0UIUd43LWO/mihxp4KU27 +%mroVPdSgpj/EUbQVPdRgha5+yLYt6KEGUxP4IR83o4caXPnlatjszeihBluP +%hYYnbEIPNfBxel7F3oQearDD8V2o30b0UAP/htBzn33QQw02xD6KsPRBD/l8 +%0pd8u7sBPdRgVohV44QN6KEGUZ1/x8StRw91UJ+496lgPXqoQ16/m/9eb/RQ +%h1yp6Oz3deihDtlHvlpuXYce6mDIH7GxZi16qIPrScsBz7XooQ6/apV1lHih +%hzqUelUGunmhhzpIh91eWLQGPdRBP6NUe8Ua9JC/P+1V2WdP9FCH56OFD1d5 +%oocIGkbYnilfjfWIwFaTKd6wGn1E4P6x41GTB9YngtEtYck7PdBLBKmGUZVD +%q7BeETzYdsLh6Cr0E4Gnw+bKYauwfvn9xBdNl1eipwgkqcojDVZiHiIw0ro1 +%IJPv44rfMyKwV7pB7N0xHxFsX5yQXOaG3iLomLbXdIcb5iWCvz6Gf+W4Yf8g +%Am1vm8rzKzA/EUQZ5hwwXIHrQQRZDDXH18sxTxEEly177rkc14cI9qyWru11 +%xXxFkGtmuyDaFdeLCFaGul+f7op5i2B+t8+iTBdcPyJghbWKNrhg/iLYrR+s +%z3bB9SSCfQdYrleXoYcY1vXPyzFbhh5iOJq+p6bKGT3EUN68J+uQM3qIQbfY +%Y/RkZ/QQg1bqf5ffOqGHGD7pbyzb5oQeYuAtyPDVdEIPMawqGHPrsSN6iGFj +%+pHCtY7oIYZXupeyhI74fZO/n6/E/99S9BCD2vclh1ctRQ8xGD0ouMVdih5i +%MEzJHrjtgB5iEPeWtXs4oIe83mEuSUIH9BBDQo/6uIf26CGff2ZjyAZ79BDD +%jTDueE179BDD6+E1rS/t0EMMA8t6L++yQw8xtB62ZE6yQw/5eAHLm4ps0UMM +%Q580QyJs0UMMe6b9dgxs0UMCV3b01HXYoIcEbK80ZF+zQQ8JtAUVqnjYoIcE +%fHXemAyzQQ8JnHKZfSvTGj3k9x9ywvZZo4cE1v7x7tbv1ughgUxVu/Z2K/SQ +%wNQPX1JuWKGHBIxkxhnrrdBDAmXujdN/sUIPCSwxWGBesgQ9JHDd5eTss0vQ +%QwLvh5+86rwEPSTAMTh/TLIEPSTwarePT/Zi9JDAv4bxlScWo4cEsk5PLbBZ +%jB4SsOHMSRIuRg8JpD4dpvfWEj0k8LHZ+EiEJXpIYNSdDeNsLdFDAj47Hqap +%W6KHBLT0nmrnLEIPCVSY6dZHL0IPKVwNFX5zWYQeUri7eIqR9iL0kAJX/1dG +%qQV6SOHI5CneVyzQQwqhST1nfSzQQz7eVqn1dAv0kAJ71ZOTneboIYXHN71M +%HpmjhxQcnGM37DNHDymEWNx3tDJHDynMGLHAV2qOHlK4b7x8eLEZekjB7eMx +%vatm6CEFE+ulwVvN0EMKKddI0Gwz9JCC8dncCqYZekjB1W+4yduF6CGFywfW +%jDq7ED2kwGl69mjtQvSQwuDe2rIZC9FDCtWnvEIHTNFD/vwt7/a+MUUPKVjH +%6XLiTNFDCn9kjvmwzhQ9pFD4yiXfyBQ9NGCbumUmU/76/4f9glI= +% "]]}}, +% AspectRatio->NCache[GoldenRatio^(-1), 0.6180339887498948], +% Axes->None, +% AxesOrigin->{0, 0}, +% Epilog->{ +% InsetBox[ +% BoxData[ +% FormBox[ +% InterpretationBox[ +% Cell[ +% BoxData[ +% FormBox["\"|q| = 0.02\"", TraditionalForm]], "Text", "TR"], +% Text["|q| = 0.02"]], TraditionalForm]], {0.8, 4}, BaseStyle \ +%-> 14], +% InsetBox[ +% BoxData[ +% FormBox[ +% InterpretationBox[ +% Cell[ +% BoxData[ +% FormBox["\"|q| = 0.05\"", TraditionalForm]], "Text", "TR"], +% Text["|q| = 0.05"]], TraditionalForm]], {1.67, 6.4}, \ +%BaseStyle -> 14], +% InsetBox[ +% BoxData[ +% FormBox[ +% InterpretationBox[ +% Cell[ +% BoxData[ +% FormBox["\"|q| = 0.07\"", TraditionalForm]], "Text", "TR"], +% Text["|q| = 0.07"]], TraditionalForm]], {2.85, 12}, \ +%BaseStyle -> 14], +% InsetBox[ +% BoxData[ +% FormBox[ +% InterpretationBox[ +% Cell[ +% BoxData[ +% FormBox["\"|q| = 0.1\"", TraditionalForm]], "Text", "TR"], \ +% +% Text["|q| = 0.1"]], TraditionalForm]], {3.2, 7}, BaseStyle \ +%-> 14], Null}, +% Frame->True, +% FrameLabel->{ +% FormBox["\"Impact parameter, b\"", TraditionalForm], +% FormBox["\"Spatial rotation, \[Chi]\"", TraditionalForm]}, +% FrameStyle->{{14, +% GrayLevel[1]}, {14, +% GrayLevel[1]}}, +% FrameTicks->{Automatic, {{0, +% FormBox["0", TraditionalForm]}, { +% NCache[Pi, 3.141592653589793], +% FormBox["\[Pi]", TraditionalForm]}, { +% NCache[2 Pi, 6.283185307179586], +% FormBox[ +% RowBox[{"2", " ", "\[Pi]"}], TraditionalForm]}, { +% NCache[3 Pi, 9.42477796076938], +% FormBox[ +% RowBox[{"3", " ", "\[Pi]"}], TraditionalForm]}, { +% NCache[4 Pi, 12.566370614359172`], +% FormBox[ +% RowBox[{"4", " ", "\[Pi]"}], TraditionalForm]}}}, +% FrameTicksStyle->{16, 16}, +% ImageSize->600, +% PlotRange->{All, All}, +% PlotRangeClipping->True, +% PlotRangePadding->{Automatic, Automatic}, +% TicksStyle->16]], "Output", +% CellChangeTimes->{3.556953242036603*^9, {3.556953596625984*^9, \ +%3.556953702375863*^9}, {3.556953796337514*^9, 3.556953956593231*^9}, \ +%{3.556954020687426*^9, 3.556954030706046*^9}, { +% 3.558693364370013*^9, 3.5586933829491863`*^9}, \ +%{3.55869345851305*^9, 3.5586934742140837`*^9}}] +%%EndMathematicaCell +p +np 33 1 m +33 273 L +469 273 L +469 1 L +cp +clip np +p +np 35 3 m +35 271 L +467 271 L +467 3 L +cp +clip np +3.239 setmiterlimit +p +np 70 3 m +70 238 L +450 238 L +450 3 L +cp +clip np +P +p +np 70 3 m +70 238 L +450 238 L +450 3 L +cp +clip np +P +p +np 70 3 m +70 238 L +450 238 L +450 3 L +cp +clip np +0 g +0.36 w +[ ] 0 setdash +3.25 setmiterlimit +78.19 226.892 m +78.919 226.724 L +79.648 226.555 L +80.376 226.386 L +81.105 226.217 L +81.834 226.048 L +82.562 225.878 L +83.291 225.707 L +84.02 225.537 L +84.749 225.366 L +85.477 225.194 L +86.206 225.022 L +86.935 224.85 L +87.663 224.678 L +88.392 224.505 L +89.121 224.331 L +89.849 224.158 L +90.578 223.984 L +91.307 223.809 L +92.035 223.635 L +92.764 223.459 L +93.493 223.284 L +94.221 223.108 L +94.95 222.932 L +95.679 222.755 L +96.407 222.578 L +97.136 222.4 L +97.865 222.222 L +98.593 222.044 L +99.322 221.865 L +100.051 221.686 L +100.779 221.507 L +101.508 221.327 L +102.237 221.147 L +102.965 220.966 L +103.694 220.785 L +104.423 220.604 L +105.152 220.422 L +105.88 220.24 L +106.609 220.057 L +107.338 219.874 L +108.066 219.691 L +108.795 219.507 L +109.524 219.323 L +110.252 219.138 L +110.981 218.953 L +111.71 218.767 L +112.438 218.581 L +113.167 218.395 L +113.896 218.208 L +114.624 218.021 L +115.353 217.833 L +116.082 217.645 L +116.81 217.457 L +117.539 217.268 L +118.268 217.078 L +118.996 216.889 L +119.725 216.698 L +120.454 216.508 L +121.182 216.316 L +121.911 216.125 L +122.64 215.933 L +123.368 215.74 L +124.097 215.547 L +124.826 215.354 L +125.554 215.16 L +126.283 214.965 L +127.012 214.77 L +127.741 214.575 L +128.469 214.379 L +129.198 214.183 L +129.927 213.986 L +130.655 213.789 L +131.384 213.591 L +132.113 213.392 L +132.841 213.194 L +133.57 212.994 L +134.299 212.794 L +135.027 212.594 L +135.756 212.393 L +136.485 212.192 L +137.213 211.99 L +137.942 211.787 L +138.671 211.584 L +139.399 211.38 L +140.128 211.176 L +140.857 210.972 L +141.585 210.766 L +142.314 210.56 L +143.043 210.354 L +143.771 210.147 L +144.5 209.939 L +145.229 209.731 L +145.957 209.522 L +146.686 209.313 L +147.415 209.103 L +148.144 208.893 L +148.872 208.681 L +149.601 208.47 L +150.33 208.257 L +151.058 208.044 L +151.787 207.83 L +152.516 207.616 L +153.244 207.401 L +153.973 207.185 L +154.702 206.969 L +155.43 206.752 L +156.159 206.534 L +156.888 206.316 L +157.616 206.097 L +158.345 205.877 L +159.074 205.656 L +159.802 205.435 L +160.531 205.213 L +161.26 204.99 L +161.988 204.767 L +162.717 204.542 L +163.446 204.317 L +164.174 204.092 L +164.903 203.865 L +165.632 203.638 L +166.36 203.409 L +167.089 203.181 L +167.818 202.951 L +168.547 202.72 L +169.275 202.489 L +170.004 202.256 L +170.733 202.023 L +171.461 201.789 L +172.19 201.554 L +172.919 201.318 L +173.647 201.081 L +174.376 200.844 L +175.105 200.605 L +175.833 200.365 L +176.562 200.125 L +177.291 199.883 L +178.019 199.641 L +178.748 199.397 L +179.477 199.153 L +180.205 198.907 L +180.934 198.661 L +181.663 198.413 L +182.391 198.164 L +183.12 197.914 L +183.849 197.664 L +184.577 197.412 L +185.306 197.158 L +186.035 196.904 L +186.763 196.649 L +187.492 196.392 L +188.221 196.134 L +188.95 195.875 L +189.678 195.615 L +190.407 195.353 L +191.136 195.091 L +191.864 194.826 L +192.593 194.561 L +193.322 194.294 L +194.05 194.026 L +194.779 193.757 L +195.508 193.486 L +196.236 193.214 L +196.965 192.94 L +197.694 192.665 L +198.422 192.388 L +199.151 192.11 L +199.88 191.83 L +200.608 191.549 L +201.337 191.266 L +202.066 190.981 L +202.794 190.695 L +203.523 190.408 L +204.252 190.118 L +204.98 189.827 L +205.709 189.534 L +206.438 189.239 L +207.166 188.942 L +207.895 188.644 L +208.624 188.343 L +209.353 188.041 L +210.081 187.737 L +210.81 187.43 L +211.539 187.122 L +212.267 186.811 L +212.996 186.499 L +213.725 186.184 L +214.453 185.867 L +215.182 185.548 L +215.911 185.226 L +216.639 184.903 L +217.368 184.576 L +218.097 184.248 L +218.825 183.917 L +219.554 183.583 L +220.283 183.247 L +221.011 182.908 L +221.74 182.566 L +222.469 182.221 L +223.197 181.874 L +223.926 181.524 L +224.655 181.171 L +225.383 180.815 L +226.112 180.455 L +226.841 180.093 L +227.569 179.727 L +228.298 179.358 L +229.027 178.986 L +229.756 178.61 L +230.484 178.23 L +231.213 177.847 L +231.942 177.46 L +232.67 177.069 L +233.399 176.674 L +234.128 176.276 L +234.856 175.872 L +235.585 175.465 L +236.314 175.053 L +237.042 174.637 L +237.771 174.216 L +238.5 173.79 L +239.228 173.359 L +239.957 172.924 L +240.686 172.482 L +241.414 172.036 L +242.143 171.584 L +242.872 171.126 L +243.6 170.662 L +244.329 170.192 L +245.058 169.716 L +245.786 169.233 L +246.515 168.744 L +247.244 168.247 L +247.972 167.743 L +248.701 167.232 L +249.43 166.713 L +250.159 166.186 L +250.887 165.65 L +251.616 165.106 L +252.345 164.553 L +253.073 163.99 L +253.802 163.417 L +254.531 162.834 L +255.259 162.241 L +255.988 161.636 L +256.717 161.02 L +257.445 160.391 L +258.174 159.75 L +258.903 159.095 L +259.631 158.426 L +260.36 157.743 L +261.089 157.044 L +261.817 156.328 L +262.546 155.595 L +263.275 154.844 L +264.003 154.074 L +264.732 153.283 L +265.461 152.471 L +266.189 151.635 L +266.918 150.774 L +267.647 149.887 L +268.375 148.972 L +269.104 148.026 L +269.833 147.047 L +270.561 146.033 L +271.29 144.98 L +272.019 143.886 L +272.748 142.746 L +273.476 141.556 L +274.205 140.31 L +274.934 139.004 L +275.662 137.63 L +276.391 136.179 L +277.12 134.642 L +277.848 133.005 L +278.577 131.258 L +279.306 129.378 L +280.034 127.344 L +280.763 125.125 L +281.492 122.683 L +282.22 119.959 L +282.949 116.88 L +283.678 113.326 L +284.406 109.112 L +285.135 103.916 L +285.864 97.083 L +286.592 86.986 L +287.321 66.511 L +288.05 107.215 L +288.778 120.201 L +289.507 125.455 L +290.236 128.764 L +290.964 131.167 L +291.693 133.043 L +292.422 134.577 L +293.151 135.87 L +293.879 136.983 L +294.608 137.958 L +295.337 138.825 L +296.065 139.602 L +296.794 140.306 L +297.523 140.948 L +298.251 141.537 L +298.98 142.081 L +299.709 142.585 L +300.437 143.054 L +301.166 143.493 L +301.895 143.904 L +302.623 144.291 L +303.352 144.655 L +304.081 145 L +304.809 145.327 L +305.538 145.636 L +306.267 145.931 L +306.995 146.212 L +307.724 146.479 L +308.453 146.735 L +309.181 146.98 L +309.91 147.214 L +310.639 147.439 L +311.367 147.655 L +312.096 147.863 L +312.825 148.062 L +313.554 148.255 L +314.282 148.44 L +315.011 148.619 L +315.74 148.792 L +316.468 148.959 L +317.197 149.12 L +317.926 149.276 L +318.654 149.427 L +319.383 149.574 L +320.112 149.716 L +320.84 149.853 L +321.569 149.987 L +322.298 150.117 L +323.026 150.243 L +323.755 150.366 L +324.484 150.485 L +325.212 150.601 L +325.941 150.713 L +326.67 150.823 L +327.398 150.93 L +328.127 151.035 L +328.856 151.136 L +329.584 151.235 L +330.313 151.332 L +331.042 151.426 L +331.77 151.518 L +332.499 151.608 L +333.228 151.696 L +333.957 151.782 L +334.685 151.866 L +335.414 151.948 L +336.143 152.028 L +336.871 152.106 L +337.6 152.183 L +338.329 152.258 L +339.057 152.331 L +339.786 152.403 L +340.515 152.474 L +341.243 152.542 L +341.972 152.61 L +342.701 152.676 L +343.429 152.741 L +344.158 152.805 L +344.887 152.867 L +345.615 152.928 L +346.344 152.988 L +347.073 153.047 L +347.801 153.105 L +348.53 153.161 L +349.259 153.217 L +349.987 153.271 L +350.716 153.325 L +351.445 153.377 L +352.173 153.429 L +352.902 153.48 L +353.631 153.53 L +354.36 153.579 L +355.088 153.627 L +355.817 153.674 L +356.546 153.721 L +357.274 153.766 L +358.003 153.811 L +358.732 153.855 L +359.46 153.899 L +360.189 153.942 L +360.918 153.984 L +361.646 154.025 L +362.375 154.066 L +363.104 154.106 L +363.832 154.145 L +364.561 154.184 L +365.29 154.222 L +366.018 154.26 L +366.747 154.297 L +367.476 154.333 L +368.204 154.369 L +368.933 154.405 L +369.662 154.44 L +370.39 154.474 L +371.119 154.508 L +371.848 154.541 L +372.576 154.574 L +373.305 154.606 L +374.034 154.638 L +374.763 154.669 L +375.491 154.7 L +376.22 154.731 L +376.949 154.761 L +377.677 154.791 L +378.406 154.82 L +379.135 154.849 L +379.863 154.877 L +380.592 154.905 L +381.321 154.933 L +382.049 154.96 L +382.778 154.987 L +383.507 155.014 L +384.235 155.04 L +384.964 155.066 L +385.693 155.092 L +386.421 155.117 L +387.15 155.142 L +387.879 155.166 L +388.607 155.19 L +389.336 155.214 L +390.065 155.238 L +390.793 155.261 L +391.522 155.284 L +392.251 155.307 L +392.979 155.33 L +393.708 155.352 L +394.437 155.374 L +395.166 155.395 L +395.894 155.417 L +396.623 155.438 L +397.352 155.458 L +398.08 155.479 L +398.809 155.499 L +399.538 155.519 L +400.266 155.539 L +400.995 155.559 L +401.724 155.578 L +402.452 155.597 L +403.181 155.616 L +403.91 155.635 L +404.638 155.653 L +405.367 155.672 L +406.096 155.69 L +406.824 155.708 L +407.553 155.725 L +408.282 155.743 L +409.01 155.76 L +409.739 155.777 L +410.468 155.794 L +411.196 155.811 L +411.925 155.827 L +412.654 155.843 L +413.382 155.859 L +414.111 155.875 L +414.84 155.891 L +415.568 155.907 L +416.297 155.922 L +417.026 155.937 L +417.755 155.952 L +418.483 155.967 L +419.212 155.982 L +419.941 155.997 L +420.669 156.011 L +421.398 156.025 L +422.127 156.04 L +422.855 156.054 L +423.584 156.067 L +424.313 156.081 L +425.041 156.095 L +425.77 156.108 L +426.499 156.121 L +427.227 156.135 L +427.956 156.148 L +428.685 156.16 L +429.413 156.173 L +430.142 156.186 L +430.871 156.198 L +431.599 156.211 L +432.328 156.223 L +433.057 156.235 L +433.785 156.247 L +434.514 156.259 L +435.243 156.271 L +435.971 156.282 L +436.7 156.294 L +437.429 156.305 L +438.158 156.316 L +438.886 156.328 L +439.615 156.339 L +440.344 156.35 L +441.072 156.36 L +441.801 156.371 L +442.53 156.382 L +s +78.19 227.244 m +78.919 227.062 L +79.648 226.879 L +80.376 226.696 L +81.105 226.513 L +81.834 226.329 L +82.562 226.144 L +83.291 225.96 L +84.02 225.774 L +84.749 225.589 L +85.477 225.403 L +86.206 225.216 L +86.935 225.029 L +87.663 224.842 L +88.392 224.654 L +89.121 224.465 L +89.849 224.277 L +90.578 224.088 L +91.307 223.898 L +92.035 223.708 L +92.764 223.518 L +93.493 223.327 L +94.221 223.135 L +94.95 222.944 L +95.679 222.751 L +96.407 222.559 L +97.136 222.366 L +97.865 222.172 L +98.593 221.978 L +99.322 221.783 L +100.051 221.589 L +100.779 221.393 L +101.508 221.197 L +102.237 221.001 L +102.965 220.804 L +103.694 220.607 L +104.423 220.409 L +105.152 220.211 L +105.88 220.013 L +106.609 219.813 L +107.338 219.614 L +108.066 219.414 L +108.795 219.213 L +109.524 219.012 L +110.252 218.811 L +110.981 218.609 L +111.71 218.406 L +112.438 218.203 L +113.167 217.999 L +113.896 217.795 L +114.624 217.591 L +115.353 217.386 L +116.082 217.18 L +116.81 216.974 L +117.539 216.767 L +118.268 216.56 L +118.996 216.352 L +119.725 216.144 L +120.454 215.935 L +121.182 215.726 L +121.911 215.516 L +122.64 215.305 L +123.368 215.094 L +124.097 214.883 L +124.826 214.67 L +125.554 214.458 L +126.283 214.244 L +127.012 214.03 L +127.741 213.816 L +128.469 213.6 L +129.198 213.385 L +129.927 213.168 L +130.655 212.951 L +131.384 212.733 L +132.113 212.515 L +132.841 212.296 L +133.57 212.076 L +134.299 211.856 L +135.027 211.635 L +135.756 211.413 L +136.485 211.191 L +137.213 210.968 L +137.942 210.744 L +138.671 210.52 L +139.399 210.294 L +140.128 210.068 L +140.857 209.842 L +141.585 209.614 L +142.314 209.386 L +143.043 209.157 L +143.771 208.927 L +144.5 208.697 L +145.229 208.466 L +145.957 208.234 L +146.686 208.001 L +147.415 207.767 L +148.144 207.532 L +148.872 207.297 L +149.601 207.06 L +150.33 206.823 L +151.058 206.585 L +151.787 206.346 L +152.516 206.106 L +153.244 205.865 L +153.973 205.623 L +154.702 205.381 L +155.43 205.137 L +156.159 204.892 L +156.888 204.646 L +157.616 204.4 L +158.345 204.152 L +159.074 203.903 L +159.802 203.653 L +160.531 203.402 L +161.26 203.15 L +161.988 202.897 L +162.717 202.643 L +163.446 202.387 L +164.174 202.131 L +164.903 201.873 L +165.632 201.614 L +166.36 201.354 L +167.089 201.092 L +167.818 200.83 L +168.547 200.565 L +169.275 200.3 L +170.004 200.033 L +170.733 199.765 L +171.461 199.496 L +172.19 199.225 L +172.919 198.953 L +173.647 198.68 L +174.376 198.405 L +175.105 198.128 L +175.833 197.85 L +176.562 197.57 L +177.291 197.289 L +178.019 197.006 L +178.748 196.722 L +179.477 196.435 L +180.205 196.148 L +180.934 195.858 L +181.663 195.567 L +182.391 195.274 L +183.12 194.979 L +183.849 194.682 L +184.577 194.383 L +185.306 194.083 L +186.035 193.78 L +186.763 193.475 L +187.492 193.169 L +188.221 192.86 L +188.95 192.549 L +189.678 192.236 L +190.407 191.921 L +191.136 191.603 L +191.864 191.284 L +192.593 190.961 L +193.322 190.637 L +194.05 190.31 L +194.779 189.98 L +195.508 189.648 L +196.236 189.313 L +196.965 188.976 L +197.694 188.635 L +198.422 188.292 L +199.151 187.946 L +199.88 187.598 L +200.608 187.246 L +201.337 186.891 L +202.066 186.533 L +202.794 186.171 L +203.523 185.807 L +204.252 185.438 L +204.98 185.067 L +205.709 184.692 L +206.438 184.313 L +207.166 183.93 L +207.895 183.544 L +208.624 183.153 L +209.353 182.759 L +210.081 182.36 L +210.81 181.957 L +211.539 181.549 L +212.267 181.137 L +212.996 180.72 L +213.725 180.299 L +214.453 179.872 L +215.182 179.44 L +215.911 179.003 L +216.639 178.56 L +217.368 178.112 L +218.097 177.657 L +218.825 177.197 L +219.554 176.73 L +220.283 176.257 L +221.011 175.777 L +221.74 175.29 L +222.469 174.796 L +223.197 174.295 L +223.926 173.785 L +224.655 173.268 L +225.383 172.742 L +226.112 172.207 L +226.841 171.662 L +227.569 171.109 L +228.298 170.546 L +229.027 169.971 L +229.756 169.387 L +230.484 168.79 L +231.213 168.182 L +231.942 167.561 L +232.67 166.927 L +233.399 166.28 L +234.128 165.617 L +234.856 164.94 L +235.585 164.246 L +236.314 163.535 L +237.042 162.806 L +237.771 162.058 L +238.5 161.289 L +239.228 160.499 L +239.957 159.686 L +240.686 158.848 L +241.414 157.985 L +242.143 157.093 L +242.872 156.17 L +243.6 155.216 L +244.329 154.226 L +245.058 153.198 L +245.786 152.13 L +246.515 151.016 L +247.244 149.854 L +247.972 148.638 L +248.701 95.265 L +249.43 93.925 L +250.159 92.513 L +250.887 91.021 L +251.616 89.437 L +252.345 87.751 L +253.073 85.948 L +253.802 84.008 L +254.531 81.914 L +255.259 79.635 L +255.988 77.137 L +256.717 74.37 L +257.445 71.271 L +258.174 67.749 L +258.903 63.665 L +259.631 58.799 L +260.36 52.774 L +261.089 44.836 L +261.817 33.16 L +262.546 10.25 L +263.275 102.86 L +264.003 118.171 L +264.732 124.159 L +265.461 127.877 L +266.189 130.553 L +266.918 132.626 L +267.647 134.311 L +268.375 135.722 L +269.104 136.932 L +269.833 137.986 L +270.561 138.919 L +271.29 139.753 L +272.019 140.505 L +272.748 141.189 L +273.476 141.814 L +274.205 142.389 L +274.934 142.921 L +275.662 143.415 L +276.391 143.875 L +277.12 144.305 L +277.848 144.709 L +278.577 145.088 L +279.306 145.446 L +280.034 145.784 L +280.763 146.105 L +281.492 146.409 L +282.22 146.698 L +282.949 146.973 L +283.678 147.236 L +284.406 147.486 L +285.135 147.726 L +285.864 147.955 L +286.592 148.175 L +287.321 148.386 L +288.05 148.589 L +288.778 148.784 L +289.507 148.972 L +290.236 149.152 L +290.964 149.327 L +291.693 149.495 L +292.422 149.657 L +293.151 149.814 L +293.879 149.965 L +294.608 150.112 L +295.337 150.254 L +296.065 150.392 L +296.794 150.525 L +297.523 150.654 L +298.251 150.78 L +298.98 150.901 L +299.709 151.02 L +300.437 151.135 L +301.166 151.246 L +301.895 151.355 L +302.623 151.46 L +303.352 151.563 L +304.081 151.663 L +304.809 151.761 L +305.538 151.856 L +306.267 151.949 L +306.995 152.039 L +307.724 152.127 L +308.453 152.213 L +309.181 152.297 L +309.91 152.379 L +310.639 152.459 L +311.367 152.537 L +312.096 152.613 L +312.825 152.688 L +313.554 152.761 L +314.282 152.832 L +315.011 152.902 L +315.74 152.97 L +316.468 153.037 L +317.197 153.102 L +317.926 153.166 L +318.654 153.228 L +319.383 153.29 L +320.112 153.35 L +320.84 153.409 L +321.569 153.466 L +322.298 153.523 L +323.026 153.578 L +323.755 153.633 L +324.484 153.686 L +325.212 153.738 L +325.941 153.789 L +326.67 153.84 L +327.398 153.889 L +328.127 153.937 L +328.856 153.985 L +329.584 154.032 L +330.313 154.078 L +331.042 154.123 L +331.77 154.167 L +332.499 154.21 L +333.228 154.253 L +333.957 154.295 L +334.685 154.336 L +335.414 154.376 L +336.143 154.416 L +336.871 154.455 L +337.6 154.494 L +338.329 154.532 L +339.057 154.569 L +339.786 154.606 L +340.515 154.642 L +341.243 154.677 L +341.972 154.712 L +342.701 154.746 L +343.429 154.78 L +344.158 154.813 L +344.887 154.846 L +345.615 154.878 L +346.344 154.91 L +347.073 154.941 L +347.801 154.972 L +348.53 155.002 L +349.259 155.032 L +349.987 155.061 L +350.716 155.09 L +351.445 155.118 L +352.173 155.146 L +352.902 155.174 L +353.631 155.201 L +354.36 155.228 L +355.088 155.255 L +355.817 155.281 L +356.546 155.306 L +357.274 155.332 L +358.003 155.357 L +358.732 155.381 L +359.46 155.406 L +360.189 155.43 L +360.918 155.453 L +361.646 155.476 L +362.375 155.499 L +363.104 155.522 L +363.832 155.544 L +364.561 155.567 L +365.29 155.588 L +366.018 155.61 L +366.747 155.631 L +367.476 155.652 L +368.204 155.672 L +368.933 155.693 L +369.662 155.713 L +370.39 155.733 L +371.119 155.752 L +371.848 155.772 L +372.576 155.791 L +373.305 155.81 L +374.034 155.828 L +374.763 155.847 L +375.491 155.865 L +376.22 155.883 L +376.949 155.9 L +377.677 155.918 L +378.406 155.935 L +379.135 155.952 L +379.863 155.969 L +380.592 155.986 L +381.321 156.002 L +382.049 156.018 L +382.778 156.034 L +383.507 156.05 L +384.235 156.066 L +384.964 156.081 L +385.693 156.097 L +386.421 156.112 L +387.15 156.127 L +387.879 156.141 L +388.607 156.156 L +389.336 156.171 L +390.065 156.185 L +390.793 156.199 L +391.522 156.213 L +392.251 156.227 L +392.979 156.24 L +393.708 156.254 L +394.437 156.267 L +395.166 156.28 L +395.894 156.293 L +396.623 156.306 L +397.352 156.319 L +398.08 156.331 L +398.809 156.344 L +399.538 156.356 L +400.266 156.368 L +400.995 156.38 L +401.724 156.392 L +402.452 156.404 L +403.181 156.416 L +403.91 156.427 L +404.638 156.439 L +405.367 156.45 L +406.096 156.461 L +406.824 156.472 L +407.553 156.483 L +408.282 156.494 L +409.01 156.505 L +409.739 156.515 L +410.468 156.526 L +411.196 156.536 L +411.925 156.546 L +412.654 156.557 L +413.382 156.567 L +414.111 156.577 L +414.84 156.587 L +415.568 156.596 L +416.297 156.606 L +417.026 156.616 L +417.755 156.625 L +418.483 156.634 L +419.212 156.644 L +419.941 156.653 L +420.669 156.662 L +421.398 156.671 L +422.127 156.68 L +422.855 156.689 L +423.584 156.697 L +424.313 156.706 L +425.041 156.715 L +425.77 156.723 L +426.499 156.732 L +427.227 156.74 L +427.956 156.748 L +428.685 156.756 L +429.413 156.764 L +430.142 156.772 L +430.871 156.78 L +431.599 156.788 L +432.328 156.796 L +433.057 156.804 L +433.785 156.811 L +434.514 156.819 L +435.243 156.826 L +435.971 156.834 L +436.7 156.841 L +437.429 156.849 L +438.158 156.856 L +438.886 156.863 L +439.615 156.87 L +440.344 156.877 L +441.072 156.884 L +441.801 156.891 L +442.53 156.898 L +s +78.19 227.796 m +78.555 227.699 L +78.919 227.602 L +79.283 227.504 L +79.648 227.407 L +80.012 227.309 L +80.376 227.211 L +80.741 227.113 L +81.105 227.016 L +81.469 226.917 L +81.834 226.819 L +82.198 226.721 L +82.562 226.622 L +82.927 226.524 L +83.291 226.425 L +83.655 226.327 L +84.02 226.228 L +84.384 226.129 L +84.749 226.03 L +85.113 225.93 L +85.477 225.831 L +85.842 225.732 L +86.206 225.632 L +86.57 225.532 L +86.935 225.433 L +87.299 225.333 L +87.663 225.233 L +88.028 225.133 L +88.392 225.032 L +88.756 224.932 L +89.121 224.832 L +89.485 224.731 L +89.849 224.63 L +90.214 224.53 L +90.578 224.429 L +90.942 224.328 L +91.307 224.227 L +91.671 224.125 L +92.035 224.024 L +92.4 223.923 L +92.764 223.821 L +93.128 223.719 L +93.493 223.618 L +93.857 223.516 L +94.221 223.414 L +94.586 223.311 L +94.95 223.209 L +95.314 223.107 L +95.679 223.004 L +96.043 222.902 L +96.407 222.799 L +96.772 222.696 L +97.136 222.593 L +97.5 222.49 L +97.865 222.387 L +98.229 222.284 L +98.593 222.18 L +98.958 222.077 L +99.322 221.973 L +99.686 221.869 L +100.051 221.765 L +100.415 221.661 L +100.779 221.557 L +101.144 221.453 L +101.508 221.349 L +101.872 221.244 L +102.237 221.14 L +102.601 221.035 L +102.965 220.93 L +103.33 220.825 L +103.694 220.72 L +104.058 220.615 L +104.423 220.51 L +104.787 220.404 L +105.152 220.299 L +105.516 220.193 L +105.88 220.087 L +106.245 219.981 L +106.609 219.875 L +106.973 219.769 L +107.338 219.663 L +107.702 219.556 L +108.066 219.45 L +108.431 219.343 L +108.795 219.236 L +109.159 219.129 L +109.524 219.022 L +109.888 218.915 L +110.252 218.808 L +110.617 218.7 L +110.981 218.593 L +111.345 218.485 L +111.71 218.377 L +112.074 218.269 L +112.438 218.161 L +112.803 218.053 L +113.167 217.945 L +113.531 217.836 L +113.896 217.727 L +114.26 217.619 L +114.624 217.51 L +114.989 217.401 L +115.353 217.291 L +115.717 217.182 L +116.082 217.073 L +116.446 216.963 L +116.81 216.853 L +117.175 216.743 L +117.539 216.633 L +117.903 216.523 L +118.268 216.413 L +118.632 216.303 L +118.996 216.192 L +119.361 216.081 L +119.725 215.97 L +120.089 215.859 L +120.454 215.748 L +120.818 215.637 L +121.182 215.525 L +121.547 215.414 L +121.911 215.302 L +122.275 215.19 L +122.64 215.078 L +123.004 214.965 L +123.368 214.853 L +123.733 214.74 L +124.097 214.628 L +124.461 214.515 L +124.826 214.402 L +125.19 214.288 L +125.554 214.175 L +125.919 214.061 L +126.283 213.948 L +126.648 213.834 L +127.012 213.72 L +127.376 213.605 L +127.741 213.491 L +128.105 213.376 L +128.469 213.262 L +128.834 213.147 L +129.198 213.032 L +129.562 212.916 L +129.927 212.801 L +130.291 212.685 L +130.655 212.57 L +131.02 212.454 L +131.384 212.337 L +131.748 212.221 L +132.113 212.105 L +132.477 211.988 L +132.841 211.871 L +133.206 211.754 L +133.57 211.636 L +133.934 211.519 L +134.299 211.401 L +134.663 211.283 L +135.027 211.165 L +135.392 211.047 L +135.756 210.928 L +136.12 210.81 L +136.485 210.691 L +136.849 210.572 L +137.213 210.452 L +137.578 210.332 L +137.942 210.213 L +138.306 210.093 L +138.671 209.973 L +139.035 209.852 L +139.399 209.732 L +139.764 209.611 L +140.128 209.49 L +140.492 209.368 L +140.857 209.247 L +141.221 209.125 L +141.585 209.003 L +141.95 208.881 L +142.314 208.758 L +142.678 208.635 L +143.043 208.513 L +143.407 208.389 L +143.771 208.266 L +144.136 208.142 L +144.5 208.018 L +144.864 207.894 L +145.229 207.77 L +145.593 207.645 L +145.957 207.52 L +146.322 207.395 L +146.686 207.269 L +147.051 207.143 L +147.415 207.017 L +147.779 206.891 L +148.144 206.764 L +148.508 206.637 L +148.872 206.51 L +149.237 206.383 L +149.601 206.255 L +149.965 206.127 L +150.33 205.999 L +150.694 205.87 L +151.058 205.741 L +151.423 205.612 L +151.787 205.483 L +152.151 205.353 L +152.516 205.223 L +152.88 205.092 L +153.244 204.962 L +153.609 204.831 L +153.973 204.699 L +154.337 204.567 L +154.702 204.435 L +155.066 204.303 L +155.43 204.17 L +155.795 204.037 L +156.159 203.904 L +156.523 203.77 L +156.888 203.636 L +157.252 203.502 L +157.616 203.367 L +157.981 203.232 L +158.345 203.096 L +158.709 202.961 L +159.074 202.824 L +159.438 202.688 L +159.802 202.551 L +160.167 202.414 L +160.531 202.276 L +160.895 202.138 L +161.26 201.999 L +161.624 201.86 L +161.988 201.721 L +162.353 201.581 L +162.717 201.441 L +163.081 201.301 L +163.446 201.16 L +163.81 201.018 L +164.174 200.877 L +164.539 200.735 L +164.903 200.592 L +165.267 200.449 L +165.632 200.305 L +165.996 200.161 L +166.36 200.017 L +166.725 199.872 L +167.089 199.727 L +167.454 199.581 L +167.818 199.435 L +168.182 199.288 L +168.547 199.141 L +168.911 198.993 L +169.275 198.845 L +169.64 198.696 L +170.004 198.547 L +170.368 198.397 L +170.733 198.247 L +171.097 198.097 L +171.461 197.945 L +171.826 197.793 L +172.19 197.641 L +172.554 197.488 L +172.919 197.335 L +173.283 197.181 L +173.647 197.026 L +174.012 196.871 L +174.376 196.716 L +174.74 196.559 L +175.105 196.403 L +175.469 196.245 L +175.833 196.087 L +176.198 195.929 L +176.562 195.77 L +176.926 195.61 L +177.291 195.449 L +177.655 195.288 L +178.019 195.126 L +178.384 194.964 L +178.748 194.801 L +179.112 194.637 L +179.477 194.473 L +179.841 194.308 L +180.205 194.142 L +180.57 193.976 L +180.934 193.809 L +181.298 193.641 L +181.663 193.472 L +182.027 193.304 L +182.391 193.134 L +182.756 192.963 L +183.12 192.791 L +183.484 192.62 L +183.849 192.447 L +184.213 192.273 L +184.577 192.098 L +184.942 191.923 L +185.306 191.747 L +185.67 191.57 L +186.035 191.392 L +186.399 191.214 L +186.763 191.035 L +187.128 190.854 L +187.492 190.673 L +187.856 190.491 L +188.221 190.309 L +188.585 190.125 L +188.95 189.94 L +189.314 189.755 L +189.678 189.568 L +190.043 189.381 L +190.407 189.192 L +190.771 189.003 L +191.136 188.813 L +191.5 188.622 L +191.864 188.429 L +192.229 188.236 L +192.593 188.042 L +192.957 187.847 L +193.322 187.65 L +193.686 187.453 L +194.05 187.254 L +194.415 187.054 L +194.779 186.854 L +195.143 186.652 L +195.508 186.449 L +195.872 186.244 L +196.236 186.039 L +196.601 185.832 L +196.965 185.625 L +197.329 185.415 L +197.694 185.205 L +198.058 184.994 L +198.422 184.781 L +198.787 184.567 L +199.151 184.351 L +199.515 184.134 L +199.88 131.817 L +200.244 131.597 L +200.608 131.376 L +200.973 131.153 L +201.337 130.93 L +201.701 130.704 L +202.066 130.477 L +202.43 130.249 L +202.794 130.019 L +203.159 129.787 L +203.523 129.554 L +203.887 129.318 L +204.252 129.082 L +204.616 128.844 L +204.98 128.604 L +205.345 128.362 L +205.709 128.118 L +206.073 127.873 L +206.438 127.625 L +206.802 127.376 L +207.166 127.125 L +207.531 126.872 L +207.895 126.616 L +208.259 126.358 L +208.624 126.099 L +208.988 125.837 L +209.353 125.573 L +209.717 125.307 L +210.081 125.038 L +210.446 124.767 L +210.81 124.494 L +211.174 124.217 L +211.539 123.939 L +211.903 123.657 L +212.267 123.373 L +212.632 123.086 L +212.996 122.797 L +213.36 122.504 L +213.725 122.208 L +214.089 121.91 L +214.453 121.608 L +214.818 121.302 L +215.182 120.994 L +215.546 120.681 L +215.911 120.366 L +216.275 120.046 L +216.639 119.723 L +217.004 119.395 L +217.368 119.064 L +217.732 118.728 L +218.097 118.389 L +218.461 118.044 L +218.825 117.695 L +219.19 117.34 L +219.554 116.982 L +219.918 116.617 L +220.283 116.248 L +220.647 115.872 L +221.011 115.491 L +221.376 115.103 L +221.74 114.71 L +222.104 114.31 L +222.469 113.903 L +222.833 113.488 L +223.197 113.067 L +223.562 112.637 L +223.926 112.199 L +224.29 111.753 L +224.655 111.297 L +225.019 110.833 L +225.383 110.358 L +225.748 109.874 L +226.112 109.378 L +226.476 108.871 L +226.841 108.353 L +227.205 107.821 L +227.569 107.276 L +227.934 106.717 L +228.298 106.144 L +228.662 105.556 L +229.027 104.951 L +229.391 104.329 L +229.756 103.689 L +230.12 103.031 L +230.484 102.352 L +230.849 101.653 L +231.213 100.932 L +231.577 100.19 L +231.942 99.426 L +232.306 98.638 L +232.67 97.827 L +233.035 96.995 L +233.399 96.143 L +233.763 95.275 L +234.128 94.395 L +234.492 93.515 L +234.856 92.647 L +235.221 91.816 L +235.585 91.055 L +235.949 90.419 L +236.314 89.987 L +236.678 89.872 L +237.042 90.228 L +237.407 91.227 L +237.771 93.008 L +238.135 95.595 L +238.5 98.813 L +238.864 102.357 L +239.228 105.928 L +239.593 109.305 L +239.957 112.388 L +240.321 115.15 L +240.686 117.611 L +241.05 119.793 L +241.414 121.734 L +241.779 123.473 L +242.143 125.035 L +242.507 126.442 L +242.872 127.722 L +243.236 128.889 L +243.6 129.959 L +243.965 130.941 L +244.329 131.852 L +244.693 132.693 L +245.058 133.477 L +245.422 134.21 L +245.786 134.895 L +246.151 135.537 L +246.515 136.14 L +246.879 136.711 L +247.244 137.249 L +247.608 137.759 L +247.972 138.243 L +248.337 138.702 L +248.701 139.14 L +249.065 139.557 L +249.43 139.955 L +249.794 140.335 L +250.159 140.699 L +250.523 141.048 L +250.887 141.382 L +251.252 141.704 L +251.616 142.013 L +251.98 142.31 L +252.345 142.596 L +252.709 142.871 L +253.073 143.138 L +253.438 143.394 L +253.802 143.643 L +254.166 143.882 L +254.531 144.115 L +254.895 144.339 L +255.259 144.557 L +255.624 144.768 L +255.988 144.972 L +256.352 145.171 L +256.717 145.364 L +257.081 145.551 L +257.445 145.733 L +257.81 145.91 L +258.174 146.082 L +258.538 146.25 L +258.903 146.413 L +259.267 146.572 L +259.631 146.727 L +259.996 146.878 L +260.36 147.025 L +260.724 147.169 L +261.089 147.309 L +261.453 147.446 L +261.817 147.579 L +262.182 147.71 L +262.546 147.837 L +262.91 147.962 L +263.275 148.084 L +263.639 148.203 L +264.003 148.32 L +264.368 148.434 L +264.732 148.546 L +265.096 148.655 L +265.461 148.763 L +265.825 148.868 L +266.189 148.97 L +266.554 149.071 L +266.918 149.17 L +267.282 149.267 L +267.647 149.362 L +268.011 149.455 L +268.375 149.547 L +268.74 149.636 L +269.104 149.724 L +269.468 149.811 L +269.833 149.896 L +270.197 149.979 L +270.561 150.061 L +270.926 150.141 L +271.29 150.22 L +271.655 150.298 L +272.019 150.374 L +272.383 150.449 L +272.748 150.523 L +273.112 150.595 L +273.476 150.667 L +273.841 150.737 L +274.205 150.806 L +274.569 150.874 L +274.934 150.941 L +275.298 151.006 L +275.662 151.071 L +276.027 151.135 L +276.391 151.198 L +276.755 151.259 L +277.12 151.32 L +277.484 151.38 L +277.848 151.439 L +278.213 151.497 L +278.577 151.554 L +278.941 151.611 L +279.306 151.666 L +279.67 151.721 L +280.034 151.775 L +280.399 151.828 L +280.763 151.881 L +281.127 151.932 L +281.492 151.983 L +281.856 152.034 L +282.22 152.083 L +282.585 152.132 L +282.949 152.181 L +283.313 152.228 L +283.678 152.275 L +284.042 152.321 L +284.406 152.367 L +284.771 152.412 L +285.135 152.457 L +285.499 152.501 L +285.864 152.544 L +286.228 152.587 L +286.592 152.63 L +286.957 152.671 L +287.321 152.713 L +287.685 152.753 L +288.05 152.794 L +288.414 152.833 L +288.778 152.872 L +289.143 152.911 L +289.507 152.949 L +289.871 152.987 L +290.236 153.025 L +290.6 153.062 L +290.964 153.098 L +291.329 153.134 L +291.693 153.17 L +292.058 153.205 L +292.422 153.24 L +292.786 153.274 L +293.151 153.308 L +293.515 153.342 L +293.879 153.375 L +294.244 153.408 L +294.608 153.44 L +294.972 153.473 L +295.337 153.504 L +295.701 153.536 L +296.065 153.567 L +296.43 153.597 L +296.794 153.628 L +297.158 153.658 L +297.523 153.688 L +297.887 153.717 L +298.251 153.746 L +298.616 153.775 L +298.98 153.803 L +299.344 153.832 L +299.709 153.86 L +300.073 153.887 L +300.437 153.914 L +300.802 153.941 L +301.166 153.968 L +301.53 153.995 L +301.895 154.021 L +302.259 154.047 L +302.623 154.072 L +302.988 154.098 L +303.352 154.123 L +303.716 154.148 L +304.081 154.173 L +304.445 154.197 L +304.809 154.221 L +305.174 154.245 L +305.538 154.269 L +305.902 154.292 L +306.267 154.315 L +306.631 154.338 L +306.995 154.361 L +307.36 154.384 L +307.724 154.406 L +308.088 154.428 L +308.453 154.45 L +308.817 154.472 L +309.181 154.493 L +309.546 154.515 L +309.91 154.536 L +310.274 154.557 L +310.639 154.578 L +311.003 154.598 L +311.367 154.618 L +311.732 154.639 L +312.096 154.659 L +312.461 154.678 L +312.825 154.698 L +313.189 154.717 L +313.554 154.737 L +313.918 154.756 L +314.282 154.775 L +314.647 154.793 L +315.011 154.812 L +315.375 154.83 L +315.74 154.849 L +316.104 154.867 L +316.468 154.885 L +316.833 154.902 L +317.197 154.92 L +317.561 154.938 L +317.926 154.955 L +318.29 154.972 L +318.654 154.989 L +319.019 155.006 L +319.383 155.023 L +319.747 155.039 L +320.112 155.056 L +320.476 155.072 L +320.84 155.088 L +321.205 155.104 L +321.569 155.12 L +321.933 155.136 L +322.298 155.152 L +322.662 155.167 L +323.026 155.183 L +323.391 155.198 L +323.755 155.213 L +324.119 155.228 L +324.484 155.243 L +324.848 155.258 L +325.212 155.272 L +325.577 155.287 L +325.941 155.301 L +326.305 155.316 L +326.67 155.33 L +327.034 155.344 L +327.398 155.358 L +327.763 155.372 L +328.127 155.386 L +328.491 155.399 L +328.856 155.413 L +329.22 155.426 L +329.584 155.439 L +329.949 155.453 L +330.313 155.466 L +330.677 155.479 L +331.042 155.492 L +331.406 155.505 L +331.77 155.517 L +332.135 155.53 L +332.499 155.542 L +332.864 155.555 L +333.228 155.567 L +333.592 155.579 L +333.957 155.592 L +334.321 155.604 L +334.685 155.616 L +335.05 155.628 L +335.414 155.639 L +335.778 155.651 L +336.143 155.663 L +336.507 155.674 L +336.871 155.686 L +337.236 155.697 L +337.6 155.708 L +337.964 155.719 L +338.329 155.731 L +338.693 155.742 L +339.057 155.753 L +339.422 155.763 L +339.786 155.774 L +340.15 155.785 L +340.515 155.796 L +340.879 155.806 L +341.243 155.817 L +341.608 155.827 L +341.972 155.838 L +342.336 155.848 L +342.701 155.858 L +343.065 155.868 L +343.429 155.878 L +343.794 155.888 L +344.158 155.898 L +344.522 155.908 L +344.887 155.918 L +345.251 155.927 L +345.615 155.937 L +345.98 155.947 L +346.344 155.956 L +346.708 155.966 L +347.073 155.975 L +347.437 155.984 L +347.801 155.994 L +348.166 156.003 L +348.53 156.012 L +348.894 156.021 L +349.259 156.03 L +349.623 156.039 L +349.987 156.048 L +350.352 156.057 L +350.716 156.065 L +351.08 156.074 L +351.445 156.083 L +351.809 156.091 L +352.173 156.1 L +352.538 156.108 L +352.902 156.117 L +353.266 156.125 L +353.631 156.133 L +353.995 156.142 L +354.36 156.15 L +354.724 156.158 L +355.088 156.166 L +355.453 156.174 L +355.817 156.182 L +356.181 156.19 L +356.546 156.198 L +356.91 156.206 L +357.274 156.214 L +357.639 156.221 L +358.003 156.229 L +358.367 156.237 L +358.732 156.244 L +359.096 156.252 L +359.46 156.259 L +359.825 156.267 L +360.189 156.274 L +360.553 156.282 L +360.918 156.289 L +361.282 156.296 L +361.646 156.303 L +362.011 156.311 L +362.375 156.318 L +362.739 156.325 L +363.104 156.332 L +363.468 156.339 L +363.832 156.346 L +364.197 156.353 L +364.561 156.36 L +364.925 156.366 L +365.29 156.373 L +365.654 156.38 L +366.018 156.387 L +366.383 156.393 L +366.747 156.4 L +367.111 156.407 L +367.476 156.413 L +367.84 156.42 L +368.204 156.426 L +368.569 156.433 L +368.933 156.439 L +369.297 156.445 L +369.662 156.452 L +370.026 156.458 L +370.39 156.464 L +370.755 156.47 L +371.119 156.476 L +371.483 156.483 L +371.848 156.489 L +372.212 156.495 L +372.576 156.501 L +372.941 156.507 L +373.305 156.513 L +373.669 156.519 L +374.034 156.524 L +374.398 156.53 L +374.763 156.536 L +375.127 156.542 L +375.491 156.548 L +375.856 156.553 L +376.22 156.559 L +376.584 156.565 L +376.949 156.57 L +377.313 156.576 L +377.677 156.581 L +378.042 156.587 L +378.406 156.592 L +378.77 156.598 L +379.135 156.603 L +379.499 156.609 L +379.863 156.614 L +380.228 156.619 L +380.592 156.625 L +380.956 156.63 L +381.321 156.635 L +381.685 156.64 L +382.049 156.646 L +382.414 156.651 L +382.778 156.656 L +383.142 156.661 L +383.507 156.666 L +383.871 156.671 L +384.235 156.676 L +384.6 156.681 L +384.964 156.686 L +385.328 156.691 L +385.693 156.696 L +386.057 156.701 L +386.421 156.706 L +386.786 156.71 L +387.15 156.715 L +387.514 156.72 L +387.879 156.725 L +388.243 156.729 L +388.607 156.734 L +388.972 156.739 L +389.336 156.743 L +389.7 156.748 L +390.065 156.753 L +390.429 156.757 L +390.793 156.762 L +391.158 156.766 L +391.522 156.771 L +391.886 156.775 L +392.251 156.78 L +392.615 156.784 L +392.979 156.788 L +393.344 156.793 L +393.708 156.797 L +394.072 156.802 L +394.437 156.806 L +394.801 156.81 L +395.166 156.814 L +395.53 156.819 L +395.894 156.823 L +396.259 156.827 L +396.623 156.831 L +396.987 156.835 L +397.352 156.84 L +397.716 156.844 L +398.08 156.848 L +398.445 156.852 L +398.809 156.856 L +399.173 156.86 L +399.538 156.864 L +399.902 156.868 L +400.266 156.872 L +400.631 156.876 L +400.995 156.88 L +401.359 156.884 L +401.724 156.887 L +402.088 156.891 L +402.452 156.895 L +402.817 156.899 L +403.181 156.903 L +403.545 156.907 L +403.91 156.91 L +404.274 156.914 L +404.638 156.918 L +405.003 156.921 L +405.367 156.925 L +405.731 156.929 L +406.096 156.933 L +406.46 156.936 L +406.824 156.94 L +407.189 156.943 L +407.553 156.947 L +407.917 156.95 L +408.282 156.954 L +408.646 156.958 L +409.01 156.961 L +409.375 156.965 L +409.739 156.968 L +410.103 156.972 L +410.468 156.975 L +410.832 156.978 L +411.196 156.982 L +411.561 156.985 L +411.925 156.989 L +412.289 156.992 L +412.654 156.995 L +413.018 156.999 L +413.382 157.002 L +413.747 157.005 L +414.111 157.008 L +414.475 157.012 L +414.84 157.015 L +415.204 157.018 L +415.568 157.021 L +415.933 157.025 L +416.297 157.028 L +416.662 157.031 L +417.026 157.034 L +417.39 157.037 L +417.755 157.04 L +418.119 157.043 L +418.483 157.047 L +418.848 157.05 L +419.212 157.053 L +419.576 157.056 L +419.941 157.059 L +420.305 157.062 L +420.669 157.065 L +421.034 157.068 L +421.398 157.071 L +421.762 157.074 L +422.127 157.077 L +422.491 157.08 L +422.855 157.083 L +423.22 157.085 L +423.584 157.088 L +423.948 157.091 L +424.313 157.094 L +424.677 157.097 L +425.041 157.1 L +425.406 157.103 L +425.77 157.105 L +426.134 157.108 L +426.499 157.111 L +426.863 157.114 L +427.227 157.117 L +427.592 157.119 L +427.956 157.122 L +428.32 157.125 L +428.685 157.127 L +429.049 157.13 L +429.413 157.133 L +429.778 157.136 L +430.142 157.138 L +430.506 157.141 L +430.871 157.143 L +431.235 157.146 L +431.599 157.149 L +431.964 157.151 L +432.328 157.154 L +432.692 157.156 L +433.057 157.159 L +433.421 157.162 L +433.785 157.164 L +434.15 157.167 L +434.514 157.169 L +434.878 157.172 L +435.243 157.174 L +435.607 157.177 L +435.971 157.179 L +436.336 157.182 L +436.7 157.184 L +437.065 157.187 L +437.429 157.189 L +437.793 157.191 L +438.158 157.194 L +438.522 157.196 L +438.886 157.199 L +439.251 157.201 L +439.615 157.203 L +439.979 157.206 L +440.344 157.208 L +440.708 157.21 L +441.072 157.213 L +441.437 157.215 L +441.801 157.217 L +442.165 157.22 L +442.53 157.222 L +s +78.19 230.21 m +78.919 229.983 L +79.648 229.756 L +80.376 229.529 L +81.105 229.302 L +81.834 229.074 L +82.562 228.847 L +83.291 228.619 L +84.02 228.391 L +84.749 228.163 L +85.477 227.935 L +86.206 227.707 L +86.935 227.479 L +87.663 227.251 L +88.392 227.023 L +89.121 226.795 L +89.849 226.567 L +90.578 226.339 L +91.307 226.111 L +92.035 225.884 L +92.764 225.656 L +93.493 225.429 L +94.221 225.201 L +94.95 224.974 L +95.679 224.747 L +96.407 224.52 L +97.136 224.294 L +97.865 224.067 L +98.593 223.841 L +99.322 223.615 L +100.051 223.39 L +100.779 223.164 L +101.508 222.939 L +102.237 222.714 L +102.965 222.49 L +103.694 222.266 L +104.423 222.042 L +105.152 221.819 L +105.88 221.596 L +106.609 221.373 L +107.338 221.151 L +108.066 220.929 L +108.795 220.707 L +109.524 220.486 L +110.252 220.265 L +110.981 220.045 L +111.71 219.825 L +112.438 219.606 L +113.167 219.387 L +113.896 219.169 L +114.624 218.951 L +115.353 218.733 L +116.082 218.517 L +116.81 218.3 L +117.539 218.085 L +118.268 217.869 L +118.996 217.655 L +119.725 217.44 L +120.454 217.227 L +121.182 217.014 L +121.911 216.801 L +122.64 216.59 L +123.368 216.378 L +124.097 216.168 L +124.826 215.958 L +125.554 215.748 L +126.283 215.539 L +127.012 163.232 L +127.741 163.025 L +128.469 162.818 L +129.198 162.612 L +129.927 162.406 L +130.655 162.201 L +131.384 161.997 L +132.113 161.794 L +132.841 161.591 L +133.57 161.39 L +134.299 161.188 L +135.027 160.988 L +135.756 160.789 L +136.485 160.59 L +137.213 160.392 L +137.942 160.194 L +138.671 159.998 L +139.399 159.803 L +140.128 159.608 L +140.857 159.414 L +141.585 159.221 L +142.314 159.029 L +143.043 158.839 L +143.771 158.648 L +144.5 158.459 L +145.229 158.271 L +145.957 158.084 L +146.686 157.898 L +147.415 157.714 L +148.144 157.53 L +148.872 157.347 L +149.601 157.166 L +150.33 156.985 L +151.058 156.806 L +151.787 156.628 L +152.516 156.452 L +153.244 156.277 L +153.973 156.103 L +154.702 155.931 L +155.43 155.761 L +156.159 155.591 L +156.888 155.424 L +157.616 155.258 L +158.345 155.094 L +159.074 154.931 L +159.802 154.771 L +160.531 154.612 L +161.26 154.455 L +161.988 154.3 L +162.717 154.148 L +163.446 153.997 L +164.174 153.849 L +164.903 153.703 L +165.632 153.56 L +166.36 153.419 L +167.089 153.28 L +167.818 153.145 L +168.547 153.012 L +169.275 152.882 L +170.004 152.754 L +170.733 152.631 L +171.461 152.51 L +172.19 152.392 L +172.919 152.278 L +173.647 152.167 L +174.376 152.06 L +175.105 151.956 L +175.833 151.856 L +176.562 151.76 L +177.291 151.668 L +178.019 151.58 L +178.748 151.497 L +179.477 151.417 L +180.205 151.342 L +180.934 151.271 L +181.663 151.205 L +182.391 151.143 L +183.12 151.086 L +183.849 151.033 L +184.577 150.985 L +185.306 150.942 L +186.035 150.904 L +186.763 150.87 L +187.492 150.841 L +188.221 150.817 L +188.95 150.797 L +189.678 150.783 L +190.407 150.773 L +191.136 150.767 L +191.864 150.766 L +192.593 150.77 L +193.322 150.778 L +194.05 150.79 L +194.779 150.806 L +195.508 150.827 L +196.236 150.851 L +196.965 150.88 L +197.694 150.911 L +198.422 150.947 L +199.151 150.986 L +199.88 151.028 L +200.608 151.073 L +201.337 151.121 L +202.066 151.172 L +202.794 151.225 L +203.523 151.281 L +204.252 151.339 L +204.98 151.398 L +205.709 151.46 L +206.438 151.524 L +207.166 151.589 L +207.895 151.656 L +208.624 151.723 L +209.353 151.792 L +210.081 151.862 L +210.81 151.933 L +211.539 152.005 L +212.267 152.077 L +212.996 152.149 L +213.725 152.222 L +214.453 152.295 L +215.182 152.368 L +215.911 152.441 L +216.639 152.515 L +217.368 152.588 L +218.097 152.661 L +218.825 152.733 L +219.554 152.806 L +220.283 152.877 L +221.011 152.949 L +221.74 153.019 L +222.469 153.09 L +223.197 153.159 L +223.926 153.228 L +224.655 153.296 L +225.383 153.364 L +226.112 153.431 L +226.841 153.497 L +227.569 153.562 L +228.298 153.626 L +229.027 153.69 L +229.756 153.753 L +230.484 153.815 L +231.213 153.876 L +231.942 153.936 L +232.67 153.995 L +233.399 154.053 L +234.128 154.111 L +234.856 154.167 L +235.585 154.223 L +236.314 154.278 L +237.042 154.332 L +237.771 154.385 L +238.5 154.437 L +239.228 154.488 L +239.957 154.539 L +240.686 154.589 L +241.414 154.637 L +242.143 154.685 L +242.872 154.733 L +243.6 154.779 L +244.329 154.824 L +245.058 154.869 L +245.786 154.913 L +246.515 154.957 L +247.244 154.999 L +247.972 155.041 L +248.701 155.082 L +249.43 155.122 L +250.159 155.162 L +250.887 155.201 L +251.616 155.239 L +252.345 155.276 L +253.073 155.313 L +253.802 155.35 L +254.531 155.385 L +255.259 155.42 L +255.988 155.455 L +256.717 155.488 L +257.445 155.521 L +258.174 155.554 L +258.903 155.586 L +259.631 155.618 L +260.36 155.648 L +261.089 155.679 L +261.817 155.709 L +262.546 155.738 L +263.275 155.767 L +264.003 155.795 L +264.732 155.823 L +265.461 155.85 L +266.189 155.877 L +266.918 155.904 L +267.647 155.93 L +268.375 155.955 L +269.104 155.98 L +269.833 156.005 L +270.561 156.029 L +271.29 156.053 L +272.019 156.077 L +272.748 156.1 L +273.476 156.122 L +274.205 156.145 L +274.934 156.167 L +275.662 156.188 L +276.391 156.209 L +277.12 156.23 L +277.848 156.251 L +278.577 156.271 L +279.306 156.291 L +280.034 156.31 L +280.763 156.33 L +281.492 156.349 L +282.22 156.367 L +282.949 156.385 L +283.678 156.404 L +284.406 156.421 L +285.135 156.439 L +285.864 156.456 L +286.592 156.473 L +287.321 156.49 L +288.05 156.506 L +288.778 156.522 L +289.507 156.538 L +290.236 156.554 L +290.964 156.569 L +291.693 156.584 L +292.422 156.599 L +293.151 156.614 L +293.879 156.628 L +294.608 156.643 L +295.337 156.657 L +296.065 156.671 L +296.794 156.684 L +297.523 156.698 L +298.251 156.711 L +298.98 156.724 L +299.709 156.737 L +300.437 156.75 L +301.166 156.762 L +301.895 156.774 L +302.623 156.787 L +303.352 156.799 L +304.081 156.81 L +304.809 156.822 L +305.538 156.833 L +306.267 156.845 L +306.995 156.856 L +307.724 156.867 L +308.453 156.878 L +309.181 156.888 L +309.91 156.899 L +310.639 156.909 L +311.367 156.92 L +312.096 156.93 L +312.825 156.94 L +313.554 156.949 L +314.282 156.959 L +315.011 156.969 L +315.74 156.978 L +316.468 156.988 L +317.197 156.997 L +317.926 157.006 L +318.654 157.015 L +319.383 157.024 L +320.112 157.032 L +320.84 157.041 L +321.569 157.049 L +322.298 157.058 L +323.026 157.066 L +323.755 157.074 L +324.484 157.082 L +325.212 157.09 L +325.941 157.098 L +326.67 157.106 L +327.398 157.113 L +328.127 157.121 L +328.856 157.128 L +329.584 157.136 L +330.313 157.143 L +331.042 157.15 L +331.77 157.157 L +332.499 157.164 L +333.228 157.171 L +333.957 157.178 L +334.685 157.185 L +335.414 157.192 L +336.143 157.198 L +336.871 157.205 L +337.6 157.211 L +338.329 157.217 L +339.057 157.224 L +339.786 157.23 L +340.515 157.236 L +341.243 157.242 L +341.972 157.248 L +342.701 157.254 L +343.429 157.26 L +344.158 157.266 L +344.887 157.271 L +345.615 157.277 L +346.344 157.283 L +347.073 157.288 L +347.801 157.294 L +348.53 157.299 L +349.259 157.304 L +349.987 157.31 L +350.716 157.315 L +351.445 157.32 L +352.173 157.325 L +352.902 157.33 L +353.631 157.335 L +354.36 157.34 L +355.088 157.345 L +355.817 157.35 L +356.546 157.354 L +357.274 157.359 L +358.003 157.364 L +358.732 157.368 L +359.46 157.373 L +360.189 157.377 L +360.918 157.382 L +361.646 157.386 L +362.375 157.391 L +363.104 157.395 L +363.832 157.399 L +364.561 157.403 L +365.29 157.408 L +366.018 157.412 L +366.747 157.416 L +367.476 157.42 L +368.204 157.424 L +368.933 157.428 L +369.662 157.432 L +370.39 157.436 L +371.119 157.439 L +371.848 157.443 L +372.576 157.447 L +373.305 157.451 L +374.034 157.454 L +374.763 157.458 L +375.491 157.462 L +376.22 157.465 L +376.949 157.469 L +377.677 157.472 L +378.406 157.476 L +379.135 157.479 L +379.863 157.482 L +380.592 157.486 L +381.321 157.489 L +382.049 157.492 L +382.778 157.496 L +383.507 157.499 L +384.235 157.502 L +384.964 157.505 L +385.693 157.508 L +386.421 157.512 L +387.15 157.515 L +387.879 157.518 L +388.607 157.521 L +389.336 157.524 L +390.065 157.527 L +390.793 157.53 L +391.522 157.532 L +392.251 157.535 L +392.979 157.538 L +393.708 157.541 L +394.437 157.544 L +395.166 157.547 L +395.894 157.549 L +396.623 157.552 L +397.352 157.555 L +398.08 157.557 L +398.809 157.56 L +399.538 157.563 L +400.266 157.565 L +400.995 157.568 L +401.724 157.57 L +402.452 157.573 L +403.181 157.575 L +403.91 157.578 L +404.638 157.58 L +405.367 157.583 L +406.096 157.585 L +406.824 157.587 L +407.553 157.59 L +408.282 157.592 L +409.01 157.594 L +409.739 157.597 L +410.468 157.599 L +411.196 157.601 L +411.925 157.603 L +412.654 157.606 L +413.382 157.608 L +414.111 157.61 L +414.84 157.612 L +415.568 157.614 L +416.297 157.616 L +417.026 157.619 L +417.755 157.621 L +418.483 157.623 L +419.212 157.625 L +419.941 157.627 L +420.669 157.629 L +421.398 157.631 L +422.127 157.633 L +422.855 157.635 L +423.584 157.637 L +424.313 157.639 L +425.041 157.64 L +425.77 157.642 L +426.499 157.644 L +427.227 157.646 L +427.956 157.648 L +428.685 157.65 L +429.413 157.652 L +430.142 157.653 L +430.871 157.655 L +431.599 157.657 L +432.328 157.659 L +433.057 157.66 L +433.785 157.662 L +434.514 157.664 L +435.243 157.666 L +435.971 157.667 L +436.7 157.669 L +437.429 157.671 L +438.158 157.672 L +438.886 157.674 L +439.615 157.675 L +440.344 157.677 L +441.072 157.679 L +441.801 157.68 L +442.53 157.682 L +s +P +0 g +0.144 w +[ ] 0 setdash +3.25 setmiterlimit +450.12 237.508 m +70.6 237.508 L +s +70.6 237.508 m +70.6 2.952 L +s +1 g +[ ] 0 setdash +70.6 2.952 m +450.12 2.952 L +s +450.12 2.952 m +450.12 237.508 L +s +0 g +[ ] 0 setdash +p +0 setlinecap +78.19 237.508 m +78.19 234.611 L +s +P +p +np 74 239 m +74 253 L +82 253 L +82 239 L +cp +clip np +p +1 w +0 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +[1 0 0 1 75.19 239.668 ] concat +1 w +[ ] 0 setdash +p +np -2.19 -1.668 m +-2.19 14.332 L +7.81 14.332 L +7.81 -1.668 L +cp +clip np +/MISOfy +{ + /newfontname exch def + /oldfontname exch def + oldfontname findfont + dup length dict begin + {1 index/FID ne{def}{pop pop}ifelse}forall + /Encoding ISOLatin1Encoding def + currentdict + end + newfontname exch definefont pop +}def +%%IncludeResource: font Times-Roman +%%IncludeFont: Times-Roman +%%BeginResource: font Times-Roman-MISO +%%BeginFont: Times-Roman-MISO +/Times-Roman /Times-Roman-MISO MISOfy +%%EndFont +%%EndResource +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +11.52 /Times-Roman-MISO Msf +0 10.5 m +(0) N +P +[1 0 0 1 -75.19 -239.668 ] concat +1 w +[ ] 0 setdash +P +P +[ ] 0 setdash +p +0 setlinecap +92.764 237.508 m +92.764 235.77 L +s +P +p +0 setlinecap +107.338 237.508 m +107.338 235.77 L +s +P +p +0 setlinecap +121.911 237.508 m +121.911 235.77 L +s +P +p +0 setlinecap +136.485 237.508 m +136.485 235.77 L +s +P +p +0 setlinecap +151.058 237.508 m +151.058 234.611 L +s +P +p +np 147 239 m +147 253 L +155 253 L +155 239 L +cp +clip np +p +1 w +0 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +[1 0 0 1 148.058 239.668 ] concat +1 w +[ ] 0 setdash +p +np -2.058 -1.668 m +-2.058 14.332 L +7.942 14.332 L +7.942 -1.668 L +cp +clip np +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +11.52 /Times-Roman-MISO Msf +0 10.5 m +(1) N +P +[1 0 0 1 -148.058 -239.668 ] concat +1 w +[ ] 0 setdash +P +P +[ ] 0 setdash +p +0 setlinecap +165.632 237.508 m +165.632 235.77 L +s +P +p +0 setlinecap +180.205 237.508 m +180.205 235.77 L +s +P +p +0 setlinecap +194.779 237.508 m +194.779 235.77 L +s +P +p +0 setlinecap +209.353 237.508 m +209.353 235.77 L +s +P +p +0 setlinecap +223.926 237.508 m +223.926 234.611 L +s +P +p +np 220 239 m +220 253 L +228 253 L +228 239 L +cp +clip np +p +1 w +0 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +[1 0 0 1 220.926 239.668 ] concat +1 w +[ ] 0 setdash +p +np -1.926 -1.668 m +-1.926 14.332 L +8.074 14.332 L +8.074 -1.668 L +cp +clip np +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +11.52 /Times-Roman-MISO Msf +0 10.5 m +(2) N +P +[1 0 0 1 -220.926 -239.668 ] concat +1 w +[ ] 0 setdash +P +P +[ ] 0 setdash +p +0 setlinecap +238.5 237.508 m +238.5 235.77 L +s +P +p +0 setlinecap +253.073 237.508 m +253.073 235.77 L +s +P +p +0 setlinecap +267.647 237.508 m +267.647 235.77 L +s +P +p +0 setlinecap +282.22 237.508 m +282.22 235.77 L +s +P +p +0 setlinecap +296.794 237.508 m +296.794 234.611 L +s +P +p +np 293 239 m +293 253 L +301 253 L +301 239 L +cp +clip np +p +1 w +0 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +[1 0 0 1 293.794 239.668 ] concat +1 w +[ ] 0 setdash +p +np -1.794 -1.668 m +-1.794 14.332 L +8.206 14.332 L +8.206 -1.668 L +cp +clip np +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +11.52 /Times-Roman-MISO Msf +0 10.5 m +(3) N +P +[1 0 0 1 -293.794 -239.668 ] concat +1 w +[ ] 0 setdash +P +P +[ ] 0 setdash +p +0 setlinecap +311.367 237.508 m +311.367 235.77 L +s +P +p +0 setlinecap +325.941 237.508 m +325.941 235.77 L +s +P +p +0 setlinecap +340.515 237.508 m +340.515 235.77 L +s +P +p +0 setlinecap +355.088 237.508 m +355.088 235.77 L +s +P +p +0 setlinecap +369.662 237.508 m +369.662 234.611 L +s +P +p +np 365 239 m +365 253 L +374 253 L +374 239 L +cp +clip np +p +1 w +0 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +[1 0 0 1 366.287 239.668 ] concat +1 w +[ ] 0 setdash +p +np -2.287 -1.668 m +-2.287 14.332 L +8.713 14.332 L +8.713 -1.668 L +cp +clip np +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +11.52 /Times-Roman-MISO Msf +0.75 10.5 m +(4) N +P +[1 0 0 1 -366.287 -239.668 ] concat +1 w +[ ] 0 setdash +P +P +[ ] 0 setdash +p +0 setlinecap +384.235 237.508 m +384.235 235.77 L +s +P +p +0 setlinecap +398.809 237.508 m +398.809 235.77 L +s +P +p +0 setlinecap +413.382 237.508 m +413.382 235.77 L +s +P +p +0 setlinecap +427.956 237.508 m +427.956 235.77 L +s +P +p +0 setlinecap +442.53 237.508 m +442.53 234.611 L +s +P +p +np 439 239 m +439 253 L +447 253 L +447 239 L +cp +clip np +p +1 w +0 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +[1 0 0 1 439.53 239.668 ] concat +1 w +[ ] 0 setdash +p +np -1.53 -1.668 m +-1.53 14.332 L +8.47 14.332 L +8.47 -1.668 L +cp +clip np +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +11.52 /Times-Roman-MISO Msf +0 10.5 m +(5) N +P +[1 0 0 1 -439.53 -239.668 ] concat +1 w +[ ] 0 setdash +P +P +[ ] 0 setdash +p +0 setlinecap +70.6 210.041 m +73.497 210.041 L +s +P +p +np 61 203 m +61 217 L +69 217 L +69 203 L +cp +clip np +p +1 w +0 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +[1 0 0 1 62.44 203.666 ] concat +1 w +[ ] 0 setdash +p +np -2.44 -1.666 m +-2.44 14.334 L +7.56 14.334 L +7.56 -1.666 L +cp +clip np +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +11.52 /Times-Roman-MISO Msf +0 10.5 m +(0) N +P +[1 0 0 1 -62.44 -203.666 ] concat +1 w +[ ] 0 setdash +P +P +[ ] 0 setdash +p +0 setlinecap +70.6 157.941 m +73.497 157.941 L +s +P +p +np 61 151 m +61 165 L +69 165 L +69 151 L +cp +clip np +p +1 w +0 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +[1 0 0 1 61.69 151.566 ] concat +1 w +[ ] 0 setdash +p +np -1.69 -1.566 m +-1.69 14.434 L +8.31 14.434 L +8.31 -1.566 L +cp +clip np +%%BeginResource: font Mathematica1 +%%BeginFont: Mathematica1 +%!PS-AdobeFont-1.0: Mathematica1 001.000 +%%CreationDate: 8/26/01 at 4:07 PM +%%VMusage: 1024 31527 +% Mathematica typeface design by Andre Kuzniarek, with Gregg Snyder and Stephen Wolfram. Copyright \(c\) 1996-2001 Wolfram Research, Inc. [http://www.wolfram.com]. All rights reserved. [Font version 2.00] +% ADL: 800 200 0 +%%EndComments +FontDirectory/Mathematica1 known{/Mathematica1 findfont dup/UniqueID known{dup +/UniqueID get 5095641 eq exch/FontType get 1 eq and}{pop false}ifelse +{save true}{false}ifelse}{false}ifelse +20 dict begin +/FontInfo 16 dict dup begin + /version (001.000) readonly def + /FullName (Mathematica1) readonly def + /FamilyName (Mathematica1) readonly def + /Weight (Medium) readonly def + /ItalicAngle 0 def + /isFixedPitch false def + /UnderlinePosition -133 def + /UnderlineThickness 20 def + /Notice (Mathematica typeface design by Andre Kuzniarek, with Gregg Snyder and Stephen Wolfram. Copyright \(c\) 1996-2001 Wolfram Research, Inc. [http://www.wolfram.com]. All rights reserved. [Font version 2.00]) readonly def + /em 1000 def + /ascent 800 def + /descent 200 def +end readonly def +/FontName /Mathematica1 def +/Encoding 256 array +dup 0/NUL put +dup 1/Eth put +dup 2/eth put +dup 3/Lslash put +dup 4/lslash put +dup 5/Scaron put +dup 6/scaron put +dup 7/Yacute put +dup 8/yacute put +dup 9/HT put +dup 10/LF put +dup 11/Thorn put +dup 12/thorn put +dup 13/CR put +dup 14/Zcaron put +dup 15/zcaron put +dup 16/DLE put +dup 17/DC1 put +dup 18/DC2 put +dup 19/DC3 put +dup 20/DC4 put +dup 21/onehalf put +dup 22/onequarter put +dup 23/onesuperior put +dup 24/threequarters put +dup 25/threesuperior put +dup 26/twosuperior put +dup 27/brokenbar put +dup 28/minus put +dup 29/multiply put +dup 30/RS put +dup 31/US put +dup 32/Space put +dup 33/Exclamation put +dup 34/ForAll put +dup 35/NumberSign put +dup 36/Exists put +dup 37/Percent put +dup 38/Ampersand put +dup 39/SmallMember put +dup 40/LParen put +dup 41/RParen put +dup 42/Star put +dup 43/Plus put +dup 44/Comma put +dup 45/Minus put +dup 46/Period put +dup 47/Slash put +dup 48/Zero put +dup 49/One put +dup 50/Two put +dup 51/Three put +dup 52/Four put +dup 53/Five put +dup 54/Six put +dup 55/Seven put +dup 56/Eight put +dup 57/Nine put +dup 58/Colon put +dup 59/SemiColon put +dup 60/Less put +dup 61/Equal put +dup 62/Greater put +dup 63/Question put +dup 64/TildeFullEqual put +dup 65/CapAlpha put +dup 66/CapBeta put +dup 67/CapChi put +dup 68/CapDelta put +dup 69/CapEpsilon put +dup 70/CapPhi put +dup 71/CapGamma put +dup 72/CapEta put +dup 73/CapIota put +dup 74/CurlyTheta put +dup 75/CapKappa put +dup 76/CapLambda put +dup 77/CapMu put +dup 78/CapNu put +dup 79/CapOmicron put +dup 80/CapPi put +dup 81/CapTheta put +dup 82/CapRho put +dup 83/CapSigma put +dup 84/CapTau put +dup 85/CapUpsilon put +dup 86/FinalSigma put +dup 87/CapOmega put +dup 88/CapXi put +dup 89/CapPsi put +dup 90/CapZeta put +dup 91/LBracket put +dup 92/Therefore put +dup 93/RBracket put +dup 94/Perpendicular put +dup 95/Underbar put +dup 96/Hat put +dup 97/Alpha put +dup 98/Beta put +dup 99/Chi put +dup 100/Delta put +dup 101/Epsilon put +dup 102/Phi put +dup 103/Gamma put +dup 104/Eta put +dup 105/Iota put +dup 106/CurlyPhi put +dup 107/Kappa put +dup 108/Lambda put +dup 109/Mu put +dup 110/Nu put +dup 111/Omicron put +dup 112/Pi put +dup 113/Theta put +dup 114/Rho put +dup 115/Sigma put +dup 116/Tau put +dup 117/Upsilon put +dup 118/CurlyPi put +dup 119/Omega put +dup 120/Xi put +dup 121/Psi put +dup 122/Zeta put +dup 123/LBrace put +dup 124/VertBar put +dup 125/RBrace put +dup 126/Tilde put +dup 127/DEL put +dup 128/FractionBarExt put +dup 129/EscapeChar put +dup 130/SelectPlaceholder put +dup 131/Placeholder put +dup 132/Continuation put +dup 133/Skeleton put +dup 134/LSkeleton put +dup 135/RSkeleton put +dup 136/Spacer put +dup 137/Cross put +dup 138/DblEqual put +dup 139/Grave put +dup 140/Acute put +dup 141/DoubleAcute put +dup 142/OverTilde put +dup 143/OverBar put +dup 144/DblUpDownArrow put +dup 145/DblUpExtens1 put +dup 146/DblLongLArrow put +dup 147/DblExtens put +dup 148/DblLongRArrow put +dup 149/DblLRArrow2 put +dup 150/DblLongLRArrow put +dup 151/UpDownArrow put +dup 152/LongLArrow put +dup 153/LongRArrow put +dup 154/LongLRArrow put +dup 155/ColonEqual put +dup 156/Diamond2 put +dup 157/NotSquareSprsetEqual put +dup 158/AtSign put +dup 159/Solidmedsqr put +dup 160/OverDot put +dup 161/CurlyCapUpsilon put +dup 162/Prime put +dup 163/LessEqual put +dup 164/Fraction put +dup 165/Infinity put +dup 166/RuleDelayed put +dup 167/ClubSuit put +dup 168/DiamondSuit put +dup 169/HeartSuit put +dup 170/SpadeSuit put +dup 171/LRArrow put +dup 172/LArrow put +dup 173/UpArrow put +dup 174/RArrow put +dup 175/DownArrow put +dup 176/Degree put +dup 177/PlusMinus put +dup 178/DoublePrime put +dup 179/GreaterEqual put +dup 180/Multiply put +dup 181/Proportional put +dup 182/PartialDiff put +dup 183/Bullet put +dup 184/Divide put +dup 185/NotEqual put +dup 186/Equivalence put +dup 187/Approxequal put +dup 188/Ellipsis put +dup 189/ArrowVertEx put +dup 190/ArrowHorizEx put +dup 191/CarriageReturn put +dup 192/Aleph put +dup 193/IFraktur put +dup 194/RFraktur put +dup 195/Weierstrass put +dup 196/CircleMultiply put +dup 197/CirclePlus put +dup 198/EmptySet put +dup 199/Union put +dup 200/Intersection put +dup 201/ProperSuperset put +dup 202/NbSpace put +dup 203/NotSubset put +dup 204/ProperSubset put +dup 205/ReflexSubset put +dup 206/Element put +dup 207/NotElement put +dup 208/Angle put +dup 209/Gradient put +dup 210/RegTM put +dup 211/Copyright put +dup 212/TM put +dup 213/Product put +dup 214/Radical put +dup 215/DotMath put +dup 216/LogicalNot put +dup 217/Wedge put +dup 218/Vee put +dup 219/DblLRArrow put +dup 220/DblLArrow put +dup 221/DblUpArrow put +dup 222/DblRArrow put +dup 223/DblDownArrow put +dup 224/Lozenge put +dup 225/LAngle put +dup 226/Diffd put +dup 227/Expe put +dup 228/Imagi put +dup 229/Sum put +dup 230/LParenTop put +dup 231/LParenEx put +dup 232/LParenBot put +dup 233/LBracketTop put +dup 234/LBracketEx put +dup 235/LBracketBot put +dup 236/LBraceTop put +dup 237/LBraceMid put +dup 238/LBraceBot put +dup 239/BraceEx put +dup 240/Slot put +dup 241/RAngle put +dup 242/Intergral put +dup 243/IntegralTop put +dup 244/IntegralEx put +dup 245/IntegralBot put +dup 246/RParenTop put +dup 247/RParenEx put +dup 248/RParenBot put +dup 249/RBracketTop put +dup 250/RBracketEx put +dup 251/RBracketBot put +dup 252/RBraceTop put +dup 253/RBraceMid put +dup 254/RBraceBot put +dup 255/Wolf put + readonly def +/PaintType 0 def +/FontType 1 def +/StrokeWidth 0 def +/FontMatrix[0.001 0 0 0.001 0 0]readonly def +/UniqueID 5095641 def +/FontBBox{-120 -220 1544 923}readonly def +currentdict end +currentfile eexec +D8061D93A8246509E76A3EC656E953B7C22E43117F5A3BC2421790057C314DAE3EFBFF49F45DA34B +424A961BE670A194E7E4BF0FF295DEE23134A14A7C08B6602621D885EE631B1D8D3003CF2093E039 +4D77FCEFCA8BA8965D1783DCAD9EFE6C7E420CF7B898933309A89F84721ADE7F3AE4443C5EAE8155 +759A9EB6F738F7BA81C192EE45DAD00F398FFD6904111BBD91BFEE328004F2A18BCCD98DCDB2CE23 +961B00F204E50EA022D00CE2B68E653626D4BB5AFA334A0D657307416FAF7AA8C43ED4DC541F1B7B +B7500B3F423D9D369F8192FD00A59FD5E6ABC70F788FB70976CC1907DDC309F4B690AA2D2BF12CAE +C493958CC0E76CE9EB5FF8BD1F1650F659E5C123EE455B7D77C39952C212AF319BF19A91E36DE52F +0EF84B602704BD6C7C94E1B0E067210DB919F6231755A2CC5D5FE129279B43A2E2CCD27F56F00B05 +C8AC10AB07FABBEFB3509088301FE78CAF8B440C5BA2FFE06BBFCD066046618F3B6AA2E4B17B296E +1F3F1560E19CBAD54E16E4B7A65622E468F6BDF97C50277E355D1DD8843D0A449A147FFBA071BA99 +CF70D7576DC18B96FEAF8070BF25F3A3141F873241EF4A07F332306B56F1D5909A4F233A9DB3A08E +E43DF38DD6DB2D6DAB908967A907303EE1FA04F048FA6EBC531738C170B8B0F095FF3B05D14C2BDC +272F7EDA8926A77D9CDA49A90AE1387A51A24ECDB2E4E287B0F95A83AD2EC0310F9B6F396AC10479 +835035FD5D4C84D91917FE8A8755C976504AB1A830ED516B5F325EA4ADFD115900D23039A2BC84EE +D21CC21E2BBE29A5E0CF28BE047CBD515DF7785F37DDD4474042B102A1F28193BB8567FF6FDEF811 +25CE9A504BE5011C0010DCEBCF321824C9DA249D8DB11F79298F7B674CEDB6F33C111F8B0115E407 +99E0FE1B6CE9F6B2A3EED1827A9CEB453D643FE5CE2540DCBCAF7B2EA2C8F0AE9434D4BAAEAB3488 +FEC7541D57179BDEAA0BB6145EA783E73E70E0AA71A4FA58E81EB510E9FD2CF4ACFBF28E48CA313C +CF5ED2BE032B7C9A07ABBEC9CCD8D5AC9F775D36BECC252B9FE01B6AA79A70E22478904DADDA08BB +7CA3B66F3A83AEEBA37406127353790348AE5FBD144ABD8E1B32D1BCC70E2BC22A63E854D38317E6 +BB97C52A6C9B0C6AB5C336CE2D417A714825DCD237F7486C33925A995CD8AD3B359176C4CA775FE2 +2C6F8A7C7343F31F39D1B9A5A744973BF65D655DDB59E3495B28DBE2A877EBB32A22A4AB8EB13C67 +02B239F6932E2DC8B4B88915923B1C2AFF2F876A31F765B91747D5A858BD632B0BE4F135AC484016 +AE1BC01E44B6653A58EE1380B6DF24AEB73220A36FA8FDE9A152C16E049D2F247A9AA71CD2DF3D9E +653054FAF518BBC1EEB43200DB0BACA93FEA9445FA5F32A99926C4F1F2370B2E3E03CEFBEECE5D5C +DE299FE1641A9CE0C90E42E7C465DF8C19C153EA76C11791F8E112853E708CD0F6EFC22E44808A44 +3686442645D643E7118D128BF34188FD313E53B8E951E605E96825738C4DC893D942C145C3E1153F +CDED16D1EE10374626F45781461FFC94C77D431BCF167FD29136A0B369631E139A59B06AC5281B3D +52470B38237B469C0E49CBE74C82A940F8AAD10E05C5DD2A8F3218C4BE40DCED0982770869190845 +D2E8BA2A1A2F9CF16DDDE418B6E2013C3258FBE9AFCDACCD57B01C4FEF3526C06FD5BAB6F195C557 +23A96FA3E5CDB2ADC9AA8989DF78F163F19E26F3B9EAF60D44B745FCA49B09D9CE5CC16D1E2C78C5 +A28F14D3374956E9721C0542A01A731A3D5A771C7B51FB72960BB22C99BC8F216530AA86C1A0346B +3D986EF1DF68BCC46EC4C809C6D54FB9C50F225ABA2C96965F4DE77E2C5D131318231C6773F0976C +DBD016B803C38B8923822BDF160FB87BBE744D0953EDEBDE87394282B9950C89F58824D731355E8F +A3CE364F742E3337A983BD1219CE8787CFA6925B560001F6F78343647821D408B60965966C16C454 +394D33268483F51984614FD9964CCE5F1AA4AB12144874A72D3FE97F4416ABE4213B4EDCA9ECF73A +937B562F978E059705E561A6D0C8B89B59B4CAB2248BFC4A6D3D98F89FF38A4D1C3E5A4570E2E2E8 +D328772E11DEA2116C260B13328045139A819F5489A2C302F311898230CD26DD03E6CE3BE75EDB86 +0D982FBC8E1E24D1F83E8CA64174495B2F32BDF0505FC96E9C65FDB0EB0C4ADA410F0A1C4BB4D551 +93B1AA5EA1F988882A56413F77CF24FF6516CD5095077BA566116797895FD7EA616D10510957025A +1DA05064FD9176303A248C94CE2A9875C03C7D8755A1A8010B712B64BAD73BEA4195D51A328F076D +12C0E52E87D98A5269D157D544CD7B4E1CAAEA6BDD59F08D0C5FBB84A6B099BECF8BEB721A874BAA +1BD1F8CDB5ED5CD3B49A763EAA36D33837667A6643B83537EF5515DBF7659E28692E0ACEB48FD051 +45534A443092E0A510B05B5B51B402CB3372A4E8BAF98A7FEB6D8BEF6B364A5EA0F3FDF301A44EE2 +3485D4493E7B4C33E0E352202931188D156983C40F7A4B615B6F5281B33FB32A2E6A0F7AE84BEA2C +5C3635D7DA17371D608847EB402270B83293EC09E4B1D85996C1CC81196BE590EC9EF0F258364746 +BC4763976FDDB3707D37AFCBDC0F4EB2B1502F137EBBB1541B992EAD43B5D64CCDF505FF2F127115 +4857C69B689A11760979F6D2BB032CF0DCCBB33D2B6F6D6BB29A1D0E371AA5869A408225C0AFF523 +CEFB08A7D3D17DF9064010363196CC569C436E720B1B4573CDAE1CD93A10FD2D4ACB14E47046B5B7 +66B75B40BA97027FEC4218980B002FAB60A9F1F5A37861B9A63F696732F8127B2C6F036BF32311B8 +FF08A489E88218092D57A99C8981EF8CBBD09DF49CC836B9C1968692D1FB551F47619F020289F1A3 +D3898A96DC1C7D39A21B49C2D0DD9508CB8A8BD6A5EB40FF86F555FA32017B67AEC07BECD659E8C4 +8DD1D43E8D1EE08A117479015F78BF20D3318224572D9C90884856E4307A8AFFC83EDD317B008484 +3BBE8EB2A4E2D70077A639FE3637C3DCF87C67F1BE62E63CC67BCEF8EBD07E030524A53DD440F2A1 +3A019B7AA89E155AAD1497974258A01DA45DE1D94BB9F925290FE9BDDA29EA3F2BF1E64DF7EBCFC4 +23AB2C7310D9D87A5CA673EE95189135E1B134B431B231428FF2BF64C8F155CBDDAD17BCB524CF7E +ABD66B75705BFFB1DDB27B72D681D7AA19FAD0FF23EEF028B606DD20D58588AACB299A3CF38372A8 +E7494A65227C1E4A231AC7843962B8A4A7BDD90F3F8B83277E696F3514139BB8DD207641B62286F0 +0E32C7FAD7029DC0E092564C7CE1BC5240FCBFB00A06F075D9536F0326CFFBA958BA7A1A11AA047B +B14E7DE16761BB0FEF19ABE85154359807C339961B9695CDED59E489CA4D9BB75D86D9EDDF0502BC +0B4EC36B1D71FCD4E03881ECEC703E5DA23B3F5DB98CB8DAED81D5BA20B844A92A4B92FE5B082952 +6837237C7F994786878404BE744D0953C676E52CB05FCE193E8827F977B31929E36E320E770A6F1E +972B84AFA21E01719759DF0132C5CF9692BAA487E86E8453C09FF97642600D1024ED5D6C7D5B387D +CB5E6147D20B4A14D7D485B5747D765C5A1CA40B9416DC4EF5DC08F43F0706B27B1C90E901556E1C +EFF304EA8DF8D727E4B7E7CEAD14E4FC7E76002DBC37B92BD0E58AF29DA7DA91E6F99DADF1A9CBDD +04648E2F5B811F2AF0729646B17D32D7EF25AD47E267EE53A61A7CD744C9ABFDB1EDB71C0705412B +15769188CA1601AF0395796FAC0E2139EF90FAA65D27AAEEEE319D2831A56CE82203523097D0574D +22742D17E519D95560B8445B5B29033BF3454B94F20C23EBE8B90DDF26D903F1D66CB39D3A64579D +39D136C537CCD9FF2D6ACE5F79DE696C7330C0C4EA179D7911B7B67858D86CEE0833AB1E105B1993 +2A9BD572C41E78FB4A2A2421514DC2066E2F56101A9027F4BBA5D48E5DA9218E81CE46B95B50380F +560C67A5D547A8D32610AECECBB6F5A09DF44994F6DAC64F7399C07E182033BC1B9A32B69C41FDFC +7E1DCDDF273F045F154D727AFEE3CDB816CF2ECDB6733C579276353DD59C9D2AFA455935C1FCD0AB +7D57F9DD79FBCC7A45E5E5A501FF17EE1C5FF0823C6FDE29C60F85F6786940D8E3540E891B5BF7F5 +D36C57AC3AD359BFAB12B215E7FC94B933386C250E6B236506FA3D151ABAD893A817772071C09144 +6E5FB23A17591A4CECAA46DD46E3C41B4578F21D8894A59B72FAF6F88EE6E514FBD2FE69447D2B59 +9A6AA8BC5C1FD5C25E50BFB5CE5DBF5AD5771BC42FCC3706B6E9F7E4FAAFF2E63ED1684C5A4C136D +609D03E31EBCF31E864AAA74D8DDBCA52F85CCF14AB739CC55617EFC964D6CC6988AA45245B19CE2 +B63CB865DF1F1DA4A200A4A043C5CB706CD303EB31C32866ED92077AB11BF136D158840EAC67E7A1 +1BC2BFDCD5894AF735D677E1AC98BF3F19F69AF75355F168632037F6EDEBF61BE5854057AD05972C +7DA8D37AE65D35738547A9D835C6351D8D732F8C0DC49D7605F00A6A6045559D3A0B0CC21DFDD75E +2FCF25522001741EBBEB5CC97DDBD9DDCE490FE3CB186C101940DD02CACB685ECCB8C1DEDCDD4156 +F5F9F6B3CA53EC6E7E8A2F8159451CD5479D91BFBF91C6B32A1E0053017369330EAD2DDE323BCAC5 +EEC91A595473F447355B1BDFB873D0B538BF54AFB8EAADE5309E1B74283218F59272E59619D66405 +E74B5A9D6323CB76AF00FB27FD984F740601248C7206F59EF7FF4E95AF95327D12C47D2D34CBFF33 +29F28236831D7F0FD9D633B940D8282E1F1D5D95616CD839C6B41A7195A22B7A320864E48943CE99 +C68E3591A97689986A6536C3A1C37DA9838FF71A8C1A03094537C95D3585DF5AD9292874D8D05720 +030133B02E2754DA24712B52D6D8871422C709532B09D147EC8ACD861FA5392A82A6C2981347E327 +1986017B8315822B5FCB19A1B31BF6909E0D6490EC823434BFCE031045D20FFC675A73EBD7A39A50 +44C3B40906186CCF6E8502CD7915F053BC8CF6BE9FDD9A0330AE943D5C9A11D60D43F5BBE8A045EF +CDB7D19C0053F4F082303442C35C432E0DA4408C5917D24A6658DB807BD754AF140CE84A34F79851 +9323060D60F4EAC0E82D3E17042BB6729C69A8B8774904C6214C2EB016C528DC1428DB41075AA6C5 +4E4D849901838C6B6DADF7B67CD0CBC6EE1B415B44654D89397274D4A6AD2BA69DD81567F5B802F2 +684DD3516ECA0F6D66046EDA0B2B38F420A238D67D98676925ECBE6711D64DAE5DBE8AC5473A2EE9 +97AE65F0715A2E5DB2C75F20D9939EF58692EDA3AEA81F25AEC888327CFA6CC13D496714E63A1A87 +11FC50250D6D23FC7A8017038281F659A685ED7F1BB1ADBF8833ABC6DBEC0D96D08334E58C67E0F9 +0046132F0D4FBCB9CDF52EE74561498B42701AB826A6DD77F46C14753748E1EC66F4BD3583FCB4F1 +DC91050CF18B0D51BC366549261282779FC9694A7B987973C0D59F65CFF3CDB88D23952E46F5EEC1 +BDA0DC354188C11B0FA191F5C11A45BB9093701B33B8E7AC1A8621793D5326E92CDD3A76FB9B67D6 +860567B9CEE7B9F9056C6E9971F642DC0BCC1D2882B5BDF1B1CDCAA3FC61775A74E70CDFC128DE0F +9606091BB8E53905108EE77A1D3C506550FCFCAE454B020379BE3A7D6C62D162697AF1383F7BC8F2 +34FD616324C1E56E3E440277862CAB2C02395D9937816117F71A6828344182E6B5AF2799E29A6611 +9C0543E135300E44746EF2EBA57C4EABB1A15D8AC6D037F4BA2BE1EB4D1A7496F9711FC67E56D4D0 +FDA4D810B5383A72ACA15872DE9F3A9890E33759CE4DA493691BCA47A92E42D950DF588C3574D6FC +72B5AF7DDE915E3F5925B3E97DEBE6A4208CE7337754045607679296C4EEEA3A3EF1915E85EB1A32 +F1BBADB2904B09806631E20BBF5E57AF11BC784C75BF049B4BC7E479F1D4AE7754CBED7B11ED80A5 +2DD0006FAE5CC23A7C234CF628B42F4104A490E7D59E8B1F2A1395D37641C478FF8CB9FB602B29FD +3E48D6087CAEE48B523887F27F69DB32BF80B760B030A6766F8F9B19DE70704DAF81D3DED2BF663D +89B5BD8AF253BB8FA59DF84A52FDED83D2737532B6D66AFB9EF0446ACD44BFAB797AB9FDB47F2E18 +8F0A55887853772EBFD029B5FA0AFBAF10A88D464BD6F634C5839B230D583E36671A51DDB1EBF471 +8ABB84D057729D514751B0EEF4F756B91DEDAD7D9AD529B3886008F1F32645F3A205F304B2A8D808 +D37A38E389B8587E8D3654DC374568FCEBBA160395BE1D132B1ACB434164525FBF250A5AA30F3520 +F0F2A75F9D1B7C6EAB0223C209A120D894D6ECA336B57B7F2AB0E2A94E6616D7539010C700311966 +7B4A9EB3A812FEF4D100AB4C036401D21DDF8AEB393074638D154418D3A7AE51CD1F0C2D5CF4B475 +3B582D5071F91E6D3AFBFB09EAABBEAB2A60A5D388D16232939B5483CF7D5C1C9D05DDC85B266F39 +6F61E179AB9FAB644040014293EB53F2B50E8751F9D92D1DAE8DC89594905A39357C0098265FBD24 +E407F9A22027E36D5608FAF15BD9E354228E3BA943EC30301ABB2CB105F3B6D57C001EBF8328A8CA +318A7B1B999AE8BF9E2FD530B669640116149B622EB3C0A8CCDE62449DE9D39E0F5E5E01CBBF4F5E +52B33A2BD60B52FA4A5CE98B7313FE4C3FA30FA07DE4516109C3EAEE97ABE430C505647DD8B3DBF2 +BB4B3A806B14A9E0F629863F15D12A1CA62E8E055FA6ACABDE1926D3231CAC271C30A3F7AAC6084D +D88628B943052B618E4E39148600AC1EDB57B0835C291F73D29C51FCA3C5EFB1DB18A5CA47433B45 +C57EB3CB28AEBC68E4171E6DE357793B0FD2A1F4E76180248017112674DAD7ACA6ECAAF209CA174A +5603CEA5CE528F20919443900636E2FC79C303EA7B467A3F001EA8CB849BCF28BF40A3364C08ABC9 +B5D935CFEDA827A8C3FE2F6ABA54017D2AD0393A05AE21F7AE1F58AE1E992B5C889219DA157FA7EE +92E291DE2F9DFC244F2CF0FDCEFCACC487F0EA830985B687556D5AF53B81814DE9CE0C6C430DCBCE +51EBC6091B4E0227732E07DF20D59E9EED4D8A83761CED84CCE244BFD6A39103A2B48A684AEC9210 +5C94495D54FD6690AF857E5A3915E6A15689F1816F75F1FC8D5769B240639B339EBE54BC6D84794D +50F4EBE892530351984C6F8BEBE097CD46F4FED7D46E32830A16F77C13F13D17003737482F02D1B6 +F04C57B4C2B1929AA315B4BE1C7C9CB55F8981508546B67E4EBF84B6026C355C5E4E07CD98C95F07 +56F6643FB1DD7D8C77C4AF4C4F23602DD3F61D1C46583071AC460E74084F7F7CF812BC53975CAAF8 +B3C1160B5D6864AF08A1733FA893CE4248C8F8B46AEFCCF317DC726BC1E5F2445E462E0591BEAAEA +49AD8E4E2D3CF07F900EC46D596E9CDB3A8710A0B93CE5DA9D35E612596A6374F35AED0EF55DC46A +8E14A91163B87417259DE926BBC3FC5423FF0AE2AA6D740BFFD26981A57C8C1D97FB04A90A567296 +B07437F94C8FFF4709213DD5D8862A777CF3F97723F43A4F913F4A30F7554ACDAE34713654E21731 +C594C3718C0547FCDAF7BB1620B2D6BB19E65596A585290CC43F50B34A2FE6EB1E495ACFFB16DFEE +8784B66FCB9359600412969E2BDA330C421C68345A797C49728450A6CF41C926AE8EBBE80BD97863 +593C3E8AB5415A8BA625957F242378948F5C7EA9C2641312E8E46955FE5C1A1824C71D3B0C9FD211 +7CC965DA7C21D257587F291AB7C594459A11B977A278C74CF5E6598B0C75ABBB2FC1B3D167D7E31D +B519F4A0BDA650A3FE7F1A281DB9B69B57A23656BD820B22D0E30B07361FE7C90933E24A32B6DE2D +F240635D543315226E32487F264AFE83EFEAC74117321A82A92F4FC7B259F26DBE74C966B4CB3F4E +3499E30B9B326F72D73919D9FA9024AAC0B95B6751AD4CE569CC3DDFC399428DF1298FB1733FFCE6 +240FB3BE3A2837E1A66E08B784CDD131B5A61423508000785CDC5610CE4DA1DD314131767C8857E3 +3D9741EF3FD7B8D0AF0371CFFA3DCF74FF2D3B421AC0339EBC05FB4B61A2F46D6BD1144747AD148B +7968D7DF4D0F742AB39B0A04A88D66F5CF9876970879879872BFDA0C56C253DE5C72016B4990CEBB +2455DCDEC7465EE7C7E1C557B570E9F3EF3E31A22DC8AB9B17F34F48E135BE7820ACE383DB7C5B05 +8A9DC855C6850E49AB7D7D00ED2D23C50AEE671B11752F0A682EFE179CECBFAB47B76676AC0E8FD1 +0A47353D3AC3477A59B0F3CAF22849DE97AAC8B79935F7C57F3052DE7E13BA0FE7CEC4685C86E841 +EA8C7D6734D0FEEFF538CC2AA1414EC9126637E169FBE4ECAFDFA29A08451B25954F0094710195E1 +69E0A6004419E432E9319BE2AEC8D93407B25B758336946C6E30032657DD857BE9C0A05F487423D2 +0C2772D4416D27FEB5CCC971DDEDFE9B8C2D7DF9DEC90D0868D5DD18850BE567A04D08310883D9B2 +D50B817D0690F8550E238C1139C0A117B48199B1B4D489C9E52C58E0CA75E6C386ADD447D8AE52D1 +D979FD52A50D82BBCB8867B5D49C19BDEC414929DB67A00AF7C6482A87E46BD11D8E4E52783E5845 +FB2CC7439F99FF6552C7288354B436B1C361AB8C2932F77B14A50A7407FC0BCC29662D710248CA46 +AC42A03FBBEF9C972783942F3721BD32BDA3273D1E353D9E013D4CFF630BFE4E7C2963FECFE350A2 +860421D17D6ACA888FA26403726A0E16BD10638D8511A2C8A36C99E9B72A422038E1149BF88A7CA1 +B2DB196333F3AD32D6FE28F18FE1ADA06FD25E4597936A924E71C188B9E8779BDBA928A182042C96 +F6A14A6FAB5C1A819DB8E9374E32F77393734A65606809E90D188F749180A3E6CA7AD8044E168677 +15FDFF350D70B14454B692715DC3AE2CAA561FB953B478E873EB19C41A8D83288451E4E910D5988F +33D83C5974DD0EE4DF2E6C849C500D0714038ECB1E9336D71D852889F2FBCA6769949699BE6BBF19 +A9318CCD7C845D0EC7FF3CFD871328CF7B45E6BBBBD16094E8ABE4D3789DEAD2C930AC8D810C911C +03AF2BDA4EBA62810F19B4506592005ACFF16EB58E33D6A71EA4DAD28A2D7B10FF89ACAB4BCC0F96 +E622EBA20347AE04C62A298257D1623977D185BB46B42CCDD733F72B37072B8DFAA5D7FF77E35618 +3F6D25EE1D951F7EBFBEA8FA17A859B8545BDB212A6BFE9C3078C32124C4E5D4DA09404E40498F76 +7B7164C13E12BF006EE8DE408070296EF0A08AF759206DB3C445BF49EAB18ECDE1FEDEFFAB653FDC +B13FA4649B35D12266FD42D0498331560E96F54D4238678F70233F56097E1944FC671D6BB1AB66CD +E0E9DC24349E44D67C36B3E3A00B07755749A597DF31C25F28D55779841BD3F6221BCDE389852DD4 +590E075C1298B36181D9F64BDCB54A556C05A9EF661EA1CC7C7549A3E1CCF79B87A6E71C3ACDECC9 +C4EFB05B643744407029258B8225DBF960DE529EEC262D1D3113F6CDDBCF4BDAB706BF085C0FF2EE +E8420CF755E46B053B774DF37C5683F8432EEC183C96176BFB24B3F478FACACBF1FCB73D83D4D857 +2D0F15783C8AE95D7CE959D794FDE1D973867D8F30A301598BDB7F2824B2629D64B88F0FF4498B6F +3728CF8916EA884C5930677E7481F90C85ED41DD28AA00E714D3A4F2CC136E417A4C591C7944C409 +70D2BCBE410A940937C3CAA118FA32317444B401968B8ECB2F0B3C8DAF6D4886C2015000A71FDAD4 +066B82312A4CD1E49A9ACFA05C3E7CA5A5CB3FA713CA0AD9E66A34730A36612C72D1F803D4CB1501 +9184FA2FDB3E5D067BC64B29299D5531565264B70FFFF86F5A5B03848E55D73337650208D21F35BB +D5C14748CBE17EB3A7E02BE53136DC69E8740C597CE28472CAEEB96EF2A5752CF17CFBB82F6C104F +2BBB50C216C49E8AB7E661207E1742B35392752051A1E409BEDCDA2654CB5155B770C8C5E4A2968A +A35CF1924D0C74A8D23AB811B7DCE60F1EBC1494A295C8D670E84B7B886A6064151065BD96F2D364 +7BA049A444CF16EB6432CAFCC70FF2E8B354F55A192C94BF08D156856A6512403F5140DF4C8D254E +DA59B2B3ADEE19A35E9A61202B711193A7E7BA8EF427152157DA5A51084EA46510864E1CD7B4FD11 +16E74D7BA769ABCFAC556BBA7CC528C18003A2AE059CC97C18263500667F6A9A8C421F2ABDD73EAD +82D9D08940DEE1688D4AA200ED80C3AFEF6A4979154D99478D4F4EB3738333E8581A755190D87BE3 +09A319ED170A107512F056E4C619D4BB1615BA6C0680117610A26462F267B76F9DBC9A7A3AC08C9A +512A44697082A2718B62FD1D565010AC96E1006F958070AB7567A33E1FF7BD450681DF6BD4EBD265 +CF12726A7EFDEFBB9BA1E596BC5C2940A4FC9DE60116C9082138F1C672977F4AA6B7986ADABBB2B0 +651A7B0C06C4BD405C58B8C81BE075997E118E10FC008AD1F9ACF9F6AAC6C9E3F6DC7FCB838720E8 +D0D9BB99F203EEA2566F18232711E832810F10DD4E2DE44A0A81603EB1162E1BDB60AA1E2D771EC2 +E6E2C3B39508E5CA03A1E2A7F2860BC6F0B57240880DF54C325F4729EEFA1D2753D57F055CDFCA5C +E9C6630980C7121FC21E2F7223E6111C18FFDA0A0A7643A213DE9525AE138814C4183BF03A26A36F +EE9199821464C845A746945413629DC53F5A2B0D8CE9282B580ED662F2F07398D6A8B7093CFCC6F5 +E0F5A7926D2862AD1CCACB84D85902038551EE3EAED02AC7754E3B65818C530A0252C049A68862DC +A459DDD937F7BA64DB16AC86885B68AF46422D7C4923070E20CBAAC9F14E43979C5D5AC4C9321016 +7CCC52E7DA272146D68D8F61DB4D60063E74F6673B41ACB601DEEB1DF73517A8C5388F00E8A9D236 +9C85DBFE4C1E9864AB52E09F465EE98C194151E66CB98E6981EFFCADBC48532E9795290CF745FDA9 +CB7FD40BB77C148A8B90C0CA50176103E2ECCAA57030F7C0882F1E891F9EEBA077AA4992FAE38C75 +5470A4C35454EBAB45271DD76E4DBB2D9147817F7D3FB800EA136D3F27C84B4D45ACEAD13D3C91EE +BD6836AC04F95E578D1B7B8CE5B718E42FD1BBE91EF9A7873F0C6DC59AD231D08CEB4AE312F83F1A +9310155D2C4F216A6FC72385C899B5390EBADE7CF7BEB028F73DD76EDEEF639E9EDE034ACB25BA57 +8C7BEC3581FEE0B221F7340570489596FC60EC805405E0D2ACF0687A62A75358B3878972D4C039D9 +07D868DD00C5F7F3342384C09B01F1926F7D37C2B862FC516361253CBBDAB354898B31B1FE58F773 +61517F2C2E106708AB659D95CE3E9E7777B7327DE01AE2D1E0C84B9EE3887C094C149700CB095D5D +A5FEAF1AA9027AF257576A7370D79FF4DB98511AA27C5C083FA0CA60A3A5E66B8DA9A22FE5DD3DDF +C529BEA71E83881D8B010D140AD686DBEC9AF4B331086F6556B695CAB14BF24B5FE64382E6F9BC21 +5E9EC40C0914B1E27BC25F43E6F555B551726A8D9CD590D5AD3732777EF3B00CBAA89F8E8E0E0347 +7D45B00181A7B196FD4919F110C0F2C0F1B41231051AB5BC8F8025ED00C10F2C2F51E97B622A4E84 +E6AADA59F896F83EFADE779B37FACC56BDCA1892A3BD965B65D51B55AC1D73ABCD16D0EADE55C0BD +3C1BE9FDB323E9FBC9835C63F757051E29E773D3491706DEEBAA0F1182F0E02D0CB701661B30770D +94E240E1358195781006E18CBFC2D83F229A89C3066E35CAE1384A0266D5A37824A089E855F11209 +9F723AF03BC1C8B1C0BCFFDEBE3EF73A40BF83F5E038B63267DE5413B88D30155E62EDCFA35C0047 +0178E5558CDA2B30C4EE2A9854C93E0E484D4363E3614E5BE829FAEAE51935386D20DBFC00B42952 +7F56FB045EC4D97B3D649415045337AF44BCF4AD9B9F9BF3EA72151DB616FF8F6B13EF66516D9640 +67460FF123C7EA525A97F1D04BDE9D3D495602620659F6E5DCF1AFC5360D1C371BDF9984C4A7B462 +180A3CAA7098E0FB0BDCE694806BA466883BD28D77DB4CFB6635BB7DB45B4D83AAD4260A4CA0D411 +0E251AE7476A95327BD6AC1AC88F85CCB705FBD09993B9E2990D51C37F1110F78B887C54E4EFDA80 +4ADAE5D81477913B6938FE1B39913C6582021A1ACA834500D9D75C9942CE2375D0A2A73805751EC0 +970D6FA62D4354337A43D85DEA6C6F3334F40221FC473DD79344D028FAC689645963B371A55CDA92 +F6BC989F4F1880AC11D8A056DF7A0EE60471800126526488B95B785698D2AC488CC027D31190ECE2 +54F80757DC9B4FF18171409C457F5FC58DD1D43E8D1EE08A6AA2F374B7C245B7A21287DC333BCB1E +EB498A2BD723EE6BB30B76E574773F70A61F1E163A25941531C049ADEDDB59AE75B7A6725D997752 +10ED356DD93D0F0AD7EE6495F07869C570125125BC84946F6AA1152CA18FCAD3B68004A7F7AFC6E0 +9EE6E1B365A4DA15DA95AB980A566DEC7394F385FE041B3B7F46D62424F4726B55DCB4BD3625CA68 +1221CE01DAE78E24F8045EF21F85C13D27D1F0F1B589F936F62F699B93EF05930C6F5730B0AFDB7A +7A829F2ECBF0DD196ED66C7E4E4E7E05B565BB98385F017D01B1305856DB747C3634BF05DAB08836 +029674ED3A4053CC3DC696F758F86970F94034B4F0DFEAA4DBDE449800DB040B55E7FC83E6B5584F +A00F7C70ED18524037CCB48A22A5A69506A825DED81D98FE93177DEEFD42B485013D4C4184CD690D +714530B56E355FB01BC92DD90A7AE8095748A872F79121A28E965E6149F37C9D5F4DF64574F605E1 +B929174AE0CF533F77EBA0E10862BBAC46BEBF583B951BD0BFC5128B08CD998DE897033E7CA8B198 +625D865701394543845CDB7A45BF82DD8B6319658E28B34FD319E38E650869742BD2672623ED9810 +8DF14CE5C911AE0AF2035B4F9CC0D1D84176CF3AEBC4834E8BBF07B7720521C4E6C081A962FE29E0 +700C4F4ECFE92C39BEDD64C3DDF52959A4102CC242C35F56139643F22613D675F970CFDF8C6A57BE +9D168C9CDF93915F66A5CB37DDB9B8B729F8131391F9D6EADC8BDD5C13D22A0EF967622F3F7C08DC +C422E3D41B3BDA6B4520C98FD08262303E042DF37B9911C1447F3DC8A854973323E1C380A02DACDF +8A53A0D1EDE9BF34A50E8B76C5AD5B15F8E25B2783BCF4B1247309E9B70CC951CF3D98C1A25E9CB7 +11235352F3BA91FABA828F2D7D91F0FFC50852860C531C20A5FAAFBCE1197CA367F0F84DEB86A8FF +A9FF4C252EB2633AA2BDAB30F2094721F482CF926DA3299452177B79251B311AA60D4CC82F5A9F50 +E942703877AF1C10CD92DCFD16CF19BC7314FDA5A85284BDE964DE2BEE782F4D52D17FD2084E0A95 +59EBD5AADCC74A6DE64C1F799385F5EC2E2F5F869F78F7289A26B03A9FD906934C3A6BA4A7B36E7C +3B77A7581BE9CD62B49C34572A870053CBA85DCDB9FDDE407B29CB3D02AD1C752B54DBB995DF0F8F +CB117CF8500B97849275A4625EF9937AFD7C8751B9B021E778F7DE9A9B191BFC470823FB8EA919BA +DB8B68755DD83C6905B118FA18FAAE216E2494FDEE9C1125C3941092C592DEC7A5B0C763E7E0D3CF +DA02AF9FFCD234A01D75C661603820C37E9A681356A6DB424F5F991FACCFF78EAE3518C0747C35E0 +8EDEA2E108CBBFFA0B2D3BFD612B5743AC95CC4A0580A6739BE4EDE6CB1E8B2F4CB5C6FA4572329A +06080E0085748067462F3EAEBCAD734DDA18BF206EAEFE9F882807694B80A63AF2F40625E98DF55F +BE08AEEEC2C1BFBC16F1BB4D391B17122EFB5FB539005A613EF5C9F154BD50F05862F813F2083CEA +149FEDC651191259BA4FAA658A42AF151B03A7B553AA79726A44AF9175A724E0D65CE84F41F3B7B0 +E0B684656EA56B4E7E654946AEFABDABCC4F3876B3C3A67373F4133FA8498DCFEBDC27476FBB28C4 +003FBFB063267FEAB2B2BB8DC647345803B2723DBA8905AB0741137C43768B434CE118954AE55DD6 +61AAA1BB60B87ADE97D4197211A0C70CDD7855783B7C570FD742AE5A5940A3D90F9EFF687C4F1E4A +D3C4F5C3B9FF20B61C0076B9FF060EB99860F31C41B5AEC0D2C4DE626C6059678DFA35BAC5F2F171 +A3BD00065AB2007EABA499E4E7F30EB994F8BA757FF9BB0C9A2E3E384BC1DD4B62036E2D70819AD0 +A535816761800CFEA50681AFBF0057E69A0CDBB4BAAFB8B15F7727BE1169BDD4FAF692F9CEC12893 +E4E4425DE4CB20F330951EB5A7FBB0FC10DE78A7F9B0EF6FA629CA13E8C2F616A1BD42B1E26E2A0B +533DEA701AB7BA93526E2439755FB9BD5CB076C3309E73807A5935AF6CDBBDABD5DD7B036324130B +8BC40163FA0999364553CFBE351509F8A5167F205E228ECD66EC9375D0E0713563AE75B6C23423AE +63EB67167F2F4512BEFFE96B90913E6920F1F8B7139F1CAC9E38482B6CD26576776A01103FDEB164 +A176023370D08906E2EF27E1E8B6F6C27EC67A86EA36A6C82B681385F3A60AD53A8512E0880D7ACB +5567F2654731CCC1796C47E18DD6CCE30F65E27DDC5A3E56BFA0460DFC3F9FF1E98B7BDA9DDCC615 +718D7C6CD8DC1270E70FDD4973B287396E2B85ADFCC83C71DBEBB97346E858CFDA78713C0EDEFEF6 +B84984D719C4729C0A3F2A7422DFFBB2AA5FE61891D3D16CDC1BA4A84E7A74B0076FEBE0C2C74F4B +B9314E5246D7E67DE23466D47C8AA93AC4859B347D8CE31FCFB4D41137B51C41BF19D626A59D0999 +FF2A4FA5FE6FA60E029494EF99C8B00700E6E752F4F9ED52F2AF5845563ED8AA5D4E19F82DC0F87E +255ADA53AC62E3D7BC788EAA135431DFF49F2D3ACB61798353B27409D149FD635690F8AD324804DE +A99D12B02F15D9C6DAA01BE2C1512BB8DBE86EB31D7034866C10558C008D69DAD8830745F2BEFC2F +FCD957D0FEC30BFEC54F3C440F3A99BFDD7C6D0D657402A064F2656694E5F5A5524CF4A7A2AD4625 +5DE9D2E9916DB9DC2C39986A221C31F89A1884ADBF7DD62D4EBD47957E7A359F2ACFD38E073E8502 +5F907941ED233EE3582AA955CEF67A8ECE6D8B301EF37B7D40ED84FA9DD604C74C8E870F9C26A2D4 +DEC8F03563D29E1DFB974CA191D4696D877A468082951B02A88884B9B760961D9C37154F32D54512 +4F0E4357B68547CAE9CDB571089752D7881613E7FD8DAA8CFB98CA9E930B48B78AE13523E43A3568 +7B42DD2F0A99034ECA1DD782DA692EFF6AC99D6734DF1AED3616B198E6C242EA7A9954B7337ABA3D +13EBF06B95E16F19047AB0EDBAB6A8928D81003E593C1F134B0E2B8C250EA251B59CD04905F57016 +1662514225C393C42BCC172DD23D8871908522CFA5CE113EC05F39E4583EBDEB5DA425E4627A4A2B +D5C511F9C9C155BC81D0EFAFB0D0F2E96BD49A5C942933336EDF9AE0CDCBB159761DFC50F6180FB5 +024D2E5C2A20233AFF282FD3B1AAE9B65D2989BB8176AA8C7A1F58E43A9AF3A6D0168CADB6930706 +C4F974282D4A23F71B0A41C75086DC1C45CB98ED68ED0E4FC62807EDEF13C6C85741B11FA957D791 +D92B750F3B7BDFCA7E148149E55EDED66700483C4D5BFC3973580F7199FD99CE6B358B508FFF5DF1 +78A5E495977D851B0B06DC7F6B38388D5C94BC8934584D8EE2F4E0CCD3332A737BC066F042B14931 +57BE93622E346FC6B293B8DA0D3EED02508AD2183454FD4D5D21235268834B257EA8B06117F67589 +3E0505E64709FDE03F2D5C82B163C29629EEBF5D408547AC363758D8D134AD7B9A55AD9C7D90B67E +6DF3AAE6867759D2A75993265118BF6C5A261C6D80EF039A0163BCF8E6B40E643D1BF87BD2592BFD +6A41EFDF9CFC2E6DDCA83FEC28B5EEEA2E363C20AFB4A13B5EEB2CA3BAEB2CA6F4824AF1A59E4CBD +884CA4C62852A095E4B13CD018669AF3898DFC4840C874B97408C811E431163887E5BB8CEAC12FA4 +A1EC50E8305137437441AE0FDF8FA4DFFFC77C05FCCC41696E40889A02DC4B1267D5B892647D6AFB +BA549F737543652D3C3A051E36BDB692DD7EA0D8964EEC27BCAE8EF5FA853C54D67A8ABEF7B01FB5 +AA473DF48CFBD3D697C9B55C852773A35B9A7C97908DB701AB66DCFB274A824B60E275E1CB341147 +36B26E50EFB1DF01F01688E09E096533E95B3AF5D09D7823DED38487C58B4F10D6AC76EB48731CED +78AB098C452AC83CCEDFE4E8E4AEB4A93A715306A096F262BFDE5036F38A3B733B1A0134904A3EE0 +8A9F7C2723FB5D0535C5B57CB80C29E292A49AF936DAC66CDE5C01640490109E679FBDC13F892438 +D70CAFB12909FD2ABFEAB23ABF6D129F5628B36FA00548ACCC39C8312030DBB87364DA44FACF3818 +D4C8ACFE3302B1487D5CFED16E17B05CE9889219C13C9DEA28C9BAE5D788578C309CB7781244E30B +7DFFFAF5A9F594B8781F849EB20B1F3A346C2D697CFFEA6AB4134DD46C86BD0F89AB3EE9DBB2F87E +988D906C21A43E5ADE58BFE82D4D4009A39EA3D1E779FC374FF21B86BE48AA4A33186DFA0F97BBB3 +218CE963643EF2A35788D613DFF934139B3EEA36377E67A713D20BD3DF04720AB49834E3FCD78908 +1FB726CF642A5B87D5D23609661F7D694EA0256F3EA0DBAB7C2CF79CF89CA0FC9D25281EE0FC16B0 +D089DC5B156462343A375F1EA2682A53F70A1F239D58080F4F884DBFFA68CC6D63365A8CC308DC5C +BC2387BF3D3107C95FF4DDC3A902B31C3F414355748B10518EBE00C92682CFA413FD071A16B8D129 +4021B0ECC5025E33F6116C89C7B983C6BFC31C5C8D7FB5E5E81D3AC500123CC05B3C8DE01357E192 +0DCFD172EB4B488CEB9E1ED5FA1D235C96FAD22B319239FDBA08ECA2C5C1192B4D7A797ECE135228 +6BBF1E59AB3B54B8886E67A82AD971DFD1EB21CC5E3512CA922F9B870A48E6DC94F94181E422D274 +2D3A14FCB3939FC8C1D62CAF79033D6EF4DCC93751BDABE588BF5D97B52AFC5084C5BC17246FF977 +7AA4D738BB9B15E534ABFD68848B879A9840EEF4774734F0BACED5E7B6177DFD430E0497E36D1077 +7654F351348BCEAAA18C3B362B2791A006782C25C9D544CF1594EA623BB4C782C6AABCA95F9CBB1A +8C86318834E1430376406D2B6CD5AB09644361B83AFF66C96CF549C2D309F7439254C6C3A5B210E8 +23F83647FF420BE66901C317349C1B305014EE7E9F90DDA917E3F853F1A8AF3DF1528A81C50B76A0 +F02E933229C2743BFA639003025697612BFD8575DCEA0BA5FFF805EEB4D9FBFA8D2014BC239E9D5C +4C87E36D1C83E010B92F43C06733976BC84AAF1C05C0A0CF45CA7746ED7E1DF5A12F2401C0FFBEAB +EFA199A7299E4BE5089C2CD83E7838F163F6284FC299B213513F803E93ABD8D759595DBF513D68BF +96031B9FB95A945B7C9153B0B315436C850FA5F1415AA2C9565F6FA39E9F5C5FB265CEEEA8C98E4D +00A72CE7F9F6677DCA7E58C1A8C111A9C6C44781867AA5FC71F36486AEE73FB81C03BF4EC728E43D +75564244AACA3D66B6D36DFD38332AD05F150D4972FD475FD087E13C9312D5A17A83411B45740153 +81CB568CF85BD66428FF9EA2C07E7BF8D0AF4469AA367DAC0230650036240634AB81766E832EBA8A +2D8BFA402DA804D264757E74B3465EE21A1EA1C92929444DAB2EC83050AD169F257B77D3F4B9BA61 +B11361F5DA6DD2DD933E101B64F9DC82945A2D421807F09F3E587D4B13BE0FDD6D7133CE890C3AC7 +1D0880418880362E27635986795E2E8426A0A7D7E8E5C41317209D957B53B6CB9E4EE7C3EEAF3315 +E006B7FD90E7A58FAE5289AE513D7751201459BE029563B58D967AD24E90DE5E96357D37E86CAEB1 +6059CD8593F92617AF636C7D32E2B074A40B6A1C40828313C8DF1BCBB002DF276D424519EEE2F234 +FF9B9B27126996834BEFB6E05A7BFE958B4AFC810E8B77F0EDDCD43E81549154F81E282276A7133C +23650ACB159EFEA53ABABAE1C1CCEF5642898A5605A285205DB40DF6C768029D8CAF85C520AA66CE +5BF1E0A0520CC94917FCC3118953403A1B16312096DBD56883F03E78A14315A5F97345E13C363C06 +3A01D49492349D60A9114A77BB9FD48FC0C3AC76D190204DC69C3ED4A265B8148F2C5F2E147A504E +4F373637C065FB894446031F78C4BDEA68088681E0C5099CAB1D13833FA87AB96E511013A9B3D806 +E71EF6E0A1442C91FC2A1795A13145ACBBF5D18880695EF11832ACD328BDE6E0A7308B12759D12C8 +6B558CDA038590787704BC1BF49EE8C788C41594332624D56082ED8627EC110233CA328D2A0BEDAE +3511719EDAA726F338D324D1577593948A8B9F0300F27FD4420638C6972EEE2D6248B87643275DB7 +69F72E8F86803184035F6A539A7CDF43A79886ECF110ECD7053FC04EB5E51B3C7625B3BF95C0F5EC +044FB7226281BC723988AC2498ACC0489DF0BFD1DA82D04FE3ACF6B63EB269BA9489F8D5D07DA9A3 +AD04BA924B99B9C1EA64AFE7BB2886513EA6730462D4FB5DD82659C7DB7687F4CD8E006581A15EA7 +715E274C9B89F66F1ACE9C2AE7698FCF7479A04F2208DEBA6DE801A6D184A8A9AF6BC1B0E37CEE3B +323DC4EF93EAA8219F946DB9F4D9C133C6CE0FCC6884F9C2F3A816C4ABEF44DD6256E7BC4574600E +1D825080660BF6858B415648258399839118F3C11410C1C29B3C208A3B54AD5D7484708DCFBCA04C +849F2AAB79E4D96328D990C63DE05DC8E804DDAE255F94FC3D56270BAFF6F86190796F91BFA018C4 +FE4FAEC3F1ABE8ADE43D0DA18E710BC1F419F77DEBAACD3BE011BB93E111B18CCEDA8EB0352934F9 +690F3E73D71655191F150BC3788677D1FE46070FDB354BCCAC8C179009553A7D67C87518131A4D8B +4FFF85FB9485C9F30F4CD31EECBC4A44CC267F6C57AA05A11C6FCC09B5CCC83F189F6A32F8EA56F2 +2D20DA4D4008F08EFB1487675CCAE22BC9494441682F4E46839F0F4D2D16AD58AD0886C60C925DB9 +C7D9AA1A7FF41C94B6289E1B72382789006F40B99B78B05ED1FB1F715CE4C0A1078AAC02EFBE6306 +F53F5F7E73DAD249995DAEBF17E5F55082CC6885A54F93F1A935E0389FE54E8B1B6C5ED19D483620 +A697873D5F18CE9A48E3C2C1C871FD4739A78782D8112602DDF8D4FC497C459067A6B118AA998740 +6C8DE97C2F09CB9D388D341EAEC0A5BB4BBBED92BE59B273C77F3D6965418669BFCE0C43D5C86275 +D8E658BE1893DA8E698DC858CA459711969B2CBF4CE294071EA572496575CC35CAF57ED49C2FF1AC +CC21E19D189B7C2A1ABB1AEAD7185675413C224CC4C0E1AF4EB76BA9F44148A95D8609838B967784 +2391DECB30BB0FEB92CC890F224FD2E9E9D34466D6091443CB69E845D4419F9A04664706FC8D2D15 +9002422367F39CA1B1CB1A6C32A65F46230CA2376C3E5125CDFD367514E087E59873EEE569B7F376 +227DB126060F063662F118C7BD01946BD04172147B601BABA952A01E0AD31AB1147D48FC2C3F52BB +75D9618E6F03F1F1EA393AF0E8474025F451616C4ED236ED831E14F40BEF5B86806B73ED64AFE7B1 +2A3C1F5036BB9AE79862EDAF13BDFFF06C94939AFDA1A749364BEE73449520111CF56181527F9568 +F3189652FA7FFDF4BA1086DC5992C6E0282B6F88D7CB73F485F8A27A77453C151B0BA40E294653A9 +73298EBECE8132B440ED4B4437283356B79CADA8198512A45044A7AF04CD02CD4DF7F47D5D1E7FE9 +52C346B01D03D1F69904D1AB5E8C433B0615E88CF4D01B3C96361F82B5CF7CB4D92FF3971E44F0C3 +317D3C5B0BC8DF4BCD4DC63474D0E0B5BEFF3177E2722D4AD4AC4B4AB6269EE948BBAB6019ECF2F5 +846A3D215F6C0D999D489215D4328875DE21F2CA243CF184280B229ECA4B8A9C5290973503AE5883 +03C67DDECC577F12B41F0D4DA266772867F9D93E1863BF76C6AEA5DE3FC6567EECE93D96F717E39E +DF536ABDFEC14DF6748DC90A2CDF6066246DF69D2745D2944123AB3A6ADCFBE7C74EA8E8D712AE86 +F76B3059178E78FB2FBE8D1F25831C70F58FB6B5922B371A27501E7463E01C844A2226CBA263B570 +4E5C4D3E50FE31435437E1ED39E6E3BF47B4E2C4588274F044B3294E7B2BFE302E76EFA3CB74108D +A6CFBBBF383F5C456128ADB5E667E1F7ECB4C3E00AB8937769E5A2830520E9FC0A1DA1662F881ECC +DD7967647B5841D8FDE1DF7C9F5475523F236005EEC0DF307BFCEF379355C30A83EDC96D6086E224 +388DC7B5E951B819347AC5A1F9FBE7EF1907726EE7E972AA1DDECBF7F72658C20FDE99FEE686D7E5 +01A7759DEF55169938F34978A6BD4DB49E494883F67E868A9AB177FA8E6F81157A95A03B4D9DB572 +EC1CFF33B450BC13E00830BBA20AFF928CCE04B4F79F3795DB54A4A8B5A2F3CB323194990050CBBB +C7CD32103E0911160FF4DFF135A77DD0CC15867B994CC88E1EC10E3A097D329DBB90FBB62981FF61 +C2521F9AB4B9393C6764E5B4361D0FBB1938456CE437142F0AAD9341588BD15EA0F6EDDACF12A62E +C025F3294AB1AC45719C5EFEE94067390D579AED4D1D36041D358CF1A24446176DCC808CE2D6CE02 +7A2C2F6E517A5ADAC722EE94A1710BF61254DB4693B30225C12B9C4F856E1D24075327017D6B288B +B52EDE713B3710778A565EFF6C89656BE3C5F590F6ECA600390C1BFDE9B0EEBC2E4FBB9E0E2F405B +39738F7969F64E8228494B298C3FFF4C7DED00B0EEC336B7EFEAA892C4A80CE9ABAAB4318FB34348 +93AAE6A90FF00B892D1DEE254DACDB268A6308E91FB628A98989956958C9634896B878CF93F4E0AB +A0170C1B7BE2A0C4A0D514D7BBBC4CA114349D4D4985E96DB7E2ABB752C7828A9E36D9B0B4551DCD +D878C06C3C68D2C214EC8121F6675D8D03545606B582B09B76B6D8608DFCED5C4A721F7008FC2014 +1D877353E8BA5DEB1CB61F7C956D4A9F8CFFC8C4FF81B2660AE4BE45F7A63141BAEDEA05C43CAC2F +A04163ACECAEF90F61E0473E5CBF1F1994076B6A72CB5C33B17DD57E2632F7C6DEF7837F8A939055 +CF357795865D86C7745DE54C6079C791850B20C0C7349472FB6018521DD5924ED1505A1B8C8F9CF4 +C892CB40795C4ADBA3CC11C8A52A1DCFA8FD334D7F3C344CB4057E80A4B66AF6A97799F8DE817CDD +0202870BBF42E76C9BABD2D9B66D10F1A68388AF1A511887FFC50EC7D07581D4C4FC3F6C4F7EFCA9 +4799D74132B5EA25DF0C9557902C7EF1E04E612D9E40DBA459513E584C3A3EE5614ACEBA165E07A7 +CA3394969C2CF1FFF28B1C7DA85451270DF0FB71DE22A03FC2F17531FD59B12B55DEA7F5F56B0DF9 +34C96E26124342571BD04FAE6A12C6EB0E21F06275605FABE91C6EDCF55B298BC4CC52891DD90360 +AA5FDC150004BAE65225FFC42D13026F9C6FE343D7CE2F52229B4846F6E23BB2BBDB6DCF60F07A74 +8F19F74A1168DC5C67BEF840A3C68CA7A4D8CE7F94610F4CEE989459D0CDF1B194C63A2B82479746 +03A89150C4C6AC67AE3A1341F9516887C6BA254F81C5B552C527765A52ED5C4FC45D575F606E465F +7C2EDD2F5927319BE737D48099C333BBA84486F5F8CC0B32052DB6E57DC55A68019788DEABF8D649 +A531C1880D07E425D55D4DD4F3966B2FBD2A0B55E5C429051DCF0E3B9CB1DE6A5B3DA05DDBBDD3CC +1C81877AED2BD272FC7A10707C07DAA54FD6CD37E15C247E3100A1A0C527727B73D45C8E02798C44 +1864A2D1D30FAF94121F0CADA24753221C85DD5B43E5F00FCAF73A1E531D9453307581C6FA28BB5C +54D93F149D3871D2E017E6E7FFF7B0BEC71B83AD12AF353CD13311D3A6F16C51938986C9B6A24EAA +06B8BE6DF27A5090B3B120D1D1E064C6C1745536C6B0AE5C899C3DCA91BC38B7E900D9614F291B9D +BAA85AFBBBB57D58C3E1FA8713CCA1BF4EED469773EB4B9605125C08A8F7E998E37BD893F3533232 +ECDF47D26E8B2A0437220FAA760DC8E90FCBEF59AF6C1C55FE1A28A4C98E2A67DD5A7E55BD4FE272 +15533A56561F0D80989BFE15B321976CDEF26FD6530EF7A368A7239CC55D7AE2B8F0E980DF63CFE6 +F562F3ADD0AB906B60682BA447CE4A86E6D5538E13C6847791D8A16F5BA29E5840847A7E33AFF57E +BBEC1A5B329A461FD0E858DE5163A2120BA12839C3A216C44F364452A2D6401EB549791012C4B65F +4FEECA2B73B2D88CA49B44493802B01A23321470A2593A8F8ADE3F88D87247851561372137E11D10 +11A733C671C71D33EC939B05060C73697EE577A8F2BAE08309585887E5F314BCC642BA2715B51E0B +4D093F6B11CD37BD9728EE90A0C92D15BD1105637052F89B417F6F36340588601C9C2BE9526D01B2 +E88EEAFA300E38B0EB5E2B54341533B31DA1193588974DC054FFBDF374960D28F0C8C1AB8505CF5C +64988DB86E17213EF0D9D6D52ADB1BCEBCD02B5E16F0866D21D7C0FE108D551E695CEAFBB83AADC7 +362727C47BF24C482EAD6F122F1F35923DE5D6A248BB36433D044F73C944E6CE4D9FBDF0417ED53C +8F56B6D389519E7A539D6BE9444A4747957FEABCFFDCA5FA54BFF46F637B3A3299988929CDE008E9 +E3C4CCA97054A822C4AAD01ECF9861AF6238E6643358B0EA141B0E161C6ABCB45F38740B344D4112 +9D4E898DAEA8F2065263D68D97966FA24BF88E61BD86CF2C7BFD1F058FCF04AEB88F3A30C9D446C6 +3611112CCF30F163C103D6C7C5AF946ADD33B50A58FCD8EC612268F7E119BDF387104F22E4C2CAE2 +DAC407F206186F12D93BA87711FB05E6E96F17DE333305196FA7C33DC06255828744B590FA0E67CC +E4B0375276FC7AB9B324978B15FC228DAC17F955C7B3D441C540192145FBD002EE20FBDF6F397F95 +336C0A056609E28430E123A432EE91594E20A8D9E5774FE8768C84CC040A706D8D3590BBC9AFE373 +4A5536162846B6B7BB7B248924F1DAFD768B9546BD2A2CFA1203D6A3FF45C8EBDE2355F01744484C +DA9FC337CF7D9D54106407F54FEEA81B77BFEBEE088F344CA2E537644B615D8D6B6A79D03F6CBD9B +573FBA87EB00410B5251A29007CFB60E711F642C19847F58333B48F66B6758E4ABE524A4671B0635 +C491341B3CDEE650CB9F774A5B6FB92AA70FEC7D9A057084214D81EA5A36A7F8EBE9922A70F2B102 +121736E0BFB178A08ADC0A58E2A9DB347FB9B0BE707C038CC19A5519C3FA9AAEF660653086191E59 +320D0E696218CE1E8EA7DB5FB3318EEC98C130F3F1C45D0D2401223421FF99BD6E1546873C6F12C6 +F45D2E1C3EE41634F5A415FC8338A18EF2299EFCECEE00F9025E79610168548BF2A52623A479EEAE +CC55BE5172B0CF07F9B04E2B2AC08A2BC839DFBA9680F2BB2E438519BF3B434C71B4AD9E64262C76 +9F6C1AD174FCFF3F41B5BD7652AB296C543F323F0A16E88C6D1FD3025C33794551DCAED303B57A87 +CD1E7FA46E16ED357CE0FEBAAD2678A4D84E4D6B1635F412465C0F3E7246407BDDF934F0E2E0F5D3 +EFE318D7D63A7B6BD0CD5556B6DA811D521408EF336CCE2D2B6777AA472A9EE0DB9FE0D6914059FE +25EFF5D7E3D2A6EB96B23669118B9EFFEE5B7FB8F1EEEA355998BB48430156F14766FD77605BBF80 +CDEF19879E8F8C07B6998AF145B0AED86FA94A952F2F49D2891D41AB0184EFA8616B139E640A3A9B +D808BDF79E283B0CC4686935D0D96630D590A5F4A7C71C05E110BF3CDB5150D8CAC418AB25419BCF +DD5EF0A2015305561CA26494E267BA89892AD21E0BFF44D48E330694A1CE12183B9A7E4E25D78EA3 +498EDF9A22DD7718ABD06DE2C28D7762F609A1E9A5C40A878FB8AB33A60383152A119B9FA077B109 +90AF19C261CE43AFC116593C30BC27EE4D8CBCA0C0298BB84327FDBDD93F073B1E06F71933C0323A +6E7FD2AABA783E9BC995C4AED621434B82B34424B768B4427EE65228E612581B0B8A7AAC3149788D +FDD106A6AB93E01771802AD93B63EC386B057690E5C34A409421E532C6614EC61A0197C13EAEE438 +35ED9BB38CF811E39CF8F154684E3D8B12E3B673152B82DD9B15A2A68A6163D2CCD72D3117F7C24C +F1575671832ECC4AC6B912882C0231050D60ACDC7D6F36C6BB4E32B6019B32D1DA08C7ACFC1DF451 +3A338FACC16D297C56C6138FB02FC7FB5BF7B9DE4C61B63C6B37B0F9CB42E6FF86693BAE1CEBB60C +9C15CB6222F547E0D0776BC5545A73A2ED3C7799F0CA3C2D5EE17849DFB15C6ECF7C2846AD10870A +00E0810F35A57770EEE9D49D05B54500DF164A02FFC324CCFDB5F828AF7307DDFBBE647E98909C73 +A3CC6BFB360042823C678EE6ACA0D658C12776F2A573656073E4F40505F5CB4A3D340B034B0FBC29 +C3B6B055D23F0BD47E44B441D430B8703883AF8EBA79081D528AF5646340A27291472B8E1F19C8BB +B4AD17C7EA1FCFCC7B52E6EBAE0BC8204AA52C08B3A63B2F07FBFF20092139143A24130191C41D2D +69077D71FC204C5FD41275DCEBEF7E5701BFF6C0A4217F6F60C2E37697C7F1C35D2451B040BA0D28 +0C9D23AAEF592BFFB436165C314C3CB75223D15694B6EF312CBCE8035A1A9172365FCCD119CD5DCC +569B84C6BBC5AC9CAB6942096034523671156FAE2012F6A24A001DCB2F35A8A031A2366CA98F1E52 +944B58FBF1852710CEE0116BD2C7D68DB956B15FB6AAA147155E9F179E67357F231F8252D728AF12 +49DAFCF6AB4EBC8637E1BA10D27555D2FAAC9EEE5E51C8BBC793ECC6011C4FEDDF7116E719147927 +0BC11D5EDD9215A4E8087A6A16A591BF7ADFDB69C4A03361C0DD078017DC5851BBF60E06A86C6C0B +E08087C99F4F9002ED5206534913353AE16C4F358BC1564A442CAE506A107D1FBC0B9ED99AFC6633 +209BEDBBB681CCE475645E92155285C00FD6985216CCE60064946F94778F7AA85ED87F5762C20FE9 +DC007954281BD6FCA8554D2A0CA5B76A3ED42EE5F44F3B276E574F64B20E1AD489753903ECD20B4B +EC88ABD1E1CF5D06AA1815AB771E350EB6D04078EC04616B977CDA8CE88C483DDEE9F28D58366D3C +224C41D19E550B5ECB9775F569C2D391F61C4667A9BD11C69A88473AA7884B823F762195CC403823 +690A32087893C29C63100A5935842F6B612C95EC9B5F07459608786310C8AE65DBBDCFED21B43191 +874E20D08F12E1384DCE1A990CA5F07DE36BD012DC9EC558FE7CC44494F48CA3BCBF1F1F11BB98BA +EBBF8691F8590F84AD849923E656860EFC0EC27496FE6D6C185791E3261027DEEE4C57032547F94E +7D593F7885526AAF054BB850C02E863D831ECFEE61A781B89867139889A362F95F48A837ADB955C9 +939F609D2EBBD56775151D2EA4B09D38FC1D824A952EE7E52849260DE61F07333076CF887A3AC2F4 +CD088C29E47715C5242E2366CB493B2FEB38C19FC159EC50EAE88409CF0A30C0A6823C45D0532C2A +72E45A17916F6CEEB475C4D4A19372AE271326697CCCAFBB43D92C25A052797186FE8314FB41FD94 +2A4B24548866BAC19A83BCD2E6979FB3C7B70B075DCDAB3EF6B6181A00A98AE73B6D968EE2DDEF07 +503A92E4FE1E0B67A90A2F351D600DF960101A15808AA99B3C680A8F50D5CBBC96D98A3A2AD5F14C +43857F4CB9DF9372FE74B5D6CA9CD801667399E778B56EF702A56F0F393137B20BF11BCFF9DFC0F0 +4E67649D07A2A5F4C42C9A929231D5BACFB6B53210E9FE311642D8BAA7358E6A7370B6CE921765B3 +68A354B42C8877E59227146409DA83E407657BEB475329F228CDFDD11BC73123234649AEF0E2E9DA +76C12AF91713828368FB778905A6B7150258695D4D9DF6111E1B28A9462002D7C476FE44A9B13F32 +9FF84930D213787932A1BA01EA608ABE7054FFDAAE2176EB960005E5407D7C1D39AEF8EAD8683A50 +D93398C584312EE4A12C07E9D55AE9981D7EF57D66499CA93EA653EDDA1BECB494662E54CD7ED8A3 +0B2A8522CAB12B2751F7E9B3B66CA0B5C8905E0F3A51F68C96E9C02F10FE515FD6133D3ED298D15E +8B1649F3D13341BDADDA7FCB838720E8D0D9DD92D0A241A0CD8E25D7B313DDAA2F25B543BB0E7965 +402ED0F24AD146E49919ABD9604ECFEA5A7A49E58664DCEFDC893F5D722CF24A44D26369F5D86569 +9632141348086A80AE528EDAFFF9D9986D5665DBCD375DF221D5EF1757D79361E5A5BCBE333B6C9C +1CF46794A7C7C776477023BB298C970F6DFF9AE6C7ADDA8CEBE73B07117BFED6CED2A36548081C79 +BDA9A70C8FC5FA16D0EFD3E9F869DD5DBDF6E70CDA4217935FEFE577B64DA1DDBADB9A092B9D1E3C +E1FD3B6E0117DDED155313A5DB7D8742C3409FC18B9743F09ADEC49BFF2FDBBEF9D5FA7110266287 +7C65E3A1421BA56E258A49D76C436C97AE2116F772CA5EEA5726BF17AD5D5CE37DC5F45235730E90 +A1A1E3087132C820EB9E0E311500F2CA193C72E2ACCB4D77ADFA34E268B014FFAB5DD1BE7187251A +A69B7BB3A517796BACEFB9ACE0114FAAEFB0D9BCA028A52F5037291232A04C2353B9663BFCBEC2D9 +30CB007954B8C6396003214262AA9CA9FA876B4191313FD1831D664863C4A19946AEB8F4E21C468B +9C94B8CAA407A74AF418DFB60D46BEE5029C884950D3BE8A58023DA864E9AB34005337D335B0B35A +91DDEB53A54C3233150E27225B0800C841E489E9EA6C12F5D95112BB723C3E88AAEDA3A942D06242 +2CD80B04DDF024ED79224E166086C5770EB10C389D0BF0327B2F753358D9BD552C04EA52BA154EEE +5A84C51FBBFC79055AD0F1243E489F82FD3D1A3D2CCB24A02DB3F306767564A2451DA405BAFFED98 +20241A82C6F4F6E1D2A36FD954540EF3C091247120F5E1B362D1EBCBF80951A3158B1547E7A0CCFE +40C03F992BAD00496C32BBE9B0A06EE9554EA3FAA247A7399A37D05329CADB006F679B58F2E5969B +13A5516A9F6949505A64B7B3FE5E748B9B9662C05E6C5CB79D64FD72C54F557ADE72880B3F9D8718 +58D5EA3FEF2BD3FCFD670794AEA6144D13782BA89648C98E7CF5160089DB9798E49BE2DEBC2669C1 +0C42AE1AD7C1FF4921EF465300977E057C0AEE61579460F56E51B6EAFC1F7F41D669ADE9610EE777 +055F927444F971121CD76A55A273CEBB481B89D6B78D0066ECE31BE3EEF65CE9FD22D22EFD6E3ED4 +536E6439782AD53550CEF1A903125F228A3E2F1AA3342B0551C59924149358F8E941969125F6E54C +8B2C068F57FE0DF91912CD71BE9492768191F4F6B70BA45C72409D4AC6E9619E8A34398E6A66E984 +55F1793D8A2C0DF30EABE2B19679318AE09014262DFBB9AED5D637653FBA1C10821908ED6E088910 +AA033E2E0798A630966D29F84845A9C937C27A268CAB8BA1AE9B32E12B52EE4B64BE5388AD32035C +7F98904F052B31D7C4819E27BCBC597E8503A5614E0DC2BBE5C51922980E3F492B61BEEB169C3EB6 +AB9F1DA82EA6BCFBCC16199923C8399B0495EE9A9E1749DAD9FB289FF3FCCF34F55DF7D94F91EF31 +B3B4C8074C567C4FAB337A337BCC2F459075244F665B079C159AAB83781E465F5259D41313183EC5 +F5F53BFB4797942F93EAD6CBF9255F9B4DD0748A3BC6BF36ACBE0127AF68EA6566B65430D0595FD2 +A7A2FF74055BF2E70BFFF2B79131F1871CEDEFB495FF914B88770654F9E5556AF535E1B9AF812004 +99288AA39D1388ACCB5B11B13596B550F2746B2A83B076F4F606F7580156E54FBF6976AA4CFC9581 +0A7FAC41A1635FDCFD6F7CD6BF738190D7F9FEAAB8C0B7CE38DD1459E2465C3B75625C8BAFE3B60A +F66ED183965AB9681A8174C44311D8EE36E468A8FFE2035B7C5AB6A372FE37FF627F4697C0D19F7C +8A1E356F829BBF2B8F4A95A49F85CA16ADDCA5C0817D6A4F7C4EAEE908DA13E0C89C9AEFF6D1D7B5 +BCD1BBF672B46C4960720CD1C74E70C78784CBFA8930576AD4067D406A0FCE9248DCE6D610D7EF0E +97F3F9CEA1D08DDA90DFF0C484DD32265FD13A2571513F361DE3061F2EA76886112AC7589B290220 +E34610277CF81535CD628CA688CA812275D7B9909757DD519F1FC89FE4D0AFE5FDB999323A470C6A +A0D9BA9CC92BAC24514E7CB3A3EAD2A70271EA8B02B2DDFEC6CE803F1B761D9BB7099FFCBF918D8E +B602946FB0DC14F0FD1289037B15A4A96A4605BBE53BCEA9112BF9746F3BDDC06CCCD808C62F2B41 +D4F508EEFB03AD22E2E154888DC63C6BEC6A21D1851A5C82397FA49BD163BA8A72527827E4B6F50F +585325219FAA9B3A2CE14A0134C19DAE50373A0F9E6DDC8205467242D11A3989D17730C8169964B9 +CC9549BE20A84FD9137DD9C9F7DEBAC3A41345DFEB0AEDCD7ED408A909000FE8D9CAC85D93052256 +7A2C9312769DC85F902D4A5F5766EA3C561549F1F2B4C5269276946809ECA26B6F51DB4CBDA9E668 +BE1023D8962C0DBCACD5BBC9E5F61C459B825036E1322737C0F196C0DF93DA76011DF2CA06F7B383 +8C672A802EA24A474ACF7A51F2DE867ECAF5674B1053CD5419F5FAC20584A3F7565D7CE584CD395B +1968B622FE3C68DAD2F0E33274DFDF03B5A8EA047B077DA1316DF487C91ECEA84E9B417EA25EC9CF +1F1CEDD7A1C2CB0D51A58BD8F9772FAED8D553141ADAB148AFDA200479CD04C0FFD1478EBC618303 +5437A5BC1AEE3218E9B27D21656EB9F31BD4E7D3186C89DF251207E8B67265585083111BC1AFD4D6 +A2773629147A29CBB4BBC3935B83392487858E0D18FFC96E57C83C4C6744C8E0DBF001DFD64B660C +CC8064907AA4BECC12376A1EB55EDF655CBBB4744C1A6166590B9572073A2AB577EF446B80567241 +389F990AE6C90B286EB48454166BBF264422FF2A387FA0B413F2295B6B188A64927DF702C232CCAE +59A2CCD1D109840A464BAC74A45B865A6667C901D86F771C4A36421308551F532497990BC15DA648 +6E322566C210C517DAADDBC24DACB39CA41611B9F961E4696D1FEC46E71C608DFDEEF19ECDD88724 +24E1BEF7176B0AFA4888BDB4C56C8690AFD03428F32740DFBC4BE22B7583DC47BBA42DF4E83C14AA +29F4E79397BBDCD2EC43338BA1F0D2CA9DA6E64A065FCB0073ACD0D86E46EEBF1454C9C172C6BAA5 +0F37FA19756B05405763387237794E9FF74E6749BF6CE5EE9145413950D342DBE5B0EFDE57163127 +2A8D060E935547E1FB0FB1FD60400FF856D027671CCAECFF7E215BE61E8A77E9BF5C72C2C1E4501A +A11B2F8574BD823574EC9598D579A9C5C525867F4BAAAA78DDA0E5BD7AC832DEA41328A507874A85 +90B7F133E743471D4FA27DFAC39C6F99E233C913183B2A039CBEB5CB3BF8825A92D83D266246D5B3 +CC7B11469E611E260C6ED16D17C9693B13B78E3F0DE2F0ABBE73FD6AE1ED25F57B4894254FFDB332 +0E65ADA53669B95CA28BB4BD166507E9D8F12727E46D2B9593186C090764FE8A95F1594291FD551C +A96E4CBE1D6FD42852B2B65E7F10C4F17707F930DD934E2A2ACBDFA40E04EABC1E54632D67AB7D5C +00DC103A3D11DCF78B6771D98ABD5CCA0B253283C67B0863C80D1A78FE6D5422568207509FDB1946 +92706C7A211B29955F6354092C9732DB2ABA8CDAF407FF25B40BF9D73317D5985E19E6C12B6AB5F5 +DD59328905F822E1EBEB87C4E386EF20CEB7EAF842700F09BDC50D7AE6442D1C93804D56FE194785 +968373A154E1F426BF76692CE3E4474360ACB9FEBD3191B8EE909E7C224EF90EEF36CD660AC9A642 +4DB5BB20B8835D365D35A442ECB2444F30466C3323001A087639B73848E3EE275406CFFB495ECDB4 +52F2A357F45D2D32BB22CAF9F9C2C44741A5341B29BB6C4322287A2A3891E1E853B976E17DD9306F +D98BDE8A0C97ABDCC7C708BD1BF49B524CD0DCECB40DDC557E9C90A1EDDEE57BBABC4C338F08A625 +E03C1C1A20DEA709051EB1A3264D7002D6DD2BB7B622AF93C7DF54F49EFA5FBA58F115A049A91875 +A2476C19F9133D0BE1B07C8102746163CEA0A98F9B62EA59C9CED7AD808DD52DDF8687933AE52A7D +9D7081150A812801D3FA78F90C4933E5DF09C991325324DEC6ED364ADF73DFC7B78953B51FBA2F81 +F264C2A94139289CEBF7ECD6D8FEE9E579BE231FE1ABBCC07B4BF1884CABDCEBFC56610A5E2B7510 +37FE804511FB5443F7B21290E38855F6DE5EE38960E02481DC57F83CFCB87C8FF1CB196CDC19B2B4 +6C7C72B64D7D45C678851ED7E2860DE7DB772BE7B33C84ADF7E6F9B2063D1263CDF55E6220753ACD +67C4701EBDC0799AF47AC58A0CCE796384A50DE6A814DD994B372630E64E5FDFF57393522F689DF7 +81C44599B21AB1C214D4ACF94F07CFEE79C628C85378B96D9007ACD4225E14DAD8C70984DC596DF1 +96BC814E7346217C94F172FA40B3DFC73C30E6E530DDE4A91F6A5166AE19EAA3D2CC3D9D6917BFD3 +1EFAC19C236463AF8D7FB7D9B3A4D6FB6D962C59B296E988561957A3C3D11F33ACF69F5768A2DA30 +462BA9AFE67D3C41A1E8368099361F50D4F6368963A48C75F1590804E7918A02EB9DA5F60F49828C +95AC60E9D86DEB7699C35037669C02D408269D6BF481EC745E4EC630F68FF5168BE5E0BDF875EEC1 +5EB9CAA9CBED1CE2A0EB4CE97C14E10114087DCBE5DE1DB6A070CBC6B68EE141B7D62ED320F7B74C +07D9762E0F5C8AF0779D38B7677ED65B5DD2F83ED06F041B5701228EFEAA0FFC031E44D6D68B274A +45FF9EB62FDA007CDC98B86831E9A668098364B421E1FE2A45D85824612A521777C6177316F0C6DB +D9847A2F61326E74A3114EAC3ABAEE456156DF125E4EDAD6BDB66E7DA6370C90ADC4AF4EC1958170 +C32D5AAF3B45BF749EE1DFAD8A5D0C03973B7C1589EAE4E67F6C87213C721E4A33466F3F54253545 +5014417CFFC9AF461CF695F5E1D7A37E4C7680A5624AA11EEA65C59BB38A96734E4A4A238C636638 +9EB8083D5AD753FA7F74EDF10054315EDD53DE61D48846F70AA9272626E23BA3DAB7CCEE819B0A88 +9CE775AA7F5205C95A19AAF475729D2C0BCAD9AB5459380A5F034C108A64B80621820D779582A198 +14058DFDCC6C2D6461AC6F98C64AABA53A2EF77CEF612EA766FE15498F56F54106D70D0F8DD4134C +8C64B282E79A96F15D4BBE0297885ACF775BA5009006315637D60AD86D25A3CA6AC5BF5B4DB95B1A +672A8C589D89101809D838236560F7690E329784C1D335203BFED3A258CD79467D16B6DA06A282BC +4B9669986CB50C54DADE3D5B20FD5CD9FDDE60AF4B5D8D9C50E77CF50DF3B36F37F381FE7E28A719 +91C8199D18258C09BD0440F5E258A5D2E22C6CFBFDC5F91228992E86532F4C0A50067BCB2D4387B2 +9FEFB8043D7BC44A322FD3629D7D92B6EEBA21B035DAC884110BDC6B22CF59B08C195BBA1C682E5F +8CF32F479937D329FE8EC6E9A3A3AA63AE95EEB766E0EACEEAD4DCF46617888AE687009112732A7A +8FA8419A4652075EDDF83E291613B66BA793D3858CEA093C79B89B0C93E11CAAB86AD1980C401713 +0B6A02545DE484FDA6E4DFBCEBBC848751B2A8821CB3F7AC96D2EA9B83B575AB60CECA41EA567EE0 +8ADAC8F1060255057527485D6B12A26D2E7EF6892865FD65FEF28F8B46249C4F19341089D59DAF82 +582CAD1A3B53C763A0E57134A57C4A24AB4FD358592ADB01BE8F1D9FAE9CA97A3BC3A0E2939913E0 +62960CC1D29ECEF9E61BAC20E92F13C49078E7F1562C9D7C01C2B300ECD6ADCAC9AA0C1F1BA30401 +0573F79D158C66D91A8D987C5239C9D4FEED1DC5C9586C4129C33E7C737C624EE9BD1EDE38E9F72A +78DC19E144B5AABF3B0FB72216815E371A5D6452684965CB7208B87CE5A27E444820E03F80AD2DF4 +E280D25D9BDE41E719BB2C939E25B7965DB162CA8665CBFE65DFDC7992A508D54FE4EE8454C11482 +7186A280D3D9EDF397640A809E3646675AB6621B9CDF42808E2F19859AC975CF70F41D2B3D22F8E0 +C180126F4A12122B207A150BC8E1819962DAEBB821DE59B7EEF8FF9219474597AF859E353B4B713F +5F1350F4049DCE99627492E396038B10A2F8E82AB679F65BE14A166E4502921BA44CCFE04E5DD3FE +B04BA47C3F7A3E7DBF7D55328AD1E96092C73EDB16C3325537295DF768E2633D01304EA0B01379AA +DAFE6CCA2AB3E246768C5AC841A458A2F69141A9A9D716D129B26643F1BBC95D8CD0ED44148F7C6A +F370201E454F4AFF7C11A8080508FEDE242343E7ADDD5A8AAF079C50765A79BD25FBBDC59EDF980F +FE0B60435692C49D20AC22F8BD1FCA3F3D8200CA26D61A30212558B54671E63BC09776A3AE7A906F +CA63281F080A00500C42C02B8F82357A3EBF572CFC4BEBA3FE86537DDDF23A861C240A31778A131E +F638C1DBB7E87A45487C092D23FD9FB2C162C3253636ED263B141178FCA9F2D5BE2D81F99B2872C4 +B3C08749CE18C9C00E75DA6B3E4C6A6DD79EBA731618EF5B5E767BB40429D8FEEC6ABFE9975746FB +3A82A03A07B7D0DA8BAECFD1F72AFE17EB0C0CF100A2D48F4449A42C482BB1D64C19F8FEA73F5BA1 +8FC9BFEE3F640C39C081669A9B0EE3FF6B2BDC0A726301EF0E2259E65BE59275C76E7A3F1C76C3A3 +3AD0E2F79198DCA39C482B4E1196238DBA937692CF319436830BBF441C0A8A04161DC0814B5DF049 +83099439EF421B6D37D351D4A988A8DFE93D796B2E8B2564C602F79E6162F56F933196A0DCE91051 +600BAFFD9D439A91F17C20CD6A9104B553D823A0317E3C8344E9F0B2560AD583BF876AE307892500 +2177AF61BDBD745CEC2B2A7931D27423D2667584AE0D6CAA2B281EB9271ADE86C493791AC9A2265B +8324F764D20DE65F6267439F1574DB02C600E771D3C743D420FA6F8BF01A977B91AF035E0D5412AB +0B85D6ED3ED9D0345ED434F9B95FD911A9D3828CD162686E6ECCD2B6A5B1104F0E6838AAC7FB3FC7 +09F08F8E82B4BFCB55D8984771F9F4D339EE7FF391448C7807A436A78B6A487D3A5A86F314B302FA +C5BE1C1DB9844F975619D615D1C7A20EC2B144797E0648CF5C044C8DD1699EEA3AC9D7E3BAA54A85 +11A932623D5ED3F0A9C3028CA439AC395F58DEAF1C0354A169D9AC7F380900D9828C3ECBB975F6FE +6BD79EA4BEA9B71F3A9B1D2EAF8F1E475B4FB99758192EBCDA21B47EA33F57C58E904DA260C801AE +CF457C84592B81CFA96C10E448D705D24871F3D1AD1FE004406C8070A54FA3747788C5B55E9462E6 +F51378BF3F848360542CAD2D5FF9EDAC84C164DFEC115A2F3D873760EAE58CC8F361B37E6CE076EF +325A1C54DFF84DB95DB7DB5B56C48ED15C5426E6153D8A94B1A35B22EAB1D7B871097DF12C093BA5 +538957AB7D0AB2E39A2D1AECB91F0A693B8F6A00601929B6C55AAE8A227CAB6404FEBCC8BC4EEEE0 +ADD4CFD7DEC225170A0063457918B9875AD7F022A8F9932ADE316E4126EAB75C1D0B2B9F44E85F1C +54755D1301345665EA630C8E885A8D9AB069DEA2CC6D12E4A0BF6E80C3AE12BC7ABE507422A5D92B +65F70B4A472DD945EBB960880EC4C34E4C206C260FDF86A997D7D399A0219A51E6F8BC1189EC0ED0 +B8686F0243BFAFD829979747442AB1DA8282F10F4C37C4E6C88D231460DA3BF34C23A4755E2F8F21 +F6D138C86B6091CB3BCE5ED170242C4CC87C010FE63DA9A2ECBDD85311DA8572AD67E40F744D2EC9 +6607701D9790574F051C859EF29291AFA301C809E0A5513DF9A7FC2DB1776DBD4A2CB622BD17811B +C0E584A8D89D4BEB17C2D0AA8BF31CD7E2B36C0E1888409788E30EAC2E46AFA1CFE457D3A19C28C5 +80669CB82CF36BF40DFAFED78F99A5D5DF189CE293413FFBA9E8D2457986C68483242AD767D5F026 +1CE303153C35D5DEB1789448088B51C48A9B8E903BBC69ED7FB0129CCE33A0337198F11DBA94FDAE +AD74BBC5E519F559094E15B03AF3EFA89DC38B4278C68D2AEEEBE4B28B351D7B72F52D94480D8CBC +06544645F20800B8284A4E7C8FAD59D0AA8EC8EC0551912CBC62694A5DD15C469BBE614FB187C084 +838D676E5A1CC8DFA8676758EB7D53FD2BA8F1C434F4F70AED8F2CE27EED2F6A82E20E30EACF9BF0 +CE28B4BF7D556815A887D777B7D75F60D2C410AA2D378B7BFAA6C3A5BF0A5EF80D3E35A0CF393A5E +BC27A895D712C6F004F1A03F9FCF493973F33E6FB106407DFD992AB0E9E36EF395663A6EEFFD71BB +2DAD9DFE6AA4685F307B8FD69BB2F74E672666414A71FA479B37D3DEF6AEAF80FA14821C65F7ABBE +5CC6DD49002216E23B3D22C282F3DE0077EA81017E79D8C3BDB61EC031CFB13FA981120A6C518F4B +4C39C9DD5AC6EDA29ABA527C9948BC3162EF65E8251C9D4E3494C6A51A41D489F8BC89250128EBD7 +0EFD01B9F03C40B6E0384364F2571F7D969016A959E4243D7AB728F0F030B8E2FB456D8E47A85898 +313B0E91C68C7A8A7226603427AC6DCB5C69924FD026E90CB0EE89AC42D874BB15AFC981079E9DC7 +1271C3E461265AF327D4AAB4AEFAB6A9DC3F84DCE7C7868D4719006344B9055C8BA952A2250B8041 +E5EF519BB788201124BE90AECAC2293A310D9565E1EA4AEB99F7ED7106649169E8EBF3DCB210706A +F2FA65158D3059DFBD7AB5B00DBB06B016F73FEDB3AE1C1CC03BC2D94B143BFBD759338EB181B1F6 +841F7B539D8D126FC5B31B244A3A00ABBB121A98F73314D1F1683F513C3CCC9A0C2180824ACE5D45 +E454062CE1217F7AFBDC60A6022B0134EDA6C5D787DE8A5925BEB374F64D612329B9AC17B6EC03F8 +56CFEE502C1FC3AAC7B6F251E8DE4147DCB1580185C406F38E6B729307EADFF6D7A0E824C9830093 +F0C4FECEEFC7FF839306FEFEB780FFBD8879F22AFDADCA4C0767B8EEAE5DB869D7BD91355F0255E1 +CAC68A81A276967F233624DE0D2082B89E2C2D1DB0F8BE0B2BD7051C4DE9B1564AA6CBA03E50386F +D685943D1EDDF5BE0EB34418C48E5EA645CBA552A0444B254E82E9E84A5B7BD0064D5EA87B1716C1 +4EF7FD14E2187FCE16FF6ECBC0A6588B30B4329626F024BDBA65457028668BC6750A4DD668D017CC +EF35CD9CF45EC73885FC91B8AD78920919B4747A710D25BB850B558C5CCF7170C20012DD0F2874A6 +699DF53EDC6C75716A5B6B06C98F4904BAD22B18C77B3EEF32DE3F45A8AC12383DA16DF6F06CD923 +D344CFC2253ECF97A52F2DC6A22539231E29A324F851265BA82BE566E42167247CEBD914EBE42EAB +E189E74FE1FF17ADA8A5F47DC9866CF86694DEE28EED333B0A8AE380557820E3F1D32B05AE27FFE1 +68267FADD310C4EE550F71704EF71F4C669952F30E485AF37561884066C0E3425C748BBAC77CC7A9 +87EC336B8BEBA44358BEA4ECFEA32494A8006E9852C4BFCB1C0F00ACC247F1F8E3F3B34539C67638 +64527F9F885132DCACBFCB1DC80EE3B2A711145DDA1D3B5F83144E2CD698D43A02B0DEB706C78D75 +A24FA39B9374E1155969FAD7D5FB477F4C3C7440DBFE1BD1DC877360E8690A6D3A64EF0A1313A520 +C49320295302227CE5625E134EA442A537505D206EE46E7E218BDA38F7B6BA124ACA0E949725CEEB +961EF8B0727E3A78287E61E65A84AC14D1014A213259A48F04C634C1F04C73B4110D0DB491250CCD +7DAE323CC8BD29BEF605DD92AA5480009DEAD1256E5C9FFB18362D63B022C2A378D15ADE2C6AE603 +1DF385CF090226F0AF889464584A9EA63B884453DE231058C5661C4F7DCF7505D7B1E48C78AA5799 +8FF39084FFF1CD18CB2989D867F2E085B291FE52367B4E8667E5CDA4F41DDBC7129DA5BDC39549E0 +8B67D9C9E4C332D91FE261728521245CBF51870F24C42F5814F393719A9E126C5693C0E776E4D8F3 +0F0288537B8E9A7C5DA4F931FC83F96A1950B1DF26C0448B646D3BF42C0429E2BD0164703FC71833 +19DDEA75CE65D9DFFE8369787FE664306D843421C2C0C3A5B210E823F8366161A96CA88D95FD6486 +5F9E5B0D53DCEE4A98AC10A8FF1BC34A46DB6016E973C9FA298D3F58228E3D9FCCCF9632556CE2E7 +F9C81E05FDB0FC1071E69A4C158E742D0B8939CA3DE33A4BE8D01D679C81C6BA9CF396A6768CA626 +05D796AA5C323E3A6208F2DA5000FC4462ED81AD0044D9959E40E4764562ADA76E33EC63271966F1 +7A13AD376A54FFA40FA247896A22C1C4A4CE51094CA1892A0B9904EB762839AAE1EDB5A0A5A69343 +CCA45F88F61926B23E6C85688862B1D10F1ED827FCCE2A427E49D960DBEE0D39EDE08D2565C6F5AD +66CA83DAC1467C38F742132F715DA7E9757A5D067FDB4A8859D148473F302BF6ECB9B7EA5C0DF851 +8F58D4D076625B92BC8201028064950D70CD40492DA83B98FFD79BD3DCD9CEE95178B6DEA9AB10B3 +4C61A74B49C3697CF714F56A9B1E366B04500C9A67704AF6F721851EA4566B96E220E7B526873F94 +E6013EA8C489639D291167BCAEFB661C96C27DC7BCD5B317C1F101CD8DF2FB29F6162B5ECE903C0D +5570C8C6325F05218850E4A5B5F94C7CE334BADDFC5DB98EF5333B4A92129F41D046D0F5EB6F342C +F362BC8E45511FCF328E2CE2D4C579516307AEC400BA207071C887F5185AF536A6827307D7698095 +E8A6F8C19812A11C32AD207FBC353172C8DF626C5C05CD24C171B3C8DAB270A74AC48E35F0A8849C +E0934B93D56C93599F5235EC441B5232257C4C6767C7B5A35830010E60E56AFBE9199B42E725A216 +C49D45A3C554767DF192F04D1A192D5CE196831EB7A56201A4A96CD44DD084729774334F698E1902 +614405347A37A4C753C0211D7F24D5265CF033E3C4D30E61886CF781D2AC30385E6021A892AB116D +1F5505635BF5C915D0300ACA8AC32CAA0F3639550C4AEB390DA7B86E53B6BB0E4819626757BA9986 +BCA4B4B18F6BF3706577A3BE146F2585025D5A36EB14E587C5469EEEB622D31FD32EBFA812B9CCDC +CFF7D17D00D9F21BF8871661F20E89A25A4543068EC509D0DF7DEA2A24FF68957943BE0FC7BD319D +92A575E12E6FB8112D72A100FEF3EE85972304BBE07FC1026CCC068E8A414F641116E51F76009C5A +F9E664BCCF93C943CFF2115235BB3290F935AA3FAB4F2E73FCDB9FA5E1866EFE278FFE7EA9DD6F89 +38CD5E5F4F31F6C659AF7EFF5B291AFB86521678B42C99275024EDAD04E5929D201A36F4A6C4DCD7 +2E349D6B9A1F90B123DEDE3DA50EDF929F9285747CD504C8F4A73D522F312D623BD65A35419C0729 +30976129B2D99B32D1DEDD81D64F7879CEDDFF04BBBF1286E07BCE651E2DEC190DFB9D25F3C1EEC8 +D7277752BB7CCC313A0FEEBF0EFFA2A189861AD4EA13AD4FDBD5160DC273F12525815F0D693C1413 +AFE4FBE09BCBD71E16C33E6CF8D18732447FFDCC2E4AF9E270D725C1D262D96E72538CA3309BCAF2 +35A3FAFAB27D265C583E6F6F062B555C97DFD89AC46E6154670ADCA13FD99F7A4B9B8BB224D43764 +8CC9DB76E177F562862C912D8CBC248A4C628FF2D0C9688611CED3DFB89064B988F16655633B7CC7 +AFAE34B2937528EA0814ED245D6B0D2AEF87A5B63E2BD7E4F7D9CFE372C295A0891F97C3855C97EC +C03C7C2A231704BED419612255F8B2C9262D48CB4FB46D63CC9697A210FA9D7BFC3BAB7E46172D3F +52A4AF9C4114BC72A5C7CBA042FA633AFD5E404F29408D4485837E55E6F9702F04C7AB410C351039 +6A78C8672F8EAD53BB9CBCED63FB9E72E7238CC88FB4E7C48C3DE3E4B80E277B952727916A4127A2 +5CC1413C390F4DAFD5253B07BC96DAE8CF4DA08330DEE580CBC1E12B75A661819E96B018D47A8B71 +B6BFAFC5E3CBFE68E5193417B6E730E6A2820838D22049BE6BB64B74AA13779D46519965ED80D5FC +30B0A6F73D26DEBD8150B3D27B3F135F608D59BB1632AD9C2E11177FAF54CBD1C4E58D58C395BAE8 +AD7C7AEEB0E1C3F0C0B7A5E7142E9A1DCCC8B4EF56C319D4A4F750857D2FD180F871772B9CC69FB9 +B222F83C3ACCB66125AF6848B2EFDCE3D2284FA5844641FB32F701FBF32F1D2F2E2233B66E36CCD1 +49FCB3FCDB6EA04367D11624717D73D9128EA7D9AABB8658BE9E9986E532 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +cleartomark{restore}if + +%%EndFont +%%EndResource +11.52 /Mathematica1 Msf +0.75 10.5 m +(p) N +P +[1 0 0 1 -61.69 -151.566 ] concat +1 w +[ ] 0 setdash +P +P +[ ] 0 setdash +p +0 setlinecap +70.6 105.842 m +73.497 105.842 L +s +P +p +np 52 98 m +52 113 L +69 113 L +69 98 L +cp +clip np +p +1 w +0 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +[1 0 0 1 53.44 99.467 ] concat +1 w +[ ] 0 setdash +p +np -2.44 -2.467 m +-2.44 14.533 L +16.56 14.533 L +16.56 -2.467 L +cp +clip np +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +11.52 /Times-Roman-MISO Msf +0 10.5 m +(2) N +11.52 /Mathematica1 Msf +9 10.5 m +(p) N +P +[1 0 0 1 -53.44 -99.467 ] concat +1 w +[ ] 0 setdash +P +P +[ ] 0 setdash +p +0 setlinecap +70.6 53.742 m +73.497 53.742 L +s +P +p +np 52 46 m +52 61 L +69 61 L +69 46 L +cp +clip np +p +1 w +0 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +[1 0 0 1 53.44 47.367 ] concat +1 w +[ ] 0 setdash +p +np -2.44 -2.367 m +-2.44 14.633 L +16.56 14.633 L +16.56 -2.367 L +cp +clip np +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +11.52 /Times-Roman-MISO Msf +0 10.5 m +(3) N +11.52 /Mathematica1 Msf +9 10.5 m +(p) N +P +[1 0 0 1 -53.44 -47.367 ] concat +1 w +[ ] 0 setdash +P +P +1 g +[ ] 0 setdash +p +0 setlinecap +78.19 2.952 m +78.19 5.849 L +s +P +p +0 setlinecap +92.764 2.952 m +92.764 4.69 L +s +P +p +0 setlinecap +107.338 2.952 m +107.338 4.69 L +s +P +p +0 setlinecap +121.911 2.952 m +121.911 4.69 L +s +P +p +0 setlinecap +136.485 2.952 m +136.485 4.69 L +s +P +p +0 setlinecap +151.058 2.952 m +151.058 5.849 L +s +P +p +0 setlinecap +165.632 2.952 m +165.632 4.69 L +s +P +p +0 setlinecap +180.205 2.952 m +180.205 4.69 L +s +P +p +0 setlinecap +194.779 2.952 m +194.779 4.69 L +s +P +p +0 setlinecap +209.353 2.952 m +209.353 4.69 L +s +P +p +0 setlinecap +223.926 2.952 m +223.926 5.849 L +s +P +p +0 setlinecap +238.5 2.952 m +238.5 4.69 L +s +P +p +0 setlinecap +253.073 2.952 m +253.073 4.69 L +s +P +p +0 setlinecap +267.647 2.952 m +267.647 4.69 L +s +P +p +0 setlinecap +282.22 2.952 m +282.22 4.69 L +s +P +p +0 setlinecap +296.794 2.952 m +296.794 5.849 L +s +P +p +0 setlinecap +311.367 2.952 m +311.367 4.69 L +s +P +p +0 setlinecap +325.941 2.952 m +325.941 4.69 L +s +P +p +0 setlinecap +340.515 2.952 m +340.515 4.69 L +s +P +p +0 setlinecap +355.088 2.952 m +355.088 4.69 L +s +P +p +0 setlinecap +369.662 2.952 m +369.662 5.849 L +s +P +p +0 setlinecap +384.235 2.952 m +384.235 4.69 L +s +P +p +0 setlinecap +398.809 2.952 m +398.809 4.69 L +s +P +p +0 setlinecap +413.382 2.952 m +413.382 4.69 L +s +P +p +0 setlinecap +427.956 2.952 m +427.956 4.69 L +s +P +p +0 setlinecap +442.53 2.952 m +442.53 5.849 L +s +P +p +0 setlinecap +450.12 210.041 m +447.223 210.041 L +s +P +p +np 451 203 m +451 217 L +459 217 L +459 203 L +cp +clip np +p +1 w +1 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +[1 0 0 1 452.28 203.666 ] concat +1 w +[ ] 0 setdash +p +np -2.28 -1.666 m +-2.28 14.334 L +7.72 14.334 L +7.72 -1.666 L +cp +clip np +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +11.52 /Times-Roman-MISO Msf +1 g +0 10.5 m +(0) N +P +[1 0 0 1 -452.28 -203.666 ] concat +1 w +[ ] 0 setdash +P +P +[ ] 0 setdash +p +0 setlinecap +450.12 157.941 m +447.223 157.941 L +s +P +p +np 451 151 m +451 165 L +460 165 L +460 151 L +cp +clip np +p +1 w +1 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +[1 0 0 1 452.28 151.566 ] concat +1 w +[ ] 0 setdash +p +np -2.28 -1.566 m +-2.28 14.434 L +8.72 14.434 L +8.72 -1.566 L +cp +clip np +11.52 /Mathematica1 Msf +1 g +0.75 10.5 m +(p) N +P +[1 0 0 1 -452.28 -151.566 ] concat +1 w +[ ] 0 setdash +P +P +[ ] 0 setdash +p +0 setlinecap +450.12 105.842 m +447.223 105.842 L +s +P +p +np 451 98 m +451 113 L +468 113 L +468 98 L +cp +clip np +p +1 w +1 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +[1 0 0 1 452.28 99.467 ] concat +1 w +[ ] 0 setdash +p +np -2.28 -2.467 m +-2.28 14.533 L +16.72 14.533 L +16.72 -2.467 L +cp +clip np +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +11.52 /Times-Roman-MISO Msf +1 g +0 10.5 m +(2) N +11.52 /Mathematica1 Msf +9 10.5 m +(p) N +P +[1 0 0 1 -452.28 -99.467 ] concat +1 w +[ ] 0 setdash +P +P +[ ] 0 setdash +p +0 setlinecap +450.12 53.742 m +447.223 53.742 L +s +P +p +np 451 46 m +451 61 L +468 61 L +468 46 L +cp +clip np +p +1 w +1 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +[1 0 0 1 452.28 47.367 ] concat +1 w +[ ] 0 setdash +p +np -2.28 -2.367 m +-2.28 14.633 L +16.72 14.633 L +16.72 -2.367 L +cp +clip np +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +11.52 /Times-Roman-MISO Msf +1 g +0 10.5 m +(3) N +11.52 /Mathematica1 Msf +9 10.5 m +(p) N +P +[1 0 0 1 -452.28 -47.367 ] concat +1 w +[ ] 0 setdash +P +P +p +np 210 257 m +210 272 L +310 272 L +310 257 L +cp +clip np +p +1 w +1 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +[1 0 0 1 211.235 257.578 ] concat +1 w +[ ] 0 setdash +p +np -2.235 -1.578 m +-2.235 15.422 L +99.765 15.422 L +99.765 -1.578 L +cp +clip np +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +10.08 /Times-Roman-MISO Msf +p +0 9 m +(I) N +P +p +3.75 9 m +(m) N +P +p +12.75 9 m +(p) N +P +p +19.5 9 m +(a) N +P +p +24.75 9 m +(c) N +P +p +30 9 m +(t) N +P +p +36.75 9 m +(p) N +P +p +43.5 9 m +(a) N +P +p +48.75 9 m +(r) N +P +p +53.25 9 m +(a) N +P +p +58.5 9 m +(m) N +P +p +67.5 9 m +(e) N +P +p +72.75 9 m +(t) N +P +p +76.5 9 m +(e) N +P +p +81.75 9 m +(r) N +P +86.25 9 m +(,) N +92.25 9 m +(b) N +P +[1 0 0 1 -211.235 -257.578 ] concat +1 w +[ ] 0 setdash +P +P +p +np 34 75 m +34 165 L +49 165 L +49 75 L +cp +clip np +p +1 w +1 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +[0 -1 1 0 35.28 164.105 ] concat +1 w +[ ] 0 setdash +p +np -1.895 -2.28 m +-1.895 14.72 L +90.105 14.72 L +90.105 -2.28 L +cp +clip np +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +10.08 /Times-Roman-MISO Msf +p +0 9 m +(S) N +P +p +6 9 m +(p) N +P +p +12.75 9 m +(a) N +P +p +18 9 m +(t) N +P +p +21.75 9 m +(i) N +P +p +24.75 9 m +(a) N +P +p +30 9 m +(l) N +P +p +36 9 m +(r) N +P +p +40.5 9 m +(o) N +P +p +46.5 9 m +(t) N +P +p +50.25 9 m +(a) N +P +p +55.5 9 m +(t) N +P +p +59.25 9 m +(i) N +P +p +62.25 9 m +(o) N +P +p +68.25 9 m +(n) N +P +75 9 m +(,) N +10.08 /Mathematica1 Msf +81.75 9 m +(c) N +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +10.08 /Times-Roman-MISO Msf +P +[0 1 -1 0 164.105 -35.28 ] concat +1 w +[ ] 0 setdash +P +P +p +np 70 3 m +70 238 L +450 238 L +450 3 L +cp +clip np +p +np 117 136 m +117 152 L +155 152 L +155 136 L +cp +clip np +p +1 w +1 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +[1 0 0 1 118.485 136.705 ] concat +1 w +[ ] 0 setdash +p +np -2.485 -1.705 m +-2.485 16.295 L +37.515 16.295 L +37.515 -1.705 L +cp +clip np +p +np -0.485 0.295 m +-0.485 13.295 L +35.515 13.295 L +35.515 0.295 L +cp +clip np +[1 0 0 1 0 0 ] concat +1 w +[ ] 0 setdash +p +np -2.485 -1.705 m +-2.485 15.295 L +37.515 15.295 L +37.515 -1.705 L +cp +clip np +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +9.72 /Times-Roman-MISO Msf +%%BeginResource: font Mathematica2 +%%BeginFont: Mathematica2 +%!PS-AdobeFont-1.0: Mathematica2 001.000 +%%CreationDate: 8/28/01 at 12:01 AM +%%VMusage: 1024 29061 +% Mathematica typeface design by Andre Kuzniarek. Copyright \(c\) 1996-2001 Wolfram Research, Inc. [http://www.wolfram.com]. All rights reserved. [Font version 2.00] +% ADL: 800 200 0 +%%EndComments +FontDirectory/Mathematica2 known{/Mathematica2 findfont dup/UniqueID known{dup +/UniqueID get 5095653 eq exch/FontType get 1 eq and}{pop false}ifelse +{save true}{false}ifelse}{false}ifelse +20 dict begin +/FontInfo 16 dict dup begin + /version (001.000) readonly def + /FullName (Mathematica2) readonly def + /FamilyName (Mathematica2) readonly def + /Weight (Medium) readonly def + /ItalicAngle 0 def + /isFixedPitch false def + /UnderlinePosition -133 def + /UnderlineThickness 20 def + /Notice (Mathematica typeface design by Andre Kuzniarek. Copyright \(c\) 1996-2001 Wolfram Research, Inc. [http://www.wolfram.com]. All rights reserved. [Font version 2.00]) readonly def + /em 1000 def + /ascent 800 def + /descent 200 def +end readonly def +/FontName /Mathematica2 def +/Encoding 256 array +dup 0/NUL put +dup 1/Eth put +dup 2/eth put +dup 3/Lslash put +dup 4/lslash put +dup 5/Scaron put +dup 6/scaron put +dup 7/Yacute put +dup 8/yacute put +dup 9/HT put +dup 10/LF put +dup 11/Thorn put +dup 12/thorn put +dup 13/CR put +dup 14/Zcaron put +dup 15/zcaron put +dup 16/DLE put +dup 17/DC1 put +dup 18/DC2 put +dup 19/DC3 put +dup 20/DC4 put +dup 21/onehalf put +dup 22/onequarter put +dup 23/onesuperior put +dup 24/threequarters put +dup 25/threesuperior put +dup 26/twosuperior put +dup 27/brokenbar put +dup 28/minus put +dup 29/multiply put +dup 30/RS put +dup 31/US put +dup 32/Space put +dup 33/Radical1Extens put +dup 34/Radical2 put +dup 35/Radical2Extens put +dup 36/Radical3 put +dup 37/Radical3Extens put +dup 38/Radical4 put +dup 39/Radical4Extens put +dup 40/Radical5 put +dup 41/Radical5VertExtens put +dup 42/Radical5Top put +dup 43/Radical5Extens put +dup 44/FixedFreeRadical1 put +dup 45/FixedFreeRadical2 put +dup 46/FixedFreeRadical3 put +dup 47/FixedFreeRadical4 put +dup 48/TexRad1 put +dup 49/TexRad2 put +dup 50/TexRad3 put +dup 51/TexRad4 put +dup 52/TexRad5 put +dup 53/TexRad5VertExt put +dup 54/TexRad5Top put +dup 55/TexRadExtens put +dup 56/LBrace1 put +dup 57/LBrace2 put +dup 58/LBrace3 put +dup 59/LBrace4 put +dup 60/RBrace1 put +dup 61/RBrace2 put +dup 62/RBrace3 put +dup 63/RBrace4 put +dup 64/LBracket1 put +dup 65/LBracket2 put +dup 66/LBracket3 put +dup 67/LBracket4 put +dup 68/RBracket1 put +dup 69/RBracket2 put +dup 70/RBracket3 put +dup 71/RBracket4 put +dup 72/LParen1 put +dup 73/LParen2 put +dup 74/LParen3 put +dup 75/LParen4 put +dup 76/RParen1 put +dup 77/RParen2 put +dup 78/RParen3 put +dup 79/RParen4 put +dup 80/DblLBracket1 put +dup 81/DblLBracket2 put +dup 82/DblLBracket3 put +dup 83/DblLBracket4 put +dup 84/DblRBracket1 put +dup 85/DblRBracket2 put +dup 86/DblRBracket3 put +dup 87/DblRBracket4 put +dup 88/LAngleBracket1 put +dup 89/LAngleBracket2 put +dup 90/LAngleBracket3 put +dup 91/LAngleBracket4 put +dup 92/RAngleBracket1 put +dup 93/RAngleBracket2 put +dup 94/RAngleBracket3 put +dup 95/RAngleBracket4 put +dup 96/LCeiling1 put +dup 97/LCeiling2 put +dup 98/LCeiling3 put +dup 99/LCeiling4 put +dup 100/LFloor1 put +dup 101/LFloor2 put +dup 102/LFloor3 put +dup 103/LFloor4 put +dup 104/LFlrClngExtens put +dup 105/LParenTop put +dup 106/LParenExtens put +dup 107/LParenBottom put +dup 108/LBraceTop put +dup 109/LBraceMiddle put +dup 110/LBraceBottom put +dup 111/BraceExtens put +dup 112/RCeiling1 put +dup 113/RCeiling2 put +dup 114/RCeiling3 put +dup 115/RCeiling4 put +dup 116/RFloor1 put +dup 117/RFloor2 put +dup 118/RFloor3 put +dup 119/RFloor4 put +dup 120/RFlrClngExtens put +dup 121/RParenTop put +dup 122/RParenExtens put +dup 123/RParenBottom put +dup 124/RBraceTop put +dup 125/RBraceMiddle put +dup 126/RBraceBottom put +dup 127/DEL put +dup 128/LBracketTop put +dup 129/LBracketExtens put +dup 130/LBracketBottom put +dup 131/RBracketTop put +dup 132/RBracketExtens put +dup 133/RBracketBottom put +dup 134/DblLBracketBottom put +dup 135/DblLBracketExtens put +dup 136/DblLBracketTop put +dup 137/DblRBracketBottom put +dup 138/DblRBracketExtens put +dup 139/DblRBracketTop put +dup 140/LeftHook put +dup 141/HookExt put +dup 142/RightHook put +dup 143/Radical1 put +dup 144/Slash1 put +dup 145/Slash2 put +dup 146/Slash3 put +dup 147/Slash4 put +dup 148/BackSlash1 put +dup 149/BackSlash2 put +dup 150/BackSlash3 put +dup 151/BackSlash4 put +dup 152/ContourIntegral put +dup 153/DblContInteg put +dup 154/CntrClckwContInteg put +dup 155/ClckwContInteg put +dup 156/SquareContInteg put +dup 157/UnionPlus put +dup 158/SquareIntersection put +dup 159/SquareUnion put +dup 160/LBracketBar1 put +dup 161/LBracketBar2 put +dup 162/LBracketBar3 put +dup 163/LBracketBar4 put +dup 164/RBracketBar1 put +dup 165/RBracketBar2 put +dup 166/RBracketBar3 put +dup 167/RBracketBar4 put +dup 168/ContourIntegral2 put +dup 169/DblContInteg2 put +dup 170/CntrClckwContInteg2 put +dup 171/ClckwContInteg2 put +dup 172/SquareContInteg2 put +dup 173/UnionPlus2 put +dup 174/SquareIntersection2 put +dup 175/SquareUnion2 put +dup 176/DblLBracketBar1 put +dup 177/DblLBracketBar2 put +dup 178/DblLBracketBar3 put +dup 179/DblLBracketBar4 put +dup 180/DblRBracketBar1 put +dup 181/DblRBracketBar2 put +dup 182/DblRBracketBar3 put +dup 183/DblRBracketBar4 put +dup 184/ContourIntegral3 put +dup 185/DblContInteg3 put +dup 186/CntrClckwContInteg3 put +dup 187/ClckwContInteg3 put +dup 188/SquareContInteg3 put +dup 189/UnionPlus3 put +dup 190/SquareIntersection3 put +dup 191/SquareUnion3 put +dup 192/DblBar1 put +dup 193/DblBar2 put +dup 194/DblBar3 put +dup 195/DblBar4 put +dup 196/BarExt put +dup 197/DblBarExt put +dup 198/OverCircle put +dup 199/Hacek put +dup 200/VertBar1 put +dup 201/VertBar2 put +dup 202/Nbspace put +dup 203/VertBar3 put +dup 204/VertBar4 put +dup 205/FIntegral put +dup 206/FIntegral2 put +dup 207/FIntegral3 put +dup 208/OverDoubleDot put +dup 209/OverTripleDot put +dup 210/OverLVector put +dup 211/OverRVector put +dup 212/OverLRVector put +dup 213/OverLArrow put +dup 214/OverArrowVectExt put +dup 215/OverRArrow put +dup 216/OverLRArrow put +dup 217/Integral put +dup 218/Summation put +dup 219/Product put +dup 220/Intersection put +dup 221/Union put +dup 222/LogicalOr put +dup 223/LogicalAnd put +dup 224/Integral1 put +dup 225/Integral2 put +dup 226/Sum1 put +dup 227/Sum2 put +dup 228/Product1 put +dup 229/Product2 put +dup 230/Union1 put +dup 231/Union2 put +dup 232/Intersect1 put +dup 233/Intersect2 put +dup 234/Or1 put +dup 235/Or2 put +dup 236/And1 put +dup 237/And2 put +dup 238/SmallVee put +dup 239/SmallWedge put +dup 240/DoubleGrave put +dup 241/Breve put +dup 242/DownBreve put +dup 243/OverTilde put +dup 244/Tilde2 put +dup 245/Tilde3 put +dup 246/Tilde4 put +dup 247/BackQuote put +dup 248/DblBackQuote put +dup 249/Quote put +dup 250/DblQuote put +dup 251/VertBar put +dup 252/DblVertBar put +dup 253/VertBarExten put +dup 254/DblVertBarExten put +dup 255/Coproduct put + readonly def +/PaintType 0 def +/FontType 1 def +/StrokeWidth 0 def +/FontMatrix[0.001 0 0 0.001 0 0]readonly def +/UniqueID 5095653 def +/FontBBox{-13 -4075 2499 2436}readonly def +currentdict end +currentfile eexec +D8061D93A8246509E76A3EC656E953B7C22E43117F5A3BC2421790057C314DAE3EFBFF49F45DD7CD +91B890E4155C4895C5126A36B01A58FDB2004471266DA05A0931953736AD8B3DEB3BCB2A24BC816A +C1C90A1577C96B9096D6F51F9E21E625ADF6C3A49867A632A605C117E6325C820121799F412E226B +EFE61F2813676F172CBD7EC10FF1EFBB92DF3A88E9378921BBD00E6024CC08EF057CECD09B824E0A +CCDAA4644296DE34D19D779A21C30666026829D38FB35A2284CAED23C8B913E7B28BB3DA7C8CE390 +4C0BAE30B0287680CCCAB2E6D4CAB2E7D786ABF54068028FD7D94FAC236094761B62B7E76F68D2BE +58C23AF85001950EFC1A9C1BB71520B78DDF6AA0058D25D041E86D01878DF56A5C48D74DCB2BBD68 +D75C94A3CE878484D28049331CE3D4364B40FAA2C754E8F443D244C5BC44B1C7868E36EAF4F7EF1F +6CB81E6CF63FABD65C29A991EB7D724DA06535AE43F3D0E2D04F6113B493C15463B4CEBFB72AB879 +7E4645F9CC0BB17E02A9626BEA4B4259F798B53B18DF2ACCF2B86BF2209CF0265DE0A46869333F98 +CCF70BF2C9239A0ABD2E97923AA5695BAFEA31E27B8F532BAA45F2980A11D069265A5312A260A627 +A765C4A08897E5C500990AE6FDA4CD6D575905468417297380EB6400CB2CF001C4B8EB79811CD8D7 +C173A337922B99DAB1048D5D03C78F78F36FEE31673D8C5FF8AD689A63AEA055CA705DB47D3AF965 +73571985E62F63866018C96EC4CA7E735C9294D8C81C03806D23CB87C0C08F86F5FA68CFC9AE48F6 +958AE016DCE4D60EB64AEAAD59D8A2592BC398BCA479FBC2F0C20C3E7F730481494C88781A6A9E0E +4F47A94619A3841FAC76A4FB252EB6FB43628AE1A4944539B1DFF672940AA5E93FFACFAC04624EF6 +7ED9C691788F0004DB7FFD1C995F2C52C0042F02F5C789F85D9E51716F3B4EDB21D4B9E660E4A892 +B747201EEC6DD6A8881FA3039664061094D1892108A2AD068D7F0251BFA72D874ECB2F42D27CC343 +052156F6A3A66D2CA6DAEF046A433FD54FEB4410315690971D0F43363EC0119B21F4BE3DFDC8C28D +BF5D68F145D3AC932EE62C32DFDEB1C48C2455392193268C893093BF911645986607DD13D8285895 +1854A7FF81FC98ADD44742907818B3C8E3187371BD9FE6EF5B4315E82C359BF2EA91D2894EE7FD9A +734BF2745D7FE8D08D29DA2A03176C992E11F1AADCE219D5E33F325BCFF4521D6D04E61B913B6C41 +740AF8BD9EA83F3AE7C4E5402366A812B1724431EE78D2028317B975E91941B591CC6C97740C453C +C7D7AB3CE97AE2F4DFAB6B9C8810A52A276BEAABD687BDA0971EE623A40B7AD6A8E69ED8BE63959D +3DCF8799E2505AC7F7B0E2FFECB0B08027A6266B7F96311B0AD78B7B6C78392AA062A73FDF179FEC +7F748929D060289F899FE417D4028FF332204FE04146BB130EF05FB57AF4BF9337EF71094DC5922E +3EF2D6A9F8257AF242019C349B65C2A3972ACA842D14EAB6A8D287456C9D7D295198F4AB7632EE43 +7D006B8124A80BBF26C1B902379D7F90080B51F982630E27B6031CE20930C273EA5D7FF0FC7E996E +67B072796CD96A7739444D21FE10DE7B57D143E4155EEE1B89F32EBCBF4C64D6D3FA1C46E06C9E9F +F99BC9BBCC61A400C7DBF812C42AAED863FE9EE3B02E731D1809F3CAB941252DE486BFE641F60F60 +C788F68519A6B04A4D6F50F02F93C6B8774B960C1FE893373D2AC2D865C487CFFE7669E1F1E73630 +7D34C15835F0453C8B0C1AE352CE1F27065F1082E6C84F86330F76B39C246315D6996AB69F81A020 +30D92CCB4C2A5AA4F4B3CAC88B2C8C9C621294A5EAB6AC3778DB99BD2F411735DC1421861417B4FD +399B365AEA45185A3D9D687546E36BB73994FB7FA3EE890AE3734BD9381B0E7AE514E8C517B87268 +7364C38D0A8379039F33336799205F2F54BBF7C2E9B30B27BCFB9FF2CD64F5D700F2455EE66B6252 +6E79ED2B0E5FF9732281CA50D27A93F259B6D4B5C7F856BB7D4F2E0F7741FA2419BBAF86C372E34D +59BC7AABC4CEF4F47EE40E118AB95A4863E16C55824D34002D59844D1F51B5DC6FB6BB5D595C4404 +1E05A84FD453A129279F894D726F6CD53BA3E234518324C5F715DAE6E7B5695326FC0C9B6CA2B53D +B25EC76BE9662388058629E70DC7BD861E188F1FF32A754A455195163CB4754D116D24E6A6300B67 +1862625E260442DEA2505E36D5F7AA4AD1FEB3B42632E382959C7E84569B2A790A0D0A208C2D4816 +AD28046B42C7A4797D424277AD9425C04DB87DCF112AE431CFFF6E4FFA979E947502AE5E1755C112 +0AE2361888B956F3F513A5975680E6E8374D8BF26C32AADC826D729E9026B14A68BC3D065E11C697 +D4D474CF963AFE083DD7D9278A0C27447E25AD70DD40B2EBAB8040164E11CD75AE3125C29806DEF4 +AD1B989F7001E227685DEF6EBE3287DE43BBA5FE2123A0EC835AECF879C13F7CFDC409901F291E89 +06C26E42B189862AFAE029F03D86D35E44E318FE16537E2B73E4F39F1E6945A3A6432438DCB6D2B2 +09814B5228D08165568617C279499ECA1B88C90300F1C88C45D4BE3DC726A59E24B46C5B2FF228C6 +E6645819C6F1D5B05737BE7353F4787EE52A21DC47A44F3C44406E79BBFDDC164682B02F4C39300D +12EF37A58E317FC1B8CE58E04BE666ED5DA75DBF752BEDDA4C7491E4D6922BCCA9CF421CE6751002 +8638EF643119841F423626D6B19A5D2CFB193B093D7646913F64614C098E5F5FF9422EBA75FA9AA8 +4F8ED114AEAB011E6F0727FB96F26BECBBAFE3AA8D0ABC5A8E9906B6CBB9E03F8CC4FCA97C884B83 +7CC33C619CD3195C55633B72D3F2D45561CD226F42B859B8099812D591886FA851107A185169FA7C +944248DE28642FA3043FF3B60236BFD781257C6FE4D56174AD16ABBF9659C05F08673A70496A0787 +C187D4367CB0CF48BD9A4FE0E481273E4909A1092626A13917DCBDE920028B06E094F5B28887B990 +32521E1720B75EB284AA6FFE53FA5CD5B903F951FCF7B33CC981FE7BCC4BDF4907ACC3AA60B69969 +A9AF204C84EC8C0F5DCB8A85E39EA9F2D4B67095A44CA0C8B072D7A61F3015D502B1A0F660C22221 +3231986D5E8C04AECBAFE999D1735A80051C06CA279D0FF6215633FB7A706454DA7236DB17AD72EE +1F6044A26A0EB77AB3BCE823E3F5E0DD31ACB029A1D17665FF16E5D1ACDDFD83CAEE1D48666D7BC6 +DADC34D317C335855D118892CBD32412F5870C3D2E599A46AA997A5E2BBDD3001C2957D81345DBED +583B72C4FB356F0C872A31A35087775EF18601930C0874EEA1ACB3ED3690EF447926439CC383087C +C9D5C6EB21EDF5941CB4E99FDA434A91676D76DC1A1BD801EECA6B0A88370B7005D41A1253CF8217 +1285986DC302B51123DBA9733BDEF0361AE0580FE6FBA5F29CF1438801586559D7436436CFE33E6A +D6EFA850BB8C9382E1A068246F370388186DC278F31F770C2C96881AC6E40823B24D6D536514A2C7 +AF3D159621080442592CAC03D6967BCBDB38FCA1A45F76F1A10027F1DCC076533C6AFC097FBCF0DA +A0078BE0828247F938AF76A87EFC14D9F5444CBCDCE637E2325D86B9D99D1ED70F44194E19F6C7A9 +9E415DC8A6E484DAAE52AAC1307A5353E8F649A35214B3F43DB5F3DB3ED06580A570E60B3E52679F +F90A3B00D4EB4DFBCF0D2F9C5545A6DE10BCC849A0BA9E18F29C6F09ED0F0DD48AD37B7925654433 +A6D02965A3813BA2EAB2E6C2004ADD216DAE99471EE518BD0DA0F534F1512A8E26286B07FEDE71E6 +0A5A057A22AEF095A8B4752F54C04CB8BC170F3D6B725B83A6780176194B21BA906E37B7923E2548 +604F8DB18E0A3E1B5FF04D00898C29C6033DAC54637CF5B068291559D8526D5201F3503FBA4EE12D +D7A6CF6271618F41FE08384521CD771FA80364D747430A071EE3D3ABDB5400DD36A0285430D537FA +F6EF8ACAF85C250D6652F327B2BD3B29E1C64E6E66C788FF1D9C3AC6DD38691CDECD0F3FF4079BAD +A2BC0CBE14AA3FCC38E3F31B3298A6995C87B34A7245ABA2C968F908D8337860507569C370654635 +570615F987531551414B5CCAF7F4D0B38F701619C553E746BD90655294270560046A925A021C98F9 +3EA8FF5B5B8A0D05AD483E6DDC5257635308C6C0FE9182D0E4FB011A00981A7B95DB5BF5A82F8B1E +B68E8822F8B1B7CF01AF11302B44307F3A71D5EB3465F793CAEB1E72D2C63E3D264380A75FF1DDA5 +00B5F82B04179EA9DAC10731FDEDF5913EFDEDDF5799D2A86EF2D16C0B52D99FCEAD392E9226AA6D +3D11D29054130C8602F703CB1EBDAAA089A02C0EBD53343A7B297836CB63E4B2C33C8760ECEB15E5 +6B59D4B296B8B724244D37651C3CB862C7135D62B2692F5A27B9374C5C3C5399E5C4DCCD76572294 +F742B1F545B736BF4C82D8F4E2941CD52C0B944261DD4CCF8A968B646662F3D187557206FF165F3C +0D3D5CA1E428D61D7936E1D00C5377A047EE80E0A5612F7FDEBB8B224270ED23A031A049E8676516 +BF66EBAFCF3F9D4975B0F212FB7A914EE45640972B61AE8E60E602DC7C20758BC07A159B08862F16 +6302D8CBEF03C4B0C73BD8504EB5B14DBC64FBDDC867FE51F76099769A7BD4FA4CF4096EAAAFD55F +9A20F6D4B84D8FD139112A43204026F15F9FF5AB6729537CCDA60369C24D7EFF4B6B971EBF0BD277 +A9AD1BF1066508A0A7DD9A8D45447A39B92D6B0F7DA4BEC2689D25F35C8C490891F053F90DEE5E2D +8C9D7FD1E23D0F1C5F57921BDB13BC9B8C3CED4FC42C4DDBF0706985A0DDABCC683FF5EA8416C225 +ABD219024432E3972C3314C30A672FD21523C83D93B2AC8D1DF023EEB1BD74E825FCD19873E63A45 +F6935E6685CF5EF472191B976F9EED2A4765E1B21B46EE1C4CB90AE89DA48E52BC4EDBAC2C855A67 +CB0BE9160F3126151CD171081192D0D6CB27E4EB2D725F31AE95FB283149F53F22BD8E414354D4BB +56724057601FE4BF34A5B188C00B0E550639CD796CC66EF895AA5315BEAD49B5639EF0878CDF2CA4 +271027678693EA212D0C11A6EA52F748AD0F62A0336BEC8497EE933EEC461E461CCD2F5291B980E2 +8B7D66690B10EEBE22B092179396EEF5D00E42E6CB73BAD4485F2063AEA6B6207E136ABB925332C2 +60F12D8B60B211A9BB15F37F42F53AC2559F5A8397DDD491D314B6DB0B50E41F0AA0A42FFDD5B9F3 +FBD8EFB7E343C06F793DA6BBEE4FAAFB233C31EAA3AD701B1F1C4F2FB05A7647439D19CC856C7D98 +EB3375B3ED2255FA33D9ACB87C1937E0B7F34C9B299C8D2A7F85D41141C598F9505C72B5AC2DE9BD +E24CDAE1DEE416786B93D4EE713E437D2C4A3251A296B785C81A8232F98ADD04B3D2B41394F8BDEA +7B602A555EDBD51A088C2277D8E86B08A0D05CB6142E33E973BB3F2CE841D323ABE6FBBF83B84272 +220F569DE23264AB672C2590D4527A29510E7F289DC2193E66FF23D83703E27E9E81572E7534B1DA +510BB846576E8A39D9CF44483F297C92317ED8E46237B3D73844B3B19D37831B44EC116CBAC3F75B +B67928C4D4E741EC95E96FAD74D852220F4F1A8FDCD273E0F6E77F09EFD5723CCA1398A021FAE947 +9CAC5922DAC8E2F46704BC216C7BCC1575A455CCE2C2A080B9FDCD0758D9D921EEB6DF96C64A31D1 +C9BEA80F48461857ED7DB635A3BABB3BB6155E835E605B09E06A2AAF6BF3EA70B8C0E098CD1A818E +30B9A4AADC284EE2B87E945B717FA73AFF5FB788E51827F6FBE319ADDD059614B493ECCE718789A2 +EB0F117EC811EC38A3F4EDEACA660612BD247425A3FB2E6022CC14FDF69B6660B37FCD4359F1BA54 +D12B1F478D76CF898824762C25A026B01C94752F6F3724C31AE788CFE992D9CA152902EEBC4AD8B7 +A5F0E68A5A0408A2F0BA71CE0D94B4A905B35F2781D7E7A2712DC62E87518BFE72A5BC4A9F36A4B3 +B1494B0C4C14705203762E0CD0B28BE31234449C7655B5D6165D7CC4A16431F7A8ECA58D25711E98 +4FF2CE123C05AF9A65D478B73739715DE62A199D47BAC65785EE1DD25AF91868F91D037C0AD754BA +CE3DC4B67F1FDCA8FD9FA39796EFA9C975DBFAA99DB70624B3563408D0048E3AAC6B4F228DC0AC08 +B9C2B63657EEDB53B46D157426A3B4B4B8CC5B4F30BC24CF9BED442DB51F3C7A0656DFBEFA401E1E +0823065499C69D51C477360FD13ACA8896A8117789C4561F3D85F3A80D18E39F1D6BF76C7876922A +1038ADAFD53F2D092369B356D0CA3FE6A27D7B9BD3985C78424C21E60F6BB46408013DFD7A30D320 +EAD9AC6E5FD36655AC6706666A76F1E426640C4B0BE692E4879991EA9EDF4596C0DDF43D4E370360 +D91E8B2839D368DA2A910AA6092337E2E20DEECF43D583CF164881079ED5A492B5EFCC1CAF91512E +0FEA8140CA3E2553733D6F743728ACAC3E643394015967DAC8839D5A804503A45DBC539FB8656D75 +2F00EECF73E7EC8746CB13F438CAFD554C01150048F758573903B0B3260AEDD78BC2EE87D201E219 +486315A4C01D95DAAB54335A4F2CAFC3F43F12A9574CD2DECCBC1858406C701EE62C281A55B729DC +EBBE74FDFF275A0A7B8B22C7490187D1839F4FF271723C140095F28221C4145C9061F9A5B3EDF8D2 +9E0DA04D9A8AF6ECD42DB897DD5C9318D636FAB698554BD9EF9B0902BFD8C96CB958773A3C4A5FCE +8A334C673206C39277E45AB50DA2661F89D621AF057CF1A7ECDE344DC7658514B4C655937E7BE010 +B0694B069FF64D5582E3A4B7F6AF6C96D056ABB20CC883AB25A9BEABB18A84F0258CA3E4F33FFB77 +9841F5970DB447969FE9C6BFDB066ACBC040648D74F553EE434BADC353450A3792EEF9CFDB2FBCD6 +07153F2EF73C1BCCE3784609F26C80193BAEF766E7CC7C33A4CAB862E6E01FC1CDF11E2FBF25FE1D +308CFF9CD924893861BABF78F762F3CADD3E0BEB38F6157CD08F1B8767606427C4A631AFC9488E6D +4D1A8F4B51ED48582BCD3089BE037ECFF18DF6175EC317EA56D4FDE37288F089532C13F7B3C1EF7D +333E7FAF8B49D95F535F60889CD7245E5CB0BEBFDAE8F7A0AC1AB7DA18F2BC06267B27403F1BAD9F +DF5F13254E96C294C4568EC7154479570E514A55208D19A4538959F7C5B2A0C9CFE4B4A40300F248 +5943C6AAB753F3F0E551727B8DA8E75305A9CE623757B36FB7D34D13CB14EE561C404CDB2D88F375 +2BBFD9FDBCC92CF110D6C35629E3040D995CD25B90BED2CE79BBDC846EAA321B1BC46DFF7845380F +BF08782D6A31EC7D41F251786FDE403A39626D6052D5189CFBB3DCFF09E81C09D0CE7D571F979509 +79B26AA4F6D07F97A33522306AD692D4D960CEF1CEA3D251A841E2A23C7AE3EA44B3F31E79808F22 +B6ED20DEE4186927394624E22D37E873B660BB8DE6FFAE058DD5817A3BBD68963D055D406F253701 +D940B5E58DAB01FDFF1C626D0D35E8E7995D37057DD07F6D4D45F152A141269A7FB81433652209B2 +B23D69BB5D8D367D95D4A94B2C2924FB83F50F651458CABCB65009912F00F485A924A61A0008DB44 +D478CAFDB7D9524204947703B822755A1301FE163A8248C8AED7073362D918D097597B24A3B579DF +FE00F47776428D2B992E1F5FAD6190ADD1C789BB9A913BB1B938EDE357BB436F734477F7BF332E36 +7C380D049AED8687B4C2AB6EB813E719718C9CE62296C24F783B16E9635A7E4402840BD26D3A0DA5 +78050C49E6D8239EBE9E053719BE94CF6D8C7942AE1660F28B21B3C1E6E15459C1FEEA4FAAE64AA7 +165824F7B939E28E51009FB778E370C6001B3F546EBB76454912D730A3F8C7F6F9EC01B9F90A2E5E +58EFF9EA99BE57A0154147C2B7A7C7E493E37C9BD0ECDEAD4AA4DBFF95D7E451246C9D4C30E71F4D +76441A297A1223FD2F8E017B10C108B0F0F67385060E9C18133A6264AB2B445F6DBCE86CA803357D +749244A6FFD8FF8AD37EBAF3787F3702764C5EE2CA7547D7A9FED5AECDD2064F7C767078579DE13C +F135CB05561B15BD9803646611422353774984D386BAD640C5EED157569356A17BB6233EB298960B +8E34209562AE170A08D15F3A29967DE067F6AD183BA1EB49A99F4899031A01410D7311BB9B7A984E +BD6A303D44CF42B40F12769D44160583BCD68C68F823DDC0D73150083404B12AAA68E97206053C6D +23FF0620231D3570A089520E928E980F56A273092DF94EB3A99FBFD877B58860231B2A761DC91A41 +A427778B06F07D4F78924FF986F837C1437B44EAD5E7C56B9CE9CCFC0F6ABDBFDBDE4A32E3FFF336 +7F7194DA20D038CC44C4413B2CAC15C05B22758569D1008EA057DCDCF4A324C924021B35B10ED632 +BBE921BE2E34795951DDA394FABF3EDCEB99B3CA15D6579559F0BBECF8DF6E6DAE427DF75657AEDC +FE180A88DDA445A5A5E239B364B8884714B0ECE259F32F1742DBAC0BFA9A1052E2B14E632B56A474 +F2C9DCA9B5FD8D62A39227CA8C208DC69E5F543A745A913641950AE0DCCE02D20D374B652E2CC41B +F0417F99C2EFCE1C23204261FD1BCED5A1E8AD4736C5F23E14482D766390B1C62A320F751CA13454 +8DBA0B08E4BA0A0CA5F6DC765F9520D15D895792BE580133B92EF3691B95331DC76A551C4AE9AB10 +24D7EFC4A02B5654057224C3433A2AD6859E3E4C40F8F0B089C846002C75ABD667C68606D7300B7D +0569753AC074BE6943AD20018835A6EA28B99C983BE3BEA9B742A76F2D7A2A26B35664D24FFBF656 +EA28D525A78298C898C0BC2DDB56FA37151AF5A08B28226CE6BF09726C37F1B0BD39DB144CBB5494 +5DC48C374BA8716F6C9A4626C95B6993DB2CCD59A7430E3A3B2E6CCAB9A801760B8548C8447D129A +01EDF187435162EC13A65C943CE9EA547C3694F88F9706AF29F5357EE59500EC080E7FB844E8021D +907EE02C344DDCB78559AD7FDA31A3031D5CA80C004DBC04BE54B38752D49DFD19F1124C059ED68F +6E85E1A3A848F98707D7413ED3DEEEA823D958CCE720B85303CF208AEBB9B799653EBE4DD16186CB +F8C0301AAC6271EF9E2CF6732A6CB8548B7CAF2399287D6AEBD5ACC7C9D0DEB85BE38150072A0184 +51D3F1A8ECD784AF8149BF932E0422EDFC608B20B46D80D3EB68D746E1EF40423CD6FA218C9F569A +3442B0E70A2D464DC59CAEBC9607333D7B8FB90349676207AACEEE5ACE8E0E9F9C5896751ED4DA00 +95D68C421D8754D665D3D58C682AAB1DD72EF9050894EB680110C3E7F02C3551D73C63CDE8B45E5C +453BC9AC1FB3145CB6F0141B8E4928351FCE66F2A5AD534E5DD8BD901CEBFEB963DE2787095D7755 +81E588D3A165BD55B51F039992567B85FD3AE92C7526E33B44B8149E57BF7E57579E37611AA29DC5 +9EC94F583181201638BD4BBEEA23BB9EF067CFEC2E436D726F401EBA897480AEF7E38B9798C6CD42 +182C43B2BFCA7D8B6B696544F6B00C7B7D0D2C70D955304A4FC8D97E317C01113404129D480AF8E8 +EC0075A94859D5A79DF5F3FDC2EEF4F0BC1113D2C92DAB9859E9944DFAF557DF43AAF42B4FADE1BB +F5AD6728F884F0D4E7671787F1A3500B00E62929147C72FED37CC222EE991630EC9AF614160872D1 +BF4666DF3B682373AB1CE36FB87C42597FF1F96D3D7B07DC8755C2304AE69B955FD2547D316E16C0 +458BEEAD37B904BC27DE764240E67A68ED5FB57BA1F9C7C4C8F2BFF745F3E6FC732FD5E37CC1DED3 +6EDE20B06FD832673AC78DFB7655D7358CA03332A18241D96BB0A45D16BF2A2B80D0A68C74C8DAB3 +F18936EF73085EEACA9B24B18EB7DFFA75C707C947E17736EB7B608C4AB90ABB53A53F44D8661485 +5D60E36CA31704053CC453F2A50B878AFCE0361EC30444F5D6009ACB5D9673E5536B11A02B659252 +A64923E738F494D6264824392234FCED4D66E0342D03189778D41AEFD907272A919AAF40066A304C +6D7831F90B347CB8EACCAC6A726B40BE4671D6A0A591DC36A30ABBF91F9E780137D80EAD43BD49AF +690A3789F39D3EBFEA9CC64B82D601B88805B6FDAC3C84C61638DFF1E391DC74FE4D08A0683BC5D4 +E6634F82F4DA357742764FFB2B8D264275F82052921F7647BD8709857BB1C98C205D13EE51C14E9A +DAD1324562267D1931B5143A2ABD173C745B7272A6FECD532B5F189C8749DE0ECD3A6B1799C1834A +414554EA6972309C48DAB44A9DC41D8B28361E89CCE4DE8AD6058469D2F603E7AA62631E80C01535 +539580E124A24E9387E3E0E58A63AFB29944207BE5929455A150AA58E27EC885CCF019CABE1B8769 +0AA7FD1F4166DF820A324FA0FE3B59F8B767BFE029A7E3ECED513A6CC622AA8CE96563219EE328CE +BD649EE99E5F108FD57646926CBA30BE3AA8E00EB4CCA282AA35C0742410477E2E5771DAB74E4181 +D91DBCF25DF36BDBDFC5AB6C73A982A390416A23C8DA10655906878AF714C3478C8A0C7534F6022B +80925A069F63834539B18D9CBE67844520A195019C15F8F858E91CC50DE001EDB52C89F06035473A +022A718893BF7F6FC0B2E6CD4C1CB26E98C1A191EA5429BAE831F464971180F5EC2CC6E6F8F9EDB8 +2E2A7CA8C5656BFBDD618F7D31635A23C73F330EC76F4543C9795600F8EA45DF62BF4E071FFE3758 +2DADBF252F2A3EB399F61BEAE10BE0FEA537C272CE850026872F4BDFE5921245147B71DAFDC8EE88 +C509B6D8AC249557725FC5D14198A2DC889A4A9ED045870F767906A226826AC93FF1E09D75B4DF79 +8FD690C5146175EF2CBED8F03C9DEEBD95AABA69E98E25A98CC96820CF1C684F02E7739F525B12C2 +72613012143FC26919B800342903624AB29219E6266716E451C9D60A4FA010B8D26B56A4C91AE1C2 +ED778E35E66B49C4DE64021894C2B39E7C883518B06E04D198B7D056A24C3E65BC9E30BF2F73F2DE +21E676A37E2AFD625220831F598E93BCBE098AD73FB6EA5CBD9D17EFBE6EE35FE4EE93BD3A75A2F7 +118EACBCCB82216DF70F56C2E82F77F072093824C6ADB800C66F0F26BF7AE513A490AC3DCF648DF8 +2E54567ECB9D6FE66E908748B7D5090910EC99EB9B222E92B058F3EF34A11918D6FCDDBE2B9C27D7 +DB19AD215E7B327689E0597963E6EC907A23A0EBFCDF86ACDC349CD8983EE83144B5B8489545AE2D +ACCDC8E553FF4A1601F42CF82A90D571E36193BDF4A7893B2637DDC0C73EC0C21BDC4BE1D02BD257 +F4C240DD6AC53A321E13FD2EF4343B11B9C8152EC02EA6C4DBF7F66C9356647A948CA9E26672BD7F +9B828FE109600B1638806DBB95DA6AD0F78050FB13AA580139C7198B1673D4AF9BB610A83A709D3B +7D7B01AFFC0A740F03A5E2E3EB7AF145E3338D46D03A83FB82DD6487A52F9494A89717FB500A26AB +C949C51FE25DEE8F78E199AA53EC1DDF9D767D8FDA77FA32F19200BDC539F00A23DEF166D97F0DF6 +64489D932D115523CED7460212BB35D887FC3507C2592ECF622FEA49AE2F04299A547ACEF75EB0C8 +8ABDFA7A042D5EE4C88D716B00E79C40173A3F7044546D093B988463623DC1649FC6CD645D01E102 +1AAD11911190D0B07C0A66AE7F9F9CDCD0D841A976A8298C26A0850FF4FD42EDECC37B97A19F7240 +3413098A81025E4451850EAF180299667A392B7D2E96C4068CE110CC3CE15C6E58CBB11CE21A3E9D +FDC88ECF14A8F2D422E1CFCDDEA320DF5CAF93E6F9AFACBADCAEFBF542775D07EBF09A96F0162438 +62662AB782A464DC7A96BAC2B0F0F043E83690C3B24432F61293A1C5B3699605EEE8339AB079BA1B +A7C65ED392B6E94FF817CC25AD32E89C95A0667F124F26B11AF5B45A9AEDE4F443429ED30130D7C4 +68C940A7C538ACBDEEF77BC084F8A24FD0060BB9CC12A710DB9DF03CD381FB6E76F79D3DE40DEA4D +FEC56ECAADEAD68DF4492DBAE69EF1663E2CF90614871094BF6F0E1C9FA0EBB2D34923A19A557BE9 +54D914F35BA044FC800D822D88B5E70CAC27D6D56C66AD6CC3C7647DC679C8D3E1D39AA8282BCD27 +982428F5FAAB76EB16BCD26A1685C044E3C7B87B3A1685279DED690D76C0F1C52B76FD13C419165E +754BDD7FEA75E26DFE2B916DD0CD40301CCC945683C8E1F49A03A0DCE1974A76B754BF04D36C2693 +969FE4C6C39D60D995738F1DE0ED6A7E0B80B40BC14B440B6B8F1085E83995E224BFF4EEC6F67EAB +103B4BB6D21F9741932DFFBE85C0BA3D2AF925D670318D1157FACAE9C09B3AAB5B1FCFC889348207 +8D5A3F7787C699C420C9BF0883D3B8B3D7753E9A146175245CA9E2EE04FBE258B6E42334EF141A41 +D68ABA286864E72F0E4ADF41C1C96E60E69320E79211984A734392C870D72B8C236AD631672AB9F0 +FE48EF2611740799DF5B3339BD49697C4DFC0557C1022AAF15C24FDC54FBDEE2129EC70473A17EEF +D202EE43A1B5C7B78A299B6EC8BC7595FDA6BD0BD22E025E8FFD89115448D99FD27BAEB680A22C59 +7295E33201199E9E1E38AF099926344D1B7CA626166CFFBA2F3D1C15AD63F0C6035A5B9BC5AD644B +3D5636C2FF3B9403AFFC3AF0460B328C390D3B416C7880A0DFF10BF512BBB933081FAF4B2E06C093 +E80950F08BDEF07D56BD042433CB0A0C72E1F17692C9F5C7AA97C31AFEFA39233C62D5430F11DD31 +478E86A36A8AD3817B0AB397C8D6935960D905994ECD2AA8299D248AA274AE0FD1F1377F0443B37E +67DE63151184DB5EDDB4DEB9CCAC76896BEBE32E30E0F3C2557429FBD4B85ADE7829428C5CC95CBE +018C17BF38FE4B26B0AB736FEF35F6E3DACF0BEBB3B795D7982075B75D87324AC28D7E5B446F04F1 +0A001FF191A5FDD10B4729E57578FC42C26D473F22C70D5629AE05FC33E50A4EBA2C5D4D63B1D147 +9ED7B8FD7A0D824413D06437118C788543A21520653572608F9172CB1D1AC529280AADAEBB5A4E30 +AF99A58EDF2952BEEA29F366FB6FE7A804DFB1D116B73B45033E9E7E9767A9F41F2FAA76F97411D6 +420FB211B4BECF6C785FFEEBD90AB932E82EB0AEC7ABFA4A7AEE53E2482617576EB28BB2A3C7044E +15F0B6521F3B073021C3CE55890951E041EFA38937F2C0683BAD1AF255CF3747AF2F0B8A92BBE44D +88F7768D35B8F4EAEF0AADA3A42E26E3E3EC25E286C40808665B80C6265716DEEFAE3A86C9B54D34 +74285F3BA2946302A065B800EC7A9694B0B715BC86D3EEB649FAB8A47D170550D9213E8B8E9367CD +FC8527955263AB2AA55FB7ADB7DA9A4E727E3E69D9C7946369CC078DD7751DCEA1C0601C57F4B5E4 +48BAD7F5F8A919632178C77B7B5F95E402DD808AD59EDC020D82399DBD3A9D9F3FD089B0909C171A +940673E361F5728A89DB3E2CD0AE2009A6D64FD85ACEF62F8B42F009BBE11EA0AC14525C2ED72E03 +0DDF4F670D18B94C07C027509F281F7B59D854A5E46F4DC544BB320C427642D84B914A2E5043B1B6 +FC94802BE925FF260775F6D17A5C55C5A5D5931F88E3D7E8485D8026545CDED1DC96D1ED7E0088CA +ECBFEB99F110A5CCDF7EF3B4190F3DA6ADCD5A46DB27C0F076B558667A1B9ED967363799307E77B0 +9859909B4E86A27639DF3A8C0B193502FD22C0298AE0398E7D33C3039D7878922AA9997C93F29655 +5F5D7BF3A34D46BA5592FE2DAC5A32DD9945852962457B81DE4B6B9050660EEE1A0D95785D824A5B +DEABACAC8A8A90E7303093F0DFE57ACDF0EF2843DD7497B1B80AE7E883735D9BD689C84A61DE8127 +3E2DCA2F64B00B62F0FA3D3B5359241525434847763059927565F4D98CB8AD1842E31488E4C1DC58 +4BEEAFFE1D3E76AA2E6C81CE2DA9F00DD32841412695C8EE17EA60499E99B97D30C32DDB0B9E473C +E65C259949129A4682DDE5DEAC0611464650236934D7C57D1EF7E8B5D9E5D7458F0FCA9795853710 +F37B5C24E39D7EE92B2D4066D533A662AE2B063B741559B24AACF24DAB6FB6786F639ABD8B34C7E7 +AF20E5FC999BA74AD93CD821B545C2531C506719605A64FC06DA8907550087A4599EFA621DDFEC17 +B904B6115BF94AAFDC56F3570065D75DADA1AB177F4C333A04A0119A89BD209DB0CDBC5DA0C8B99F +EFF54B2F4FB4BF95AC573EBE6D5CC8110E6387365CCECA5630F5105C887DD5803DC1376986456634 +C3B3BBC235A72AF168CD5B350E0A8BBC303A2CFC37FF627F4697C0D19BEAE28FC3996E967CEAC4FC +8D9D309E2FA65172E899285BAD3F8B45B38C9C2BCE94C31911079850A040C08789EE377B9E652A10 +01EE4F44420757358E183D48EED67C3008E6F05C3971C732B98ABC24271527B267D8B10735CB1FBE +773E33FA51B5B472E402676E3590C7BE28BFFDE77AC34544718A20833C9891A176AA3A62D686E072 +7AB2150A1E77FAD5012D0299593B0222CA38CED2B9953B1E5893F176132F1197609D04F2F1D647B6 +F44B2EB0AD94211733F226B570E9D963AF9A6DF04FDFA26C0BDF31EDC41DA521F9D0090A9FA5DD13 +B9D977329F6412815A8C52C3290DD42EDBD312592DACBE0BFDEA209F389DE8E4B5D8ED51B46F1557 +C2B50098C2262D3DB298E12C0AC3E03B82CD2807CE04E109ADD00EB181D701E4BC3622DE8A86E977 +3D6C4AEB830F3283BCCEA663AFAB740B546C3577E9182EFE660AB380F0504590CEEC89313A608A29 +9F9DFFE22DA6296EA3E39857D7229885C78F097E7E7845E6C908A0570D4ED0AE320DFADB7AF87E5D +F85AFCD1B271B672813C0A0E2EFBAC5275807ACD3A2F09EAB95DE6F571E3F3C827FB3EA9DE89DEB5 +4B8B14770305B23EDE569571D0BB8BAF4811E12A0DD5BA4809818D2FE088DC1CD4BE72EECB36C819 +AC25B41BADFA27D5839D548CEED7DD18F5F2BF69EFCAC0ECD4FD942995E930C147E1A7AD93628180 +E62F20F3779824324C5A1C35ECEF68DE30BF5DFDB5DDEBF66CBC459B2C7FBCF0ADC0274D137BE67E +B22FA117C85CF7D52BBBB4CA5F9A6F73AFC23BF2E23B4B1EEACD33DAA3187F1D104843876EB44322 +67EDDDED02B6A507D13E3B9F012FCB8C9F0D14D951415BCFB20B3211B5B9860B0C6826BE597F2F9C +94DA2788E65107C5CC77CE1265E33DDE9378AF9019E7E68522997470A52088253FDCA09AF9F071C2 +988CEBDB46B7F7C8D08B5467A1B3FA0EFC552C5E20D4B9D565AFEF9B520FA2F544E802EB8E8E0C76 +21FF63F4A5C0C59F94E9E1731D8F3C80C772805DE264C7501E705BB21EC37A1379BEF8B8A9E50EB5 +6FE9CF9C10C9D25CBDC68124D2133B2DB6348175537EF872CCB8B1787330A5ACFEA87E2BE6615DFE +442EC74BBED30021A0437ED3E9DBA6EC49A824F0374B446271DE6E1B16AC74816F6216BAB7329725 +8CFBA83C178F5EC009C57404391898BCC3314411F129F12D68218AB6D0BCCE2E5AA9AA1D5FEE1E2F +0AFAA4BCC3D226C5512B456CA8F28DE54858F18DE2B30AB4FA02840859988BDE7ECECB4EB0002523 +C6EC40BAC2E7ABC411329F803DE2DCE1EEB354E4E6771E4328ADEE4E713AD248BF4F91108C52B169 +140F33D5C56F1EA2240E7E182C060187E29020139C373B4A6CC4D2156F7C15590D3C07C98535853F +4DF901EA9F2C66510C190D9456EE037DCDAA428D433CC2231B2B627CE2B5304B6A4630576BC48984 +66D7A8BB75D53ECA10C74D434A4E50B1A706ED6C7BA274A9CAD5D929B9BB8A631825A9C32A8F468D +578507DF2291DEAB6338ECC92CE8664D4B1C211A4CCE186679B6C71ACD5655B97ED8E552B09C1C85 +387749406C549057DEFC059CC85639203160B8FF05A48F7D5C4F452B111891846A521674C0E2734D +50B8C7E7B5D9F438C58DB139A6509DE3495388E0D7AD24F64FE73707C7BFB8CB06FA0E0C41346B98 +220E007E28515428C1874AC996819F16CB152C16F89CCDB3F9C83070AD90337F1823AC0A48B72749 +C6C29A8FDE1EC2E76B0D29FF711891EC81D0ED0B3349E9FDC413047731D70C33E57D2C4B637C8FCA +B027CADCB3E11F94F61CF3A56E4D90E8550F456BB90638DB6118229C9B74C9533508F343C0EB422F +87627EFB562C7730E1A804E3E4DC80FC0F199CE210045ECB1E3313C3364F78A500A8ACBFCAE0F7D6 +56FDC8B1BB95262A32ED7562A62EE5CF989235D1E641D726F34D215242D44A946662EE94E765A3C8 +75557732FB4DE1CC2699202802D4A5D99C621478C1C6D583FEE8CBDAF54C73C8C17BC73F1B414EEA +BD901409B83E98D62749F9E742FCA7C632C176D323E72FAB241D143950B87AFCA5B7B75936FC6638 +1FD0E537C30D744E970A08636D27AE7A277F3838BEB7D1BF821F331D483FCEE4EF9FF98F350B5B3E +CF2D6A5BBE95862FD5DEA6D3A5322DE6723B5201FF81EB1D1BC5BD0F77CC1737837655BE23E0662E +AFDAB16BC0635F40DA516BEBA8128C414D6EB5F5AF5F98B8C0129606FCF536181E7A8ECA563BBFDF +0AC65F1932F1DF20DDD6739F7B1EFEFFE282FB6DF35222E8148FB5968BC7E40A582D7B146E374270 +D3D014849E898E91997288BE44220B6B6E431B7AE3F2F7C5BF3E3444F5088F9F42B7F676EA14671B +C70A84B77BC275E82516040F7B9DDC582C0FE335852A83C31BE3B3F716F17253AE57372D14951A2B +58F69C2DF7B93052823311E4208A72C10D0625869BC5F3808D231E86CD259824D7E6C7669013CC55 +B61E4C20C0041C35BBD7F1C291EE7A3CAE016A8C90C56F22C515375252FC3E188B80940816EA5117 +88A2FC7AEEEEDAB9E0A33F2C82D886F9BE029BFA1348DAD16874751460DC149CAB5189D061E7C804 +1939D80A03BB529E3580A235F8C37EE25C503BECB9C31CB91904BFF4460837A1165A7474C83B5773 +5945BE04F3FAC3381310E4BEF8D8D4A7343B75D23BEFC58060C48BCEB52566A021C197ADCE5FA025 +1AD31CF2F90CF6A72122C38FEEACE6BE36176B1A990DBC42A33F0BC0090799C2F6C8AE6990725562 +B07725B3DD15C9011205C28700DF82AE4F00F9842DDEA3BB5C15D3A4CDCD18E692427505D7B24CEB +40CD7AE0D81A4C83A0F9ED579F924FCB19D9D017E60C6500CC64572E0161EBA57EBC11A5932F24FE +9F1AF444B3C657AD162BD39682D23D6355EF5D84440A124138CEAC85C926BDF484AD7B976D9A44AC +6015C25354DCD72A889474F31B8BD3CB7371B95A9729FF0E46EA3644477AA4C11FF5913D917B7742 +065F0593482B6E6EEC9EE63633A6A963819F3E6A2920136B17C982353F1F071B3D585DD24B22DE9E +EFB2B34F776DA85F85E9E107D16960AD67046476ADEC509FCFC64E8AAA6427935FC231C817A21C71 +6DCCE088EA4186DFF0A3A7A1C367615B8E7462DA176C9F9EA893DD04E29DFBF88679991AAB79A172 +48C06E2BCF3B91C108E09331FB57D94BE85EDCC66DA8225FF4B38E12F8563398E62622EBD2EAB098 +691EDED4D5D7AFC360AD6F263C043DAF483DA05CF70DD8BA8F96D2A5A87043DFACFBBBB3F8A378E2 +A896897DD48D8B13888A023AE6AD778DE5FA991907E731E5C5B0A3DABDC360D77CC71C59C34506C6 +39C21BA9FF7A9CF322C21B457D62F20448BA19CB765C4C0AE7CAD9A972F60ED60A21C92AB665537F +EAC8738AF8A27D3946F759162731F62C0A657CED40C66B8A9941EC2559074279CE0F6E10BE3F44C1 +D517E10D85EDA6BB6D097F4DF55A3DB7D50679675A781FA1FFFD6F1A8349B2870C8114A05F5F7645 +3B38446D57ED63FF8731661F0FEA79033E4C8B5CFA29CEC43355780C5E2EE86CCD449577EBDC0140 +47AA5CEC980CEA8200867212DDDAC234BEFC9FDFFDB43DD32F44883EC6F2963D4D28171E19E144FE +1BE2B8FCE99016691A00E4EA594F94E973E899D14DC44486BA6B4278DCB292FA5C7E6D73068A3BA5 +1557C3F072547E7F2F869D4E9AC03514276EBDB0920FA04E67E2934A250B1A502A8D06A25037CE59 +920D0E136C02D5DDEE2EDBE31A38BA32C4122AF89F295ADDF579FBFC72391283DC1914E9322A63E9 +44A280ABE7CEFA54ED2EF42B79FA97EF21EE83EF20CE34850FB66C378EC7C08B2BAB924F58FB8123 +FEFB43A385BC1EB922AD8360750FC1B0D8A303AD19286308B7A39A5086A50A8FDF7D60188342A9F6 +42286540945790524174800F8C44ED71306ACC3437FB49D8FC43FBF8E88103A76B4A92D95DB9B45A +FA067E31EAEFE6BC818D11D7CB8566BAB418B596A7494FC7326AB3CC029D010917B305CE585B194B +C5415088BC7AC7852A6D52EABD223E2634DCB29080217F6755B023C591F08C7E5D72267664136639 +9766EDF511FA744675D473AB37BED0ABD92E04049AA9008014C5EEC1B0443C6C86302CF6A3C38BDC +B8D9E0538E349BD930707DFB002700B5EB427192AD6105E01B8C2FE488CF617E9EACE73EFE3BAFD0 +F87CB57E02AD31627E6439188006655D6B992B393F4858254C2106FE9A3F0EF7347347C66C94A999 +D49527A2A177EE20A08BF594FF1E08CB091D22A8C1569320EB5145FE4A2674151750620B5EEC822F +A48C5F8B565DE0E18AD05F99827FF24D3BE03B007774F25284844D0F1F8F95643646960F303A831D +4C2C4ED9E0664C1D705137C157671D62179B47FA4A6441DAE99C2F7C8765C4C931EF345CD8F92D11 +E290B2FDEB1B0FAB4BA661A4511F75768808AC1DF2FE79BC285B976D364ED25C64EDEE62E8E035A4 +B79344D55B1E7E2B43AF1CF94ABFC8D0CA5E89240EEA231464449B831F1B3F9EF01AD07B38F0B402 +712A0346892A1DBBBCDBCC827220CE7F492CD7471FAD35B43E71CA14F1F1A9CEA740C4E1A98337B1 +5EB97B10AD57DAA9E9ED134CBB4614321D548C6A71D8ED95900E7947A7E4331D7DF3EF367F6DE8F3 +113A7DDBEA0F741F9C189B8B586B83671475A492AAF9994D884FEF3A646ED4F272668DDDB05EA230 +399223AE63088D636AE6AC7CE2DA06CA6AADE9272FECE86D0EEA8290B927B17450DA6F34A3D566E2 +096300CD8D5A34139489228ECFEB104714FF907A6E1D3DE35BC0FCCF45A2781AFC5562CCDB627E06 +F23DDBEBD4212F36C332C4A5A9498032213DA7C3FD03FC4832D1F2AC9EFEE3B840BF8356A16E14CE +989C37E6234CAC7A215DAE7C4DE2E2B6D9A876F709422113B503556A4BBD0ADC107B6B639F1BAC9C +6FAC7F4092D23C04EB8684C9D0A5F184160CB660CF6E8672ABE1AFA596EA86890DD22D0A406B2118 +9BB626943F378227132475A25710B75E5B3BB2ED7DC0412A0A079E2AC311ED55AD8E7B2A1A55FC84 +E62D61398511B70877F3DDDFEE5D033A9ACB66899021951378EAFB9E9A799AC9686FBC2E9E9B3A51 +6DA9DECFDE87FA4BC042A5D26C2117E29AEE8840B18361B7B38B21493401E931B431EAB1A3371628 +EF13BE5A0C64A3B9F8B6A29D209884706D2A9AC85B86E3839706269366EC7E53F31BA4219F741E55 +21E42F0A10B7B29E839B924AD90861FDFE3A3D446D1E32C06E66A5D7187A63E590000D1356718648 +7C99BC31088356C9ED29BD80C61E442B81E15657AB191E90EE77A6804C762C45D3C1937EA17454CB +D76D781A0C96A0914B9DE3D3984BAF6075D3A25AC69BEB34CC413D26C39824B83F853DF864C269F6 +8443970933FEF93208BAE4DB3BBE90DD3CABF6EAAD2F6CE664CFA05999FB1CC406A3502DAA6C8145 +3C69CD218B18BF0B9654FC3637EBAB8007A2EEA6ABDD11FB338E89FEC84B344857804D028F849E44 +5982E294384A442390AD36D7C4182EDD7A05BE6744FCBD3BBE6FAF4796063CF42499F2DEC302AEA7 +B64FEF6DD74F278FB5C2897CFBB87FE03538B2739E25EDEB806142E0030F7413018EC1833840BF37 +269E21DDFF67B8059BDC83DE9C6461F3EC2BC2224D2585AFA2AABEFE7D3B2A899C3E08F00AF2A707 +55C145C6BFFAC8F96B54EE682C3C8CE01BB44EB574E1C721974F236E8A2AA28DF0A4AD285EC4DE58 +DBD3A2FAC8A20173AE84CBF877559ECCEC64D9448F8CA0FE5272BEA6543738D5EDD54B73AED3C4CD +172F91C4F70616B36D37B1252D355820DA88536C829B1542C1EF4F76375360E7123525744F55001E +71F5AB1E5B39A5248CCC6789647F1FAE5E989A8A8ECAA2A9116ED69DC9B9AC25A743F70AC4B62D72 +5F120D94431528EF8C74611F7529BE325AF84663989C219B70274584D1EC4485E11AEFFE4A29F534 +6912577C010FC753DB47204BFD9E504027B335EEBD952FD299E5562407234C5DBF0B839D1010AE10 +5D56766F87910E44AC7968842833A302882AB481FE0AD444911F7EB8555DBB9F3D062E9E9FF3B529 +4E9A3B3AED4AECE34C816BE7FBCDAEBA33FDC491C725F13801A6BE162F7F8E99491E8BF77F2D2010 +D9FDD78BA2606A28810CB5D88CE00218D49609C62E96BBD36110DD611C3573EA341FD2AF6FE0C932 +58565D4A6C88CDA3951E287168A478F5EE074BAA9676EF5911D8EDF8D66A7E8F3BED1BB786F480F4 +423C3D3CDED2E80AB76CF5CE5A53B092A44FE52806D8EA72033BD3E7BCF1DA9C870108F32D8987FC +25E7D873985C3C4882A5CDFE7A8B51F3754842FD6F1FF6235DBB88F04989BB2F2816A476B513C10F +AB6F81CF115EF5044D3366A4E192EF68D385B6B6F4BDA7D14D9627F40843035CA80DE49F9DB52CD8 +714F769DF97F73E3152E8DE34D8C37163D485750F8F4E37AE8A3C3BF54D97BC3B2978985B557F9E2 +9F0537CB743EBFA0B7864BBEA9C126F13C02CECFDA50A8019F90900F409B6D700CBB9EEE18FD1952 +D496DBFDBAC800FB83B37C705367F182D91B21C7F6C242D8735A75343C84DBFFE583337DE2A95890 +660584B513C5BEB7A0926BCA7B7DC3ED4D080CC3F1264A4215ACD35DCC62D896B4354F2F7254444A +7235E0E3D53D02583710DBFF2CD55AE5E61D25ED1B3C3B6708E5BB308A3D658F043C26B881C949C1 +0940AF6BDFD2DB0D544DE119BC7F7B03451E61FE18845000D350AD6D04A09D8E3E999E6DAC6AB73F +818A11EAD345EAED03BA083A6EEE7E9CA8CFB760FCBC88B8DBE0887F79AB430913604F15272F9C73 +DAD19D591B40CB7863414A8FAB21C41F80A4BB0A3AFD9D4B1322487429149470DE62F305906F1244 +2AE20521BE034F159A7E7EA211A2FC6193AF59CBDD4B43207BCDE8697DD515459F80F8EDB982C97C +05ED3996E03891DD7EEAD505F6A71A924CC1CEF29053ABC8F0B5F56D0DA1249F317406822C225863 +ECEED46BE0072EDDFDF5F63DC8E94FC119087A66E394A653D5AC774407B006B35C406E7EE4385565 +78290F8CB8B131B88BD78CB87A11CDA44C5A199BC71388A81F2F30E2C003094E793969673E8D0906 +1F4A3FAB9B14C52EC89BACA1C52703F000A967EEC445E5423D3BCB9253D91AA64BB26727C8461FA7 +FF61022B4C6A9E793901D3407487B4962A16B564CAC93D7AA28A22C28318F69770E12DF9D6CFFF17 +09EE0604890191217696AA52630231FE11153761310A72D60E6925AD6B9D63A66047F32B9425C91E +57505CFFE42A90185451297C2CAD408B0CA4F8E923EC26A3D5D66448550AFA3CE3BE9296C8149878 +F853F2A7C3B2E98899C8F9B47B1405F96D2B22E9F1CD62A2945AB62F67AB0297982809A829826BC0 +F24A7777508EE0A71BA7588663D8118E3BAC936A61FF4A628EE96C0B9AE05072A5A4307E68EF2C3E +97A46EB31A2A7D4A33CE9C44E1111D73D9D3C6A0F22F50D8C22153C2CBB5BE187C0F2F37708237D6 +FEBC445843CF88F4C3A249B39DC971CA003A78028F8A2CB3BFBD2C26CFE457A9561350AF93E60295 +D21E1C2024312B1F2F76F2EAEB822CA72412F860F5A87DF705C2F82E681AB9AF45A19023E02538B6 +9E0F273BB4811F07D153029BF988D3EB66358D987895B96B5EC4C24F3409C1EE1B5978B1EC8F3E2E +75FDF2BEDB0AF0CC66481FA98ADBA8DF4D8C8EB800F88C7776BACEE6F61095FC2CA891574F309E1C +0C27E37D8B03472DB3FB8D6668E286501118F7DADBF1106687AEC6DC4C162D22E3BD0BD42DBED782 +BA4707ED5181DAA9ACED58FB358DA0AA9B63AB4394D42360C3F5082A6F168CF41D381073A1D99CA3 +3BD97F62446D62059BF4A8616A8809147B739400362748EDCF39FFD2BF2C16D4632C06A5D43B48D5 +0D0B98E4449B4F1D39659DCCE8AC72A2E8F32487FF8686E550299F37A6353A8E558D4A8B074C2F5B +864DBC8FA3391E3B5135FC738E4C13868D67234489B6AE382792FD5214D5F9E5249AD65C433C22A4 +D63FA7A36A48A339F443AB39C23D2025741186C8B18AAE9952D41E25E930D6905B29F85A4589E9D3 +95FF040E3F72FBF29650D4DA2B6FA27F60DAC4169DC9764021F4E7E094FA25F6B5AF25602C593266 +ADED528EAE6C967E66F0BA05F258E34CF6AA5488D3F7406C2AA9D9FD9C533E827F26862D348B5223 +A690E40953F337352C8245F1861A19E5326490F2A9742917B5546884E8036DE0874363F812CF6FF9 +574DFD5BA77A1DD7C5778B2B9A2E22F2482744E2CE9323E590C60FF02412CC7AB0EC30D0EC857D27 +A4E3D8B35FD69FE28287B2160AC0BCF645A0654403D26B05041654B17D82928044BBAC40871BC3FD +D8EFC3207928BDE5D66926ED199017B223AAEBA563F2723AFFAB737F6482DD269F44ECCA3B32FA03 +FFCE3ED882B449BEE196F59E6616EF1A2F08B42B1A184727D5BD96DF83972BE1B5F8CF098F61B84A +B5BBCBF231E099CFC07D4748D43F129D123FD8051628564931E43A70BC09BF20AE2C0ABB009014AF +89753F91ACB574C5A218A47A02DA3AE44D3F688F9D96076AED9EDE7388B2935C01FD400BA7EC9574 +96E317C6931E3ED7078A53CB4CEE4E56311F4D8A368AE981606AD7E9DB0EA2A10E079476D9881596 +8C9675D9CF15E29B9328600FECCC02B484D8749B4154D69CF90997AD650D881735AA71289AE93FB5 +8C56686C1F9FB0E696CC0285A1A870373E5DCAC285A1B4FE903CC30B8ACAD2E4613873ED77D813D2 +9FA4984A7530F5B046A71011D97CDE4BAE9648AD54537A1D87A5AF1B92560DD7064F3EDD3CCFA7A4 +FBD6166D067945F103C13B3019540C3FE706804A7A00E1D28A0C26A40AC5A8845E39631A00099CE9 +88C3F12C8954EA84BF268D99E2E13726BF9C63474A5FC874CBF723BD48A5461177789E11B4F1CC63 +0FF4D60DE4F01422C1029E664782232A8BEFC38CD058135C79E015A55BA933AD8D446A81051D956E +429779863DBA60F4258DFC62D1DC3CC3862C5D310579417FEF4D7642ACBA8BA5284DC5833F581150 +ACF91709D6B3A41395960197AB43E63B8C6C2F745DEB4647E298341F3E3023D7DA22509340E28140 +97A0C193493711E60C5DA99C464D8DFC83A61291BD0E13AB6A42C81253C0F1B37E71E7706BF2D662 +76C60A3A7DECCC58E56524A200F8C6C0512FAD2FEB51F5C24109E284FADFFD8484A7A053E8EA544F +AFC1C7BA21E4824866090E542B8BB0BE603060A36D8A8CD64EC92D6037B438EA6A7F3A23E9608F29 +02E8DB10F2854D89E2CE6F093E6804299305BFF3D1601C2830F793B92CC2542A6CB0E9DA602E00FF +DEF234702D0DEFCD270F2984642F13B818F65BD407B61227A94AB11E7ACE8D40849808AB3A7E6EFE +B2D4F3B9FCD233B8497B35299DF28F651B0B2960B4545BF2C05952229EB1CF676DA761995413051E +885A529957538A8B2C6BBDCEDB2A3F4104004B880624C2F55B544EEE8DD29231386492598C2BE995 +6E7BA78FA75FAEBED43807FAF072839BAA02333D38BF4A59B1F3ACEA5C7BC188C0BE8A8BCF2069BB +E36BDB2203EAC19D249C4ACFBF8F9717111B7F4637D631D058EAE0CD4E4E8A9F0ACE1BE19B3A241C +9C6DCE2513690473D8F4A59E1A7FCC926885CC324086981FE0C6AADB8F48116822C59B1E93F53829 +77CC88B82FEEDD2B4CC6095691FFA1419D5A6850D3576C4E705C676850D0BCAB84D52791355DCC7D +70A7F5CF603B4D0D7F0CF4F25AEF44F21A2D627D45D306DE0BE1C794AB90DD1EECAB2D61A115D3D4 +AFAD1914E808B16BC868FD48208E1F915B0E8ECFD59AA5895CD7ACF95E0DCE87DD8B12F683C8EFD9 +625CD388337C262013626A06ED60556FA70A8D425D36B48E430758AB4CAD34A656F457A60E4DF933 +07C4D5B2698501E6D1F270CFF70E47DE38A5FCA2B04D7BEC3A2945EB93C49F1D366835581B42F43C +C99D71F13F45A9FF8D12E26C43E1B994BE5AB44E5309B0F936D78C93169D666DDE6D18E33A5E016F +32278897FD7E76BAFE39498C6A849F4A6D882D109C40B42488059554CC95530FBBAB2591DCFADED7 +3EE5F2F2BBF17F4A131B8126F9E0AEB4B379CEE4EAD92A1BB29E3789EC19671E77558B4DE961629F +28B49DB4D8FAAF541D23205844EAA801FEA468D26F32BF9CAC30BCA244246A55F600BFBB61C5E8C4 +10CA07319DD094770DFFC1CB700DF67097F61C46036353C8AB3A5E5198445A194BF189E20490E970 +7D2C03C1A003BC782A66841AE5DDEED2297BB6DD019C98A66A8F279748DA39C85CE2082D09210EAF +CA995591A1A3DCA52EFC9A752DAE0CFB125127DA2932AAAAD7E9850AD78D48304260B4C270EFF12B +160DEF2C2B8E30E8C137975AD20046F37A72F1355F31D878334D96313D330C24EE7350D4042AAE2F +A345EDCEB133121D4B39645B1D6114D0597C3301B4CA56DA2B4A457D7A51BD13B7AC61FE6E1CD451 +6253F606FD4B57E9F4895CAC93691EEBC2AC992CC5D122DD3FC6A9EC8FD337CD402F03F901CE7986 +2F4F4E4500617DA0F913E357BED3ED04F49FD61FD1C66606CB231C3B7A5042C7C07EAB2E02BE8CF6 +AEE5E16B4AB725B5FB5D01EAD4887E365BC2ACA579BD80E0AA686E4A08DFFC70F99132353E3D5898 +5205807271753BA3DB7264C4567DF5FE999514F28E1DD6D3E966D8810978B140F8DD9BB259078A47 +013BCF247C37F543C0899B532F34843CA56F18F688B42A12DDE2A90CA457860540B6FA138F753DAB +E7331188ED6F535480FBFE934F68EFB1C9C16D4F11EDB35F944EAE63751101928EDD0E7AFE64D7C8 +5E9CAFCBA88450DEF9122A245FC1ECCF9EF8DD94EE6A70CF16ECAB39B52597AB1E8C47B6DA4FF0DE +C7D0FABC84DDCC8C652DD7C941DB3FDCC5F0542A8F433AF9FDF4D393E123884E1DD5D359D46DAC61 +0694020BAE84B3BD4C068E3BC871BE21DA13571BB61387E207926769236776B5B31A4A462902966C +DC3D92BE171F10EF8395D2402F0C492A3FE55979CB903CFF2CD2319CE4B46481489E798A131635CB +2E70147193FE3C8F4570FD01BE10E004B17341C4DB8B029BCBBC45D31227A684E5F38F5D6F0821C3 +ED13D31DBCFF51BD759C84A98145FC86D82F871D2D83F43C3DD7FE9A064120338A7BC63A2C60667E +25B50EA1C267174B334F4437856295A6B826F54C3EA9ED39CA6909A0F6D9669F1E75A7A05CFBE7B4 +2C330668E311872177F0BE3A9B3EAE611EB48721AAC2F10C3CCD897CEA8A136E5E10C2337BC5EEB2 +FBC1A3646A6B6792CA3946BA5D4D135D929547042A2F0D0A202A4D86E3F7098C823E7AE4331CEC6B +607F6AA434180B4153F6B10DCC914A92D6D0934551BC9DDB3C78065B2177B264216AF5524D798AE6 +2A90D00A70CB36C5B9950499163C2C1B04339FA76D28E03A4D0C80FCF7BF29B8A188C67EAB6A4BE7 +8C07713C7EE09043301B5BFD60222DD0D0943180AFB286D2953A8A12661986A4812E2C0DE5B3E703 +DAB34AF0E9306A5711D286AD09A3C6AB80841491BD0E5A1D1ABE1D600CB494BC17EC4F74B45870F6 +AC41EFE16BB6C87F382DFA4B2B8DDC9C2E912FD139A2FFD5C92D836F3D749EEB985C62A376849751 +A6AC56B1F679A85FDAD9448DC7A4CFE323AFB540408547C53297DB6FE9A0B08901BC285997934A2A +1772090FBA175CF4660764B87A21A738519D5B619840D15F45DF3589E8B80A6DDF1F395B65345869 +58C7060DC131700DFF6E25962494583085E6F8BAEA557A5666E6634E4704D0C07BB0A2EB228A7BEF +EB890B4EEC638303B8005BCCE922CF3A7AE627206F2946A142B0095FF960BB8B8F9C975B6FF07479 +2D5C3DFA125B7BE7A8356D8B44E264AF6AA582DB84BA09D2FFDC2213903FE8FE16DE5EF61E518DE0 +6A29D98E217038A4CA4D219E4F114858CA493AEF0CD6495A7C5EF1ADA06AB543051B1A5213952D46 +648BE06D15B1728768BB853CE32943AB0988D172227780CE82D1A1D297D0D6ECC51B290E156645B6 +9BD54699940AB17EBE10EDF258BBA6BFEA39F4F0B066FF6B3FA16C7C72F2565CC028F249BAA4B488 +B48A2513DCC5D1E205FB874BCFE45612DF4EDAF815CDD53CBB80842B429B1AFA32D35EA58E17F4E7 +252C2C9A737AAECFC25FD8CA5520D3EA38AF71C61B88F31FB53A7F5369305D63495ADABA455C3C4C +35D9FE423A00CFBB278CD482D3FD33BEEAC1F359AD9B6AA17D60CC46FAB670ABFB3B2B4161B9EB9D +949A06CC3B734F63DE821FE0B8EA065B6F79C0601E46E8CEB6E2DE0C052771E0EC7012063F1AC46C +3FC454767469225AA266784DD77256C6FDE25D7D857FCEF2562AEBE38A9A47063AEF91449723E680 +B36D824BB95BE95C9802F7AD4DF1AF37B4777A1E116A7EEF770F0A499BC9F9675A775503091D4EBD +F55118782E3E54AEBC67A0545E8D75BA5A482C6CEC50595D45AF041664689AA4338C1428870CDC15 +BFEEF788C1D1E87B3389103225E2619120B129FDF048DF3F5DDAFF1CE87428E6BFA591B91D82720C +E4A72FBB952403435248657ECD5456CA814FA0ECBE70BC3D391AEA0A195AE8FBE92D054AD0F3E549 +841ACDCE59DCAA9DAC20348A1D05DF7B4127C75F4C6607EF8501F741CBC96AD8D429A4CA8034CA52 +9AB673EE706F1FF51DD93F45802031EEBF8F3AD29D2A74888B1CB344F88ACEB9B4DEA13ECAE0A3B7 +1FF5CAA38D0DC484B96E90251D56732B85DB8A8DBF10E0A5921121CFDFDB6EA9CA45B98584401C3F +346BD026DA2A17E75CEEB74E48667F9BF5C538623E88021F0C24EC7D082C3E1FFDE5A6F68F0F3F6D +2B61547C4C14614118F7942851B090D6C8D80BA06D9139CB5AEB0EF77DEF2376C0BF602FB1083178 +27E86DDCC00622438FD7A268C0252CA2E20DA887A9D5ED251FD5CCE811E514D702206E413DEE7528 +3A6AEF793F5E3E3B0B10E59226102DF2A7347A95B96E39C6B6ABD1FB4B7CDC0813D7390E2819EE50 +7E5458E06D43CC3BF16E40CEC4E64909615CBFCD233B5D316BC8B8B46243CDB7F2FBECA2F208D0A7 +985048E88A5E685A9EE8C3A351FFCFB522C1EE41A8E4EF0A080C0D110D2A0D8A980AF1F604D1CD52 +3CF41D08A45EB809AF11F530C138F256FFD49BC20F77005D004AC85FD563E8E8BA5F79CC60FDE714 +1416F4C14FFF281ECE2BE1D167B7B1ECE17790454F795B056CE4DF1D08F25F0E5E2A16CFA066AF97 +F3A80015068FA2A1D65F329A5CF7856114A77EE7295C7929CA27796D8C51B31347CBC7C4EEF1E75D +12237C558BE5B65DCAA4CDDCB419E543B1785DF8B225C2E9778839123E6F85E53D925C6D2FC0327A +EF9CA13D1F2F9B3E510A1A4190D3057227621788AFB6567132238BE86559BCA006B85AFBB8AFE5D7 +A8CE58AF731F2550108C6B8CD63632184B1E218F01881CB94CEBFFC310F263565A39C83C874AE474 +AA213F7DD9CB3B8446A3E47E81BACF7B16E4A80899BF2D30C28F9DE0678DF364589DA6A454398E30 +21A92AD1D8B0DC494D96A06C7568E34547F0E68829E5D15F6500ECD7403B40B5CC2A479D0F8CE3E8 +709861608AED046339BE055BAED1A6BD2311CF918E74378D893710D42A769671326E947F108A38C2 +3F92EF5C6A50EFE36E858671F17151C719B9C7D60E8E429F088616D616080DC676760BE83A3F5229 +6C4B13CA3818E3FEB56D51DB5979F28063F7D537C15493D57CAA1E55438C01C794336D9F21520484 +FE5B5BAEAD7121E3CCC5086E2F2191DBEE9527CA61CE85CC0A4D99EA29169B17A10B3D4372EA493D +48CF572E570CF48B3B7512268A9AC4CC161F97695D19412C36F1D67522E272B1C18B6122A355B43C +37636E71462503C43C1AEF5ACE34A6442075B59892BA54E9B5A99B9733BAF64161450F8ECF4FB2B2 +DA6F9AAEBC827CD9AEF94BB463935C26E1DD5DDCA5BA87E0EFB62D9D3226DC28427EC097B68C9EE1 +E47D125F884F8656C8AD55D625A8F7F1A306383A5036A12E63B6FAC4A215AC88725611EBA74B6770 +B20F45356879DB807E9C9105D14C83104B2DCB4F274A2F37152425935B3F2D1633E4444540F7411B +24C17055850C9528D912F9DD40984CA1B3BE277F82198BC99B80233B8AAB674A44B42B9123E886B7 +B3161D48B4AA24970BB75A983569690BFD4B92E6ECB410DDCA14A3BF59057397FF1AF159BE230216 +FF2F7009C3A3DDD81F2BD1F5C10C2C2F30A8095D7371427AC9D527AC6794CF8593303F786F21CCBE +36DFBE01B0ADD78DB3C9483D9DB09A9E2577A3A4296E7BD09C41F5C91B29C9D7E69EF06B5BDB66E0 +853C3DB133769BC8858121A350CADC1D61C77C1A313833D077938AB2E10EF970590256479B1549B0 +401A9C5E97F12A269A305B372F0EFC035B06AE3E2187D6E3A62DE3B4E8075F0ECF5BE32A5B97A4AC +23A7335C4AB29917129C08250DBD1D5BC123C92E821BBB1A7598E32DDDF1876C6FBB7B858FD317D7 +6022955595338AAD2BFB3B17DA11380E7473A5F566C6329E0F38D9A67E68FD4B8CFCC82FC0BD7BA3 +9A25D5BD0952CC71CF0BD7B5EE184A8E62FBB366D95AB051BC3A80E9F6C27EC100E00C4A002291B0 +4D758A9683657FCB07A2AA8B07DF585CD4205B4DC55330E8A2A367CBE966E84618ACFCAAF81C8A9D +3A3165FE5A623720A0C11CBDD5CA200100DD2C970A09B124D98987D6A2CA7CBB40DA5B585B86FCB3 +8E96F54C64A921D7A5D2F805C67339DC4FC026FB2EE533BB9700F66F4AD58949B3DB75D770C4D7C5 +C23DC720D78124A7ABF30CDFF10C708219903431C7B1A19317341CEA22AA11A588F8AF9BFA4AAC40 +31EF22F13BA597BD1E5958CEA741274197113CB0B7975424C17F73733ED30BDC0170CD0084BB7DC1 +8F031BEF2A6C44D0EA0EBB84E31D5B4C50B63DF0AF96AAF33E3C986D4B82D161E2F9049DE9710EF8 +A11BA0E08266A3547F20567E582EDB47633772D37FCCD119AF5B11F338098F185D5B055975F56092 +CC6979FF49487D69E08A4E8754FD51D29410F56E0F3EFB9C3B86253B3B0A39E9D217604F664CC696 +634D216524F976D066034DDE8EDF5E8F9644337C50C7D8E2230B38E0EE88C53DEEDB3363477E32CB +88B3ACB6931B9717FC93F8D1A9DDDA3A7D8A56783F2B651A1DE216493C34DCD17A7635D21CEC0770 +751424B599B00CE950E60D8A8B3444F1629220DF073137E2ADE1B6243C1C69BD5E10450B948BFCBA +46A841B98BCE7C86E120789C73C87E581868021E68F78CB903AA6D494331174CBF944221DEA9E567 +A2542BD399C5E471D972FAB7E8950AEFF3D91A1296E685B0BFF91367C2703DCAB10AB236DE603E3E +993C4C9020EEBFE89726AB9FB92AF9D371D7188448CAB9FD2704506C39F0842E36EB8B9AAFB1F26F +CD366E66725AD28B19FA57537757EC71B04B451F056C3AEBFA04D1C0CABC9492B6B8D239EEC36776 +D6B515ED43A66AB4342BE4C8B2027F2D008EA231A24B472DA8352A05DDEE31CBC3577E5814DD2D4E +C17A216A7C8FFB27012346C9ED12F7819B96A5B135B6196E888C9AC73D7D4B7DC370E2FBFA17FD74 +0BF516CFF69294493900BFD63721A537BEFB31C5262567103F9CEA4E8DB02964B983E1AF190ECCEF +41F552C45E9B94E29AE3F129687EC35719F591C1987A08DCED3B822344DF81A70AE78E14A81EF1A1 +A77FD5D19F7D35B7C12A473EE11C655E15DC5D3C94F226CBDA85377338BFCEA18359176CA7EED622 +84F9015F2D592E27F1037C95570CFDCA3B9B90D35DB8C341434BBF04C0E692D4C2C3F59EF386CD1C +5A8C783198EBE42C89E3B64C662F7875325982E9299C18DBD1FD2257DD964F9F9DDEEBFE56E4AE9E +8163E8C58581BFD5818BF396CCDE3A66F58E17BDD262D63E5D9AE0D0E43C304CCAC4776B87D40F6B +5AD7E625B2065FAABA81AAF2E2D32E0ACAB12DB2A9FE9C6160FBA7DE5AF019810AD9C64B2E6567B0 +F0108E8EDEC635F4BA88BDEBD3561CDBBB9063B4D19C493E0CA4F551255A7DF6BCE96C17A5DD4877 +7F654F4F114CF29ECDB9779F63EECDC04E1FA06E48701547A8F96483B4195C0DE90B0FD1B95B5F12 +5C43BB973D0B6414A994595359289B5FFEE4A08D684C2E7E3F417585581318D54DF2EEAE7CF36E2C +A1A70EA76154B88C1E4FFDF5EBC28ABE264B40583F2DE1F761DC25DF242396AE502CC63EFD6EE284 +DB37B0DF36A8833ED3EA5A1DB372C8E1F3203E6E945A53D83B87250CD72C851F68A602E7BCF92DDC +E600D518069F8900F3BCA434D21694229572D55F307E0FAFA3DAEA864BAA19F227097963CE83882D +22FB7F1AA3FE558A3669BB7FA37C0A591B4BF3E2A2FF85BFEDE5E424E0AE337EABDFD67BBF38E160 +09A687D2E7C1882DB79304D722EACA233EFA489B10E8D4D404D12A5A4683FDE377A9A952CCAB257E +ABB408D75FF130206DC3447F26E74D1D00354313E340878917177DBD2AA5A2A70E2087D551DA5181 +6FAD07F6E826DB0BF21560BB26906D3100E12AA3801D4A8BDCBF1A0A8D58F1054EE2A0DB04ADDF3F +EAF1FD6E322BBEE274A4995EFFEAAD0F24D9FB45730F6BA0F42D88BE4AEBE9777F8AF508DED61024 +EF955B26ACEC51AF5C21BAD7AD93CC0C9DBE03C0FE9637A3099E5EF329051C87FFF70042D788F21F +4DE645FEBF58374F7E38A9AFE3DE4D2888DD807A09169DA8516DFE37591C122A4798343C1A8121C7 +430F244EE5B19A21897A4423E21CE0492E75C9320E37BD65F1EACA7FC6FE032842E4D985E666E633 +AE5CC62B3449404672B284EA5C6A01E927787104ECCE1354D1C0E5AA2452B7B12937B946B74EFA98 +8C5C79EEE5ACDCFC994CAA853AFA08EB9E180C5E898FDDF8903EB0863E98A4FA537207C154CE5B98 +EF4E97FB6A1CBB07C45D34221EED26998EC864475D231FF76E830A7C0900C4B5FCB980E3F67F4EAE +3DD8086CFA1874E65C424646C7A8F84272DAB04A5984FCE3F4B89380B3A5C6F04EA3B683CC224913 +9209136336AC9349AA89690B5DE0D93E92F996BA7E346B043EBD45A35FA297DB70E9A6250B138674 +FDDFA609BE11EBA8106EEE3923B4E2657CF7A82443C25022A5DED862E8E3A5BFA7B8AC1C1B804B23 +C08A7D8FE594140E8432C1A5E183FE361B6B8C763054458798B756A6CD2535FF4667C634DF78AFBC +C87D40DCD56FFFA12CFC6EDC6A8AF41AF657E0137320624F1895D9AA84AABAC5F3653E977B054C52 +92B06FEAAAC0E5C7FD45B6654D0D9CCDF292A8489E1E6CD929F0AF25B9604CE33BD25662133CEE99 +CDBBD00F865431193767480700CA019D694B38D695CC29F732B5B39B6CE654F1AA18AC3223B60E55 +3FC3C3E114E6A2E59617BFD58AD8E429200B59E035DB7D67C8DC6C72001D005924670ECF7A06FF5F +7B3DD5556DDDE1BE5163F7CD6FC969033EBBAD85856522ECA91F2A200A75BDDA69070240D86C2D7D +959F1DBE45D488A96F308269E8262327A410D057446F596418DF4A12267A7A3FF5ADEA0846896D3A +EFE3D5C72387F7EEEE809BCCD23D1126B86C45A0F66404FAF617D03379A2E44865051E92B4C835F7 +21492147DE3DCCE47EAD192D3F10A5DD459634D6C253F4D09DD98E7DDC836EED8DE08A78A6F6FB93 +84565CF6DA8D4C948144272D5F8787643B9B550F96E42A8CFC0F1C1F2B14D83201199E9E1F5BC0E6 +51E39E16A744930F4409C61CDF9F456C7EAC5C62BD22CE0DDCCDF3755DC670FDC8FEBF09F241BF95 +1A1694BD70B9695A15653F719DF4374AFC6C27F58DD144253BDF86FC1BB3D4FEAEEB9196BCEC7168 +AF1488AB7072751FA24C6642B87DCADF4B2427631E7D7FA39D126410189CD8E24CF0A490FDC7045A +A9A83D02CAB57B9C27211FE1805080FBCEF23B86CDB19885A574C589BDB15C4CB3651FA3D2D6B619 +4449B16D927047E376A84F9423562CD548D192AD0A57E0D5B41010D1C7D87929DB6F456B0A073DF9 +A8220BEB3D4DA01518B5C85C82ABCC821BEEC1965283DABF6AF3AC55ABDDAEF1B53E6119DBB4A114 +44FB1769F9891B5DC931ADFEC8ECEFFA179427FCB08C1B149EDA70717C5E9322F3CE9405438481F3 +90968A38061EDAA2223147D6143877E4C4E645EC0A9803A933116D610491FDC639DF69B418156772 +E14A428864982D3230EFFAA1D2D3388B0F70D8FE202CDD6CB0E97B3290ECCF4A1A69D93C11D3D735 +FF0B5A9A161A86CA4F16B7C231B8BF71D5083697B2F24C0BDAA6E83E5DD2222DA248D4ED3B5509CC +7CA40D8D5A2507A1D40FC1AE9486343CA2B2C65B6CED9B1F4C0535ADF7BECCE45E1DB74C7417B06D +897C6ECDD05F068857D931B3D960103628675BE2FB82DA774ED3786670D8C2BA4ECC36C203C7F7E0 +9C97A09E3B2E2C3EC30B53A8825519B664D09F149AB73F183A4A22C8F20E2052F76649AB881BA28C +6C3C3950EA9B3961F87F6AEFF24DD7B4E10DE28C15DCB27F593F98CBC9CDE19360C5531B2A0C6DC1 +8FAE2832AF49BF9522C068F3036516F711AADEE496EE4E3EFA2F55EA4891DEC6D8A868E0B0017076 +3040CA4D42A73A71057DFE315FF8625BBD74F41E5CA77B7DF096C2F4F0D51B1184CA9F2C8517FCB3 +956C44873D630E94EAA1D2D1451B332770172B2D7A21ECAC864C612235C0B39ADF55EF074F2073FA +D3B54A66B07AEA1FB495A9F7269BD1C07692B0B762DA6881EE6B265ACED0BF0794C0397F8D8B13FF +275BE77561067E2C1FA536131184682BFD32384C6488012D29E8E55838E5A5AA7C40C20AB6B03BFD +BF4EFD2001A612100D585BAC1C77C1CB1ADAF2B000E09686091AB7D1AB6ADE395A03580BD78E961D +14D052E7D4A61227534B55FACAFC4E8F9326DE35BA53A463F7D94B705698300771185DB19E78FABC +D0AE4FCE005B79C795B692F2D9C00B6A61D4B343C35E417BBA169EE82A2E4AE204A126B08A94191C +6E5B5E8328A147BD6ED5A5AD5C9143A50C47789DCFA699720336AFFBD6B1646D8C35139B0DC34340 +C76C7E4FD72DABF80BF64BA04742D07B380E20A678EBCB19057F2346FEC653F1302992279DCCD2E8 +902B2B8F78435AF3400DAE319E94E3148BA88C056701D524DD67FF368C85EC6366F31689A62FFC03 +4BE436588ECBB8B41E8C43112F3B65F50D20A5EC51A26FE899E74731B01C7771F75B76070DC0B223 +1845BE9C09670E65C4DF54C0FB36511B735251AEEBD13FDC0FCFC3134D8DA826E4100521CFEAB202 +B83267EB3F69AEEA25FDE1E9C86407E38AB4CA2D1B91607EFC96DDC5BB10FCD46DEAA5FFED196959 +12302ED55DFACFDC6F22C1528AE3A9902B75F46A489352C87B0F5056FD149DDE67219A3C3D1DD875 +BAD81AD443E0F90DC79D979E10B4262DD20B255B04BBBE5C988B23667135CC61D988928F5F07753A +C76807203942F6B62A178A1E5CBBFBBAEBE735D09B747BF00C360F2E2B6C9F2261F7DB018EDF40B1 +3DB4B7962D4D2F858E1FA6376F21ED9CEA4BEE07FFE27F136BF60352AFB71CDBFF7E65F6B4624E16 +C6E5AB7FF60B4711A178FEE691DD8D362B14175A69070FBC5B9EB15248E4DFDA3C9453335D0E1EB2 +7714E4624C7215A73B53402B02CF7AA05A14CE1E5AE161B75F218BF0EE1215D3CD925D5ACB7DBD2E +BD8E4405433F432C491999794C814D5B384B7A1C0AB28A11CBD0A6EA12678508CF86232309B0BBF7 +EEA929FB7951F5A6B367C5AC57DD7D3B3C1E2188DD4664D14FBC32B1A1EB53D7EE7F55F4D5C2D014 +528EBB7F0E595F7618721451EE6B83EB240A6C4D33377893D4EF542F47EB2845A09759D5554C74DC +5E9109FFC8C929CF1AC446D8149957720EE4FB670D3CA61378549DB992126B23618CF49361D6D4B1 +C73C3D37E4A4465ABB349CFA34E9351D1192E366267EDF02DE432ABC80792B0CFD41FFD0AAA42E63 +3F5B2177A351D33477C636CA573CB02C07F7F7A41C9F1BC4C112BD6459DD130757D2BD6F47495C3F +92E99522871DAC2865 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +cleartomark{restore}if + +%%EndFont +%%EndResource +9.72 /Mathematica2 Msf +0 9 m +(\310) N +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +9.72 /Times-Roman-MISO Msf +2.25 9 m +(q) N +9.72 /Mathematica2 Msf +7.5 9 m +(\310) N +9.72 /Mathematica1 Msf +12 9 m +(=) N +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +9.72 /Times-Roman-MISO Msf +p +20.25 9 m +(0) N +P +p +24.75 9 m +(.) N +P +p +27 9 m +(0) N +P +p +31.5 9 m +(2) N +P +P +[1 0 0 1 0 0 ] concat +1 w +[ ] 0 setdash +1 w +0 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +P +P +[1 0 0 1 -118.485 -136.705 ] concat +1 w +[ ] 0 setdash +P +P +p +np 181 96 m +181 112 L +219 112 L +219 96 L +cp +clip np +p +1 w +1 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +[1 0 0 1 181.505 96.904 ] concat +1 w +[ ] 0 setdash +p +np -1.505 -1.904 m +-1.505 16.096 L +38.495 16.096 L +38.495 -1.904 L +cp +clip np +p +np 0.495 0.0956 m +0.495 13.096 L +37.495 13.096 L +37.495 0.0956 L +cp +clip np +[1 0 0 1 0 0 ] concat +1 w +[ ] 0 setdash +p +np -1.505 -0.904 m +-1.505 15.096 L +38.495 15.096 L +38.495 -0.904 L +cp +clip np +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +9.72 /Times-Roman-MISO Msf +9.72 /Mathematica2 Msf +0 9 m +(\310) N +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +9.72 /Times-Roman-MISO Msf +2.25 9 m +(q) N +9.72 /Mathematica2 Msf +7.5 9 m +(\310) N +9.72 /Mathematica1 Msf +12 9 m +(=) N +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +9.72 /Times-Roman-MISO Msf +p +20.25 9 m +(0) N +P +p +24.75 9 m +(.) N +P +p +27 9 m +(0) N +P +p +31.5 9 m +(5) N +P +P +[1 0 0 1 0 0 ] concat +1 w +[ ] 0 setdash +1 w +0 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +P +P +[1 0 0 1 -181.505 -96.904 ] concat +1 w +[ ] 0 setdash +P +P +p +np 267 3 m +267 19 L +305 19 L +305 3 L +cp +clip np +p +1 w +1 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +[1 0 0 1 267.864 4.035 ] concat +1 w +[ ] 0 setdash +p +np -1.864 -2.035 m +-1.864 15.965 L +38.136 15.965 L +38.136 -2.035 L +cp +clip np +p +np 0.136 -0.0353 m +0.136 12.965 L +36.136 12.965 L +36.136 -0.0353 L +cp +clip np +[1 0 0 1 0 0 ] concat +1 w +[ ] 0 setdash +p +np -1.864 -1.035 m +-1.864 14.965 L +38.136 14.965 L +38.136 -1.035 L +cp +clip np +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +9.72 /Times-Roman-MISO Msf +9.72 /Mathematica2 Msf +0 9 m +(\310) N +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +9.72 /Times-Roman-MISO Msf +2.25 9 m +(q) N +9.72 /Mathematica2 Msf +7.5 9 m +(\310) N +9.72 /Mathematica1 Msf +12 9 m +(=) N +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +9.72 /Times-Roman-MISO Msf +p +20.25 9 m +(0) N +P +p +24.75 9 m +(.) N +P +p +27 9 m +(0) N +P +p +31.5 9 m +(7) N +P +P +[1 0 0 1 0 0 ] concat +1 w +[ ] 0 setdash +1 w +0 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +P +P +[1 0 0 1 -267.864 -4.035 ] concat +1 w +[ ] 0 setdash +P +P +p +np 295 86 m +295 102 L +328 102 L +328 86 L +cp +clip np +p +1 w +1 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +[1 0 0 1 295.617 86.954 ] concat +1 w +[ ] 0 setdash +p +np -1.617 -1.954 m +-1.617 16.046 L +33.383 16.046 L +33.383 -1.954 L +cp +clip np +p +np 0.383 0.0458 m +0.383 13.046 L +32.383 13.046 L +32.383 0.0458 L +cp +clip np +[1 0 0 1 0 0 ] concat +1 w +[ ] 0 setdash +p +np -1.617 -0.954 m +-1.617 15.046 L +33.383 15.046 L +33.383 -0.954 L +cp +clip np +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +9.72 /Times-Roman-MISO Msf +9.72 /Mathematica2 Msf +0 9 m +(\310) N +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +9.72 /Times-Roman-MISO Msf +2.25 9 m +(q) N +9.72 /Mathematica2 Msf +7.5 9 m +(\310) N +9.72 /Mathematica1 Msf +12 9 m +(=) N +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +9.72 /Times-Roman-MISO Msf +p +20.25 9 m +(0) N +P +p +24.75 9 m +(.) N +P +p +27 9 m +(1) N +P +P +[1 0 0 1 0 0 ] concat +1 w +[ ] 0 setdash +1 w +0 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +P +P +[1 0 0 1 -295.617 -86.954 ] concat +1 w +[ ] 0 setdash +P +P +P +P +P +1 w +0 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +%Trailer +%EOF diff --git a/services/clsi/test/acceptance/fixtures/examples/epstopdf/main.tex b/services/clsi/test/acceptance/fixtures/examples/epstopdf/main.tex new file mode 100644 index 0000000000..c35a378422 --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/epstopdf/main.tex @@ -0,0 +1,10 @@ +\documentclass{article} + +\usepackage{graphicx} +\usepackage{epstopdf} + +\begin{document} + +\includegraphics[width=\textwidth]{image} + +\end{document} diff --git a/services/clsi/test/acceptance/fixtures/examples/epstopdf/output.pdf b/services/clsi/test/acceptance/fixtures/examples/epstopdf/output.pdf new file mode 100644 index 0000000000..199333ddf0 Binary files /dev/null and b/services/clsi/test/acceptance/fixtures/examples/epstopdf/output.pdf differ diff --git a/services/clsi/test/acceptance/fixtures/examples/feynmf/main.tex b/services/clsi/test/acceptance/fixtures/examples/feynmf/main.tex new file mode 100644 index 0000000000..c36ed70919 --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/feynmf/main.tex @@ -0,0 +1,28 @@ +\documentclass[a4paper]{article} +\usepackage{feynmf} + +\begin{document} + +\setlength{\unitlength}{1mm} + +\begin{fmffile}{diagram} + +\begin{center} +\begin{fmfgraph*}(41,17) +\fmfleftn{i}{2} +\fmfrightn{o}{2} +\fmflabel{$g_2$}{i1} +\fmflabel{$g_1$}{i2} +\fmflabel{$p_2$}{o1} +\fmflabel{$p_1$}{o2} +\fmf{quark}{i1,v1} +\fmf{quark}{i2,v1} +\fmfblob{.35w}{v1} +\fmf{quark}{v1,o1} +\fmf{quark}{v1,o2} +\end{fmfgraph*} +\end{center} + +\end{fmffile} + +\end{document} \ No newline at end of file diff --git a/services/clsi/test/acceptance/fixtures/examples/feynmf/output.pdf b/services/clsi/test/acceptance/fixtures/examples/feynmf/output.pdf new file mode 100644 index 0000000000..bb7fe9099c Binary files /dev/null and b/services/clsi/test/acceptance/fixtures/examples/feynmf/output.pdf differ diff --git a/services/clsi/test/acceptance/fixtures/examples/feynmp/main.tex b/services/clsi/test/acceptance/fixtures/examples/feynmp/main.tex new file mode 100644 index 0000000000..6027bf904f --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/feynmp/main.tex @@ -0,0 +1,28 @@ +\documentclass[a4paper]{article} +\usepackage{feynmp} + +\begin{document} + +\setlength{\unitlength}{1mm} + +\begin{fmffile}{diagram} + +\begin{center} +\begin{fmfgraph*}(41,17) +\fmfleftn{i}{2} +\fmfrightn{o}{2} +\fmflabel{$g_2$}{i1} +\fmflabel{$g_1$}{i2} +\fmflabel{$p_2$}{o1} +\fmflabel{$p_1$}{o2} +\fmf{quark}{i1,v1} +\fmf{quark}{i2,v1} +\fmfblob{.35w}{v1} +\fmf{quark}{v1,o1} +\fmf{quark}{v1,o2} +\end{fmfgraph*} +\end{center} + +\end{fmffile} + +\end{document} \ No newline at end of file diff --git a/services/clsi/test/acceptance/fixtures/examples/feynmp/options.json b/services/clsi/test/acceptance/fixtures/examples/feynmp/options.json new file mode 100644 index 0000000000..a280541cfe --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/feynmp/options.json @@ -0,0 +1,3 @@ +{ + "compiler": "latex" +} diff --git a/services/clsi/test/acceptance/fixtures/examples/feynmp/output.pdf b/services/clsi/test/acceptance/fixtures/examples/feynmp/output.pdf new file mode 100644 index 0000000000..66268b2b7e Binary files /dev/null and b/services/clsi/test/acceptance/fixtures/examples/feynmp/output.pdf differ diff --git a/services/clsi/test/acceptance/fixtures/examples/fontawesome/main.tex b/services/clsi/test/acceptance/fixtures/examples/fontawesome/main.tex new file mode 100644 index 0000000000..42bfa8e55c --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/fontawesome/main.tex @@ -0,0 +1,12 @@ +\documentclass{article} +\usepackage{fontawesome} + +\begin{document} +Cloud \faCloud + +Cog \faCog + +Database \faDatabase + +Leaf \faLeaf +\end{document} diff --git a/services/clsi/test/acceptance/fixtures/examples/fontawesome/output.pdf b/services/clsi/test/acceptance/fixtures/examples/fontawesome/output.pdf new file mode 100644 index 0000000000..327d317b29 Binary files /dev/null and b/services/clsi/test/acceptance/fixtures/examples/fontawesome/output.pdf differ diff --git a/services/clsi/test/acceptance/fixtures/examples/fontawesome_xelatex/main.tex b/services/clsi/test/acceptance/fixtures/examples/fontawesome_xelatex/main.tex new file mode 100644 index 0000000000..5158b672f4 --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/fontawesome_xelatex/main.tex @@ -0,0 +1,16 @@ +\documentclass{article} +\usepackage{fontspec} +\defaultfontfeatures{Extension = .otf} % this is needed because + % fontawesome package loads by + % font name only +\usepackage{fontawesome} + +\begin{document} +Cloud \faCloud + +Cog \faCog + +Database \faDatabase + +Leaf \faLeaf +\end{document} diff --git a/services/clsi/test/acceptance/fixtures/examples/fontawesome_xelatex/options.json b/services/clsi/test/acceptance/fixtures/examples/fontawesome_xelatex/options.json new file mode 100644 index 0000000000..a2e0c09897 --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/fontawesome_xelatex/options.json @@ -0,0 +1,3 @@ +{ + "compiler": "xelatex" +} diff --git a/services/clsi/test/acceptance/fixtures/examples/fontawesome_xelatex/output.pdf b/services/clsi/test/acceptance/fixtures/examples/fontawesome_xelatex/output.pdf new file mode 100644 index 0000000000..b5a12e39a6 Binary files /dev/null and b/services/clsi/test/acceptance/fixtures/examples/fontawesome_xelatex/output.pdf differ diff --git a/services/clsi/test/acceptance/fixtures/examples/glossaries/main.tex b/services/clsi/test/acceptance/fixtures/examples/glossaries/main.tex new file mode 100644 index 0000000000..336f70868c --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/glossaries/main.tex @@ -0,0 +1,17 @@ +\documentclass{article} + +\usepackage{glossaries} +\makeglossaries + +\newglossaryentry{Physics}{ + name=Physics, + description={is the study of stuff} +} + +\begin{document} + +To solve various problems in \Gls{Physics} it can useful to express any arbitrary piecewise-smooth function as a Fourier Series composed of multiple sine and cosine funcions. + +\printglossaries + +\end{document} diff --git a/services/clsi/test/acceptance/fixtures/examples/glossaries/output.glg b/services/clsi/test/acceptance/fixtures/examples/glossaries/output.glg new file mode 100644 index 0000000000..6bae571d8f --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/glossaries/output.glg @@ -0,0 +1,7 @@ +This is makeindex, version 2.15 [TeX Live 2011] (kpathsea + Thai support). +Scanning style file ./output.ist...........................done (27 attributes redefined, 0 ignored). +Scanning input file output.glo....done (1 entries accepted, 0 rejected). +Sorting entries...done (0 comparisons). +Generating output file output.gls....done (6 lines written, 0 warnings). +Output written in output.gls. +Transcript written in output.glg. diff --git a/services/clsi/test/acceptance/fixtures/examples/glossaries/output.glo b/services/clsi/test/acceptance/fixtures/examples/glossaries/output.glo new file mode 100644 index 0000000000..0b6f71e75f --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/glossaries/output.glo @@ -0,0 +1 @@ +\glossaryentry{Physics?\glossaryentryfield{Physics}{\glsnamefont{Physics}}{is the study of stuff}{\relax }|setentrycounter[]{page}\glsnumberformat}{1} diff --git a/services/clsi/test/acceptance/fixtures/examples/glossaries/output.gls b/services/clsi/test/acceptance/fixtures/examples/glossaries/output.gls new file mode 100644 index 0000000000..128261a191 --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/glossaries/output.gls @@ -0,0 +1,6 @@ +\glossarysection[\glossarytoctitle]{\glossarytitle}\glossarypreamble +\begin{theglossary}\glossaryheader +\glsgroupheading{P}\relax \glsresetentrylist % +\glossaryentryfield{Physics}{\glsnamefont{Physics}}{is the study of stuff}{\relax }{\glossaryentrynumbers{\relax + \setentrycounter[]{page}\glsnumberformat{1}}}% +\end{theglossary}\glossarypostamble diff --git a/services/clsi/test/acceptance/fixtures/examples/glossaries/output.ist b/services/clsi/test/acceptance/fixtures/examples/glossaries/output.ist new file mode 100644 index 0000000000..1861f247c7 --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/glossaries/output.ist @@ -0,0 +1,29 @@ +% makeindex style file created by the glossaries package +% for document 'output' on 2013-7-28 +actual '?' +encap '|' +level '!' +quote '"' +keyword "\\glossaryentry" +preamble "\\glossarysection[\\glossarytoctitle]{\\glossarytitle}\\glossarypreamble\n\\begin{theglossary}\\glossaryheader\n" +postamble "\%\n\\end{theglossary}\\glossarypostamble\n" +group_skip "\\glsgroupskip\n" +item_0 "\%\n" +item_1 "\%\n" +item_2 "\%\n" +item_01 "\%\n" +item_x1 "\\relax \\glsresetentrylist\n" +item_12 "\%\n" +item_x2 "\\relax \\glsresetentrylist\n" +delim_0 "\{\\glossaryentrynumbers\{\\relax " +delim_1 "\{\\glossaryentrynumbers\{\\relax " +delim_2 "\{\\glossaryentrynumbers\{\\relax " +delim_t "\}\}" +delim_n "\\delimN " +delim_r "\\delimR " +headings_flag 1 +heading_prefix "\\glsgroupheading\{" +heading_suffix "\}\\relax \\glsresetentrylist " +symhead_positive "glssymbols" +numhead_positive "glsnumbers" +page_compositor "." diff --git a/services/clsi/test/acceptance/fixtures/examples/glossaries/output.pdf b/services/clsi/test/acceptance/fixtures/examples/glossaries/output.pdf new file mode 100644 index 0000000000..297385b8d1 Binary files /dev/null and b/services/clsi/test/acceptance/fixtures/examples/glossaries/output.pdf differ diff --git a/services/clsi/test/acceptance/fixtures/examples/gnuplot/main.tex b/services/clsi/test/acceptance/fixtures/examples/gnuplot/main.tex new file mode 100644 index 0000000000..09077a5724 --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/gnuplot/main.tex @@ -0,0 +1,26 @@ +\documentclass{article} +\usepackage{pgfplots} +\usepackage{nopageno} + +\pgfplotsset{compat=newest} + +\begin{document} + +\begin{tikzpicture} + \begin{axis} + \addplot +[no markers, + raw gnuplot, + thick, + empty line = jump + ] gnuplot { + set contour base; + set cntrparam levels discrete 0.003; + unset surface; + set view map; + set isosamples 500; + splot x**3-3*x+3-y**2; + }; + \end{axis} +\end{tikzpicture} + +\end{document} \ No newline at end of file diff --git a/services/clsi/test/acceptance/fixtures/examples/gnuplot/output.pdf b/services/clsi/test/acceptance/fixtures/examples/gnuplot/output.pdf new file mode 100644 index 0000000000..84efdc5942 Binary files /dev/null and b/services/clsi/test/acceptance/fixtures/examples/gnuplot/output.pdf differ diff --git a/services/clsi/test/acceptance/fixtures/examples/hebrew/main.tex b/services/clsi/test/acceptance/fixtures/examples/hebrew/main.tex new file mode 100644 index 0000000000..0eb48d9116 --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/hebrew/main.tex @@ -0,0 +1,14 @@ +\documentclass{article} +\usepackage[utf8x]{inputenc} +\usepackage[hebrew,english]{babel} + +\begin{document} +\selectlanguage{hebrew} + + כדי לכתוב משהו באנגלית חייבים להשתמש במקרו הבא וכאן + + ממשיכים לכתוב בעברית. טקסט נוסחאות תמיד יהיה בכיוון שמאל-לימין + +\selectlanguage{english} +This is a test. +\end{document} diff --git a/services/clsi/test/acceptance/fixtures/examples/hebrew/output.pdf b/services/clsi/test/acceptance/fixtures/examples/hebrew/output.pdf new file mode 100644 index 0000000000..09767bd88d Binary files /dev/null and b/services/clsi/test/acceptance/fixtures/examples/hebrew/output.pdf differ diff --git a/services/clsi/test/acceptance/fixtures/examples/knitr/main.Rtex b/services/clsi/test/acceptance/fixtures/examples/knitr/main.Rtex new file mode 100644 index 0000000000..add779afce --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/knitr/main.Rtex @@ -0,0 +1,13 @@ +\documentclass{article} +\begin{document} + +Hello world $x^2 = 0$. + +%% chunk options: cache this chunk +%% begin.rcode my-cache, cache=TRUE +% set.seed(123) +% x = runif(10) +% sd(x) # standard deviation +%% end.rcode + +\end{document} \ No newline at end of file diff --git a/services/clsi/test/acceptance/fixtures/examples/knitr/output.pdf b/services/clsi/test/acceptance/fixtures/examples/knitr/output.pdf new file mode 100644 index 0000000000..7a839f7b13 Binary files /dev/null and b/services/clsi/test/acceptance/fixtures/examples/knitr/output.pdf differ diff --git a/services/clsi/test/acceptance/fixtures/examples/knitr_utf8/main.Rtex b/services/clsi/test/acceptance/fixtures/examples/knitr_utf8/main.Rtex new file mode 100644 index 0000000000..29d575e949 --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/knitr_utf8/main.Rtex @@ -0,0 +1,35 @@ +\documentclass{article} +\usepackage[utf8]{inputenc} +\usepackage[spanish]{babel} + +\begin{document} + +\tableofcontents + +\vspace{2cm} %Add a 2cm space + +\begin{abstract} +Este es un breve resumen del contenido del +documento escrito en español. +\end{abstract} + +\section{Sección Introductoria} +Esta es la primera sección, podemos agregar +algunos elementos adicionales y todo será +escrito correctamente. Más aún, si una palabra +es demaciado larga y tiene que ser truncada, +babel tratará de truncarla correctamente +dependiendo del idioma. + +\section{Sección con teoremas} +Esta sección es para ver que pasa con los comandos +que definen texto + +%% chunk options: cache this chunk +%% begin.rcode my-cache, cache=TRUE +% set.seed(123) +% x = runif(10) +% sd(x) # standard deviation +%% end.rcode + +\end{document} diff --git a/services/clsi/test/acceptance/fixtures/examples/knitr_utf8/output.pdf b/services/clsi/test/acceptance/fixtures/examples/knitr_utf8/output.pdf new file mode 100644 index 0000000000..2d63d1af08 Binary files /dev/null and b/services/clsi/test/acceptance/fixtures/examples/knitr_utf8/output.pdf differ diff --git a/services/clsi/test/acceptance/fixtures/examples/latex_compiler/image.eps b/services/clsi/test/acceptance/fixtures/examples/latex_compiler/image.eps new file mode 100644 index 0000000000..fb131b9c36 --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/latex_compiler/image.eps @@ -0,0 +1,6673 @@ +%!PS-Adobe-3.0 EPSF-1.2 +%%BoundingBox: 0 0 432 268 +%%HiResBoundingBox: 0 0 432 268 +%%Creator: (Wolfram Mathematica 8.0 for Linux x86 (64-bit) (February 23, 2011)) +%%CreationDate: (Monday, October 8, 2012)(15:03:46) +%%Title: Clipboard +%%DocumentNeededResources: font Times-Roman +%%DocumentSuppliedResources: font Times-Roman-MISO +%%+ font Mathematica2 +%%+ font Mathematica1 +%%DocumentNeededFonts: Times-Roman +%%DocumentSuppliedFonts: Times-Roman-MISO +%%+ Mathematica2 +%%+ Mathematica1 +%%DocumentFonts: Times-Roman +%%+ Times-Roman-MISO +%%+ Mathematica2 +%%+ Mathematica1 +%%EndComments +/p{gsave}bind def +/P{grestore}bind def +/g{setgray}bind def +/r{setrgbcolor}bind def +/k{setcmykcolor}bind def +/w{setlinewidth}bind def +/np{newpath}bind def +/m{moveto}bind def +/Mr{rmoveto}bind def +/Mx{currentpoint exch pop moveto}bind def +/My{currentpoint pop exch moveto}bind def +/X{0 rmoveto}bind def +/Y{0 exch rmoveto}bind def +/N{currentpoint 3 -1 roll show moveto}bind def +/L{lineto}bind def +/rL{rlineto}bind def +/C{curveto}bind def +/cp{closepath}bind def +/F{eofill}bind def +/f{fill}bind def +/s{stroke}bind def +/S{show}bind def +/tri{p 9 6 roll r 6 4 roll m 4 2 roll L L cp F P}bind def +/Msf{findfont exch scalefont[1 0 0 -1 0 0]makefont setfont}bind def +1 -1 scale 0 -267.698 translate +-35.28 -2.88 translate +[1 0 0 1 0 0 ] concat +1 w +0 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit + +%%MathematicaCell +%Cell[BoxData[ +% GraphicsBox[{{}, {}, +% {GrayLevel[0], LineBox[CompressedData[" +%1:eJw113dcTf8fB/B7697q7tW0KSoJWRnp/ba3rCR7kxmSzKy+KFlFvqSMjB++ +%ESqKrlVEKJoy2nvv3S/O+5x/7uPce8/n83m/nu+zeq7cOmeNBofDqeVyOH8+ +%2a0l/9EWydgK9V7d4EmZe47Cm8LwOycM2X1fGDzdYkfqz3L1024exbOfBoC3 +%r26ui2c5/R4EpUfSFFnDytWX/v2z/Q9yO+VvM84uo/8Hg9/5EpPBp8vUJbP/ +%fBMCXy8fN5GPKqPjn4DGhdnXo/JK1cKUG86jheEwxHn2wDHnSmm8Z7DcMeyV +%7+hStfni069rzZ7D73FreM8KSmj8KKiZGhB1z6dEHdRxdMqNl+C31zh+u20J +%zfcK1nC8d2oVFqsH/93egLor7NzkU0zzvwWPY/98uDG6WP2m1qxjhmhwtBjk +%dye/iNbzDkRHH6e5ny1Sz/k74XvY7J513WxUEa0vFhJ+vlgTkFOoztzzZ8AP +%YDckMqHAu5DWGwf9rDutaBhWqN72Z3nOn2DLwfSeGb8LaP2fobqXp8v54wVq +%RiMedJ1rPhpaFVA98XBvmqp6Y1q+evLfCRIgKtrukO+hfKovAa4/0ex0wDxf +%/We2xae/wuWhSVqYkEf1foM7E+x2fnPLU/8tJ+Ub9MHHQYN75FH9iZCe2ui9 +%4F2uuvuf5XRLghFBj47Yb8mlPJLAyiiZ11kvV71u7Z8tGcxC4sIeROZQPikQ +%nNGyS29ljvrPaLrBKXB/zgzOGJ0cyisVnGs38MYEZ6vr/gxXmwpxOW67tedl +%U35pMMcjofO/jVlq278DfoegKVuPNQVkUZ7f4RpHXT5wfJb67/I80mF2ZJu1 +%cWEm5fsDHKa6JZd5Z6o/xf3ZfoDBO+2sPYMyKe+fYGHW3z0pOUOt93eBv+DB +%/IdHm/ZkUP6/4Mi8AfcqumWo/w63+DfofvIPWuzxmzwy4HDdvBtr4n5RPRng +%XyQ/26D8RT4ZMPzRQcuhjj+pvgxocL11Ky/gB3llQtVuy7W2OelUbyYkKzUb +%upink18mhO8U4sXN36n+LKgLm1j3X0gaeWaB1zML89G1qZRHFmim+1ksHZ5K +%vtlgedzAUmNvCuWTDQ3HXh8c/iKZvLPBRX+wU01bEuWVA6+K352eiUnknwMT +%axKOmR9KpPxywHbtC6ejr75RP+RCoPeYCnfuN8ozF3oOWGKVjV+pP3LBe7L5 +%piz3BMo3Dxx73Vu6Niqe+iUPxjkazH/X8IXyzoM+e25rp+74TP2TD+LzNpol +%pXGUfz4kRp4W8dZ9pH7KhytWwuBOv2PJowD+O3xdbDv/PXkUQOigqX62cTHk +%UQAmpw6MmzEmmjwKID7AsmxD6BvyKAQn433ymWavyaMQ9Dj2C8ZeekkehfD2 +%tIXdFv0o8iiCLxaLbU3qItRn/noUgeSth6vXt3DyKAKT2d+7fgx+Qh7FUOYz +%5qzF8RDyKAazMPW0oKj75FEMtptcBlWtu0UeJTCxx4K8oZKr5FEChh625dcX +%+ZBHCdxdculc2bQ95FEK/jDse0aTGzAepXDat36zh6EPMB6lEOMyLXttSyAw +%HmXw0vl9VIrLLWA8yiDsQt/zKyvuA+NRBjv2/d43+GkIMB7lUHT/5ubmpifA +%eJTD2mtGW4vgKTAe5fB4Z5evQccigfGoAOVTaPVLiAKmngqY/6hX1yGyV8D4 +%VEBui2yWT9hrYOqrAGPprh6ey94C41UBT9Mc+z4XxABTbwVYR3y/ZB36Dhi/ +%Crh4w3aAYmUsMPVXgmNgbMYq+UdgPCvBzrn8foY6jvKohF1ulbIi58/A+FbC +%qfuxDgGKeMqnEmpM34d7FscD410J2DMwyigmgfKqgsnmb18fvPYVGP8qyP+i +%eXn3/m+UXxVk1g8+OnVhIjDnZxWU1nmvz7FOojyroIeBPsdSPxmY/qiCWTF9 +%JVibTPlWwzDfRG2DpBRg+qUaTjQei30Zmkp5V8O1LS5aQ/zSgOmfanAvvXnN +%fvd3yr8a7G59+7JjcTow/VQNMr7DyVn4gzxq4Oo/D/X5vX+SRw30CbVN8hT+ +%Io8aWFESNqam4hd51MCExLtuY1J/k0cN3LLSbRmxPIM8asBzeCet0MQM8qiB +%xasjHkZMySSPWoiyEMg7qTPJoxby2zPkrUOyyKMWLhklHVp0L4s8aiFlYNjQ +%vr2yyaMWTljpGO/5N5s8asG5x7V9qMghjzp4963x2KkTOeRRB5EuJi12Grnk +%UQeF/fc1B+3NJY+O/4+32L6lNpc86mCRzYR5UVvzyKMO9DZbrbtYlEce9WA1 +%w8COvzafPOoh3SfIODcznzzqwe12cr91SwvIox5SRvB2uKYXkEc98DhqF6lj +%IXnUw9beZyJtUgrJowFsrQ6d0ZpfRB4NYHrH/+TapCLyaIAuOL1mtn0xeTTA +%GuPw70VJxeTRABNkzUUqhxLyaACvueemlaeWkEcDOFnuMly9qJQ8GsFlgFfM +%gV+l5NEI+U+NetquLCOPRngeGBIYmFdGHo2wcvfdxR82lpNHI5zRh4MnK8vJ +%oxG4C3e46NhUkEcTNMd1Tw5wryCPJpi5wunA1TcV5NEEPv2vtpRoVwJzvWyC +%hNniq7emV5JHE+j1eBv69GwleTTBucifASNTKsmjGQ6uu2yt37WKPJph027d +%liWrqsijGZZWO1vp3K0ij2ZIWrG+uVtlFXk0w5uBsu6Bw6vJoxnEvr7uFw5W +%k0cLZAa39qx4X00eLdCw/9iod4oa8miBzg+mjuIvqiGPFni9sK/u26Aa8miB +%Al/97Y1lNeTRAv945ufdGFFLHi3Qpbvry89Ha8mjFbJ6eHq7xdeSRyu4t5vZ +%X+9SRx6t8HFCVbC9Ux15tMJJ19DlHmF15NEKBUP6rQJePXm0wrlbvnoec+rJ +%ow2GN6beXXKtnjzaIEQ7Qvmhop482mD5z+vvorGBPNrApmT4yTlnG8ijDfQq +%YhoOZjWQRxsIRxUOnz2kkTzaoelrk27YP43k0Q6orNB8m9ZIHu2w1HNA0X7L +%JvJoB0Mb7tisQ03k0Q4nnwiKeSlN5NEOrolmkc/6NZMHB0+MWM0dc6SZ6uFg +%7LMxG3Z/byYfDm6x7mLnOqiF6uOg79Tpd829WsiLgzNttkwMz2mBv+Wu5eC3 +%2QNna0Mr+XFw67ivTf0vtdL1gYPJni0OpnWt5MlBz/itIby5bZQHB1sbMyRR +%D9vIl4Mng7Y/Wydrp3w4+GOPlMvf2k7eHDwaGWJx6ks75cXF5DI/5+OGHGT8 +%ueh/JmX++ykcZPLj4nHJw1On9nKQ6QcujnPtZ5PxHweZPLmYMH6oV0QGB5n+ +%4OL7L1PajHW5yOTLRRvp2tM9J3OR6RcuvjN3mfxkHxeZvLnIyX8mKwzhItM/ +%XLR7Glv1NJ+LTP5c3Ou/b/LgbhrI9BMXh4UZzZ9nr4EMhwbKe4SeMfXWQMZD +%A9/FH4OwaA1kPDRwxL86ri1tGsh4aGBk9AfkjtBExkMDd7rFhH/boYlM/2ng +%4ATDJ1seaCLj0THvBndRdrEmMh4a2Du8LXiYOQ8ZDw18dd4yfPs6HjIeGmia +%1DnC7xYPGQ8NtN/c//GDPB4yHho4LPTEwxhTPjIeGhj4wmluhRMfGQ9NLJ7n +%mGv8H588NHHZ7mzu/ko+eWjij+WDrPjWWuShiUM9n54O3a9FHproO9Y5/0m0 +%FnloomCt/IGmTJs8NHG00ZFz9x21yUMTM0cbX4i9qU0empi9YeGrzdXa5KGJ +%Xvo9TS+P1SEPTaxVVV3c76NDHprYMNZ2uixPhzx4+NEnJXbXSAF58DBb97z7 +%xzMC8uBh2zLR5oGFAvLg4QHhp+f3xgnJg4cRws6zVl8VkgcPraICnnu0C8mD +%h14jQjcPXyEiDx7GpEws8owWkQcPV1zemBzdT0wePFzjsF5Hx09MHjzUuXtS +%5ceTkAcPJzs6TQ/YKSEPHgZO/xLhXCQhDz4mdptgumiVlDz4uPCrVpRPhpQ8 +%+HjQZoT/uZUy8uBjr415hx8UysiDj6tc5vYeOUpOHny89DlzY8RROXnw8YP4 +%2ODrCXLy6Dh+bFe1XS8FefCx3n/ZZ4tdCvLg45ul2VYv4xXkwccGvW3hdwco +%yYOPe54UTHjkqyQPLbzbdNf7AkdFHlrIUWPfEBcVeXT0kUty5/FVKvLQQr7R +%zaMz9uqSR0dfRW7eoKfUIw8tdO/WLXFihB55aGGd1ZKK9W765KGF41+08r7P +%NSAPLTzbeGeVaIEheWihmb5sW85FI/LQwtHDQspjbDuThxbqTQ8JHBXclTy0 +%8NGVKzfH2fUkD208suB8pPknQ/LQxrkbyiR29/TIQxtTp7aeKF+rSx7aOOrC +%4WEXL6nIQxsrrU5OsNVSkYc2Opd6f15yTkke2rhlkNmQe4OV5NFxXpgZWaZm +%sx7a+CT3WZoikPXQxvCAL9Y/VrIe2vhc5jRvuaWCPDr2HbF5eaucPHQwNt7k +%dUGHN+Ohg8szu38bf1dOHjroOoNTnO0hJw8dNLh9xX/Wajl56ODH7Zn+AyfI +%yUMHHS8WbhlqJicPHayrWcPvLpEjc//UwWNdgnq45cvIQwc1LfudCQmXkYcO +%9p/le+K+p4w8dNBUEuTfbbmMPHTQwS6g5JO1jDx00LKqzOSEQkYeAlyvv2CP +%WSl7fgjwXtXzlkMf2PNDgJ2Gvm1w/p+UPAQIid39v5+QkocAz37gLb2+UUoe +%AnQ03/Xp3kwpeQhwEH93Yf4gKXkIULVkY9dRhlLyEODI1Z+X+LdJyEOAe0VR +%B6pyJeQhwJeuv+v6f5aQhwBX5R4QTA2XkIcQ+00ct2nwNQl5CHFSXO2vn14S +%8hCi/y/dk2N3SchDiI0ub9bbr5KQhxCD7zSaSmdJyEOIptmFtStGS8hDiP8z +%vvlmmoWEPIRosnSx6K2RhDyEuDVm966XOhLyEGL/5o2FoxvY65UQy276/BhW +%ICYPIVb0vOMXlComDyH+1+p95UismDxE+LzfgvNxEWLyEKEgPUCx976YPEQY +%O2uA8mSAmDxEGCbuv6X5jJg8RLguUKV8e0RMHiKcK3jUNcdVTB4i9JiQmDp/ +%g5g8Ova33QgwXComDxFW/HvZ1XyOmDxE+H2cfOGRiWLyEOHPuV0/m4wSk4cI +%Rw4yGS4cKCYPMb7rbJ08qLeYPMQoWBQ86XInMXmI0eHZiU0oF5OHGL3HDbja +%U0tMHmI06GPUbNMiIg8xrkz1MThdJSIPMYYeLQs1KBSRhxiN6nPOJv5m7x9i +%PHTWI/p1sog8xHhsAudK1icReYjx48pae6uO+w3jIcbS10cy7j8XkYcY7beN +%z5j/REQeErzdq+Rh3/si8pDgogMWm0yDROQhQcPN9tEz/EXkIcFrpVMXXfYV +%kYcE3Ve7L5Z6i8hDgvsWHku//cfhr4cET9WPX7n6gIg8JPhTc/GC8btE5CFB +%jwdPJkzscGQ8JDgqLkTo5CQiDwka3NnW9f5KEXlIMLXx8TtpRx8wHlI0Gfrg +%/ml7EXlIMfRmulV/OxF5SHH1ovT9RZNF5CHFSdue178eKyIPKb5clnwkzIb1 +%6LhObBxhGT2M9ZCiw+ry96UDWQ8pfnXPnzDQgvWQ4qgVQi/P3qyHFH3vnX/R +%2p31kOJQ3dTo451YDykG8swCzfVYDynumvhQniVjPWR4e2LdqYdC1kOGd/wm +%p/ryWQ8Z1h+OifHmsB4yDGyy5V5uFpKHDAsXqVIj64TkIcOf+d2tKyuF5CHD +%AylXDEeUCslDhpv2nfjtWyAkDxmeOjjzCDdHSB4yPGuVevvgbyF5yHDv1AVN +%inQhecjwtYk793GykDzk2NX8Ysuar0KqR46iVP5Q889C8pFj3kuDSS2xQqpP +%joYDWuf/ihaSlxxf+PUoi38lpHrleOOkdvjXF0Lyk6Pa521i1jMh1S/Hx+1G +%CZww9vlMjm2Lp6RZPmLzkGNBj/bY9cFCZN5nOu476/YWP7zL5iNHq7DgG1q3 +%2ec3OVaevW3qdIPNS47lccqA1EAhPT/IMZ0/ycTen81PjsZDV+/4eVFI/SDH +%6c5vmredZ/OU48iN7p7Kc0LqDzl6XXU2Up9i85Xjhv5Nuq5eQuoXOQb5BPUb +%cZzNW47TJA8rtDyE1D9yjPfwP/T7EJu/HOf17rv69QEh9ZMcz7Xoj324l/VQ +%YJ5Gb7M7bqyHAuHBsCF3d7IeCkx4fu126HbWQ4G2ZxsHfdzKeijQftr1psJN +%rIcCM8y/LFFuYD0UaB0SrTt+HeuhwHqfrF0HVrMeCtTvMz3z1QrWQ4FCboNS +%uox9flZgnx4tUSsXsx4KfHuv2kvtyHoocMWXDVEmDqyHAo2CTZeem8d6KNBj +%qnO99hzWQ4EH7B9P9LBjPRToGHFHXziD9VBgb4d9tRemsh4KvHz1XTeLyayH +%Ant8CV8XM4H1UOCMkVYjncaxHgpcN6abg2oM69FR75Tvs97ash4KxM3JbXtt +%WA8Fpr25fWXkSNZDidf1lpa3W7MeSuzbuVfEx6GshxI3Ogi0AwazHko85/Xo +%k6sV66FE25/LdtoPYD2U6PZsQdJIS9ZDiQOv6Bv0sWA9lCi4yNtoYM56KHFl +%U6yt1JT1UOJUt4hRot6shxI3KOSPJMashxLN93vl6PVkPZTY/L6+xLg766HE +%IapVUuuurEfHfHe+JNh1Zj2UOCWiJGyzEeuhxBXVRulnDFgPJf7PetaiZ3qs +%R8f+4bSwPBXroURV1to4QyXrocQj/V2WzJKzHkq8O2DNvpNS1kOJfcIUNz+J +%WQ8lFojPfFWKWA8lBqgn9VoiYD1UKHTg6t/XZj1UOPfEleh2Puuhwp+xr7Y7 +%8FgPFcZ3VWs+0WA9On4/cmO2Lpf1UGFfYd85u9vZ90cV3ihKm5/VKiAPFdrc +%mxNm1yIgDxXqn71l/KpJQB4qPFUxy2FYo4A8VDhoZoDmw3oBeagwwSZpgGWd +%gDxU6HqWj8E1AvJQ4dV1Rw8PrhaQhwp/VxQufV4pII+O96i4M7mTKwTkoUK/ +%DTv6p5UJyEOFlY+G/LOpVEAeKtxxcYAbr0RAHh3vJZHL1gQWCchDhbc1upWP +%7nhfZjxUqO57Lfp3voA8VLjxznOlR56APFR474X0i2WugDxUuDpzSmJatoA8 +%dPHMBqeU41kC/D+QSguY +% "]]}, +% {GrayLevel[0], LineBox[CompressedData[" +%1:eJw113dczfsfB/BzTvPMzoispGGEzJtrv98qZFzRtSJZyYpCXDKvkK3749rE +%jcxKSEY5lAZpUlFJpb3XaY9fnPfn+0+P+n7P5/N5v57v8/30MV7lZr+Gx+Fw +%VFwO5+dPdg3+Y5N4+KVq5W79wOm5nofA0/+3/IGu7PdzEN594CYdqFY+73u4 +%bN7z6/Cs6XVygozdvwX6g/qU18VWKS9f+nndg0fWhkbCzVX0fCCk7Bv4qFZe +%pSyf9/MvwdBjiWr0ndBK+vxT6BD6xJg4VioF6X7ukwShMKbG1HA1p5LGewHZ +%++0H7btVoTR3PBOhGhQGO2rTps+3raDxX4P+DdstzWXlyltdn073ewOhltbC +%ZWfKab63kL88dvbVUeXK0b+uSEiV5ReeTy2j+d/B1ee6G5bvLFNGqgZ1zRAF +%O5xbi+t7ldF6YuBqovuk2eGlSvtfE8ZCg8fgHNflpbS+9xAbPnuZE7dUmev5 +%c8APwLkqCRD6ldB6P0LyuaUuJ2xKlFt+Ls89Hqwnx71NKCim9SdA2Lp9JzKP +%FCvVGkmg52Y18uHAYqonCYKa3nNmxBYpbX9NkAzXJAc2PlhXRPUlwy3jzsI4 +%3SLlz9kcz6RA5tkn7hF3C6neT2CYE3l5l22h8lc56Z8gZmfeAlVRAdX/GdxP +%PHIY712gNPq5nL6pUGIc6jhlQAHlkQq/dwwM1YvKV651+XmlQdEq8YQbq/Mp +%n3TQ+K3kdQM3X/lzNP3AdEjs7GfW7cYPyusLRINQ0jTph7Lh53CqL3Aq4suQ +%S5l5lN9XUOVmFPJ25Skn/xowA/zPXTQf2j2P8syA50NHfen+JFf5a3mHM6Fk +%pgKi7HIp3yxQZedNtizPUcZ//HllQYjzNff1R3Mo728wKLf4nINZjrLbrwVm +%w8fBR5b3P/Cd8s+GaTsvhotCs5W/hnP8Dk5X27ttrPhGHjkw0WnO10mm36ie +%HFgd86Jn4OIs8smBsOJpIT6nMqm+HDjyg38t+20GeeXCbW2vRc9UX6neXPC2 +%2u/FM/9KfrnA3eSv/W7pF6o/Dza+Oe7deiqdPPOg7MDX9TeUaZRHHvydM2hj +%YnUq+f6AKzGlzm7GqZTPD5iXYM7bN+8zef+AJ2KTqsoDnyivfPhkG+SQEpRC +%/vlwPim0b7/sZMovH2xsj1/OFyZTPxRAwve5vbnjkijPAugR4NA8LC6B+qMA +%rlVsSZ9lGk/5FsK9U3H3eZ5x1C+FIGlW/uuZ+J7yLuwab8GecNNY6p8iGO9+ +%4EzhjmjKvwgcbTSuPIt9R/1UBDGWv3lb9owkj2Lw06yb4r3uLXkUQ7NjBkdv +%k5I8iqFu3o8HI7XDyKMYcFl/j9arz8mjBB79+8a1bUQIeZTAyqiAxNa3weRR +%Am8MF036cuMheZRCt1PtYX7Pbyt9fnmUwoDjh5J/O3eNPEohzF0ybo3DGfIo +%A6ltcsLzU0vJowwKl/+5aPPxo6D2KINhTwt+t553GdQe5ZAoVsaeHn0L1B7l +%0G3btXHHpj4AtUc51C31i9g/LBjUHhVQNfNA46vwp6D2qADz/unbP9o9B7VH +%BdhscL75Kf8VqD0q4UyNM7zYqwS1RyW0FS7vcffkW1B7VEJvQWa3MY6RoPao +%gjEF5+18LaJA7VEFpx/vbjvOiQG1RxV8Xvjmo0NqLKg9qkF6LNBP+eAD1VMN +%a68EO1sd+ghqn2qwG7Dkej+nBKqvGvz17Zf0MkwCtVc1bPg2vL1EmEz1VsPY +%1QLfqNZkUPtVQ+VX5Qf/8hSqvwYMBla+cMn+BGrPGuAG7p1skfyZ8qiByg+T +%fpS9SwW1bw2sjO5Xe/tFGuVTA6/GTHA7F5QOau8aMJlqZ+3l/4XyqoXIurm3 +%V1//Cmr/Whi4fyLf5UIG5VcL1teK3Lz/yQT197MWjF2PZoeczKI8a+HJvVnv +%dY99A3V/1MLmiKySE0eyKd866FXzunrm4e+g7pc6GBXTuf+SVQ7lXQfc2kWB +%+pE5oO6fOrjbvqZ4ik0u5d/1/O4B3lrRudRPdRDwMbl9v20eedRDbIXy7am4 +%PPKoh8yLgZZWdj/Iox7e7L5w6+anH+RRD2aen4fdXJxPHvVQ5j55vEd2PnnU +%g2dzg26+cwF51EPtjUdT+OUF5KECYWhP5+JtheShAvel//O93lZIHl33VU4h +%zYeLyEMFE6Lt+hpJi8lDBa17/+gluVJMHioY1So/8W5ACXk0QIjDswKbJyXk +%0QBr37y56Iul5NEAW+L8xsQllJJHA7xvaX4Wv6yMPBogvnlQw7OKMvJoAGXd +%UdHefeXk0QivfDJmWEoryKMRhnlJL3z+r4I8GiHgjPNchzGV5NEI/w4LPZH+ +%oZI8GmGUym6X3Yoq8mgEh2aVLKKhijyaYE5q1jKT6dXk0QQlw8w+LztbTR5N +%IE57eXFUTjV5NMEGvVozT4sa8miCfO302fN315BHE3zof8Ip4n0NeTTB5rTT +%VyJ61JJHM3B2Xk+yX1dLHs2QluP7ZF9XX6o9mqGh3qvZll9HHs1gpJ138fGS +%OvJohhGpbSvCH9aRRzMknvxTd3NnHXm0AHSGXky0ryePFhgzufVOhn89ebTA +%FIXlf0da60H9vmwBB72ipsa5KvJogVjf7lLjOyryaIFkc9tGfoeKPFrBcOti +%8aMFDeTRCrevX3GxCGwgj1boF5dvtFmnkTxaISfwndOBlY3k0QomRgY/Noc1 +%kkcrHHlwr8aiRxN5tEF+5KrEDI8m8mgDX/25591TmsijDXQ0C3PLRzSTRxtE +%X4j0W+nTTB5t0DvJ1zClupk82mBZvHTxNPsW8mgD/rT3CyKftpBHOzxtfHd/ +%aY9W8miHovSG97y9reTRDkGizVMS81rJox3mbDuT/nZGG3m0w4qNx4wKgtvI +%ox0875Q9ntm7nTw6IPjI56aWw+3k0QFXt3OOltW0k0cHuKnyAu2Xd5BHBwQd +%uh5mkNBBHh0wanODxazJneTRAaNzd5xvDeokj04oWeJZcEnGQbVHJ7wr2nRE +%PJuDao9O+G+tcdRcbw6qPTqhbrGv65ZIDqo9OkF/4PUH2zhcVHt0wgl/XbcN +%k7lIxw8UJI05u2gvF9X1cBCl9scwnItqHw6aTkgy+62Di+r6OFh4PmCbFfJQ +%7cXBD/d77v3Li4e/ynXhYNbMBSPjY3io9uOg2bkZWavEGqh+P3DQ4KzK64/5 +%Gqj25ODMx3O27L+qgeo8OCjteBpiXqiBal8O8rYlr5w+UhPV+XAQ7jcpyvZq +%otqbg8YbRm0e+1ET1XlxUf/FX74j+2ih2p+Lnat6DO3cpEX5cfFl8FiLgLda +%qO4HLh4VGQ9ebqBNeXLxRVzfxQPctFHdH1z8ZJQ01uK9NuXLRV9pypgL/XVQ +%3S9dOXlM2Hf0kA7lzcVlwvVLpIU6qO4fLjYt9xi3c6Yu5c9FLc+P2U3Buqju +%Jy7+I9g47mofPnnwcNhL311hx/nkwcPoDudTfm188uBhvJ5BwPGtAvLg4d8O +%UWbPywXkwUOx8/LprzYKUd1/PBxfHFflXyUkDx6+CVq3a+guEXnw8O7Cjffu +%6orJg4cbfWIL4q6LyYOHt5Pfz5AF9SYPHnb7LBoSy+1DHjwMM3QOaV3chzx4 +%GGR6rLdhSB/y0MC/0/Iza7obkocGZk8JsRXuNyQPDVz1oXTUkkpD8tBANIve +%2telL3lo4Pht33pvKOpLHhp4v8+2qhEeRuShgTcW/jN/rE4/8tDAThPrP244 +%9iMPDZQs3DHHLqwfeWjg14FBwQJzY/LQQM9v376Y3jEmDw08qLI/vWKSCXlo +%otuIJIlzowl5aOLIwRn+O8pNyaPr/iGRbdX8/uShiQZZ3+dO6DGIPDTxYWd8 +%jCKjJ3loYknACkHIoO7koYmPex61bXymTx6aOH5MmMAxWUEemijWd/3DaKiC +%PDTR8L1NYa+HcvLQxChweatvIycPTVyy0ju6tlxGHpr4+ftTU/xPRh5aGP17 +%4m7jlTLy0MIBPoOzjg2UkYcWLo25u1G7XkoeWniJJ+x5LUpKHlo4u1D/wror +%UvLQwo+9dwYleEjJQwtv3g84NXWelDy0MP+CXbTbCCl5aGFa6qvF9TIpeWhh +%k7zVtVeZHnlooXsfk+jqED3y0EJN/81nZYf0yEMba819Xcct0CMPbXwdHjWF +%a65HHtoY9Ubv3ymdEvLQRp6Z7+176RLy0MaRL+6M7PtYQh7aaOx83Hn9aQl5 +%aGNV+czgTa4S8tDGluKpjzVnS8hDGz1qb+jqW0jIQxtNjZdpe+pJyKNrfQOu +%pPSvE5OHNmrsSQpsSxeThzb2EY/dXRYuJg8dLHGqds+7JSYPHdTP0f6ccFJM +%Hjro8yfY+G8Xk4cOLg/33Dx/uZg8dNBb9iQ2aYaYPHTQSDJimNRSTB466G/S +%mqpjLCYPHTTfGaJ5VywmDx107N1rZ2WLiDx0cGSywcfEYhF56GD47/XdbNNF +%5KGDzQ+99s+OFpGHLmbrTHzyKUREHrpYzdsd8e22iDx0cfSGqMmrzovIQxeH +%9c7hO3iLyEMXX05J7/F6p4g8dLG5V8m8UxtE5KGLi55effDOUYTq/VMXvxqp +%+jrYichDF2M8suNmW4nIQxc5OS79L1qKyEMX2wyyD04wF5GHLh75Ni1wmKGI +%PHQxooeBdJtMRB58/LtgtCNPW0QefMy//1dxVouQPPgYv2b31tau96nag4+v +%XgSecCoQkgcfl5ekGWhkCsmDj896xRgXJgnJg4+Dd52M1IoRkgcfT1gIuCvC +%heTBx3spQcl1T4TkwcdvB9Ymvr4vJA8+2rqeLgq7KSQPPl6/sci++qKQPARo +%5yX0/NNHSB4CXLpte1WRt5A8BHhO5BR2b7+QPAT4tv2R34W/hOQhwDcnF395 +%7Mb2DwFqu64c27iW7R8CDDgy+tnqFULyEODU0szHzYuF5CHA0nqN5KfzhOQh +%wPXNrYfPzxSShwCXcS1DL1sLyUOAbgdbPkVMFJKHAEuMv6tEY4TkIURJdIVo +%13AheQgx2DsmX9OceQix0Op+aJAJ8+iqqxjSPfswDyFO/2qdv6o78xCi6Vfj +%UBcp8xDioI8Hg70FzEOIs2dGit9pMg8hjjBJutirU0AeQuzu1/j2RLOAPLpy +%0fJw6V4vIA8h5o/au+ZFpYA8RJhitX7dthIBeYhwT8PVy9PyBeQhQutX872G +%f2f7uQgnjHs/aEQG289FuNEsbfTUVAF5iNDC/4iPe5KAPET4wcZD+1GcgDxE +%6DVP8kQjRkAeInx18bnTxggBeYhQ3zH0ZmG4gDxEqMed+JvHCwF5iNCy4mu/ +%biEC8hChysMuOPqRgDzEaFw9euvxhwLyEOPShA6bFXcF5CHGPtutA6fdEpCH +%GJ10Ok5MvCEgj6733mj9xdZXBeQhRpdHdpccLgrIQ4yTps4u3X9OQB5iHLiE +%0/+pj4A8xJguWu/SdJJ5iDFlgK/FzGPMo+s9G9Gt495h5iFGf4HLgx4HmYcE +%b1yO/ufcPuYhweDq0j2Gu5mHBL+9rjj55C/mIcFdaXXOCz2YhwR3xjsO0trC +%PCRYse+k6s0m5iFBt14Bhkc3MA8JDrsksF26lnlIcHPGWfPxzsxDgsbufZ+a +%rWQeEuSb/q+ppxPzkGBBt57+PZcyDwmKeesHmy1mHnq4qseQK+MWMA893JOn +%cXixPfPQw5PWAScP2jEPPbxzQFUQMpt56OH7IXOSamcwDz18azD56LjpzEMP +%df13NR+1YR56qCzjD86bwjz08EuMz1MbYB56aJt57a+gicxDD+tdtf82Hc88 +%9DDZ82xf39+ZhxT3h5z+x9SS1SPFpcX3W4JGMR8pxqc8gqkjWH1STH3s0TvP +%gnlJ0fSDzcIjQ1i9UozrnDxplDnzk6JzxSyrwgGsfik6ZZ22v2nGPKXoenXo +%59UmLA8pZo9qX2jRT0DnGSnaD18wqMOQ5SPFT52Gw1J7M28pHtedavekJ8tL +%irEjxuZeNBDQ/w9SfL3uqMehbiw/Kc77WuC4Q8H6QYobrrQI3GQsTynOsLm4 +%c5Me6w8pHtq1ymarmOUrxYhYTYO9QtYvUsw38Lx9is/yluKQXe9e+umw/pHi +%rPMh+W+0WP5SNJ46uyNPg/WTFDO+WFQJeMxDhqtj/XljOcxDhhkV3kUbOth5 +%RIaH95Q5/td1HlF7yPBskEonp4WdT2RoLbr+p0kznzxk6PV41sv1jXzykGFm +%wZX1z1R88pBh9/DWYzr1fPKQYa0lRC6r5ZOHDDfYTk57Xs2n75sMeZYPAntU +%8clDht3qvYP3VPDJQ4Z7jYOHFnbti2oPGbbt8Hr5ZymfPGRoar9hX1Qxnzxk +%2KNuz/cJRXzykKEiup/LswI+eciwMbNshmU+nzy66onIcnyexycPGRY6KEWQ +%yycPGTqvtDr64TufPGRd++W6IodsPnl0Pe+4Pqk8i08eMrx+uWz6oUw+echQ +%33SWX98Mdh6U4z1RfHb4Fz55yFFof7f7inTmIceTcycaaacxDznGrYvTfPSZ +%echxzb31lss+MQ85BuS2TpekMA85Jtne3hSRxDzkODzlwlLPROYhx/xdlncs +%E5hH13p8EuPqPjIPOe6LmjE+JI55yHGuR3CO5wfmIcd0T9v/Wb1nHnLsNcRv +%oSSWechxXuTV4qxo5iHHPSr90YFRzKPr+VkNd7zeMQ854qL+q5dEMg85rm41 +%0bWMYB5y5G7b1iF/yzzkeG7B/rJaJfPoWp972j9pr5mHHHdecVgWFs485Cg7 +%fbrzVhjzkGPaC9l2n1fMQ4HXE9eH73vJPBRoNUU0x+0F81Dg6CVyyernzEOB +%X6sbZQ6hzEOBKxx5bfOeMQ8F7iqT1c4OYR4KfPhxnfGsp8yj69z3tDhx5hPm +%ocC+kdut/njMPBTIvdB9rX0w81DgmS9xdQ6PmIcCqw6dPLc6iHko0GtC761u +%gcxDgTNqHhzeG8A8FLjK23n86YfMQ4ELx0zk3HzAPLrGFy6c8ew+81DgvLuu +%ofH3mIcC1xTuVRXeZR4KNLvnNIB3l3kocOe3yQeN7jCPrvWIXGPBn3ko8Nje +%KcNX3mYeCjRasrvl0C3mocDl/LOj7vsxD31U8aOPp/zHx/8Dq98lgg== +% "]]}, +% {GrayLevel[0], LineBox[CompressedData[" +%1:eJw92XVYVNvXwPGhmWKKDhEMbEUM1Ktrid3YCihiKxa2qIAoBnaDioqg2Ipd +%iIFSiiAlId3dHe/8nLXf+ec+4zDnnL0++3tm5rlmyzfPWaXM4XCKVTic//2X +%PbQjVt3cYFYdulf78aRs1+3g/sXs10Yue34Ivlu9ilpRXRX6potX6ew3p6D3 +%mIPB81Kq6PULcCLT8uSYz1WhV3z/PeDzLT+b7vfY31+HuqG1aZyzVaFls//3 +%L/6w03WFS8Ju9v5AMHs28NatZVWhvOSALaN5QbCxuKlu5WR2vHtw9IJdTI9B +%VaG9HU5/qe/1ENLfKIen67HjP4Zpa0yFxp2VoYHydycHPIX7g7qt3xhTSecL +%hulPXSKe+1WGWv17PIfsgLEJRRsq6fwv4Ph7nrbhf5WhX+t7yc/wEj41GBkO +%4lfS9byGjdHN0aNTK0LnKE4Ih78b3xp5r4Ku7y04mTSt67e7IjTb9X8HfAfn +%qnfacSdV0PV+gKqCRz9zdCpCXf53eVtCYAVf9jMor5yu/yPsteqMdHheHqrQ +%+ASeE0MylDzLaT2f4Exd3RV/2/LQyf9O8Bly7xvs72taTuv7DEFfs/Y9LC8L +%/d/Z5KcEbtZSf+MPZbTeryAJG3d0t3dZ6L/lJH+F/FuvdvxYVEbrD4PBwxY3 +%yyzKQk3/dzldvoGp46os2/pSmsc3cJDdtNj5tTR0zer/Pb5D65m2Bu+zpTSf +%cICEdKubjqWh/zua9uNwcNjeZdT1/qU0rwiYe0IWeaq1JLThf4erj4CUA15n +%N0SW0PwiIWxa4f1xl0tCx/w7YBSYHjlkpLyqhOYZBQ4TT4z4OLgk9N/leUXD +%U6zf6sgpofn+gKRLQzM5McWhP3/8ewDf763D8avFNO+f0PbXeKXGuuJQnX8X +%GAPqNjONXYYV0/xjIM7JqiFWpTj03+EcfkGBXmhit7gi8oiFoea/nddeL6L1 +%xEJiqvYdX+ci8omFlFNZbh+ti2h9seD+ZKJ7sloRecXBDY/pq9N+F9J64+CY +%hQ8/+UYh+cWBe9SQ/z5vKKT1/4bvzt+KL44oJM/fwD9oc9tZvZDm8RsuRK8d +%1iu+gHzjgXMoKiPxRgHNJx6W+IU/2r2hgLzjYYX/8yz+iAKaVwKExV/tf0Kt +%gPwTYM3Er5eUf+fT/BLA5dZI8fLr+bQfEsFpc9cL79bn0zwTwbjlV1nHsHza +%H4mQvN5NNkoln+abBEe2XJ239Fce7ZckaIjUXbXvah7NOwlS2/5YHFqTR/sn +%GVotM57vs8qj+SfDHu1xHWs7c2k/JYNd9439JkXnkscfaEvj6Usu55LHH2j0 +%MkqOXp5LHn/A13995p4BueTxB56knjxq0JJDHilwf6nG5wffcsgjBRYdsftt +%cTaHPFLgs9vTyEsOOeSRCvYf9h4rtMgJPfPPIxU0jvNVR9dmk0cqSIzUc90+ +%ZpNHGvwYtS324bFs8kgD2xubT36fl00eaVBQ9X1/smk2eaSDU6uKb0JJFnmk +%Q0+uWuOHl1nkkQ53annfrnpkkcdfUDq+bZXTtCzy+AtN+3+46OtmkcdfaNlj +%cufG50zyyICzi7UHpCzIJI8M8I/aYZRcmkEeGZAuWWr52yODPDJB9PSkNFAn +%gzwywW30om5T7/8lj0wYZlh0+euYv+SRBWbFaR0Yn07ryYLgbNNLm9ekk08W +%TEm6vdK9NY3WlwXlPw3/XDydRl5ZcG7bss0e3dJovVlw1K/oVP/XqeSXBd+G +%PJ4cPTWV1p8NxVMKbC0zUsgzG1JOO0494pJC88iGiPx7NrdUU8g3Gy6Kxzje +%vvyH5pMN6a1DL13q84e8s0HT0UAyISSZ5pUDw/bsX58/K5n8cyBsQ6bvvJwk +%ml8OOK5v331mexL1mQOcHxDwQz2J5pkDHaOFWaE+ibQ/cmDtfjO/q30Sab65 +%cMBlgWzShwTaL7mwdUzLk6QZCTTvXNihrZ3aLzOe9k8ubN7/Jsp5SzzNPxf0 +%cnydzynF037KheHdIq9uOPebPPJgdYKpBXT7TR55cClx4tqE53HkkQf+eht/ +%TB0fRx55oPJSctAnIZY88uDswgHWL1bGkkceCPaa2B8u/kUeeTBw29fBNZq/ +%yCMfbv1NO2vTK4Y88iEvob/n6kk/ySMfVreUCKtW/SCPfNCf/eQU/1A0eeTD +%3uhlBma3osgjH8oadgmuh0aSRwHIek/vofQ3gjwKAB1GDMpqDiePArDy3cs7 +%oxtOHgWgE/9+/73B38mjAAbqlZU+nvmNPAogWtnSqff6MPIohNJC7Y/WXl/J +%oxCiFoS/HHTzC3kUgsEj9ef+7z6TRyGI+L0CTiZ8Io9CODOieOGZ9FDyKISc +%Xe5/F2t9JI8i6Dzq0aMJP5BHEfxYfyqqzuUdeRTB+T32vLRbb8ijCIKsH327 +%HfeKPIrAvjN+XDfOS/IogvXBJqKSAc/Jowhix63hdtgHk0cxOP83dMgXyRPy +%KAbPoaf7DVv7gDyK4b8dU5/afAwij2JY/evarHeSQPIohlvzB00dsOomeRSD +%o/vxzqz1vuRRArsTZaVzNM6RRwl8nvJshfYUL/IogafF2fnCn+voflkCHwev +%0zgVtQUUHiWwMtHiid64I6DwKIG6D0fX+krPg8KjFP7Embw9e+wKKDxKYdPQ +%8eMfKvmDwqMU5t6o5Ol+DgSFRykkcDpDAw7cBYVHKchOtK6WTHgICo9SeDKA +%Z/pK9SkoPMpAd+noUVGFwaDwKINIx7KNrtHPQeFRBpaW81ISnr4EhUcZpGWU +%ds649BoUHmWQ9KjT5sL+t6DwKIO+r3q1c1a9B4VHGTzLyf4weWYIKDzK4Rtu +%MRpoHQoKj3IYZZf3adnZT6DwKIe/qycen3LkMyg8yqFL1igfbbcvoPAoBxU/ +%G+G77V9B4SF//ip+KW4IA4VHBbgOM88UrvwGCo8KmOXzNPazw3dQeFTAgfqw +%9PL54aDwqICffYpCvGdFkEcFfM/ZZL17SiR5VMDxSV8Tt46PIo9KaEjs8mgG +%RJNHJej8mvV8+qgf5FEJu0KMcvyG/ySPSpjvn198dkgMeVRC+fvY86qDf5FH +%JVzYaFAxQD+WPKqgclvtm02XY2k9VTAtN6mbnl4c+VRB7dlrZXqX42h9VTB0 +%4fusgXq/yasKmhcmX313+Tf8W+7qKjgU+2D8Lv148quCHqoLQ375xoPi/iA/ +%vn1/tzFGCeRZBUPumZ9W9UugeVTBjA+LDfRME8m3ClaHR5697p9I86mCbDuz +%Oyu7J5F3FaTd/V1+PiiJ5lUNE23umRX0SSb/ajhuONbmiPx7jGJ+1eCghIa+ +%g//QfqgG3xNPHgte/6F5VkP4l+3hBaNSaH9Uw9NUx3Fln1JovtXwsNqzfMfE +%VNov8ufvT2k6/EileVfD/KcvLh6ck0b7pxoM9Mr366ek0fyr4aeT3ZZWx3Ta +%T9VQHBI1aW5hOnnUgFr40sdKm/+SRw28nhxwR6nxL3nUwKrOX3FH3DPIowaK +%DI/lzdLMJI8aWBIWl3jgbCbtvxq4Mi8x6I4wizxqYNyJn2qX52SRRw3EHxUM +%iricRR7y4wVd0xz5N4s8aiBn9Phbf82zyaMGVKpGiB+szSaPGkh92f3Yg8fZ +%5FEDvMXqFcV12eRRC5xxO1rmjMohj1r4e33qT65nDnnUwtnYX5dqInLIoxbm +%LbpiqinOJY9aGKqnKVi8MJc8aqFQ8mtp4fVc8qgFu6v+V98V5JJHLaRr3Twe +%PSCPPGrB4m3IQY1deeRRCy3LNqqvD80jj1pQ43HaLDXzyUN+PXfjK6xn55NH +%HTgdWbLK7ko+edSBpvY9i4jcfPKog3737p850L+APOrgS5vw0rZdBeRRB/7O +%2c+DPheQRx0E1AgdtQSF5FEHPl39e6csKCSPOkj/o4Qp/oXkUQfz/Fc/E5UX +%kkcd3LbS+3DRuog86kB0eELEskNF5FEHPd1X9F0SW0QedRAvOvr9rXExedRD +%2LvqyCXrismjHjbN21jR81UxedTDt4DYpctUSsijHsww7VyYbQl51EPkWusd +%ftdLyKMeYkK6C26WlZBHPdiEZvatGVlKHvWwIXj7voPHSsmjHob0DN22608p +%edRD/rzaO18tysijHjr87p5evKuMPOoh/rvznOnhZeTRABt87ilt0isnjwb4 +%41I+qHZNOXk0gJnJjx0Rb8rJowEe1RzrVcStII8GaN88qmKRfQV5NED+144/ +%Ux9VkEcDTOAZzdzWWUEeDfC8JHWj6pxK8miA99WDs7MDK8mjAQ7ZbpCNaKok +%jwYI/FRlGNejijwaADr2rI2ZVUUeDXBqit7Quj1V5NEIz5qrtNYEVpFHI1zx +%+vAzPKaKPBrhq75j8IHmKvJohIvaSeUruleTRyNYmxuZuc6qJo9GKFvNmRDq +%Wk0ejTAxqb3PpDvV5NEI+guqVIrjqsmjEZRTalzT26vJoxHMqkdpN/euIY9G +%2P22Z8qwBTXk0QidX3LLP3nWkEcTcLtnmxx+UkMeTbDQ4eqU1ek15NEEM/c5 +%V5zm1pJHE3iPW8ipH1ZLHk1g+ZRvfnJlLXk0gavLI32Hc7Xk0QQ8aC3a8KmW +%Pj+bIKET1j+vqCWPJlCa9PLGCJM68miCQwYTZqpOryOPJtBqfSZrknem8GiC +%GXYux0bcryOPJkgZ3e/E55Q68mgG7V+/9m3g1pNHM9TxdtusH1FPHs0Q5587 +%JmhdPXk0w6TdoweNvlJPHs2w+/Sjbs1R9eTRDKbJzq86WuvJoxlcZLOU5/Rv +%II9mUNpbujhnaQN5NMPZiMaAkDMN5NEMWZMHL6j40kAezZAU8mPIKvk+Ung0 +%Q2FHjptJr0byaIGVPXtv7WnfSB4tMMVr5FuXU43k0QL9HhWNNZY7KzxaYETl +%S2N+QyN5tMDYqEvR0/o0kUcLvBo/7savpU3k0QIbe8R+DDvfRB4t0PfdzB6N +%EU3k0QI7Fm5o9OpoIo8WCLFYOF8/Q4oKjxaIfXJO716pFBUeLaD5JF40q1mK +%Co8WkG36XifUkKHCoxVarG0PpWvLUOHRChmaHZN/mstQ4dEKCw+Z7Pw5SIYK +%j1b45N1rS9EYGSo8WsFhsINJlxkyVHi0wpqVnGtb7WWo8GiFQ5udshPWyVDh +%0QptGxdtddgtQ4VHK1SEZ5nUHpahwqMVat2dBPcuylDh0QqOlrsa9gTKUOEh +%//vpD6rXPZehwqMN7IOXzHX9IkOFRxvYuukdvhYnQ4VHG2SmvHEpzJKhwqMN +%rH4ccJxYJUOFRxv0O9/o+aNThgqPNjgwrO7ZZpE2KjzaYGHiEu3hptqo8GiD +%8+laa7oO1EaFRxu8v1jxujtoo8KjDUz6en6ZOUubPNogfH/ieD9HbfJoAyja +%0SLdok0ebVAx8uqpJx7a5NEO626UqK09q00e7VBuUpc46ZY2ebTDD2fJ7kXP +%tcmjHQb7LjA4FqZNHu1wYULt4cJEbfJoh9l/zu7dXqhNHu2g17Ww26BmbfJo +%h2U3eF15fB3yaAdlw/fnzU10yEP+3MZnxcqBOuTRDk3LqnwSx+qQRzvMeZw4 +%fc88HfLogEQ3t6Xz1uiQRwcsueMhXemqQx4dMNxNsvjxSR3y6ICSEaeDevvr +%kEcHWOxy6Z33Qoc8OqBVvfJBSoQOeXTA/uH3tsn+6pBHB+ztlr/0WLUOeXRA +%26WGmxPUdcmjA5Tm9soZY6RLHh3gZDq2+PAgXfLogFmrHs/Qm6hLHh1gddNA +%udFelzw64YptnorJVl3y6IQ+1UOWXTuqSx6dsPH4VgOXG7rk0QkhLuU9/F7p +%kkcnpFefi+kVo0senaAzwfqdYYEueXSC2q4wvmOHLnl0wpi/Wp56enrk0Qmn +%BY5lYwbpkYf8+ZGlvIQpeuTRCcsObXuXukKPPDpBd9vgCkc3PfLg4L4bhfdd +%fPVoPRz8kHxCvf2FHvlwMPY294xxnB6tj4NuEw8e+16uR14cNEy2tdTh69N6 +%Odir4Ty3vZc++XEw7WTKxzuT9Gn9HDR+YN2larU+eXIwtCxGWH1Yn+bBwQil +%P88ig/RR8XuGg9OcvVLXRurTfDiof23AqOJSffLmYPLNgPEzRQY0Lw4K04Xd +%Aq0MUPH9gYOcZuONnYsMaH4cDBKHa69wN6D9wMFxyz28iu8Y0Dw5uGLtg+sn +%fhnQ/uDgn54R8TubDWi+HDzQ2NF6s7sh7RcOWnIe2JrONqR5c1DdL+Zoi5sh +%7R8Obgy4u6zbY0OaPwffzEk79iPDkPYTB20M1B8ki43IQwknfM4Zaz3eiDyU +%8HAT72L8biPyUEL19xdFux8bkYcSbsxtHPktz4g8lLDzmajFxMiYPJQwymRD +%6WtbY/JQwqS5QeXcQ8bkoYRio/jMzmfG5KGED8x9z0xKNSYPJZzqeMSgvs6Y +%elPCaxNmDBe2GZOHEo7fYdTVqMCYPJTQPnZyq/NdY/JQwkpf9Z+bRxqTh/z9 +%vMC0l1eMyEMJhzyueFUXb0geSsiPFJ01b2YeSmh0vXfJTWPmoYQyk6FqxtP1 +%yUMJ7XY9Vg47qUceSng0+kLj8Fxd8lDC0dkvSmymsZ7lr7tVeZwMY/cnJWyo +%35//aLoOeShh1/aYyxOztclDGTt8Bl1K+//7rzKqOz/MaeqtTR7K2Ffz0Zf6 +%VPb5qIy/3+/9r/Ac+3xRxm6hya2/bdnnpTKGe7wWWGizzxtltKn3GV6eJiUP +%ZdQN6xfWFiQlD2V0KDJKu7RLSh7KOMki3mX6VCl5KOOOlgwDblcpeSjj9skD +%T65pkpCHMp5eobPVNF5CHsp4Yu2CublPJOQhX1+QqdGDUxLyUMZXt4/b9N0s +%IQ9l1MozzbKdLSEPZSzh+quVDpGQhzLe7TjSu8hAQh7y+Ri+knTjSMhDvl7t +%tEzfQjF5KKOSUso6vVgxeShjd+eFPrffislDGfd/abUyDhSThzL2i6vftOW0 +%mDxUcIy7hZ/PXjF5qGBj4rTxXmvF5KGCz6fbv7VcICYPFZxpO7DywHgxeahg +%c8VNHXcrMXmo4M//bjiKuonJQwVbu8WsHCkTk4cKtvCvDstWEZOHChbVP1Dq +%XSIiDxW0sbkzY9dPEXmooJnOw1sfgkXkoYJ8lWnd4i+JyEMF7bc0xETuE5GH +%Cm6/8PTjiRUi8lDB9NERyWrTROShgufn3JwxzEpEHipo+XLsXB1jEXmo4M0Y +%8UM/NRF5qOCms35XvlVqkYcKBjtZHz2YqkUeKqjT8Wzat29a5KGCNeu7jrwd +%rEUeKmg4++bkTj8t8lDBBKt7L7K8tchDBeFQ7dzRu7XIQxWnDgmMEa/WIg9V +%jPT2rbadp0UeqvjNs2O/yjgt8lDFDM/T3C6DtchDFc8Ihx/yMdMiD1XUv3Gj +%p6tEizxU0a7s/In3SlrkoYondYLHz6oRkocq2jxetnxsrpA8VNGZa831ShCS +%h/x1/dm3TL8LyUMVh/f7O0PtjZA8VNEqqN9ly/tC8lDFiVHCF8+uCclDFR3a +%ElN3nhaShyre6Ts02sNTSB6qaB2f6xmzQ0geqhhq+Mhr8ToheaiiZnjnDosl +%QvJQxcMfDacMnC0kD1W8cWe01dYJQvJQxc04e2PFCCF5yOc5v9zjzgAheaji +%f86LOk53E5KHKo4Xhbk80xeShxq+//7KkaclJA813DvtcffjKkLyUMPO1LGb +%xzQLyEMNh8ycsbd7pYA81FBzafC4ofkC8lDDZTqLTm9NE5CHGpZ83dUtM05A +%Hmo4OfI+uEQIyEMNt3vUDx0UKiAPNfRatq639JWAPNRw4+s6E9NHAvJQw1yl +%J5NnBwrIQw1/Lr3RHnhVQB5quDXe84b5eQF5qOH333bdQrwF5KGGK/8ILT08 +%BeShhhseZoU4ugrIQw1jq9+kLdsqIA81NNo91v3QegF5qOGLVhXJ9+UC8pDP +%79jYwB72AvJQw69P6sJuzRWQhxo+5R+fNma6gDzUcMfb/a4N4wXkoYZ/Ays6 +%I0cLyEMdDVTjo94ME5CHOoYtGZjyaaCAPNSxxwZeeVYv5qGOylayRV3MmYc6 +%Kk3bULDNiHmo49PDe3pkaTMPdczUNLBbo8U81LFzrOC8iibzUMcgt4jVL5WY +%hzqeqNRxcW/lk4c6JmXMVXes55OHOu6rThsxr5JPHur4M2BM45JiPnmo4xKx +%uoVrLp881DEw6q7347988lDHN00bDjQm88lDHR1XPmmx/c0nD3UM2TGr5f0P +%Pnmo41uLfPPR4XzyUMf3XScm/vjMJw91HL0xw3jzBz55qOOaWbUt3V/zyUMd +%v0wzby8P5pOHOvZ0con48pBPHvJ5Tc4/8zCITx4aOL0gyuz2LT55aKBHbdzG +%h3588tBAFeWOO999+OShgYPuDl1Xdp5PHhq4T999TI/TfPLQwAdrLSY7e/PJ +%QwMbi5ZqhnjxyUMDV6dzLc0P8MlDAys7V/c6u49PHhqobpPqJN7NPDSwn8Y5 +%U79tzEMDNV+knB+6mXloYEfTy81/1zMPDYztkht/ZjXz0MDD4Sufzl7OPDRQ +%X9u0xWQp89DANYMMZzcuZh4amOxU/Tp9PvPQwL4R9f4/ZzMPDez9dtLh6BnM +%QwOPTg6I+z2FeWigmv3EcQUTmIcGcvu7RKjaMA8NLDFvshw4hnlo4NZjQZdW +%jmQemphpvsY7YBjz0MQV6v0elg9mHppoNeveoLEDmYcmzk0/GHijL/PQxEXh +%uhyNXsxDfrzpAR57ujMPTUzqca9fXVfmoYmhb2o/7DZhHppoPO+JqaYh89DE +%6w45//nrMg9NvBf6MBNkzEMTF98Z3a9UxDw08THf8JafgHloom5tSuICLp9+ +%f8rPd6StzEideWhi3TqxZrEy89BED8f5Az508shDEwNd327wbeORhybqhF2f +%tq+ZRx7y9RmE9Hdu4JGHJg7Jq3uyrJZHHpo4zcZCd0kVjzw0ce/X+Sucynnk +%IZ+v8fwZziU88tDESouOcrdCHnlw0aBvbqRvHo88uHi83XTju2weeXBxwfTq +%1twMHnlwcbLm9q/SdB55cDHt5rlBU1N45MFFvp2T9+EkHnlw8dQmA6/oeB55 +%cDH8nN4unTgeeXAx0/Ne56oYHnlw8cql5SEfo3nkwcVjmya3GkfyyIOLXX0m +%9T3wnUceXGzWbU8s/cojDy6WdB8w3+Ezjzy4+GDw+te/P/LIg4vWx9OCZ33g +%kQcX3wgmmce/ZR5c1N8cKXR4zTy4GCBy8C5+wTy4uK1gw4V9z5gHF98GCLrq +%PWUeXOzhHVf48hHz4OKQ08eP2D1gHlzc3vKsWfUe8+Bi28bAvy/uMA8epsVX +%aq8NZB487Mrv9sbsFvPg4f2tKh8zbzAPHkbFb7UN9GMePMzQnvZjw1XmwUO9 +%BVuPjfJlHjx0nucUL7zMPHj4ouBeVP4F5sFD4cQTsz+dYx48PLX4euutM8yD +%hzu52hVHTjEP+XUc0lbfdoJ58NDnQr27kzfz4GGu/lWzeUeZBw9DHk57PP0w +%8+BhdPnpBZMPMQ8eFo7JmjDFk3nwcNecFS0zPJgHD7+nxzfNd2Me8jnv1lJe +%vo958HDgJf3D21yZBw9t1+isOrabefBQypEW+O9kHjycXTN04aftzIOHomsj +%qrK2Mg8+ui0xDldzYR7y+9Cd8V0HbmYefAy4UHnJfiPzkN8nNrhPOuHMPOT3 +%sbbi+Z/WMQ8+frC/kdO0hnnw8b86s19Wq5mH/L543/zPtpXMg4/L591seLmc +%efAx92fuxbZlzIOPYpHD3YmOzIOPEVM6Us4vYR58FF1WM8y3Zx58XNX+NNPa +%jnnw8XifAMGZRcyDjxMnqF8pWcA8+HhS2WP2lPnMQ35fvJJ69f5c5sHH4RyL +%3lpzmAcf0xd9qdlhyzz4eFWUbJY9k3nwceDjZp+ZM5gHH826aPf+NI158NGg +%aM9Iq6nMQ/658tYp+v5k5iFAs0dzw7tNYh4C1Lh3a5P/BOYhQLcOpzVm45mH +%ALd0fNALsGEeApxun7Cl91jmIcC7pTJRMDAPATrH2W3+bwzzEGBS6C7zqP+Y +%hwA3+ElLFo9iHgL8o5TBqRjBPOTfe0uyfQ9ZMw8BxvYP5pkMZx4C7GNjFfZ6 +%KPMQoP9Tw/L5Q5iH/Hvfw8fRDYOZhwBfF6X4+FoyDwEO2NeUPGYQ8xDgs9zZ +%WDCAeQhwtNeGfWf7Mw8BRs8O7j6mH/MQoM+kdQ3lfZiHAPe47hx4ozfzEKD9 +%1GPFc3sxD/n36h7h/XgWzEOAPz73bP3cg3kIMSanydWtO/MQ4sUTGVUjuzEP +%IX7RXb6t1Yx5CLFS1yL3Q1fmIUT3wDfOB0yZh/x30/4818ldmIcQh5760CYy +%YR5CPPSpMyPNiHkI0XLryJV3DZmHEBOnJq3bZcA8hPj2L+f1ZH3mIcSI+Dgv +%Iz3mIcQFrqHSah3mIUTrETFvw7WZhxB7Buzz8JcxDyHOzR9lsF/KPITYlqGe +%YCdhHkKc/t3+ywgx85DPozM92FDEPIR4xpQf2S5kHvLX7wXeyhEwDyEunryU +%E8VnHkI8V9hd/TmPeQgxuM/PD35c5iH/3edxcI23JvPQwhGnFlvs0WAe8t/5 +%9SZX1qkzDy2M9HB+YqfGPOS/s9+VBc1UZR5aaF615MJ4Feahhd57M9tHKTMP +%Law+btIyRIl5aKGL2oIRgzjMQwvPLVxr2a+TSx5aqFbb9rpPB5c8tDCxxapv +%33YueWhh6YjlZv3auOShhYVHuv4a2MolDy3c7jkwf0gLlzy08EzQMruRzVzy +%0EK35W6fbJq45KGFuW0DNKc3cslDC78Vx6QtbOCShxYKVk1atFL+uavw0MJ3 +%JywOba3jkocWFl+J6eJZyyUP+Xq9hxy8UMMlDy0cr+kfcqeaSx5a+OitrOhd +%FZc8tLDPz+9r4iq55CFC3cSka0UVXPIQYR/D1c5K8ucKDxHOv6xhZ1TOJQ8R +%ThumNmF4GZc8RPh+bMvcefLvDQoPEc749DhnawmXPESo4pq8/1wxlzxE2COm +%0fFFEZc8RLindO/VpELmIcIt3OdzWwuYhwgLB9w50bWAeYjQr8T29cR85iG/ +%3guD52zOYx4i/Har+bNPLvMQ4X2Tl9Zfc5iHCO0GaAytzGYeIqySFv0yzmYe +%Imzt+Nx3Wpb8e9M/DxF6fGtw35vJPER40v7gvocZzEOEO9y2xGX8ZR4ilIQc +%PSL9yzxEuOqS7bpJ6cxDhJrfbdfuT2MeIowcYnTlRSrzEOPie38sylNoPWpi +%HDql++yeKcxHjJMD9qx3+sNV/L4SiTFj9PrVfsnMS4zCLocbUpNovQZiHJQb +%9Uk/ifmJsf/GH6sXJdL6u4lxn3FXb58E5ilG28lvrFPjaR4DxGjS093TJJ75 +%yq/vcOVJp9+0X63FCHc44XfimLcYI3vN61keS/OyEaPHU9fbVrHMX4x/0qe4 +%7/tF85suRpedvZ98i2H7QYwOa5MniWNongvFeHez5lr7n2x/iFG6qSwj6AfN +%10mMu33E3vXRXPr/M2LcmfLOcXw0zdtZjKFFtyaej2L7R4xTQxKm5kXS/HeI +%Uav+cvbQSLafxDjs774DRyPIw0OMF6dKPNPD2f4So9L7oNGDwsnDW4xL736x +%PvydPE6LUfy08EP6N/K4IMa9nQNdhnxj+0+Mzlofu58II4/rYoz1v7Qr/yvb +%j2Lsod3zGH4lj7tiNL/qtfXqF7Y/xVgbURTR+Jk8notxTop9+bzP7P4hn2fR +%nsPPPpFHiBi9v8ycLfnE9q8Yx7ROt3YJJY9wMdpMKNz7+yPbz2J8bRmYN/gj +%ecSJ8Zn3tbGXQtj+FqOeS6R58wfySJfP67j7tSUf2H4Xo07WyxVf3pNHgRjD +%v3Gn9XrP9r8Y59343n7qHXlUiTH54CnlhresBzHyup8/svQtebSIceIky6jw +%N6wPCfImunEGv2F9SHB5w+kF116zPiT4yajIU/M160OCI3RTi7a/Yn1I8P6B +%rvNyXrI+JHhmXvDbWS9ZHxLcmnd7QOgL1ocEN2+z2j/gBetDgpUOlrIbz1kf +%EhRJTs8TP2d9SHD6l/SOA89YHxLM1vXIqwtmfUjQRFY+Ym0w60OCQ66V6aY/ +%ZX3Ir0fXPmX2U9aHBK8Orov+/oT1IcGVfNmm0U9YHxJU7Xzj+OIx60OC5Q+l +%yX0fsz4k6DRo95/AR+x+KsFeTU+bTR6xPiRombYs+vJD1ocEfU+UBkgfsj4k +%aBqy/NnJB6wPCe538+XzHrA+JDiH093/8H3Wh/z6ZitPUr3P+pA/r3dw8rzH +%+pBghVvIcqV7rA8Jrg3r2ONxl/UhwdATlQ2cu6wPCRZPNz1+IIj1IcHMEVwP +%5SDWhwTx5gMrrzusDwmm3+NlaNxhfUiwR9rXTO/brA8J7ozO6SW6zfqQ4MJ+ +%M36dD2R9SHCFZuZ4g0DWhwSl16q8bgSwPiTodUWrqEcA60OC9kX3vz68xfqQ +%yH9PRlUNucX6kOAMfdd+If6sDwk6SAP6TfQnjwIJTvjoZhZ7k/UhwbFGz/Xt +%brI+JBhXku6fd4P1Id9PE/c1b77B+pBgxrQ67bbrrA8pug2fa3f0OutDik/s +%dq7Quc76kOLMhcEzA/xYH1I8YCrbaenH+pCiclBYbug11ocUc0x9fs26xvqQ +%4rqI/g8yr7I+pNhRa6W+5SrrQ37+RWeclK6yPqTo02XbwPNXWB9SvGp+jtvj +%CutDig8Ww7nXvqwPKR4/kxs71Zf1IcXYniYLM3xYH1IcvXhb3VYf1of89cu9 +%MjR8WB9SBM/lln6XWR9StN07c7bVZdaHFIc2+a2JvMT6kGJJxeHJyy6xPqS4 +%I8o2o/Ei60OKl/PcY09fZH1IsV4y06zXRdaH/HifNJs/XWB9SDFyx9M3dhdY +%H/J5j7C2rTvP+pDiO9kjvdPnWR9SXPGr5mDv86wPKf52F+K3c6wPKQq2meg6 +%nWN9SHHMqoCX7WdZH1LMU3Oec+Us60OKTpsLXYafZX1IcXF08qLEM6wPKe50 +%SF+77QzrQ4oG5zdNlp5hfcjnYf94TvBp1ocU9z27mmZ7mvUhxe4xfl2rT7E+ +%pNimOePz2VOsD7m/Wr+8wadYH3JfTumwhJOsDykeGzR0z86TrA8pJrmHb9I/ +%yfqQ4vh5zRbvT7A+pFho88pu6QnWhxS//ne9WukE60OKfbgD228fZ31IMfPS +%lZCpx1kfUvQYc+ZXpTfrQ4YXu3wruODN+pDhbmn/8yO9WR8y/HZhQlvWMdaH +%DMdm7j5/5BjrQ4ZvRjvYDTjG+pDhzqcLkhOPsj5kqPLMInX/UdaHDCP9Hkzs +%eZT1IcOS1idhMUdYHzJU35aXt+sI60OGsn6qaHaE9SHDISk7rKIPsz5k2K1o +%ydYdh1kfMpxnOrzG9DDrQ4ZDBeP+RHmxPmRoXmG/facX60O+fjX1ueZerA8Z +%+k7Xt4s5xPqQYbD5r7+uh1gfMrwQvJHb6xDrQ4b97cVWiQdZHzIcPmvBE8+D +%rA8Z3r/829jyIOtDhjru+ksyPVkfMsxcN8zllCfrQz7Pvu8jRnuyPmR4t8fg +%JeUHWB/yeW1sWuB3gPUhw6kfg/rNOMD6kKGueVpnuwfrQ4bTnxkrPfFgfchw +%WlwNd5kH60OG1qXyu4wH60OGASPqm766sz5kuMP53eqd7qwPGbo+K2ro5c76 +%kGGb106zdDfWh3z+41f7nHZjfchQeewUu3FurA8Zbnru4dq4n/Uhwz/n3oc9 +%2M/6kOHxVe+PLNvP+pCh1bCJ3jr7WR8yTHjbMjl6H+tDhhmZCYke+1gfMvy1 +%wSV/2D7Wh3y/nMsYV76X9SHDo9OOBwfsZX3I3/986F27vawP+d/r6CyU7mV9 +%aGNE04ukSFcu/h+i+QLA +% "]]}, +% {GrayLevel[0], LineBox[CompressedData[" +%1:eJw113lczNsbB/BpmmavZokkW7cI19ZybZfOI5VoVymKJCJbiVC3ouxLJJWI +%uOLey00JP1uYuAiFlLQo2hftm/b6DXOe7z+9pu/M+Z7n8z5zzjM6a3yXrmMy +%GIxOJQbjx1+8Ul26/o4JaJf9oZG8qCxoP7EvejblzHx8HU3Kp3Tv3KfSLrs/ +%5kC9w/0EYvLPcO7Gt230/hUSCL43zWPaZOfO/riukUvnfW4OX9lG359MLp2e +%4fRVr03W4PDjP6nkOLep5s+GVvr5O8R/ZtyTlXdaZfz8RL/5/HvkN9fQC5rB +%rXS8B0R9W1JLxsJW2ST3k886Jz4i3df91u0UtNLxn5CuwPe3dXNbZFfkn85P +%TCdX6xcp551roc97SsaeXSA7sKZFZvTz+o+cu2fBNpjcQp//nGw94u32sqJZ +%9l/nRPkTXpBj6y1fGm5vpvPJIAe1JiYnMZtlS38+8BVJ3xWvPzOqic7vNXmX +%EvnwjU6TrCzox4BviOGo0dt9UhvpfLPIRH1zkfaCRtm2H9Pze0vYlebXKrIb +%6PzfkfS0E4bpqxtkCo1sovf0TMejlnpaTzYxStlZk763Xmb58wEfiEWWzrh2 +%UT2t7wMZ+76vYOaf32Q/nuZ+Moes+8e++ILBN1pvLulmDSpNe1Yn+1lOfi7J +%2q+kW7C0jtb/kahbvitKrqiVjf0xnTF55G7pwekXd9TSPPLIxOEub9JUamXr +%vX9cn8iI7SY3hWdqaD75ZJnBKub+iTWyH6NpJOeTzZuAO/FhNc2rgESvbe6u +%saqWff8xXGcBufAx51FuSRXNr5DYvXROH+ZXJTP5OWARmRzfp7qDWUXzLCLW +%He4uddGVsp/TO/CZBCzmBH3Sr6T5FpOh/7UEZD2skL3N+nEVE6dLHZ6DNhU0 +%7xIyI377/ZCyctmwnxP8QtiJLrGTAspp/l/I4/P321R45bKfw7l/JfY7Pe5r +%XyijHqVkzICdT4JBGa2nlFyws3TUfllKfUpJsdLhEqZbKa2vlPS/D9zlWPqV +%epURrdyQ2z6Cr7TeMtKt22sTP/ML9Ssjq13q/FevKaH1l5M7ET3VshPF1LOc +%kDuSwZK0zzSPcjLX0C00qK6I+lYQ3U3SeDfNIppPBdGPdB78xaKQeleQw8KO +%x3sCCmhelWTqNqdxm6/mU/9K4mhePz4z7xPNr5K4f+v9PMj+RNdDFel6wdRM +%nJ1H86wi1zh3H52OZoNifVSR624L1xgks0GRbzXZ8i79iyyDDYr1Uk36NijX +%TStjgyLvamL6yND/VC8bFOunhlxcJ/izUMoBRf41JInt/og3lQOK9VRDLryI +%mDDVggMKj1rSvuLwQkMPDig8asn1lPDrWrs5oPCoJbuW/6vaFskBhUct0Q4X +%cFKvcUDhUUfMohOuOT3jgMKjjqiP6tSsLeKAwqOOpAdUqy1r54DC4xvRyOmX +%3RZwIfKnxzfya5ZdbKcuFxQe38jbm0kfpfO4oPCoJ5n9jp1jnbig8Kgn+5M4 +%9fzNXFB41JNAPe7Bin1cUHg0kKIzyeHR8VxQeDSQB8Xx18ff5oLCo4Esn9v6 +%9NIbLig8GoljSnrGYBkXFB6NJOiwh/eMHi71aCRXhwseWol41KOJbMn0Zi3S +%51GPJpImWOM8zIRHPZqIzW1OZoYTj3o0k4TR0+4s38SjHs3kaKnV8PQwHvVo +%JiwDHw+lOB71aCFWMIM1NplH62khUS9reRrPedSnhVgbGJ//XMij9bUQVePI +%wh3NPOrVQiKs1OrqWHxabwt54B+UPmUkn/q1kFcjWx1Np/Np/a3EyPjRhwlm +%fOrZSlK5r5vyXfk0j1bCuFbW5rCFT31bSalhsvf5MD7Np5W0rPhNIymGT71b +%SXH1dM2Qa3yaVxvxbw3J037Mp/5thPVCemR3Np/m10ZeXnTNiKngg+L72Ubu +%elZxt37n0zzbSO7iPZUqPAFdH21EZ6bqTXttAc23nZjbs7udpgroemknc097 +%zFcnApp3O3kxm1+xw15A1087+T1jUVCkp4Dm305m/hK/aqm/gK6ndhJ0+qHa +%w3AB9eggy2sdZ72NElCPDtJQlKsTdllAPToIz1qq/y5VQD06CPu37G1P0gXU +%o4McKw2fZ/FeQD06SEZtZLRXiYB6dJCjG7duEdULqEcnCf3rz9k23QLq0UkK +%HErbR6gIqUcn+Tt+dukmsZB6dJKsC8b3zEYLqUcn6XltrHt5opB6dJI6rvX6 +%UCMh9fhOVmUM+uTNF1KP7yQyqOvBP4uE1OM7ebvdM6zNXkg9vhPd3P2bUpcL +%qcd38m6q/5QyTyH1+E469l2Yvd9HSD26SB37zalYPyH16CLrJ++ql+4SUo8u +%EqezIHgwWEg9ukiQC+uEY7iQenSRoqilT6SHhNSji+zZ4Fv7+zEh9egmH9Sm +%2r0/IaQe3US3503em1NC6tFNJp2McjOIFlKPbjLayrKOGSukHt3k5DdG3IIz +%QurRTbQttkqb5K8VHt0E3L5bCeKE1KOH7LnrnHNOfl/h0UP+47jMuxSLHj1E +%dbxgkXYMevSQvcabWBqn0aOHzDDfueB4JHr0kD7fuqDDEejRS3Z1nq/jH0WP +%XmJw+Z3WiIPo0UtsjmnF3AsT0v2yl7wemPBLQzB69JJTUu20tF3o0UsKTQaL +%J/mjRx/JC1N78Ptm9Ogjz6Z5CLrXoUcfMbw4RcvLAz36yGpXJdtwV/ToI9yC +%m87uDujRR9JWbwvrWIwe/eTS+3y2gyl69JMvo6bl75yLHv3Ex+PTk42G6NFP +%vubv/NNwMnr0E795re45OujRT9gr8sfba6FHPzENeTGYJEKPAfIhKHKoiYMe +%A2TNeda/2kMC6jFAjpjxcmZ+F1CPATL54f63CxoF1GOA/JUOdxdUCqjHAPFe +%/+z4/M8C6jFIApqjOUY5AuoxSMIuGSye8FpAPQZJV9XacaPk32+FxyDpfMxa +%NeyegHoMkqf3v/2nkYz71SCJPrabMe4q7ldDJDUmjGt4HverIeIoOKu+7DTu +%V0Pk1OQRJYeO4n41RPr3Maa+DsP9aojcC7YyHBWI+9UQmfXilvp+P9yvGDBB +%i1U7uB7rYUD7pkTdUx64fzHAMMi9ZI4L1seASZ4uen22uJ8x4KXppLAPFgL4 +%Wa43A/ROTD3z0gT3NwbUloqO58wU0P2BAQEaVqo903C/Y0BC2JK7s/QxDwbY +%JwiXxY7F/U8+fuHBa6ojMB8G9J4rq7oswv2QATc812gv5WFeSlAyh9czion7 +%oxLMspycxOrj0/yUABqjVTkdeH4pQaL5yJLxjXyapxI0vp/DW12N55kSJI3R +%s7n7lU/zVYIp1e6dEwvxfFMCW/u7pXdy+DRvJQh+ZfjOPQvPOyXYslY8oPOS +%T/NXgm0HC58y0vH8U4KeUCLpesCnHky4t/d4GP8OnodMmLUuzW9mMp96MCGx +%57ZO8D94PjLBOfn60+LLfOrBhJXR622WXsDzkgm/ivcwq8/wqQcTtG1SNkdE +%4fnJhNa7anE2EXzqwYSooazB8YfxPGXCwemZK4ftw/6ACQsjR87QCuVTDyY8 +%VdeuNw7EfoEJSapm1T47+NRDGeIfx7Ym+2L/oAy/eV2yUd2EHspwYkdeQag3 +%eiiDkW6OWGUNeihDjdGXlxdXoocyjH2X3WazHD2U4Y1txr9qzuihDJ8fP3lW +%YY8eyuA/+GHtG2v0UAb192eVn1uihzIE2M43yjZDD2X41M1PagD0YIF63PhC +%7fnowYJXGr7PV8xBDxa8WP5r/7+/oQcL7G61HxUaogcLtoYdbv9jGnqwYPtS +%k4yByejBgojzR8Mi9NGDBcPZA+ZT9NCDBQZeB1IKx6EHCz5/U74YOxo9WLCs +%rt3McyR6sKDu2j3vOZrowYKKPz6+HquBHirQo9PDlIrRQwUCnM9HaaihhwoE +%dwY80BGghwq8rPaYO4+LHiqwt1LNxksFPVQg+6lgZCwTPVRgR88vbz8O8aiH +%ChBPVcexA9i/qkBJlaZbQC+PesjvP9FOyuviUQ8V2FXtc9q0k0c9VODwHKWZ +%D9qw32XDgb73z+e2YH/NBqXogIEXjdj/sqE0EhLc63nUgw2XN6Sf7K/FfpgN +%1rKBwqvV2I+zIS2WMcG1Evtj+Xhz42KGl/OoBxt87w0zK/6K/TIbTB24XddL +%sH9nQ9jhb9Xhn3nUgw3m1o4Fa+T9tsKDDR990q4syedRDzZ0ufZdn5eH/T4H +%1mjV+M3M5VEPDri0n1SZ/YFHPTjwNeBxKrznUQ8OJIZYDjq8xd8HHAi0LXyz +%MZNHPTiw+9n220df86gHB1zvORWnZqAHByygmXx9gR4cyDArDBz2HD04kKSf +%luvwDD04cPNzqUtMOnrI75cHZ355gh5cuKW82Xv6Y/Tgwh33tcUH0tCDC5wl +%3ZnlD9CDC8Yfnn02v48eXJCcDhtMvoseXHC9IRga/T/04ELyQG9M1G0ePT+5 +%ULv5oonqLfTgQlTK/7wjbqIHF/bYjd8iTUEPLixq+scj4QZ6cCEwM9FrWhJ6 +%yOfj98Du+XX04EHXaaWkVdfQgwftgWNeD/6NHjzY57t7deJf6MGDzQWMYuur +%6MEDr4sZ4r5E9OCBVbzm8OTL6MGDML249+v+RA8ehLfpOOlcQg8eHKpLaitL +%QA8e6OU97//rAnrwYHLMQnO/8+jBAzuN2Ffz49GDD51Z043Uz6EHH4pWm9hV +%xqEHH2xcSooen0EPPviOq4qMj0UPPvz++Oyp4Bj04EOL+Pkjz2j04ANv7Mnz +%S06jBx/e39qvNysKPfhwNXFzoP4p9ODDwI2cbdqR6MGH7sTqPZKT6MGHhfXb +%U4Qn0IMPnBmH7vIj0EMAq41/1RMeRw95H+HsrSk6hh7yvm3oYq/mUfQQwOxr +%Goa6R9BDAAvVHhobHEYPAUStdHY0PYQeAvC3t/BadhA95H3Rp7YNWw6ghwDq +%0z1WHNqPHvK+4tIo3Sv70EMAWrmRr/8LRw/550e/elgVhh5CMPUKuCAIQw8h +%KJtHjTHaix5CmB5XHr5yD3oIoWMo6tvRUPSQ/66asD7vQQh6CKH1jmpCQzB6 +%yPve/KHfdYLRQwgjuLVrXf9ADyE070v5cCoIPYTAE1otfxuIHvLXHZJPgkD0 +%EELgUNYU693oIYSWRP+CE7vQQxWKwtR4H3eihyo8d24pH7kTPVTB0WNayNoA +%9FCFsoHWTyk70EMV3EadujOwHT1UITmj09lmO3qowqHbK9IT/NFDFe6daE5s +%24YeqpB9vcHccht6qAIj2/fART/0UAWf6kSVHl/0UIUd43LWO/mihxp4KU27 +%mroVPdSgpj/EUbQVPdRgha5+yLYt6KEGUxP4IR83o4caXPnlatjszeihBluP +%hYYnbEIPNfBxel7F3oQearDD8V2o30b0UAP/htBzn33QQw02xD6KsPRBD/l8 +%0pd8u7sBPdRgVohV44QN6KEGUZ1/x8StRw91UJ+496lgPXqoQ16/m/9eb/RQ +%h1yp6Oz3deihDtlHvlpuXYce6mDIH7GxZi16qIPrScsBz7XooQ6/apV1lHih +%hzqUelUGunmhhzpIh91eWLQGPdRBP6NUe8Ua9JC/P+1V2WdP9FCH56OFD1d5 +%oocIGkbYnilfjfWIwFaTKd6wGn1E4P6x41GTB9YngtEtYck7PdBLBKmGUZVD +%q7BeETzYdsLh6Cr0E4Gnw+bKYauwfvn9xBdNl1eipwgkqcojDVZiHiIw0ro1 +%IJPv44rfMyKwV7pB7N0xHxFsX5yQXOaG3iLomLbXdIcb5iWCvz6Gf+W4Yf8g +%Am1vm8rzKzA/EUQZ5hwwXIHrQQRZDDXH18sxTxEEly177rkc14cI9qyWru11 +%xXxFkGtmuyDaFdeLCFaGul+f7op5i2B+t8+iTBdcPyJghbWKNrhg/iLYrR+s +%z3bB9SSCfQdYrleXoYcY1vXPyzFbhh5iOJq+p6bKGT3EUN68J+uQM3qIQbfY +%Y/RkZ/QQg1bqf5ffOqGHGD7pbyzb5oQeYuAtyPDVdEIPMawqGHPrsSN6iGFj +%+pHCtY7oIYZXupeyhI74fZO/n6/E/99S9BCD2vclh1ctRQ8xGD0ouMVdih5i +%MEzJHrjtgB5iEPeWtXs4oIe83mEuSUIH9BBDQo/6uIf26CGff2ZjyAZ79BDD +%jTDueE179BDD6+E1rS/t0EMMA8t6L++yQw8xtB62ZE6yQw/5eAHLm4ps0UMM +%Q580QyJs0UMMe6b9dgxs0UMCV3b01HXYoIcEbK80ZF+zQQ8JtAUVqnjYoIcE +%fHXemAyzQQ8JnHKZfSvTGj3k9x9ywvZZo4cE1v7x7tbv1ughgUxVu/Z2K/SQ +%wNQPX1JuWKGHBIxkxhnrrdBDAmXujdN/sUIPCSwxWGBesgQ9JHDd5eTss0vQ +%QwLvh5+86rwEPSTAMTh/TLIEPSTwarePT/Zi9JDAv4bxlScWo4cEsk5PLbBZ +%jB4SsOHMSRIuRg8JpD4dpvfWEj0k8LHZ+EiEJXpIYNSdDeNsLdFDAj47Hqap +%W6KHBLT0nmrnLEIPCVSY6dZHL0IPKVwNFX5zWYQeUri7eIqR9iL0kAJX/1dG +%qQV6SOHI5CneVyzQQwqhST1nfSzQQz7eVqn1dAv0kAJ71ZOTneboIYXHN71M +%HpmjhxQcnGM37DNHDymEWNx3tDJHDynMGLHAV2qOHlK4b7x8eLEZekjB7eMx +%vatm6CEFE+ulwVvN0EMKKddI0Gwz9JCC8dncCqYZekjB1W+4yduF6CGFywfW +%jDq7ED2kwGl69mjtQvSQwuDe2rIZC9FDCtWnvEIHTNFD/vwt7/a+MUUPKVjH +%6XLiTNFDCn9kjvmwzhQ9pFD4yiXfyBQ9NGCbumUmU/76/4f9glI= +% "]]}}, +% AspectRatio->NCache[GoldenRatio^(-1), 0.6180339887498948], +% Axes->None, +% AxesOrigin->{0, 0}, +% Epilog->{ +% InsetBox[ +% BoxData[ +% FormBox[ +% InterpretationBox[ +% Cell[ +% BoxData[ +% FormBox["\"|q| = 0.02\"", TraditionalForm]], "Text", "TR"], +% Text["|q| = 0.02"]], TraditionalForm]], {0.8, 4}, BaseStyle \ +%-> 14], +% InsetBox[ +% BoxData[ +% FormBox[ +% InterpretationBox[ +% Cell[ +% BoxData[ +% FormBox["\"|q| = 0.05\"", TraditionalForm]], "Text", "TR"], +% Text["|q| = 0.05"]], TraditionalForm]], {1.67, 6.4}, \ +%BaseStyle -> 14], +% InsetBox[ +% BoxData[ +% FormBox[ +% InterpretationBox[ +% Cell[ +% BoxData[ +% FormBox["\"|q| = 0.07\"", TraditionalForm]], "Text", "TR"], +% Text["|q| = 0.07"]], TraditionalForm]], {2.85, 12}, \ +%BaseStyle -> 14], +% InsetBox[ +% BoxData[ +% FormBox[ +% InterpretationBox[ +% Cell[ +% BoxData[ +% FormBox["\"|q| = 0.1\"", TraditionalForm]], "Text", "TR"], \ +% +% Text["|q| = 0.1"]], TraditionalForm]], {3.2, 7}, BaseStyle \ +%-> 14], Null}, +% Frame->True, +% FrameLabel->{ +% FormBox["\"Impact parameter, b\"", TraditionalForm], +% FormBox["\"Spatial rotation, \[Chi]\"", TraditionalForm]}, +% FrameStyle->{{14, +% GrayLevel[1]}, {14, +% GrayLevel[1]}}, +% FrameTicks->{Automatic, {{0, +% FormBox["0", TraditionalForm]}, { +% NCache[Pi, 3.141592653589793], +% FormBox["\[Pi]", TraditionalForm]}, { +% NCache[2 Pi, 6.283185307179586], +% FormBox[ +% RowBox[{"2", " ", "\[Pi]"}], TraditionalForm]}, { +% NCache[3 Pi, 9.42477796076938], +% FormBox[ +% RowBox[{"3", " ", "\[Pi]"}], TraditionalForm]}, { +% NCache[4 Pi, 12.566370614359172`], +% FormBox[ +% RowBox[{"4", " ", "\[Pi]"}], TraditionalForm]}}}, +% FrameTicksStyle->{16, 16}, +% ImageSize->600, +% PlotRange->{All, All}, +% PlotRangeClipping->True, +% PlotRangePadding->{Automatic, Automatic}, +% TicksStyle->16]], "Output", +% CellChangeTimes->{3.556953242036603*^9, {3.556953596625984*^9, \ +%3.556953702375863*^9}, {3.556953796337514*^9, 3.556953956593231*^9}, \ +%{3.556954020687426*^9, 3.556954030706046*^9}, { +% 3.558693364370013*^9, 3.5586933829491863`*^9}, \ +%{3.55869345851305*^9, 3.5586934742140837`*^9}}] +%%EndMathematicaCell +p +np 33 1 m +33 273 L +469 273 L +469 1 L +cp +clip np +p +np 35 3 m +35 271 L +467 271 L +467 3 L +cp +clip np +3.239 setmiterlimit +p +np 70 3 m +70 238 L +450 238 L +450 3 L +cp +clip np +P +p +np 70 3 m +70 238 L +450 238 L +450 3 L +cp +clip np +P +p +np 70 3 m +70 238 L +450 238 L +450 3 L +cp +clip np +0 g +0.36 w +[ ] 0 setdash +3.25 setmiterlimit +78.19 226.892 m +78.919 226.724 L +79.648 226.555 L +80.376 226.386 L +81.105 226.217 L +81.834 226.048 L +82.562 225.878 L +83.291 225.707 L +84.02 225.537 L +84.749 225.366 L +85.477 225.194 L +86.206 225.022 L +86.935 224.85 L +87.663 224.678 L +88.392 224.505 L +89.121 224.331 L +89.849 224.158 L +90.578 223.984 L +91.307 223.809 L +92.035 223.635 L +92.764 223.459 L +93.493 223.284 L +94.221 223.108 L +94.95 222.932 L +95.679 222.755 L +96.407 222.578 L +97.136 222.4 L +97.865 222.222 L +98.593 222.044 L +99.322 221.865 L +100.051 221.686 L +100.779 221.507 L +101.508 221.327 L +102.237 221.147 L +102.965 220.966 L +103.694 220.785 L +104.423 220.604 L +105.152 220.422 L +105.88 220.24 L +106.609 220.057 L +107.338 219.874 L +108.066 219.691 L +108.795 219.507 L +109.524 219.323 L +110.252 219.138 L +110.981 218.953 L +111.71 218.767 L +112.438 218.581 L +113.167 218.395 L +113.896 218.208 L +114.624 218.021 L +115.353 217.833 L +116.082 217.645 L +116.81 217.457 L +117.539 217.268 L +118.268 217.078 L +118.996 216.889 L +119.725 216.698 L +120.454 216.508 L +121.182 216.316 L +121.911 216.125 L +122.64 215.933 L +123.368 215.74 L +124.097 215.547 L +124.826 215.354 L +125.554 215.16 L +126.283 214.965 L +127.012 214.77 L +127.741 214.575 L +128.469 214.379 L +129.198 214.183 L +129.927 213.986 L +130.655 213.789 L +131.384 213.591 L +132.113 213.392 L +132.841 213.194 L +133.57 212.994 L +134.299 212.794 L +135.027 212.594 L +135.756 212.393 L +136.485 212.192 L +137.213 211.99 L +137.942 211.787 L +138.671 211.584 L +139.399 211.38 L +140.128 211.176 L +140.857 210.972 L +141.585 210.766 L +142.314 210.56 L +143.043 210.354 L +143.771 210.147 L +144.5 209.939 L +145.229 209.731 L +145.957 209.522 L +146.686 209.313 L +147.415 209.103 L +148.144 208.893 L +148.872 208.681 L +149.601 208.47 L +150.33 208.257 L +151.058 208.044 L +151.787 207.83 L +152.516 207.616 L +153.244 207.401 L +153.973 207.185 L +154.702 206.969 L +155.43 206.752 L +156.159 206.534 L +156.888 206.316 L +157.616 206.097 L +158.345 205.877 L +159.074 205.656 L +159.802 205.435 L +160.531 205.213 L +161.26 204.99 L +161.988 204.767 L +162.717 204.542 L +163.446 204.317 L +164.174 204.092 L +164.903 203.865 L +165.632 203.638 L +166.36 203.409 L +167.089 203.181 L +167.818 202.951 L +168.547 202.72 L +169.275 202.489 L +170.004 202.256 L +170.733 202.023 L +171.461 201.789 L +172.19 201.554 L +172.919 201.318 L +173.647 201.081 L +174.376 200.844 L +175.105 200.605 L +175.833 200.365 L +176.562 200.125 L +177.291 199.883 L +178.019 199.641 L +178.748 199.397 L +179.477 199.153 L +180.205 198.907 L +180.934 198.661 L +181.663 198.413 L +182.391 198.164 L +183.12 197.914 L +183.849 197.664 L +184.577 197.412 L +185.306 197.158 L +186.035 196.904 L +186.763 196.649 L +187.492 196.392 L +188.221 196.134 L +188.95 195.875 L +189.678 195.615 L +190.407 195.353 L +191.136 195.091 L +191.864 194.826 L +192.593 194.561 L +193.322 194.294 L +194.05 194.026 L +194.779 193.757 L +195.508 193.486 L +196.236 193.214 L +196.965 192.94 L +197.694 192.665 L +198.422 192.388 L +199.151 192.11 L +199.88 191.83 L +200.608 191.549 L +201.337 191.266 L +202.066 190.981 L +202.794 190.695 L +203.523 190.408 L +204.252 190.118 L +204.98 189.827 L +205.709 189.534 L +206.438 189.239 L +207.166 188.942 L +207.895 188.644 L +208.624 188.343 L +209.353 188.041 L +210.081 187.737 L +210.81 187.43 L +211.539 187.122 L +212.267 186.811 L +212.996 186.499 L +213.725 186.184 L +214.453 185.867 L +215.182 185.548 L +215.911 185.226 L +216.639 184.903 L +217.368 184.576 L +218.097 184.248 L +218.825 183.917 L +219.554 183.583 L +220.283 183.247 L +221.011 182.908 L +221.74 182.566 L +222.469 182.221 L +223.197 181.874 L +223.926 181.524 L +224.655 181.171 L +225.383 180.815 L +226.112 180.455 L +226.841 180.093 L +227.569 179.727 L +228.298 179.358 L +229.027 178.986 L +229.756 178.61 L +230.484 178.23 L +231.213 177.847 L +231.942 177.46 L +232.67 177.069 L +233.399 176.674 L +234.128 176.276 L +234.856 175.872 L +235.585 175.465 L +236.314 175.053 L +237.042 174.637 L +237.771 174.216 L +238.5 173.79 L +239.228 173.359 L +239.957 172.924 L +240.686 172.482 L +241.414 172.036 L +242.143 171.584 L +242.872 171.126 L +243.6 170.662 L +244.329 170.192 L +245.058 169.716 L +245.786 169.233 L +246.515 168.744 L +247.244 168.247 L +247.972 167.743 L +248.701 167.232 L +249.43 166.713 L +250.159 166.186 L +250.887 165.65 L +251.616 165.106 L +252.345 164.553 L +253.073 163.99 L +253.802 163.417 L +254.531 162.834 L +255.259 162.241 L +255.988 161.636 L +256.717 161.02 L +257.445 160.391 L +258.174 159.75 L +258.903 159.095 L +259.631 158.426 L +260.36 157.743 L +261.089 157.044 L +261.817 156.328 L +262.546 155.595 L +263.275 154.844 L +264.003 154.074 L +264.732 153.283 L +265.461 152.471 L +266.189 151.635 L +266.918 150.774 L +267.647 149.887 L +268.375 148.972 L +269.104 148.026 L +269.833 147.047 L +270.561 146.033 L +271.29 144.98 L +272.019 143.886 L +272.748 142.746 L +273.476 141.556 L +274.205 140.31 L +274.934 139.004 L +275.662 137.63 L +276.391 136.179 L +277.12 134.642 L +277.848 133.005 L +278.577 131.258 L +279.306 129.378 L +280.034 127.344 L +280.763 125.125 L +281.492 122.683 L +282.22 119.959 L +282.949 116.88 L +283.678 113.326 L +284.406 109.112 L +285.135 103.916 L +285.864 97.083 L +286.592 86.986 L +287.321 66.511 L +288.05 107.215 L +288.778 120.201 L +289.507 125.455 L +290.236 128.764 L +290.964 131.167 L +291.693 133.043 L +292.422 134.577 L +293.151 135.87 L +293.879 136.983 L +294.608 137.958 L +295.337 138.825 L +296.065 139.602 L +296.794 140.306 L +297.523 140.948 L +298.251 141.537 L +298.98 142.081 L +299.709 142.585 L +300.437 143.054 L +301.166 143.493 L +301.895 143.904 L +302.623 144.291 L +303.352 144.655 L +304.081 145 L +304.809 145.327 L +305.538 145.636 L +306.267 145.931 L +306.995 146.212 L +307.724 146.479 L +308.453 146.735 L +309.181 146.98 L +309.91 147.214 L +310.639 147.439 L +311.367 147.655 L +312.096 147.863 L +312.825 148.062 L +313.554 148.255 L +314.282 148.44 L +315.011 148.619 L +315.74 148.792 L +316.468 148.959 L +317.197 149.12 L +317.926 149.276 L +318.654 149.427 L +319.383 149.574 L +320.112 149.716 L +320.84 149.853 L +321.569 149.987 L +322.298 150.117 L +323.026 150.243 L +323.755 150.366 L +324.484 150.485 L +325.212 150.601 L +325.941 150.713 L +326.67 150.823 L +327.398 150.93 L +328.127 151.035 L +328.856 151.136 L +329.584 151.235 L +330.313 151.332 L +331.042 151.426 L +331.77 151.518 L +332.499 151.608 L +333.228 151.696 L +333.957 151.782 L +334.685 151.866 L +335.414 151.948 L +336.143 152.028 L +336.871 152.106 L +337.6 152.183 L +338.329 152.258 L +339.057 152.331 L +339.786 152.403 L +340.515 152.474 L +341.243 152.542 L +341.972 152.61 L +342.701 152.676 L +343.429 152.741 L +344.158 152.805 L +344.887 152.867 L +345.615 152.928 L +346.344 152.988 L +347.073 153.047 L +347.801 153.105 L +348.53 153.161 L +349.259 153.217 L +349.987 153.271 L +350.716 153.325 L +351.445 153.377 L +352.173 153.429 L +352.902 153.48 L +353.631 153.53 L +354.36 153.579 L +355.088 153.627 L +355.817 153.674 L +356.546 153.721 L +357.274 153.766 L +358.003 153.811 L +358.732 153.855 L +359.46 153.899 L +360.189 153.942 L +360.918 153.984 L +361.646 154.025 L +362.375 154.066 L +363.104 154.106 L +363.832 154.145 L +364.561 154.184 L +365.29 154.222 L +366.018 154.26 L +366.747 154.297 L +367.476 154.333 L +368.204 154.369 L +368.933 154.405 L +369.662 154.44 L +370.39 154.474 L +371.119 154.508 L +371.848 154.541 L +372.576 154.574 L +373.305 154.606 L +374.034 154.638 L +374.763 154.669 L +375.491 154.7 L +376.22 154.731 L +376.949 154.761 L +377.677 154.791 L +378.406 154.82 L +379.135 154.849 L +379.863 154.877 L +380.592 154.905 L +381.321 154.933 L +382.049 154.96 L +382.778 154.987 L +383.507 155.014 L +384.235 155.04 L +384.964 155.066 L +385.693 155.092 L +386.421 155.117 L +387.15 155.142 L +387.879 155.166 L +388.607 155.19 L +389.336 155.214 L +390.065 155.238 L +390.793 155.261 L +391.522 155.284 L +392.251 155.307 L +392.979 155.33 L +393.708 155.352 L +394.437 155.374 L +395.166 155.395 L +395.894 155.417 L +396.623 155.438 L +397.352 155.458 L +398.08 155.479 L +398.809 155.499 L +399.538 155.519 L +400.266 155.539 L +400.995 155.559 L +401.724 155.578 L +402.452 155.597 L +403.181 155.616 L +403.91 155.635 L +404.638 155.653 L +405.367 155.672 L +406.096 155.69 L +406.824 155.708 L +407.553 155.725 L +408.282 155.743 L +409.01 155.76 L +409.739 155.777 L +410.468 155.794 L +411.196 155.811 L +411.925 155.827 L +412.654 155.843 L +413.382 155.859 L +414.111 155.875 L +414.84 155.891 L +415.568 155.907 L +416.297 155.922 L +417.026 155.937 L +417.755 155.952 L +418.483 155.967 L +419.212 155.982 L +419.941 155.997 L +420.669 156.011 L +421.398 156.025 L +422.127 156.04 L +422.855 156.054 L +423.584 156.067 L +424.313 156.081 L +425.041 156.095 L +425.77 156.108 L +426.499 156.121 L +427.227 156.135 L +427.956 156.148 L +428.685 156.16 L +429.413 156.173 L +430.142 156.186 L +430.871 156.198 L +431.599 156.211 L +432.328 156.223 L +433.057 156.235 L +433.785 156.247 L +434.514 156.259 L +435.243 156.271 L +435.971 156.282 L +436.7 156.294 L +437.429 156.305 L +438.158 156.316 L +438.886 156.328 L +439.615 156.339 L +440.344 156.35 L +441.072 156.36 L +441.801 156.371 L +442.53 156.382 L +s +78.19 227.244 m +78.919 227.062 L +79.648 226.879 L +80.376 226.696 L +81.105 226.513 L +81.834 226.329 L +82.562 226.144 L +83.291 225.96 L +84.02 225.774 L +84.749 225.589 L +85.477 225.403 L +86.206 225.216 L +86.935 225.029 L +87.663 224.842 L +88.392 224.654 L +89.121 224.465 L +89.849 224.277 L +90.578 224.088 L +91.307 223.898 L +92.035 223.708 L +92.764 223.518 L +93.493 223.327 L +94.221 223.135 L +94.95 222.944 L +95.679 222.751 L +96.407 222.559 L +97.136 222.366 L +97.865 222.172 L +98.593 221.978 L +99.322 221.783 L +100.051 221.589 L +100.779 221.393 L +101.508 221.197 L +102.237 221.001 L +102.965 220.804 L +103.694 220.607 L +104.423 220.409 L +105.152 220.211 L +105.88 220.013 L +106.609 219.813 L +107.338 219.614 L +108.066 219.414 L +108.795 219.213 L +109.524 219.012 L +110.252 218.811 L +110.981 218.609 L +111.71 218.406 L +112.438 218.203 L +113.167 217.999 L +113.896 217.795 L +114.624 217.591 L +115.353 217.386 L +116.082 217.18 L +116.81 216.974 L +117.539 216.767 L +118.268 216.56 L +118.996 216.352 L +119.725 216.144 L +120.454 215.935 L +121.182 215.726 L +121.911 215.516 L +122.64 215.305 L +123.368 215.094 L +124.097 214.883 L +124.826 214.67 L +125.554 214.458 L +126.283 214.244 L +127.012 214.03 L +127.741 213.816 L +128.469 213.6 L +129.198 213.385 L +129.927 213.168 L +130.655 212.951 L +131.384 212.733 L +132.113 212.515 L +132.841 212.296 L +133.57 212.076 L +134.299 211.856 L +135.027 211.635 L +135.756 211.413 L +136.485 211.191 L +137.213 210.968 L +137.942 210.744 L +138.671 210.52 L +139.399 210.294 L +140.128 210.068 L +140.857 209.842 L +141.585 209.614 L +142.314 209.386 L +143.043 209.157 L +143.771 208.927 L +144.5 208.697 L +145.229 208.466 L +145.957 208.234 L +146.686 208.001 L +147.415 207.767 L +148.144 207.532 L +148.872 207.297 L +149.601 207.06 L +150.33 206.823 L +151.058 206.585 L +151.787 206.346 L +152.516 206.106 L +153.244 205.865 L +153.973 205.623 L +154.702 205.381 L +155.43 205.137 L +156.159 204.892 L +156.888 204.646 L +157.616 204.4 L +158.345 204.152 L +159.074 203.903 L +159.802 203.653 L +160.531 203.402 L +161.26 203.15 L +161.988 202.897 L +162.717 202.643 L +163.446 202.387 L +164.174 202.131 L +164.903 201.873 L +165.632 201.614 L +166.36 201.354 L +167.089 201.092 L +167.818 200.83 L +168.547 200.565 L +169.275 200.3 L +170.004 200.033 L +170.733 199.765 L +171.461 199.496 L +172.19 199.225 L +172.919 198.953 L +173.647 198.68 L +174.376 198.405 L +175.105 198.128 L +175.833 197.85 L +176.562 197.57 L +177.291 197.289 L +178.019 197.006 L +178.748 196.722 L +179.477 196.435 L +180.205 196.148 L +180.934 195.858 L +181.663 195.567 L +182.391 195.274 L +183.12 194.979 L +183.849 194.682 L +184.577 194.383 L +185.306 194.083 L +186.035 193.78 L +186.763 193.475 L +187.492 193.169 L +188.221 192.86 L +188.95 192.549 L +189.678 192.236 L +190.407 191.921 L +191.136 191.603 L +191.864 191.284 L +192.593 190.961 L +193.322 190.637 L +194.05 190.31 L +194.779 189.98 L +195.508 189.648 L +196.236 189.313 L +196.965 188.976 L +197.694 188.635 L +198.422 188.292 L +199.151 187.946 L +199.88 187.598 L +200.608 187.246 L +201.337 186.891 L +202.066 186.533 L +202.794 186.171 L +203.523 185.807 L +204.252 185.438 L +204.98 185.067 L +205.709 184.692 L +206.438 184.313 L +207.166 183.93 L +207.895 183.544 L +208.624 183.153 L +209.353 182.759 L +210.081 182.36 L +210.81 181.957 L +211.539 181.549 L +212.267 181.137 L +212.996 180.72 L +213.725 180.299 L +214.453 179.872 L +215.182 179.44 L +215.911 179.003 L +216.639 178.56 L +217.368 178.112 L +218.097 177.657 L +218.825 177.197 L +219.554 176.73 L +220.283 176.257 L +221.011 175.777 L +221.74 175.29 L +222.469 174.796 L +223.197 174.295 L +223.926 173.785 L +224.655 173.268 L +225.383 172.742 L +226.112 172.207 L +226.841 171.662 L +227.569 171.109 L +228.298 170.546 L +229.027 169.971 L +229.756 169.387 L +230.484 168.79 L +231.213 168.182 L +231.942 167.561 L +232.67 166.927 L +233.399 166.28 L +234.128 165.617 L +234.856 164.94 L +235.585 164.246 L +236.314 163.535 L +237.042 162.806 L +237.771 162.058 L +238.5 161.289 L +239.228 160.499 L +239.957 159.686 L +240.686 158.848 L +241.414 157.985 L +242.143 157.093 L +242.872 156.17 L +243.6 155.216 L +244.329 154.226 L +245.058 153.198 L +245.786 152.13 L +246.515 151.016 L +247.244 149.854 L +247.972 148.638 L +248.701 95.265 L +249.43 93.925 L +250.159 92.513 L +250.887 91.021 L +251.616 89.437 L +252.345 87.751 L +253.073 85.948 L +253.802 84.008 L +254.531 81.914 L +255.259 79.635 L +255.988 77.137 L +256.717 74.37 L +257.445 71.271 L +258.174 67.749 L +258.903 63.665 L +259.631 58.799 L +260.36 52.774 L +261.089 44.836 L +261.817 33.16 L +262.546 10.25 L +263.275 102.86 L +264.003 118.171 L +264.732 124.159 L +265.461 127.877 L +266.189 130.553 L +266.918 132.626 L +267.647 134.311 L +268.375 135.722 L +269.104 136.932 L +269.833 137.986 L +270.561 138.919 L +271.29 139.753 L +272.019 140.505 L +272.748 141.189 L +273.476 141.814 L +274.205 142.389 L +274.934 142.921 L +275.662 143.415 L +276.391 143.875 L +277.12 144.305 L +277.848 144.709 L +278.577 145.088 L +279.306 145.446 L +280.034 145.784 L +280.763 146.105 L +281.492 146.409 L +282.22 146.698 L +282.949 146.973 L +283.678 147.236 L +284.406 147.486 L +285.135 147.726 L +285.864 147.955 L +286.592 148.175 L +287.321 148.386 L +288.05 148.589 L +288.778 148.784 L +289.507 148.972 L +290.236 149.152 L +290.964 149.327 L +291.693 149.495 L +292.422 149.657 L +293.151 149.814 L +293.879 149.965 L +294.608 150.112 L +295.337 150.254 L +296.065 150.392 L +296.794 150.525 L +297.523 150.654 L +298.251 150.78 L +298.98 150.901 L +299.709 151.02 L +300.437 151.135 L +301.166 151.246 L +301.895 151.355 L +302.623 151.46 L +303.352 151.563 L +304.081 151.663 L +304.809 151.761 L +305.538 151.856 L +306.267 151.949 L +306.995 152.039 L +307.724 152.127 L +308.453 152.213 L +309.181 152.297 L +309.91 152.379 L +310.639 152.459 L +311.367 152.537 L +312.096 152.613 L +312.825 152.688 L +313.554 152.761 L +314.282 152.832 L +315.011 152.902 L +315.74 152.97 L +316.468 153.037 L +317.197 153.102 L +317.926 153.166 L +318.654 153.228 L +319.383 153.29 L +320.112 153.35 L +320.84 153.409 L +321.569 153.466 L +322.298 153.523 L +323.026 153.578 L +323.755 153.633 L +324.484 153.686 L +325.212 153.738 L +325.941 153.789 L +326.67 153.84 L +327.398 153.889 L +328.127 153.937 L +328.856 153.985 L +329.584 154.032 L +330.313 154.078 L +331.042 154.123 L +331.77 154.167 L +332.499 154.21 L +333.228 154.253 L +333.957 154.295 L +334.685 154.336 L +335.414 154.376 L +336.143 154.416 L +336.871 154.455 L +337.6 154.494 L +338.329 154.532 L +339.057 154.569 L +339.786 154.606 L +340.515 154.642 L +341.243 154.677 L +341.972 154.712 L +342.701 154.746 L +343.429 154.78 L +344.158 154.813 L +344.887 154.846 L +345.615 154.878 L +346.344 154.91 L +347.073 154.941 L +347.801 154.972 L +348.53 155.002 L +349.259 155.032 L +349.987 155.061 L +350.716 155.09 L +351.445 155.118 L +352.173 155.146 L +352.902 155.174 L +353.631 155.201 L +354.36 155.228 L +355.088 155.255 L +355.817 155.281 L +356.546 155.306 L +357.274 155.332 L +358.003 155.357 L +358.732 155.381 L +359.46 155.406 L +360.189 155.43 L +360.918 155.453 L +361.646 155.476 L +362.375 155.499 L +363.104 155.522 L +363.832 155.544 L +364.561 155.567 L +365.29 155.588 L +366.018 155.61 L +366.747 155.631 L +367.476 155.652 L +368.204 155.672 L +368.933 155.693 L +369.662 155.713 L +370.39 155.733 L +371.119 155.752 L +371.848 155.772 L +372.576 155.791 L +373.305 155.81 L +374.034 155.828 L +374.763 155.847 L +375.491 155.865 L +376.22 155.883 L +376.949 155.9 L +377.677 155.918 L +378.406 155.935 L +379.135 155.952 L +379.863 155.969 L +380.592 155.986 L +381.321 156.002 L +382.049 156.018 L +382.778 156.034 L +383.507 156.05 L +384.235 156.066 L +384.964 156.081 L +385.693 156.097 L +386.421 156.112 L +387.15 156.127 L +387.879 156.141 L +388.607 156.156 L +389.336 156.171 L +390.065 156.185 L +390.793 156.199 L +391.522 156.213 L +392.251 156.227 L +392.979 156.24 L +393.708 156.254 L +394.437 156.267 L +395.166 156.28 L +395.894 156.293 L +396.623 156.306 L +397.352 156.319 L +398.08 156.331 L +398.809 156.344 L +399.538 156.356 L +400.266 156.368 L +400.995 156.38 L +401.724 156.392 L +402.452 156.404 L +403.181 156.416 L +403.91 156.427 L +404.638 156.439 L +405.367 156.45 L +406.096 156.461 L +406.824 156.472 L +407.553 156.483 L +408.282 156.494 L +409.01 156.505 L +409.739 156.515 L +410.468 156.526 L +411.196 156.536 L +411.925 156.546 L +412.654 156.557 L +413.382 156.567 L +414.111 156.577 L +414.84 156.587 L +415.568 156.596 L +416.297 156.606 L +417.026 156.616 L +417.755 156.625 L +418.483 156.634 L +419.212 156.644 L +419.941 156.653 L +420.669 156.662 L +421.398 156.671 L +422.127 156.68 L +422.855 156.689 L +423.584 156.697 L +424.313 156.706 L +425.041 156.715 L +425.77 156.723 L +426.499 156.732 L +427.227 156.74 L +427.956 156.748 L +428.685 156.756 L +429.413 156.764 L +430.142 156.772 L +430.871 156.78 L +431.599 156.788 L +432.328 156.796 L +433.057 156.804 L +433.785 156.811 L +434.514 156.819 L +435.243 156.826 L +435.971 156.834 L +436.7 156.841 L +437.429 156.849 L +438.158 156.856 L +438.886 156.863 L +439.615 156.87 L +440.344 156.877 L +441.072 156.884 L +441.801 156.891 L +442.53 156.898 L +s +78.19 227.796 m +78.555 227.699 L +78.919 227.602 L +79.283 227.504 L +79.648 227.407 L +80.012 227.309 L +80.376 227.211 L +80.741 227.113 L +81.105 227.016 L +81.469 226.917 L +81.834 226.819 L +82.198 226.721 L +82.562 226.622 L +82.927 226.524 L +83.291 226.425 L +83.655 226.327 L +84.02 226.228 L +84.384 226.129 L +84.749 226.03 L +85.113 225.93 L +85.477 225.831 L +85.842 225.732 L +86.206 225.632 L +86.57 225.532 L +86.935 225.433 L +87.299 225.333 L +87.663 225.233 L +88.028 225.133 L +88.392 225.032 L +88.756 224.932 L +89.121 224.832 L +89.485 224.731 L +89.849 224.63 L +90.214 224.53 L +90.578 224.429 L +90.942 224.328 L +91.307 224.227 L +91.671 224.125 L +92.035 224.024 L +92.4 223.923 L +92.764 223.821 L +93.128 223.719 L +93.493 223.618 L +93.857 223.516 L +94.221 223.414 L +94.586 223.311 L +94.95 223.209 L +95.314 223.107 L +95.679 223.004 L +96.043 222.902 L +96.407 222.799 L +96.772 222.696 L +97.136 222.593 L +97.5 222.49 L +97.865 222.387 L +98.229 222.284 L +98.593 222.18 L +98.958 222.077 L +99.322 221.973 L +99.686 221.869 L +100.051 221.765 L +100.415 221.661 L +100.779 221.557 L +101.144 221.453 L +101.508 221.349 L +101.872 221.244 L +102.237 221.14 L +102.601 221.035 L +102.965 220.93 L +103.33 220.825 L +103.694 220.72 L +104.058 220.615 L +104.423 220.51 L +104.787 220.404 L +105.152 220.299 L +105.516 220.193 L +105.88 220.087 L +106.245 219.981 L +106.609 219.875 L +106.973 219.769 L +107.338 219.663 L +107.702 219.556 L +108.066 219.45 L +108.431 219.343 L +108.795 219.236 L +109.159 219.129 L +109.524 219.022 L +109.888 218.915 L +110.252 218.808 L +110.617 218.7 L +110.981 218.593 L +111.345 218.485 L +111.71 218.377 L +112.074 218.269 L +112.438 218.161 L +112.803 218.053 L +113.167 217.945 L +113.531 217.836 L +113.896 217.727 L +114.26 217.619 L +114.624 217.51 L +114.989 217.401 L +115.353 217.291 L +115.717 217.182 L +116.082 217.073 L +116.446 216.963 L +116.81 216.853 L +117.175 216.743 L +117.539 216.633 L +117.903 216.523 L +118.268 216.413 L +118.632 216.303 L +118.996 216.192 L +119.361 216.081 L +119.725 215.97 L +120.089 215.859 L +120.454 215.748 L +120.818 215.637 L +121.182 215.525 L +121.547 215.414 L +121.911 215.302 L +122.275 215.19 L +122.64 215.078 L +123.004 214.965 L +123.368 214.853 L +123.733 214.74 L +124.097 214.628 L +124.461 214.515 L +124.826 214.402 L +125.19 214.288 L +125.554 214.175 L +125.919 214.061 L +126.283 213.948 L +126.648 213.834 L +127.012 213.72 L +127.376 213.605 L +127.741 213.491 L +128.105 213.376 L +128.469 213.262 L +128.834 213.147 L +129.198 213.032 L +129.562 212.916 L +129.927 212.801 L +130.291 212.685 L +130.655 212.57 L +131.02 212.454 L +131.384 212.337 L +131.748 212.221 L +132.113 212.105 L +132.477 211.988 L +132.841 211.871 L +133.206 211.754 L +133.57 211.636 L +133.934 211.519 L +134.299 211.401 L +134.663 211.283 L +135.027 211.165 L +135.392 211.047 L +135.756 210.928 L +136.12 210.81 L +136.485 210.691 L +136.849 210.572 L +137.213 210.452 L +137.578 210.332 L +137.942 210.213 L +138.306 210.093 L +138.671 209.973 L +139.035 209.852 L +139.399 209.732 L +139.764 209.611 L +140.128 209.49 L +140.492 209.368 L +140.857 209.247 L +141.221 209.125 L +141.585 209.003 L +141.95 208.881 L +142.314 208.758 L +142.678 208.635 L +143.043 208.513 L +143.407 208.389 L +143.771 208.266 L +144.136 208.142 L +144.5 208.018 L +144.864 207.894 L +145.229 207.77 L +145.593 207.645 L +145.957 207.52 L +146.322 207.395 L +146.686 207.269 L +147.051 207.143 L +147.415 207.017 L +147.779 206.891 L +148.144 206.764 L +148.508 206.637 L +148.872 206.51 L +149.237 206.383 L +149.601 206.255 L +149.965 206.127 L +150.33 205.999 L +150.694 205.87 L +151.058 205.741 L +151.423 205.612 L +151.787 205.483 L +152.151 205.353 L +152.516 205.223 L +152.88 205.092 L +153.244 204.962 L +153.609 204.831 L +153.973 204.699 L +154.337 204.567 L +154.702 204.435 L +155.066 204.303 L +155.43 204.17 L +155.795 204.037 L +156.159 203.904 L +156.523 203.77 L +156.888 203.636 L +157.252 203.502 L +157.616 203.367 L +157.981 203.232 L +158.345 203.096 L +158.709 202.961 L +159.074 202.824 L +159.438 202.688 L +159.802 202.551 L +160.167 202.414 L +160.531 202.276 L +160.895 202.138 L +161.26 201.999 L +161.624 201.86 L +161.988 201.721 L +162.353 201.581 L +162.717 201.441 L +163.081 201.301 L +163.446 201.16 L +163.81 201.018 L +164.174 200.877 L +164.539 200.735 L +164.903 200.592 L +165.267 200.449 L +165.632 200.305 L +165.996 200.161 L +166.36 200.017 L +166.725 199.872 L +167.089 199.727 L +167.454 199.581 L +167.818 199.435 L +168.182 199.288 L +168.547 199.141 L +168.911 198.993 L +169.275 198.845 L +169.64 198.696 L +170.004 198.547 L +170.368 198.397 L +170.733 198.247 L +171.097 198.097 L +171.461 197.945 L +171.826 197.793 L +172.19 197.641 L +172.554 197.488 L +172.919 197.335 L +173.283 197.181 L +173.647 197.026 L +174.012 196.871 L +174.376 196.716 L +174.74 196.559 L +175.105 196.403 L +175.469 196.245 L +175.833 196.087 L +176.198 195.929 L +176.562 195.77 L +176.926 195.61 L +177.291 195.449 L +177.655 195.288 L +178.019 195.126 L +178.384 194.964 L +178.748 194.801 L +179.112 194.637 L +179.477 194.473 L +179.841 194.308 L +180.205 194.142 L +180.57 193.976 L +180.934 193.809 L +181.298 193.641 L +181.663 193.472 L +182.027 193.304 L +182.391 193.134 L +182.756 192.963 L +183.12 192.791 L +183.484 192.62 L +183.849 192.447 L +184.213 192.273 L +184.577 192.098 L +184.942 191.923 L +185.306 191.747 L +185.67 191.57 L +186.035 191.392 L +186.399 191.214 L +186.763 191.035 L +187.128 190.854 L +187.492 190.673 L +187.856 190.491 L +188.221 190.309 L +188.585 190.125 L +188.95 189.94 L +189.314 189.755 L +189.678 189.568 L +190.043 189.381 L +190.407 189.192 L +190.771 189.003 L +191.136 188.813 L +191.5 188.622 L +191.864 188.429 L +192.229 188.236 L +192.593 188.042 L +192.957 187.847 L +193.322 187.65 L +193.686 187.453 L +194.05 187.254 L +194.415 187.054 L +194.779 186.854 L +195.143 186.652 L +195.508 186.449 L +195.872 186.244 L +196.236 186.039 L +196.601 185.832 L +196.965 185.625 L +197.329 185.415 L +197.694 185.205 L +198.058 184.994 L +198.422 184.781 L +198.787 184.567 L +199.151 184.351 L +199.515 184.134 L +199.88 131.817 L +200.244 131.597 L +200.608 131.376 L +200.973 131.153 L +201.337 130.93 L +201.701 130.704 L +202.066 130.477 L +202.43 130.249 L +202.794 130.019 L +203.159 129.787 L +203.523 129.554 L +203.887 129.318 L +204.252 129.082 L +204.616 128.844 L +204.98 128.604 L +205.345 128.362 L +205.709 128.118 L +206.073 127.873 L +206.438 127.625 L +206.802 127.376 L +207.166 127.125 L +207.531 126.872 L +207.895 126.616 L +208.259 126.358 L +208.624 126.099 L +208.988 125.837 L +209.353 125.573 L +209.717 125.307 L +210.081 125.038 L +210.446 124.767 L +210.81 124.494 L +211.174 124.217 L +211.539 123.939 L +211.903 123.657 L +212.267 123.373 L +212.632 123.086 L +212.996 122.797 L +213.36 122.504 L +213.725 122.208 L +214.089 121.91 L +214.453 121.608 L +214.818 121.302 L +215.182 120.994 L +215.546 120.681 L +215.911 120.366 L +216.275 120.046 L +216.639 119.723 L +217.004 119.395 L +217.368 119.064 L +217.732 118.728 L +218.097 118.389 L +218.461 118.044 L +218.825 117.695 L +219.19 117.34 L +219.554 116.982 L +219.918 116.617 L +220.283 116.248 L +220.647 115.872 L +221.011 115.491 L +221.376 115.103 L +221.74 114.71 L +222.104 114.31 L +222.469 113.903 L +222.833 113.488 L +223.197 113.067 L +223.562 112.637 L +223.926 112.199 L +224.29 111.753 L +224.655 111.297 L +225.019 110.833 L +225.383 110.358 L +225.748 109.874 L +226.112 109.378 L +226.476 108.871 L +226.841 108.353 L +227.205 107.821 L +227.569 107.276 L +227.934 106.717 L +228.298 106.144 L +228.662 105.556 L +229.027 104.951 L +229.391 104.329 L +229.756 103.689 L +230.12 103.031 L +230.484 102.352 L +230.849 101.653 L +231.213 100.932 L +231.577 100.19 L +231.942 99.426 L +232.306 98.638 L +232.67 97.827 L +233.035 96.995 L +233.399 96.143 L +233.763 95.275 L +234.128 94.395 L +234.492 93.515 L +234.856 92.647 L +235.221 91.816 L +235.585 91.055 L +235.949 90.419 L +236.314 89.987 L +236.678 89.872 L +237.042 90.228 L +237.407 91.227 L +237.771 93.008 L +238.135 95.595 L +238.5 98.813 L +238.864 102.357 L +239.228 105.928 L +239.593 109.305 L +239.957 112.388 L +240.321 115.15 L +240.686 117.611 L +241.05 119.793 L +241.414 121.734 L +241.779 123.473 L +242.143 125.035 L +242.507 126.442 L +242.872 127.722 L +243.236 128.889 L +243.6 129.959 L +243.965 130.941 L +244.329 131.852 L +244.693 132.693 L +245.058 133.477 L +245.422 134.21 L +245.786 134.895 L +246.151 135.537 L +246.515 136.14 L +246.879 136.711 L +247.244 137.249 L +247.608 137.759 L +247.972 138.243 L +248.337 138.702 L +248.701 139.14 L +249.065 139.557 L +249.43 139.955 L +249.794 140.335 L +250.159 140.699 L +250.523 141.048 L +250.887 141.382 L +251.252 141.704 L +251.616 142.013 L +251.98 142.31 L +252.345 142.596 L +252.709 142.871 L +253.073 143.138 L +253.438 143.394 L +253.802 143.643 L +254.166 143.882 L +254.531 144.115 L +254.895 144.339 L +255.259 144.557 L +255.624 144.768 L +255.988 144.972 L +256.352 145.171 L +256.717 145.364 L +257.081 145.551 L +257.445 145.733 L +257.81 145.91 L +258.174 146.082 L +258.538 146.25 L +258.903 146.413 L +259.267 146.572 L +259.631 146.727 L +259.996 146.878 L +260.36 147.025 L +260.724 147.169 L +261.089 147.309 L +261.453 147.446 L +261.817 147.579 L +262.182 147.71 L +262.546 147.837 L +262.91 147.962 L +263.275 148.084 L +263.639 148.203 L +264.003 148.32 L +264.368 148.434 L +264.732 148.546 L +265.096 148.655 L +265.461 148.763 L +265.825 148.868 L +266.189 148.97 L +266.554 149.071 L +266.918 149.17 L +267.282 149.267 L +267.647 149.362 L +268.011 149.455 L +268.375 149.547 L +268.74 149.636 L +269.104 149.724 L +269.468 149.811 L +269.833 149.896 L +270.197 149.979 L +270.561 150.061 L +270.926 150.141 L +271.29 150.22 L +271.655 150.298 L +272.019 150.374 L +272.383 150.449 L +272.748 150.523 L +273.112 150.595 L +273.476 150.667 L +273.841 150.737 L +274.205 150.806 L +274.569 150.874 L +274.934 150.941 L +275.298 151.006 L +275.662 151.071 L +276.027 151.135 L +276.391 151.198 L +276.755 151.259 L +277.12 151.32 L +277.484 151.38 L +277.848 151.439 L +278.213 151.497 L +278.577 151.554 L +278.941 151.611 L +279.306 151.666 L +279.67 151.721 L +280.034 151.775 L +280.399 151.828 L +280.763 151.881 L +281.127 151.932 L +281.492 151.983 L +281.856 152.034 L +282.22 152.083 L +282.585 152.132 L +282.949 152.181 L +283.313 152.228 L +283.678 152.275 L +284.042 152.321 L +284.406 152.367 L +284.771 152.412 L +285.135 152.457 L +285.499 152.501 L +285.864 152.544 L +286.228 152.587 L +286.592 152.63 L +286.957 152.671 L +287.321 152.713 L +287.685 152.753 L +288.05 152.794 L +288.414 152.833 L +288.778 152.872 L +289.143 152.911 L +289.507 152.949 L +289.871 152.987 L +290.236 153.025 L +290.6 153.062 L +290.964 153.098 L +291.329 153.134 L +291.693 153.17 L +292.058 153.205 L +292.422 153.24 L +292.786 153.274 L +293.151 153.308 L +293.515 153.342 L +293.879 153.375 L +294.244 153.408 L +294.608 153.44 L +294.972 153.473 L +295.337 153.504 L +295.701 153.536 L +296.065 153.567 L +296.43 153.597 L +296.794 153.628 L +297.158 153.658 L +297.523 153.688 L +297.887 153.717 L +298.251 153.746 L +298.616 153.775 L +298.98 153.803 L +299.344 153.832 L +299.709 153.86 L +300.073 153.887 L +300.437 153.914 L +300.802 153.941 L +301.166 153.968 L +301.53 153.995 L +301.895 154.021 L +302.259 154.047 L +302.623 154.072 L +302.988 154.098 L +303.352 154.123 L +303.716 154.148 L +304.081 154.173 L +304.445 154.197 L +304.809 154.221 L +305.174 154.245 L +305.538 154.269 L +305.902 154.292 L +306.267 154.315 L +306.631 154.338 L +306.995 154.361 L +307.36 154.384 L +307.724 154.406 L +308.088 154.428 L +308.453 154.45 L +308.817 154.472 L +309.181 154.493 L +309.546 154.515 L +309.91 154.536 L +310.274 154.557 L +310.639 154.578 L +311.003 154.598 L +311.367 154.618 L +311.732 154.639 L +312.096 154.659 L +312.461 154.678 L +312.825 154.698 L +313.189 154.717 L +313.554 154.737 L +313.918 154.756 L +314.282 154.775 L +314.647 154.793 L +315.011 154.812 L +315.375 154.83 L +315.74 154.849 L +316.104 154.867 L +316.468 154.885 L +316.833 154.902 L +317.197 154.92 L +317.561 154.938 L +317.926 154.955 L +318.29 154.972 L +318.654 154.989 L +319.019 155.006 L +319.383 155.023 L +319.747 155.039 L +320.112 155.056 L +320.476 155.072 L +320.84 155.088 L +321.205 155.104 L +321.569 155.12 L +321.933 155.136 L +322.298 155.152 L +322.662 155.167 L +323.026 155.183 L +323.391 155.198 L +323.755 155.213 L +324.119 155.228 L +324.484 155.243 L +324.848 155.258 L +325.212 155.272 L +325.577 155.287 L +325.941 155.301 L +326.305 155.316 L +326.67 155.33 L +327.034 155.344 L +327.398 155.358 L +327.763 155.372 L +328.127 155.386 L +328.491 155.399 L +328.856 155.413 L +329.22 155.426 L +329.584 155.439 L +329.949 155.453 L +330.313 155.466 L +330.677 155.479 L +331.042 155.492 L +331.406 155.505 L +331.77 155.517 L +332.135 155.53 L +332.499 155.542 L +332.864 155.555 L +333.228 155.567 L +333.592 155.579 L +333.957 155.592 L +334.321 155.604 L +334.685 155.616 L +335.05 155.628 L +335.414 155.639 L +335.778 155.651 L +336.143 155.663 L +336.507 155.674 L +336.871 155.686 L +337.236 155.697 L +337.6 155.708 L +337.964 155.719 L +338.329 155.731 L +338.693 155.742 L +339.057 155.753 L +339.422 155.763 L +339.786 155.774 L +340.15 155.785 L +340.515 155.796 L +340.879 155.806 L +341.243 155.817 L +341.608 155.827 L +341.972 155.838 L +342.336 155.848 L +342.701 155.858 L +343.065 155.868 L +343.429 155.878 L +343.794 155.888 L +344.158 155.898 L +344.522 155.908 L +344.887 155.918 L +345.251 155.927 L +345.615 155.937 L +345.98 155.947 L +346.344 155.956 L +346.708 155.966 L +347.073 155.975 L +347.437 155.984 L +347.801 155.994 L +348.166 156.003 L +348.53 156.012 L +348.894 156.021 L +349.259 156.03 L +349.623 156.039 L +349.987 156.048 L +350.352 156.057 L +350.716 156.065 L +351.08 156.074 L +351.445 156.083 L +351.809 156.091 L +352.173 156.1 L +352.538 156.108 L +352.902 156.117 L +353.266 156.125 L +353.631 156.133 L +353.995 156.142 L +354.36 156.15 L +354.724 156.158 L +355.088 156.166 L +355.453 156.174 L +355.817 156.182 L +356.181 156.19 L +356.546 156.198 L +356.91 156.206 L +357.274 156.214 L +357.639 156.221 L +358.003 156.229 L +358.367 156.237 L +358.732 156.244 L +359.096 156.252 L +359.46 156.259 L +359.825 156.267 L +360.189 156.274 L +360.553 156.282 L +360.918 156.289 L +361.282 156.296 L +361.646 156.303 L +362.011 156.311 L +362.375 156.318 L +362.739 156.325 L +363.104 156.332 L +363.468 156.339 L +363.832 156.346 L +364.197 156.353 L +364.561 156.36 L +364.925 156.366 L +365.29 156.373 L +365.654 156.38 L +366.018 156.387 L +366.383 156.393 L +366.747 156.4 L +367.111 156.407 L +367.476 156.413 L +367.84 156.42 L +368.204 156.426 L +368.569 156.433 L +368.933 156.439 L +369.297 156.445 L +369.662 156.452 L +370.026 156.458 L +370.39 156.464 L +370.755 156.47 L +371.119 156.476 L +371.483 156.483 L +371.848 156.489 L +372.212 156.495 L +372.576 156.501 L +372.941 156.507 L +373.305 156.513 L +373.669 156.519 L +374.034 156.524 L +374.398 156.53 L +374.763 156.536 L +375.127 156.542 L +375.491 156.548 L +375.856 156.553 L +376.22 156.559 L +376.584 156.565 L +376.949 156.57 L +377.313 156.576 L +377.677 156.581 L +378.042 156.587 L +378.406 156.592 L +378.77 156.598 L +379.135 156.603 L +379.499 156.609 L +379.863 156.614 L +380.228 156.619 L +380.592 156.625 L +380.956 156.63 L +381.321 156.635 L +381.685 156.64 L +382.049 156.646 L +382.414 156.651 L +382.778 156.656 L +383.142 156.661 L +383.507 156.666 L +383.871 156.671 L +384.235 156.676 L +384.6 156.681 L +384.964 156.686 L +385.328 156.691 L +385.693 156.696 L +386.057 156.701 L +386.421 156.706 L +386.786 156.71 L +387.15 156.715 L +387.514 156.72 L +387.879 156.725 L +388.243 156.729 L +388.607 156.734 L +388.972 156.739 L +389.336 156.743 L +389.7 156.748 L +390.065 156.753 L +390.429 156.757 L +390.793 156.762 L +391.158 156.766 L +391.522 156.771 L +391.886 156.775 L +392.251 156.78 L +392.615 156.784 L +392.979 156.788 L +393.344 156.793 L +393.708 156.797 L +394.072 156.802 L +394.437 156.806 L +394.801 156.81 L +395.166 156.814 L +395.53 156.819 L +395.894 156.823 L +396.259 156.827 L +396.623 156.831 L +396.987 156.835 L +397.352 156.84 L +397.716 156.844 L +398.08 156.848 L +398.445 156.852 L +398.809 156.856 L +399.173 156.86 L +399.538 156.864 L +399.902 156.868 L +400.266 156.872 L +400.631 156.876 L +400.995 156.88 L +401.359 156.884 L +401.724 156.887 L +402.088 156.891 L +402.452 156.895 L +402.817 156.899 L +403.181 156.903 L +403.545 156.907 L +403.91 156.91 L +404.274 156.914 L +404.638 156.918 L +405.003 156.921 L +405.367 156.925 L +405.731 156.929 L +406.096 156.933 L +406.46 156.936 L +406.824 156.94 L +407.189 156.943 L +407.553 156.947 L +407.917 156.95 L +408.282 156.954 L +408.646 156.958 L +409.01 156.961 L +409.375 156.965 L +409.739 156.968 L +410.103 156.972 L +410.468 156.975 L +410.832 156.978 L +411.196 156.982 L +411.561 156.985 L +411.925 156.989 L +412.289 156.992 L +412.654 156.995 L +413.018 156.999 L +413.382 157.002 L +413.747 157.005 L +414.111 157.008 L +414.475 157.012 L +414.84 157.015 L +415.204 157.018 L +415.568 157.021 L +415.933 157.025 L +416.297 157.028 L +416.662 157.031 L +417.026 157.034 L +417.39 157.037 L +417.755 157.04 L +418.119 157.043 L +418.483 157.047 L +418.848 157.05 L +419.212 157.053 L +419.576 157.056 L +419.941 157.059 L +420.305 157.062 L +420.669 157.065 L +421.034 157.068 L +421.398 157.071 L +421.762 157.074 L +422.127 157.077 L +422.491 157.08 L +422.855 157.083 L +423.22 157.085 L +423.584 157.088 L +423.948 157.091 L +424.313 157.094 L +424.677 157.097 L +425.041 157.1 L +425.406 157.103 L +425.77 157.105 L +426.134 157.108 L +426.499 157.111 L +426.863 157.114 L +427.227 157.117 L +427.592 157.119 L +427.956 157.122 L +428.32 157.125 L +428.685 157.127 L +429.049 157.13 L +429.413 157.133 L +429.778 157.136 L +430.142 157.138 L +430.506 157.141 L +430.871 157.143 L +431.235 157.146 L +431.599 157.149 L +431.964 157.151 L +432.328 157.154 L +432.692 157.156 L +433.057 157.159 L +433.421 157.162 L +433.785 157.164 L +434.15 157.167 L +434.514 157.169 L +434.878 157.172 L +435.243 157.174 L +435.607 157.177 L +435.971 157.179 L +436.336 157.182 L +436.7 157.184 L +437.065 157.187 L +437.429 157.189 L +437.793 157.191 L +438.158 157.194 L +438.522 157.196 L +438.886 157.199 L +439.251 157.201 L +439.615 157.203 L +439.979 157.206 L +440.344 157.208 L +440.708 157.21 L +441.072 157.213 L +441.437 157.215 L +441.801 157.217 L +442.165 157.22 L +442.53 157.222 L +s +78.19 230.21 m +78.919 229.983 L +79.648 229.756 L +80.376 229.529 L +81.105 229.302 L +81.834 229.074 L +82.562 228.847 L +83.291 228.619 L +84.02 228.391 L +84.749 228.163 L +85.477 227.935 L +86.206 227.707 L +86.935 227.479 L +87.663 227.251 L +88.392 227.023 L +89.121 226.795 L +89.849 226.567 L +90.578 226.339 L +91.307 226.111 L +92.035 225.884 L +92.764 225.656 L +93.493 225.429 L +94.221 225.201 L +94.95 224.974 L +95.679 224.747 L +96.407 224.52 L +97.136 224.294 L +97.865 224.067 L +98.593 223.841 L +99.322 223.615 L +100.051 223.39 L +100.779 223.164 L +101.508 222.939 L +102.237 222.714 L +102.965 222.49 L +103.694 222.266 L +104.423 222.042 L +105.152 221.819 L +105.88 221.596 L +106.609 221.373 L +107.338 221.151 L +108.066 220.929 L +108.795 220.707 L +109.524 220.486 L +110.252 220.265 L +110.981 220.045 L +111.71 219.825 L +112.438 219.606 L +113.167 219.387 L +113.896 219.169 L +114.624 218.951 L +115.353 218.733 L +116.082 218.517 L +116.81 218.3 L +117.539 218.085 L +118.268 217.869 L +118.996 217.655 L +119.725 217.44 L +120.454 217.227 L +121.182 217.014 L +121.911 216.801 L +122.64 216.59 L +123.368 216.378 L +124.097 216.168 L +124.826 215.958 L +125.554 215.748 L +126.283 215.539 L +127.012 163.232 L +127.741 163.025 L +128.469 162.818 L +129.198 162.612 L +129.927 162.406 L +130.655 162.201 L +131.384 161.997 L +132.113 161.794 L +132.841 161.591 L +133.57 161.39 L +134.299 161.188 L +135.027 160.988 L +135.756 160.789 L +136.485 160.59 L +137.213 160.392 L +137.942 160.194 L +138.671 159.998 L +139.399 159.803 L +140.128 159.608 L +140.857 159.414 L +141.585 159.221 L +142.314 159.029 L +143.043 158.839 L +143.771 158.648 L +144.5 158.459 L +145.229 158.271 L +145.957 158.084 L +146.686 157.898 L +147.415 157.714 L +148.144 157.53 L +148.872 157.347 L +149.601 157.166 L +150.33 156.985 L +151.058 156.806 L +151.787 156.628 L +152.516 156.452 L +153.244 156.277 L +153.973 156.103 L +154.702 155.931 L +155.43 155.761 L +156.159 155.591 L +156.888 155.424 L +157.616 155.258 L +158.345 155.094 L +159.074 154.931 L +159.802 154.771 L +160.531 154.612 L +161.26 154.455 L +161.988 154.3 L +162.717 154.148 L +163.446 153.997 L +164.174 153.849 L +164.903 153.703 L +165.632 153.56 L +166.36 153.419 L +167.089 153.28 L +167.818 153.145 L +168.547 153.012 L +169.275 152.882 L +170.004 152.754 L +170.733 152.631 L +171.461 152.51 L +172.19 152.392 L +172.919 152.278 L +173.647 152.167 L +174.376 152.06 L +175.105 151.956 L +175.833 151.856 L +176.562 151.76 L +177.291 151.668 L +178.019 151.58 L +178.748 151.497 L +179.477 151.417 L +180.205 151.342 L +180.934 151.271 L +181.663 151.205 L +182.391 151.143 L +183.12 151.086 L +183.849 151.033 L +184.577 150.985 L +185.306 150.942 L +186.035 150.904 L +186.763 150.87 L +187.492 150.841 L +188.221 150.817 L +188.95 150.797 L +189.678 150.783 L +190.407 150.773 L +191.136 150.767 L +191.864 150.766 L +192.593 150.77 L +193.322 150.778 L +194.05 150.79 L +194.779 150.806 L +195.508 150.827 L +196.236 150.851 L +196.965 150.88 L +197.694 150.911 L +198.422 150.947 L +199.151 150.986 L +199.88 151.028 L +200.608 151.073 L +201.337 151.121 L +202.066 151.172 L +202.794 151.225 L +203.523 151.281 L +204.252 151.339 L +204.98 151.398 L +205.709 151.46 L +206.438 151.524 L +207.166 151.589 L +207.895 151.656 L +208.624 151.723 L +209.353 151.792 L +210.081 151.862 L +210.81 151.933 L +211.539 152.005 L +212.267 152.077 L +212.996 152.149 L +213.725 152.222 L +214.453 152.295 L +215.182 152.368 L +215.911 152.441 L +216.639 152.515 L +217.368 152.588 L +218.097 152.661 L +218.825 152.733 L +219.554 152.806 L +220.283 152.877 L +221.011 152.949 L +221.74 153.019 L +222.469 153.09 L +223.197 153.159 L +223.926 153.228 L +224.655 153.296 L +225.383 153.364 L +226.112 153.431 L +226.841 153.497 L +227.569 153.562 L +228.298 153.626 L +229.027 153.69 L +229.756 153.753 L +230.484 153.815 L +231.213 153.876 L +231.942 153.936 L +232.67 153.995 L +233.399 154.053 L +234.128 154.111 L +234.856 154.167 L +235.585 154.223 L +236.314 154.278 L +237.042 154.332 L +237.771 154.385 L +238.5 154.437 L +239.228 154.488 L +239.957 154.539 L +240.686 154.589 L +241.414 154.637 L +242.143 154.685 L +242.872 154.733 L +243.6 154.779 L +244.329 154.824 L +245.058 154.869 L +245.786 154.913 L +246.515 154.957 L +247.244 154.999 L +247.972 155.041 L +248.701 155.082 L +249.43 155.122 L +250.159 155.162 L +250.887 155.201 L +251.616 155.239 L +252.345 155.276 L +253.073 155.313 L +253.802 155.35 L +254.531 155.385 L +255.259 155.42 L +255.988 155.455 L +256.717 155.488 L +257.445 155.521 L +258.174 155.554 L +258.903 155.586 L +259.631 155.618 L +260.36 155.648 L +261.089 155.679 L +261.817 155.709 L +262.546 155.738 L +263.275 155.767 L +264.003 155.795 L +264.732 155.823 L +265.461 155.85 L +266.189 155.877 L +266.918 155.904 L +267.647 155.93 L +268.375 155.955 L +269.104 155.98 L +269.833 156.005 L +270.561 156.029 L +271.29 156.053 L +272.019 156.077 L +272.748 156.1 L +273.476 156.122 L +274.205 156.145 L +274.934 156.167 L +275.662 156.188 L +276.391 156.209 L +277.12 156.23 L +277.848 156.251 L +278.577 156.271 L +279.306 156.291 L +280.034 156.31 L +280.763 156.33 L +281.492 156.349 L +282.22 156.367 L +282.949 156.385 L +283.678 156.404 L +284.406 156.421 L +285.135 156.439 L +285.864 156.456 L +286.592 156.473 L +287.321 156.49 L +288.05 156.506 L +288.778 156.522 L +289.507 156.538 L +290.236 156.554 L +290.964 156.569 L +291.693 156.584 L +292.422 156.599 L +293.151 156.614 L +293.879 156.628 L +294.608 156.643 L +295.337 156.657 L +296.065 156.671 L +296.794 156.684 L +297.523 156.698 L +298.251 156.711 L +298.98 156.724 L +299.709 156.737 L +300.437 156.75 L +301.166 156.762 L +301.895 156.774 L +302.623 156.787 L +303.352 156.799 L +304.081 156.81 L +304.809 156.822 L +305.538 156.833 L +306.267 156.845 L +306.995 156.856 L +307.724 156.867 L +308.453 156.878 L +309.181 156.888 L +309.91 156.899 L +310.639 156.909 L +311.367 156.92 L +312.096 156.93 L +312.825 156.94 L +313.554 156.949 L +314.282 156.959 L +315.011 156.969 L +315.74 156.978 L +316.468 156.988 L +317.197 156.997 L +317.926 157.006 L +318.654 157.015 L +319.383 157.024 L +320.112 157.032 L +320.84 157.041 L +321.569 157.049 L +322.298 157.058 L +323.026 157.066 L +323.755 157.074 L +324.484 157.082 L +325.212 157.09 L +325.941 157.098 L +326.67 157.106 L +327.398 157.113 L +328.127 157.121 L +328.856 157.128 L +329.584 157.136 L +330.313 157.143 L +331.042 157.15 L +331.77 157.157 L +332.499 157.164 L +333.228 157.171 L +333.957 157.178 L +334.685 157.185 L +335.414 157.192 L +336.143 157.198 L +336.871 157.205 L +337.6 157.211 L +338.329 157.217 L +339.057 157.224 L +339.786 157.23 L +340.515 157.236 L +341.243 157.242 L +341.972 157.248 L +342.701 157.254 L +343.429 157.26 L +344.158 157.266 L +344.887 157.271 L +345.615 157.277 L +346.344 157.283 L +347.073 157.288 L +347.801 157.294 L +348.53 157.299 L +349.259 157.304 L +349.987 157.31 L +350.716 157.315 L +351.445 157.32 L +352.173 157.325 L +352.902 157.33 L +353.631 157.335 L +354.36 157.34 L +355.088 157.345 L +355.817 157.35 L +356.546 157.354 L +357.274 157.359 L +358.003 157.364 L +358.732 157.368 L +359.46 157.373 L +360.189 157.377 L +360.918 157.382 L +361.646 157.386 L +362.375 157.391 L +363.104 157.395 L +363.832 157.399 L +364.561 157.403 L +365.29 157.408 L +366.018 157.412 L +366.747 157.416 L +367.476 157.42 L +368.204 157.424 L +368.933 157.428 L +369.662 157.432 L +370.39 157.436 L +371.119 157.439 L +371.848 157.443 L +372.576 157.447 L +373.305 157.451 L +374.034 157.454 L +374.763 157.458 L +375.491 157.462 L +376.22 157.465 L +376.949 157.469 L +377.677 157.472 L +378.406 157.476 L +379.135 157.479 L +379.863 157.482 L +380.592 157.486 L +381.321 157.489 L +382.049 157.492 L +382.778 157.496 L +383.507 157.499 L +384.235 157.502 L +384.964 157.505 L +385.693 157.508 L +386.421 157.512 L +387.15 157.515 L +387.879 157.518 L +388.607 157.521 L +389.336 157.524 L +390.065 157.527 L +390.793 157.53 L +391.522 157.532 L +392.251 157.535 L +392.979 157.538 L +393.708 157.541 L +394.437 157.544 L +395.166 157.547 L +395.894 157.549 L +396.623 157.552 L +397.352 157.555 L +398.08 157.557 L +398.809 157.56 L +399.538 157.563 L +400.266 157.565 L +400.995 157.568 L +401.724 157.57 L +402.452 157.573 L +403.181 157.575 L +403.91 157.578 L +404.638 157.58 L +405.367 157.583 L +406.096 157.585 L +406.824 157.587 L +407.553 157.59 L +408.282 157.592 L +409.01 157.594 L +409.739 157.597 L +410.468 157.599 L +411.196 157.601 L +411.925 157.603 L +412.654 157.606 L +413.382 157.608 L +414.111 157.61 L +414.84 157.612 L +415.568 157.614 L +416.297 157.616 L +417.026 157.619 L +417.755 157.621 L +418.483 157.623 L +419.212 157.625 L +419.941 157.627 L +420.669 157.629 L +421.398 157.631 L +422.127 157.633 L +422.855 157.635 L +423.584 157.637 L +424.313 157.639 L +425.041 157.64 L +425.77 157.642 L +426.499 157.644 L +427.227 157.646 L +427.956 157.648 L +428.685 157.65 L +429.413 157.652 L +430.142 157.653 L +430.871 157.655 L +431.599 157.657 L +432.328 157.659 L +433.057 157.66 L +433.785 157.662 L +434.514 157.664 L +435.243 157.666 L +435.971 157.667 L +436.7 157.669 L +437.429 157.671 L +438.158 157.672 L +438.886 157.674 L +439.615 157.675 L +440.344 157.677 L +441.072 157.679 L +441.801 157.68 L +442.53 157.682 L +s +P +0 g +0.144 w +[ ] 0 setdash +3.25 setmiterlimit +450.12 237.508 m +70.6 237.508 L +s +70.6 237.508 m +70.6 2.952 L +s +1 g +[ ] 0 setdash +70.6 2.952 m +450.12 2.952 L +s +450.12 2.952 m +450.12 237.508 L +s +0 g +[ ] 0 setdash +p +0 setlinecap +78.19 237.508 m +78.19 234.611 L +s +P +p +np 74 239 m +74 253 L +82 253 L +82 239 L +cp +clip np +p +1 w +0 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +[1 0 0 1 75.19 239.668 ] concat +1 w +[ ] 0 setdash +p +np -2.19 -1.668 m +-2.19 14.332 L +7.81 14.332 L +7.81 -1.668 L +cp +clip np +/MISOfy +{ + /newfontname exch def + /oldfontname exch def + oldfontname findfont + dup length dict begin + {1 index/FID ne{def}{pop pop}ifelse}forall + /Encoding ISOLatin1Encoding def + currentdict + end + newfontname exch definefont pop +}def +%%IncludeResource: font Times-Roman +%%IncludeFont: Times-Roman +%%BeginResource: font Times-Roman-MISO +%%BeginFont: Times-Roman-MISO +/Times-Roman /Times-Roman-MISO MISOfy +%%EndFont +%%EndResource +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +11.52 /Times-Roman-MISO Msf +0 10.5 m +(0) N +P +[1 0 0 1 -75.19 -239.668 ] concat +1 w +[ ] 0 setdash +P +P +[ ] 0 setdash +p +0 setlinecap +92.764 237.508 m +92.764 235.77 L +s +P +p +0 setlinecap +107.338 237.508 m +107.338 235.77 L +s +P +p +0 setlinecap +121.911 237.508 m +121.911 235.77 L +s +P +p +0 setlinecap +136.485 237.508 m +136.485 235.77 L +s +P +p +0 setlinecap +151.058 237.508 m +151.058 234.611 L +s +P +p +np 147 239 m +147 253 L +155 253 L +155 239 L +cp +clip np +p +1 w +0 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +[1 0 0 1 148.058 239.668 ] concat +1 w +[ ] 0 setdash +p +np -2.058 -1.668 m +-2.058 14.332 L +7.942 14.332 L +7.942 -1.668 L +cp +clip np +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +11.52 /Times-Roman-MISO Msf +0 10.5 m +(1) N +P +[1 0 0 1 -148.058 -239.668 ] concat +1 w +[ ] 0 setdash +P +P +[ ] 0 setdash +p +0 setlinecap +165.632 237.508 m +165.632 235.77 L +s +P +p +0 setlinecap +180.205 237.508 m +180.205 235.77 L +s +P +p +0 setlinecap +194.779 237.508 m +194.779 235.77 L +s +P +p +0 setlinecap +209.353 237.508 m +209.353 235.77 L +s +P +p +0 setlinecap +223.926 237.508 m +223.926 234.611 L +s +P +p +np 220 239 m +220 253 L +228 253 L +228 239 L +cp +clip np +p +1 w +0 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +[1 0 0 1 220.926 239.668 ] concat +1 w +[ ] 0 setdash +p +np -1.926 -1.668 m +-1.926 14.332 L +8.074 14.332 L +8.074 -1.668 L +cp +clip np +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +11.52 /Times-Roman-MISO Msf +0 10.5 m +(2) N +P +[1 0 0 1 -220.926 -239.668 ] concat +1 w +[ ] 0 setdash +P +P +[ ] 0 setdash +p +0 setlinecap +238.5 237.508 m +238.5 235.77 L +s +P +p +0 setlinecap +253.073 237.508 m +253.073 235.77 L +s +P +p +0 setlinecap +267.647 237.508 m +267.647 235.77 L +s +P +p +0 setlinecap +282.22 237.508 m +282.22 235.77 L +s +P +p +0 setlinecap +296.794 237.508 m +296.794 234.611 L +s +P +p +np 293 239 m +293 253 L +301 253 L +301 239 L +cp +clip np +p +1 w +0 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +[1 0 0 1 293.794 239.668 ] concat +1 w +[ ] 0 setdash +p +np -1.794 -1.668 m +-1.794 14.332 L +8.206 14.332 L +8.206 -1.668 L +cp +clip np +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +11.52 /Times-Roman-MISO Msf +0 10.5 m +(3) N +P +[1 0 0 1 -293.794 -239.668 ] concat +1 w +[ ] 0 setdash +P +P +[ ] 0 setdash +p +0 setlinecap +311.367 237.508 m +311.367 235.77 L +s +P +p +0 setlinecap +325.941 237.508 m +325.941 235.77 L +s +P +p +0 setlinecap +340.515 237.508 m +340.515 235.77 L +s +P +p +0 setlinecap +355.088 237.508 m +355.088 235.77 L +s +P +p +0 setlinecap +369.662 237.508 m +369.662 234.611 L +s +P +p +np 365 239 m +365 253 L +374 253 L +374 239 L +cp +clip np +p +1 w +0 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +[1 0 0 1 366.287 239.668 ] concat +1 w +[ ] 0 setdash +p +np -2.287 -1.668 m +-2.287 14.332 L +8.713 14.332 L +8.713 -1.668 L +cp +clip np +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +11.52 /Times-Roman-MISO Msf +0.75 10.5 m +(4) N +P +[1 0 0 1 -366.287 -239.668 ] concat +1 w +[ ] 0 setdash +P +P +[ ] 0 setdash +p +0 setlinecap +384.235 237.508 m +384.235 235.77 L +s +P +p +0 setlinecap +398.809 237.508 m +398.809 235.77 L +s +P +p +0 setlinecap +413.382 237.508 m +413.382 235.77 L +s +P +p +0 setlinecap +427.956 237.508 m +427.956 235.77 L +s +P +p +0 setlinecap +442.53 237.508 m +442.53 234.611 L +s +P +p +np 439 239 m +439 253 L +447 253 L +447 239 L +cp +clip np +p +1 w +0 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +[1 0 0 1 439.53 239.668 ] concat +1 w +[ ] 0 setdash +p +np -1.53 -1.668 m +-1.53 14.332 L +8.47 14.332 L +8.47 -1.668 L +cp +clip np +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +11.52 /Times-Roman-MISO Msf +0 10.5 m +(5) N +P +[1 0 0 1 -439.53 -239.668 ] concat +1 w +[ ] 0 setdash +P +P +[ ] 0 setdash +p +0 setlinecap +70.6 210.041 m +73.497 210.041 L +s +P +p +np 61 203 m +61 217 L +69 217 L +69 203 L +cp +clip np +p +1 w +0 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +[1 0 0 1 62.44 203.666 ] concat +1 w +[ ] 0 setdash +p +np -2.44 -1.666 m +-2.44 14.334 L +7.56 14.334 L +7.56 -1.666 L +cp +clip np +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +11.52 /Times-Roman-MISO Msf +0 10.5 m +(0) N +P +[1 0 0 1 -62.44 -203.666 ] concat +1 w +[ ] 0 setdash +P +P +[ ] 0 setdash +p +0 setlinecap +70.6 157.941 m +73.497 157.941 L +s +P +p +np 61 151 m +61 165 L +69 165 L +69 151 L +cp +clip np +p +1 w +0 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +[1 0 0 1 61.69 151.566 ] concat +1 w +[ ] 0 setdash +p +np -1.69 -1.566 m +-1.69 14.434 L +8.31 14.434 L +8.31 -1.566 L +cp +clip np +%%BeginResource: font Mathematica1 +%%BeginFont: Mathematica1 +%!PS-AdobeFont-1.0: Mathematica1 001.000 +%%CreationDate: 8/26/01 at 4:07 PM +%%VMusage: 1024 31527 +% Mathematica typeface design by Andre Kuzniarek, with Gregg Snyder and Stephen Wolfram. Copyright \(c\) 1996-2001 Wolfram Research, Inc. [http://www.wolfram.com]. All rights reserved. [Font version 2.00] +% ADL: 800 200 0 +%%EndComments +FontDirectory/Mathematica1 known{/Mathematica1 findfont dup/UniqueID known{dup +/UniqueID get 5095641 eq exch/FontType get 1 eq and}{pop false}ifelse +{save true}{false}ifelse}{false}ifelse +20 dict begin +/FontInfo 16 dict dup begin + /version (001.000) readonly def + /FullName (Mathematica1) readonly def + /FamilyName (Mathematica1) readonly def + /Weight (Medium) readonly def + /ItalicAngle 0 def + /isFixedPitch false def + /UnderlinePosition -133 def + /UnderlineThickness 20 def + /Notice (Mathematica typeface design by Andre Kuzniarek, with Gregg Snyder and Stephen Wolfram. Copyright \(c\) 1996-2001 Wolfram Research, Inc. [http://www.wolfram.com]. All rights reserved. [Font version 2.00]) readonly def + /em 1000 def + /ascent 800 def + /descent 200 def +end readonly def +/FontName /Mathematica1 def +/Encoding 256 array +dup 0/NUL put +dup 1/Eth put +dup 2/eth put +dup 3/Lslash put +dup 4/lslash put +dup 5/Scaron put +dup 6/scaron put +dup 7/Yacute put +dup 8/yacute put +dup 9/HT put +dup 10/LF put +dup 11/Thorn put +dup 12/thorn put +dup 13/CR put +dup 14/Zcaron put +dup 15/zcaron put +dup 16/DLE put +dup 17/DC1 put +dup 18/DC2 put +dup 19/DC3 put +dup 20/DC4 put +dup 21/onehalf put +dup 22/onequarter put +dup 23/onesuperior put +dup 24/threequarters put +dup 25/threesuperior put +dup 26/twosuperior put +dup 27/brokenbar put +dup 28/minus put +dup 29/multiply put +dup 30/RS put +dup 31/US put +dup 32/Space put +dup 33/Exclamation put +dup 34/ForAll put +dup 35/NumberSign put +dup 36/Exists put +dup 37/Percent put +dup 38/Ampersand put +dup 39/SmallMember put +dup 40/LParen put +dup 41/RParen put +dup 42/Star put +dup 43/Plus put +dup 44/Comma put +dup 45/Minus put +dup 46/Period put +dup 47/Slash put +dup 48/Zero put +dup 49/One put +dup 50/Two put +dup 51/Three put +dup 52/Four put +dup 53/Five put +dup 54/Six put +dup 55/Seven put +dup 56/Eight put +dup 57/Nine put +dup 58/Colon put +dup 59/SemiColon put +dup 60/Less put +dup 61/Equal put +dup 62/Greater put +dup 63/Question put +dup 64/TildeFullEqual put +dup 65/CapAlpha put +dup 66/CapBeta put +dup 67/CapChi put +dup 68/CapDelta put +dup 69/CapEpsilon put +dup 70/CapPhi put +dup 71/CapGamma put +dup 72/CapEta put +dup 73/CapIota put +dup 74/CurlyTheta put +dup 75/CapKappa put +dup 76/CapLambda put +dup 77/CapMu put +dup 78/CapNu put +dup 79/CapOmicron put +dup 80/CapPi put +dup 81/CapTheta put +dup 82/CapRho put +dup 83/CapSigma put +dup 84/CapTau put +dup 85/CapUpsilon put +dup 86/FinalSigma put +dup 87/CapOmega put +dup 88/CapXi put +dup 89/CapPsi put +dup 90/CapZeta put +dup 91/LBracket put +dup 92/Therefore put +dup 93/RBracket put +dup 94/Perpendicular put +dup 95/Underbar put +dup 96/Hat put +dup 97/Alpha put +dup 98/Beta put +dup 99/Chi put +dup 100/Delta put +dup 101/Epsilon put +dup 102/Phi put +dup 103/Gamma put +dup 104/Eta put +dup 105/Iota put +dup 106/CurlyPhi put +dup 107/Kappa put +dup 108/Lambda put +dup 109/Mu put +dup 110/Nu put +dup 111/Omicron put +dup 112/Pi put +dup 113/Theta put +dup 114/Rho put +dup 115/Sigma put +dup 116/Tau put +dup 117/Upsilon put +dup 118/CurlyPi put +dup 119/Omega put +dup 120/Xi put +dup 121/Psi put +dup 122/Zeta put +dup 123/LBrace put +dup 124/VertBar put +dup 125/RBrace put +dup 126/Tilde put +dup 127/DEL put +dup 128/FractionBarExt put +dup 129/EscapeChar put +dup 130/SelectPlaceholder put +dup 131/Placeholder put +dup 132/Continuation put +dup 133/Skeleton put +dup 134/LSkeleton put +dup 135/RSkeleton put +dup 136/Spacer put +dup 137/Cross put +dup 138/DblEqual put +dup 139/Grave put +dup 140/Acute put +dup 141/DoubleAcute put +dup 142/OverTilde put +dup 143/OverBar put +dup 144/DblUpDownArrow put +dup 145/DblUpExtens1 put +dup 146/DblLongLArrow put +dup 147/DblExtens put +dup 148/DblLongRArrow put +dup 149/DblLRArrow2 put +dup 150/DblLongLRArrow put +dup 151/UpDownArrow put +dup 152/LongLArrow put +dup 153/LongRArrow put +dup 154/LongLRArrow put +dup 155/ColonEqual put +dup 156/Diamond2 put +dup 157/NotSquareSprsetEqual put +dup 158/AtSign put +dup 159/Solidmedsqr put +dup 160/OverDot put +dup 161/CurlyCapUpsilon put +dup 162/Prime put +dup 163/LessEqual put +dup 164/Fraction put +dup 165/Infinity put +dup 166/RuleDelayed put +dup 167/ClubSuit put +dup 168/DiamondSuit put +dup 169/HeartSuit put +dup 170/SpadeSuit put +dup 171/LRArrow put +dup 172/LArrow put +dup 173/UpArrow put +dup 174/RArrow put +dup 175/DownArrow put +dup 176/Degree put +dup 177/PlusMinus put +dup 178/DoublePrime put +dup 179/GreaterEqual put +dup 180/Multiply put +dup 181/Proportional put +dup 182/PartialDiff put +dup 183/Bullet put +dup 184/Divide put +dup 185/NotEqual put +dup 186/Equivalence put +dup 187/Approxequal put +dup 188/Ellipsis put +dup 189/ArrowVertEx put +dup 190/ArrowHorizEx put +dup 191/CarriageReturn put +dup 192/Aleph put +dup 193/IFraktur put +dup 194/RFraktur put +dup 195/Weierstrass put +dup 196/CircleMultiply put +dup 197/CirclePlus put +dup 198/EmptySet put +dup 199/Union put +dup 200/Intersection put +dup 201/ProperSuperset put +dup 202/NbSpace put +dup 203/NotSubset put +dup 204/ProperSubset put +dup 205/ReflexSubset put +dup 206/Element put +dup 207/NotElement put +dup 208/Angle put +dup 209/Gradient put +dup 210/RegTM put +dup 211/Copyright put +dup 212/TM put +dup 213/Product put +dup 214/Radical put +dup 215/DotMath put +dup 216/LogicalNot put +dup 217/Wedge put +dup 218/Vee put +dup 219/DblLRArrow put +dup 220/DblLArrow put +dup 221/DblUpArrow put +dup 222/DblRArrow put +dup 223/DblDownArrow put +dup 224/Lozenge put +dup 225/LAngle put +dup 226/Diffd put +dup 227/Expe put +dup 228/Imagi put +dup 229/Sum put +dup 230/LParenTop put +dup 231/LParenEx put +dup 232/LParenBot put +dup 233/LBracketTop put +dup 234/LBracketEx put +dup 235/LBracketBot put +dup 236/LBraceTop put +dup 237/LBraceMid put +dup 238/LBraceBot put +dup 239/BraceEx put +dup 240/Slot put +dup 241/RAngle put +dup 242/Intergral put +dup 243/IntegralTop put +dup 244/IntegralEx put +dup 245/IntegralBot put +dup 246/RParenTop put +dup 247/RParenEx put +dup 248/RParenBot put +dup 249/RBracketTop put +dup 250/RBracketEx put +dup 251/RBracketBot put +dup 252/RBraceTop put +dup 253/RBraceMid put +dup 254/RBraceBot put +dup 255/Wolf put + readonly def +/PaintType 0 def +/FontType 1 def +/StrokeWidth 0 def +/FontMatrix[0.001 0 0 0.001 0 0]readonly def +/UniqueID 5095641 def +/FontBBox{-120 -220 1544 923}readonly def +currentdict end +currentfile eexec +D8061D93A8246509E76A3EC656E953B7C22E43117F5A3BC2421790057C314DAE3EFBFF49F45DA34B +424A961BE670A194E7E4BF0FF295DEE23134A14A7C08B6602621D885EE631B1D8D3003CF2093E039 +4D77FCEFCA8BA8965D1783DCAD9EFE6C7E420CF7B898933309A89F84721ADE7F3AE4443C5EAE8155 +759A9EB6F738F7BA81C192EE45DAD00F398FFD6904111BBD91BFEE328004F2A18BCCD98DCDB2CE23 +961B00F204E50EA022D00CE2B68E653626D4BB5AFA334A0D657307416FAF7AA8C43ED4DC541F1B7B +B7500B3F423D9D369F8192FD00A59FD5E6ABC70F788FB70976CC1907DDC309F4B690AA2D2BF12CAE +C493958CC0E76CE9EB5FF8BD1F1650F659E5C123EE455B7D77C39952C212AF319BF19A91E36DE52F +0EF84B602704BD6C7C94E1B0E067210DB919F6231755A2CC5D5FE129279B43A2E2CCD27F56F00B05 +C8AC10AB07FABBEFB3509088301FE78CAF8B440C5BA2FFE06BBFCD066046618F3B6AA2E4B17B296E +1F3F1560E19CBAD54E16E4B7A65622E468F6BDF97C50277E355D1DD8843D0A449A147FFBA071BA99 +CF70D7576DC18B96FEAF8070BF25F3A3141F873241EF4A07F332306B56F1D5909A4F233A9DB3A08E +E43DF38DD6DB2D6DAB908967A907303EE1FA04F048FA6EBC531738C170B8B0F095FF3B05D14C2BDC +272F7EDA8926A77D9CDA49A90AE1387A51A24ECDB2E4E287B0F95A83AD2EC0310F9B6F396AC10479 +835035FD5D4C84D91917FE8A8755C976504AB1A830ED516B5F325EA4ADFD115900D23039A2BC84EE +D21CC21E2BBE29A5E0CF28BE047CBD515DF7785F37DDD4474042B102A1F28193BB8567FF6FDEF811 +25CE9A504BE5011C0010DCEBCF321824C9DA249D8DB11F79298F7B674CEDB6F33C111F8B0115E407 +99E0FE1B6CE9F6B2A3EED1827A9CEB453D643FE5CE2540DCBCAF7B2EA2C8F0AE9434D4BAAEAB3488 +FEC7541D57179BDEAA0BB6145EA783E73E70E0AA71A4FA58E81EB510E9FD2CF4ACFBF28E48CA313C +CF5ED2BE032B7C9A07ABBEC9CCD8D5AC9F775D36BECC252B9FE01B6AA79A70E22478904DADDA08BB +7CA3B66F3A83AEEBA37406127353790348AE5FBD144ABD8E1B32D1BCC70E2BC22A63E854D38317E6 +BB97C52A6C9B0C6AB5C336CE2D417A714825DCD237F7486C33925A995CD8AD3B359176C4CA775FE2 +2C6F8A7C7343F31F39D1B9A5A744973BF65D655DDB59E3495B28DBE2A877EBB32A22A4AB8EB13C67 +02B239F6932E2DC8B4B88915923B1C2AFF2F876A31F765B91747D5A858BD632B0BE4F135AC484016 +AE1BC01E44B6653A58EE1380B6DF24AEB73220A36FA8FDE9A152C16E049D2F247A9AA71CD2DF3D9E +653054FAF518BBC1EEB43200DB0BACA93FEA9445FA5F32A99926C4F1F2370B2E3E03CEFBEECE5D5C +DE299FE1641A9CE0C90E42E7C465DF8C19C153EA76C11791F8E112853E708CD0F6EFC22E44808A44 +3686442645D643E7118D128BF34188FD313E53B8E951E605E96825738C4DC893D942C145C3E1153F +CDED16D1EE10374626F45781461FFC94C77D431BCF167FD29136A0B369631E139A59B06AC5281B3D +52470B38237B469C0E49CBE74C82A940F8AAD10E05C5DD2A8F3218C4BE40DCED0982770869190845 +D2E8BA2A1A2F9CF16DDDE418B6E2013C3258FBE9AFCDACCD57B01C4FEF3526C06FD5BAB6F195C557 +23A96FA3E5CDB2ADC9AA8989DF78F163F19E26F3B9EAF60D44B745FCA49B09D9CE5CC16D1E2C78C5 +A28F14D3374956E9721C0542A01A731A3D5A771C7B51FB72960BB22C99BC8F216530AA86C1A0346B +3D986EF1DF68BCC46EC4C809C6D54FB9C50F225ABA2C96965F4DE77E2C5D131318231C6773F0976C +DBD016B803C38B8923822BDF160FB87BBE744D0953EDEBDE87394282B9950C89F58824D731355E8F +A3CE364F742E3337A983BD1219CE8787CFA6925B560001F6F78343647821D408B60965966C16C454 +394D33268483F51984614FD9964CCE5F1AA4AB12144874A72D3FE97F4416ABE4213B4EDCA9ECF73A +937B562F978E059705E561A6D0C8B89B59B4CAB2248BFC4A6D3D98F89FF38A4D1C3E5A4570E2E2E8 +D328772E11DEA2116C260B13328045139A819F5489A2C302F311898230CD26DD03E6CE3BE75EDB86 +0D982FBC8E1E24D1F83E8CA64174495B2F32BDF0505FC96E9C65FDB0EB0C4ADA410F0A1C4BB4D551 +93B1AA5EA1F988882A56413F77CF24FF6516CD5095077BA566116797895FD7EA616D10510957025A +1DA05064FD9176303A248C94CE2A9875C03C7D8755A1A8010B712B64BAD73BEA4195D51A328F076D +12C0E52E87D98A5269D157D544CD7B4E1CAAEA6BDD59F08D0C5FBB84A6B099BECF8BEB721A874BAA +1BD1F8CDB5ED5CD3B49A763EAA36D33837667A6643B83537EF5515DBF7659E28692E0ACEB48FD051 +45534A443092E0A510B05B5B51B402CB3372A4E8BAF98A7FEB6D8BEF6B364A5EA0F3FDF301A44EE2 +3485D4493E7B4C33E0E352202931188D156983C40F7A4B615B6F5281B33FB32A2E6A0F7AE84BEA2C +5C3635D7DA17371D608847EB402270B83293EC09E4B1D85996C1CC81196BE590EC9EF0F258364746 +BC4763976FDDB3707D37AFCBDC0F4EB2B1502F137EBBB1541B992EAD43B5D64CCDF505FF2F127115 +4857C69B689A11760979F6D2BB032CF0DCCBB33D2B6F6D6BB29A1D0E371AA5869A408225C0AFF523 +CEFB08A7D3D17DF9064010363196CC569C436E720B1B4573CDAE1CD93A10FD2D4ACB14E47046B5B7 +66B75B40BA97027FEC4218980B002FAB60A9F1F5A37861B9A63F696732F8127B2C6F036BF32311B8 +FF08A489E88218092D57A99C8981EF8CBBD09DF49CC836B9C1968692D1FB551F47619F020289F1A3 +D3898A96DC1C7D39A21B49C2D0DD9508CB8A8BD6A5EB40FF86F555FA32017B67AEC07BECD659E8C4 +8DD1D43E8D1EE08A117479015F78BF20D3318224572D9C90884856E4307A8AFFC83EDD317B008484 +3BBE8EB2A4E2D70077A639FE3637C3DCF87C67F1BE62E63CC67BCEF8EBD07E030524A53DD440F2A1 +3A019B7AA89E155AAD1497974258A01DA45DE1D94BB9F925290FE9BDDA29EA3F2BF1E64DF7EBCFC4 +23AB2C7310D9D87A5CA673EE95189135E1B134B431B231428FF2BF64C8F155CBDDAD17BCB524CF7E +ABD66B75705BFFB1DDB27B72D681D7AA19FAD0FF23EEF028B606DD20D58588AACB299A3CF38372A8 +E7494A65227C1E4A231AC7843962B8A4A7BDD90F3F8B83277E696F3514139BB8DD207641B62286F0 +0E32C7FAD7029DC0E092564C7CE1BC5240FCBFB00A06F075D9536F0326CFFBA958BA7A1A11AA047B +B14E7DE16761BB0FEF19ABE85154359807C339961B9695CDED59E489CA4D9BB75D86D9EDDF0502BC +0B4EC36B1D71FCD4E03881ECEC703E5DA23B3F5DB98CB8DAED81D5BA20B844A92A4B92FE5B082952 +6837237C7F994786878404BE744D0953C676E52CB05FCE193E8827F977B31929E36E320E770A6F1E +972B84AFA21E01719759DF0132C5CF9692BAA487E86E8453C09FF97642600D1024ED5D6C7D5B387D +CB5E6147D20B4A14D7D485B5747D765C5A1CA40B9416DC4EF5DC08F43F0706B27B1C90E901556E1C +EFF304EA8DF8D727E4B7E7CEAD14E4FC7E76002DBC37B92BD0E58AF29DA7DA91E6F99DADF1A9CBDD +04648E2F5B811F2AF0729646B17D32D7EF25AD47E267EE53A61A7CD744C9ABFDB1EDB71C0705412B +15769188CA1601AF0395796FAC0E2139EF90FAA65D27AAEEEE319D2831A56CE82203523097D0574D +22742D17E519D95560B8445B5B29033BF3454B94F20C23EBE8B90DDF26D903F1D66CB39D3A64579D +39D136C537CCD9FF2D6ACE5F79DE696C7330C0C4EA179D7911B7B67858D86CEE0833AB1E105B1993 +2A9BD572C41E78FB4A2A2421514DC2066E2F56101A9027F4BBA5D48E5DA9218E81CE46B95B50380F +560C67A5D547A8D32610AECECBB6F5A09DF44994F6DAC64F7399C07E182033BC1B9A32B69C41FDFC +7E1DCDDF273F045F154D727AFEE3CDB816CF2ECDB6733C579276353DD59C9D2AFA455935C1FCD0AB +7D57F9DD79FBCC7A45E5E5A501FF17EE1C5FF0823C6FDE29C60F85F6786940D8E3540E891B5BF7F5 +D36C57AC3AD359BFAB12B215E7FC94B933386C250E6B236506FA3D151ABAD893A817772071C09144 +6E5FB23A17591A4CECAA46DD46E3C41B4578F21D8894A59B72FAF6F88EE6E514FBD2FE69447D2B59 +9A6AA8BC5C1FD5C25E50BFB5CE5DBF5AD5771BC42FCC3706B6E9F7E4FAAFF2E63ED1684C5A4C136D +609D03E31EBCF31E864AAA74D8DDBCA52F85CCF14AB739CC55617EFC964D6CC6988AA45245B19CE2 +B63CB865DF1F1DA4A200A4A043C5CB706CD303EB31C32866ED92077AB11BF136D158840EAC67E7A1 +1BC2BFDCD5894AF735D677E1AC98BF3F19F69AF75355F168632037F6EDEBF61BE5854057AD05972C +7DA8D37AE65D35738547A9D835C6351D8D732F8C0DC49D7605F00A6A6045559D3A0B0CC21DFDD75E +2FCF25522001741EBBEB5CC97DDBD9DDCE490FE3CB186C101940DD02CACB685ECCB8C1DEDCDD4156 +F5F9F6B3CA53EC6E7E8A2F8159451CD5479D91BFBF91C6B32A1E0053017369330EAD2DDE323BCAC5 +EEC91A595473F447355B1BDFB873D0B538BF54AFB8EAADE5309E1B74283218F59272E59619D66405 +E74B5A9D6323CB76AF00FB27FD984F740601248C7206F59EF7FF4E95AF95327D12C47D2D34CBFF33 +29F28236831D7F0FD9D633B940D8282E1F1D5D95616CD839C6B41A7195A22B7A320864E48943CE99 +C68E3591A97689986A6536C3A1C37DA9838FF71A8C1A03094537C95D3585DF5AD9292874D8D05720 +030133B02E2754DA24712B52D6D8871422C709532B09D147EC8ACD861FA5392A82A6C2981347E327 +1986017B8315822B5FCB19A1B31BF6909E0D6490EC823434BFCE031045D20FFC675A73EBD7A39A50 +44C3B40906186CCF6E8502CD7915F053BC8CF6BE9FDD9A0330AE943D5C9A11D60D43F5BBE8A045EF +CDB7D19C0053F4F082303442C35C432E0DA4408C5917D24A6658DB807BD754AF140CE84A34F79851 +9323060D60F4EAC0E82D3E17042BB6729C69A8B8774904C6214C2EB016C528DC1428DB41075AA6C5 +4E4D849901838C6B6DADF7B67CD0CBC6EE1B415B44654D89397274D4A6AD2BA69DD81567F5B802F2 +684DD3516ECA0F6D66046EDA0B2B38F420A238D67D98676925ECBE6711D64DAE5DBE8AC5473A2EE9 +97AE65F0715A2E5DB2C75F20D9939EF58692EDA3AEA81F25AEC888327CFA6CC13D496714E63A1A87 +11FC50250D6D23FC7A8017038281F659A685ED7F1BB1ADBF8833ABC6DBEC0D96D08334E58C67E0F9 +0046132F0D4FBCB9CDF52EE74561498B42701AB826A6DD77F46C14753748E1EC66F4BD3583FCB4F1 +DC91050CF18B0D51BC366549261282779FC9694A7B987973C0D59F65CFF3CDB88D23952E46F5EEC1 +BDA0DC354188C11B0FA191F5C11A45BB9093701B33B8E7AC1A8621793D5326E92CDD3A76FB9B67D6 +860567B9CEE7B9F9056C6E9971F642DC0BCC1D2882B5BDF1B1CDCAA3FC61775A74E70CDFC128DE0F +9606091BB8E53905108EE77A1D3C506550FCFCAE454B020379BE3A7D6C62D162697AF1383F7BC8F2 +34FD616324C1E56E3E440277862CAB2C02395D9937816117F71A6828344182E6B5AF2799E29A6611 +9C0543E135300E44746EF2EBA57C4EABB1A15D8AC6D037F4BA2BE1EB4D1A7496F9711FC67E56D4D0 +FDA4D810B5383A72ACA15872DE9F3A9890E33759CE4DA493691BCA47A92E42D950DF588C3574D6FC +72B5AF7DDE915E3F5925B3E97DEBE6A4208CE7337754045607679296C4EEEA3A3EF1915E85EB1A32 +F1BBADB2904B09806631E20BBF5E57AF11BC784C75BF049B4BC7E479F1D4AE7754CBED7B11ED80A5 +2DD0006FAE5CC23A7C234CF628B42F4104A490E7D59E8B1F2A1395D37641C478FF8CB9FB602B29FD +3E48D6087CAEE48B523887F27F69DB32BF80B760B030A6766F8F9B19DE70704DAF81D3DED2BF663D +89B5BD8AF253BB8FA59DF84A52FDED83D2737532B6D66AFB9EF0446ACD44BFAB797AB9FDB47F2E18 +8F0A55887853772EBFD029B5FA0AFBAF10A88D464BD6F634C5839B230D583E36671A51DDB1EBF471 +8ABB84D057729D514751B0EEF4F756B91DEDAD7D9AD529B3886008F1F32645F3A205F304B2A8D808 +D37A38E389B8587E8D3654DC374568FCEBBA160395BE1D132B1ACB434164525FBF250A5AA30F3520 +F0F2A75F9D1B7C6EAB0223C209A120D894D6ECA336B57B7F2AB0E2A94E6616D7539010C700311966 +7B4A9EB3A812FEF4D100AB4C036401D21DDF8AEB393074638D154418D3A7AE51CD1F0C2D5CF4B475 +3B582D5071F91E6D3AFBFB09EAABBEAB2A60A5D388D16232939B5483CF7D5C1C9D05DDC85B266F39 +6F61E179AB9FAB644040014293EB53F2B50E8751F9D92D1DAE8DC89594905A39357C0098265FBD24 +E407F9A22027E36D5608FAF15BD9E354228E3BA943EC30301ABB2CB105F3B6D57C001EBF8328A8CA +318A7B1B999AE8BF9E2FD530B669640116149B622EB3C0A8CCDE62449DE9D39E0F5E5E01CBBF4F5E +52B33A2BD60B52FA4A5CE98B7313FE4C3FA30FA07DE4516109C3EAEE97ABE430C505647DD8B3DBF2 +BB4B3A806B14A9E0F629863F15D12A1CA62E8E055FA6ACABDE1926D3231CAC271C30A3F7AAC6084D +D88628B943052B618E4E39148600AC1EDB57B0835C291F73D29C51FCA3C5EFB1DB18A5CA47433B45 +C57EB3CB28AEBC68E4171E6DE357793B0FD2A1F4E76180248017112674DAD7ACA6ECAAF209CA174A +5603CEA5CE528F20919443900636E2FC79C303EA7B467A3F001EA8CB849BCF28BF40A3364C08ABC9 +B5D935CFEDA827A8C3FE2F6ABA54017D2AD0393A05AE21F7AE1F58AE1E992B5C889219DA157FA7EE +92E291DE2F9DFC244F2CF0FDCEFCACC487F0EA830985B687556D5AF53B81814DE9CE0C6C430DCBCE +51EBC6091B4E0227732E07DF20D59E9EED4D8A83761CED84CCE244BFD6A39103A2B48A684AEC9210 +5C94495D54FD6690AF857E5A3915E6A15689F1816F75F1FC8D5769B240639B339EBE54BC6D84794D +50F4EBE892530351984C6F8BEBE097CD46F4FED7D46E32830A16F77C13F13D17003737482F02D1B6 +F04C57B4C2B1929AA315B4BE1C7C9CB55F8981508546B67E4EBF84B6026C355C5E4E07CD98C95F07 +56F6643FB1DD7D8C77C4AF4C4F23602DD3F61D1C46583071AC460E74084F7F7CF812BC53975CAAF8 +B3C1160B5D6864AF08A1733FA893CE4248C8F8B46AEFCCF317DC726BC1E5F2445E462E0591BEAAEA +49AD8E4E2D3CF07F900EC46D596E9CDB3A8710A0B93CE5DA9D35E612596A6374F35AED0EF55DC46A +8E14A91163B87417259DE926BBC3FC5423FF0AE2AA6D740BFFD26981A57C8C1D97FB04A90A567296 +B07437F94C8FFF4709213DD5D8862A777CF3F97723F43A4F913F4A30F7554ACDAE34713654E21731 +C594C3718C0547FCDAF7BB1620B2D6BB19E65596A585290CC43F50B34A2FE6EB1E495ACFFB16DFEE +8784B66FCB9359600412969E2BDA330C421C68345A797C49728450A6CF41C926AE8EBBE80BD97863 +593C3E8AB5415A8BA625957F242378948F5C7EA9C2641312E8E46955FE5C1A1824C71D3B0C9FD211 +7CC965DA7C21D257587F291AB7C594459A11B977A278C74CF5E6598B0C75ABBB2FC1B3D167D7E31D +B519F4A0BDA650A3FE7F1A281DB9B69B57A23656BD820B22D0E30B07361FE7C90933E24A32B6DE2D +F240635D543315226E32487F264AFE83EFEAC74117321A82A92F4FC7B259F26DBE74C966B4CB3F4E +3499E30B9B326F72D73919D9FA9024AAC0B95B6751AD4CE569CC3DDFC399428DF1298FB1733FFCE6 +240FB3BE3A2837E1A66E08B784CDD131B5A61423508000785CDC5610CE4DA1DD314131767C8857E3 +3D9741EF3FD7B8D0AF0371CFFA3DCF74FF2D3B421AC0339EBC05FB4B61A2F46D6BD1144747AD148B +7968D7DF4D0F742AB39B0A04A88D66F5CF9876970879879872BFDA0C56C253DE5C72016B4990CEBB +2455DCDEC7465EE7C7E1C557B570E9F3EF3E31A22DC8AB9B17F34F48E135BE7820ACE383DB7C5B05 +8A9DC855C6850E49AB7D7D00ED2D23C50AEE671B11752F0A682EFE179CECBFAB47B76676AC0E8FD1 +0A47353D3AC3477A59B0F3CAF22849DE97AAC8B79935F7C57F3052DE7E13BA0FE7CEC4685C86E841 +EA8C7D6734D0FEEFF538CC2AA1414EC9126637E169FBE4ECAFDFA29A08451B25954F0094710195E1 +69E0A6004419E432E9319BE2AEC8D93407B25B758336946C6E30032657DD857BE9C0A05F487423D2 +0C2772D4416D27FEB5CCC971DDEDFE9B8C2D7DF9DEC90D0868D5DD18850BE567A04D08310883D9B2 +D50B817D0690F8550E238C1139C0A117B48199B1B4D489C9E52C58E0CA75E6C386ADD447D8AE52D1 +D979FD52A50D82BBCB8867B5D49C19BDEC414929DB67A00AF7C6482A87E46BD11D8E4E52783E5845 +FB2CC7439F99FF6552C7288354B436B1C361AB8C2932F77B14A50A7407FC0BCC29662D710248CA46 +AC42A03FBBEF9C972783942F3721BD32BDA3273D1E353D9E013D4CFF630BFE4E7C2963FECFE350A2 +860421D17D6ACA888FA26403726A0E16BD10638D8511A2C8A36C99E9B72A422038E1149BF88A7CA1 +B2DB196333F3AD32D6FE28F18FE1ADA06FD25E4597936A924E71C188B9E8779BDBA928A182042C96 +F6A14A6FAB5C1A819DB8E9374E32F77393734A65606809E90D188F749180A3E6CA7AD8044E168677 +15FDFF350D70B14454B692715DC3AE2CAA561FB953B478E873EB19C41A8D83288451E4E910D5988F +33D83C5974DD0EE4DF2E6C849C500D0714038ECB1E9336D71D852889F2FBCA6769949699BE6BBF19 +A9318CCD7C845D0EC7FF3CFD871328CF7B45E6BBBBD16094E8ABE4D3789DEAD2C930AC8D810C911C +03AF2BDA4EBA62810F19B4506592005ACFF16EB58E33D6A71EA4DAD28A2D7B10FF89ACAB4BCC0F96 +E622EBA20347AE04C62A298257D1623977D185BB46B42CCDD733F72B37072B8DFAA5D7FF77E35618 +3F6D25EE1D951F7EBFBEA8FA17A859B8545BDB212A6BFE9C3078C32124C4E5D4DA09404E40498F76 +7B7164C13E12BF006EE8DE408070296EF0A08AF759206DB3C445BF49EAB18ECDE1FEDEFFAB653FDC +B13FA4649B35D12266FD42D0498331560E96F54D4238678F70233F56097E1944FC671D6BB1AB66CD +E0E9DC24349E44D67C36B3E3A00B07755749A597DF31C25F28D55779841BD3F6221BCDE389852DD4 +590E075C1298B36181D9F64BDCB54A556C05A9EF661EA1CC7C7549A3E1CCF79B87A6E71C3ACDECC9 +C4EFB05B643744407029258B8225DBF960DE529EEC262D1D3113F6CDDBCF4BDAB706BF085C0FF2EE +E8420CF755E46B053B774DF37C5683F8432EEC183C96176BFB24B3F478FACACBF1FCB73D83D4D857 +2D0F15783C8AE95D7CE959D794FDE1D973867D8F30A301598BDB7F2824B2629D64B88F0FF4498B6F +3728CF8916EA884C5930677E7481F90C85ED41DD28AA00E714D3A4F2CC136E417A4C591C7944C409 +70D2BCBE410A940937C3CAA118FA32317444B401968B8ECB2F0B3C8DAF6D4886C2015000A71FDAD4 +066B82312A4CD1E49A9ACFA05C3E7CA5A5CB3FA713CA0AD9E66A34730A36612C72D1F803D4CB1501 +9184FA2FDB3E5D067BC64B29299D5531565264B70FFFF86F5A5B03848E55D73337650208D21F35BB +D5C14748CBE17EB3A7E02BE53136DC69E8740C597CE28472CAEEB96EF2A5752CF17CFBB82F6C104F +2BBB50C216C49E8AB7E661207E1742B35392752051A1E409BEDCDA2654CB5155B770C8C5E4A2968A +A35CF1924D0C74A8D23AB811B7DCE60F1EBC1494A295C8D670E84B7B886A6064151065BD96F2D364 +7BA049A444CF16EB6432CAFCC70FF2E8B354F55A192C94BF08D156856A6512403F5140DF4C8D254E +DA59B2B3ADEE19A35E9A61202B711193A7E7BA8EF427152157DA5A51084EA46510864E1CD7B4FD11 +16E74D7BA769ABCFAC556BBA7CC528C18003A2AE059CC97C18263500667F6A9A8C421F2ABDD73EAD +82D9D08940DEE1688D4AA200ED80C3AFEF6A4979154D99478D4F4EB3738333E8581A755190D87BE3 +09A319ED170A107512F056E4C619D4BB1615BA6C0680117610A26462F267B76F9DBC9A7A3AC08C9A +512A44697082A2718B62FD1D565010AC96E1006F958070AB7567A33E1FF7BD450681DF6BD4EBD265 +CF12726A7EFDEFBB9BA1E596BC5C2940A4FC9DE60116C9082138F1C672977F4AA6B7986ADABBB2B0 +651A7B0C06C4BD405C58B8C81BE075997E118E10FC008AD1F9ACF9F6AAC6C9E3F6DC7FCB838720E8 +D0D9BB99F203EEA2566F18232711E832810F10DD4E2DE44A0A81603EB1162E1BDB60AA1E2D771EC2 +E6E2C3B39508E5CA03A1E2A7F2860BC6F0B57240880DF54C325F4729EEFA1D2753D57F055CDFCA5C +E9C6630980C7121FC21E2F7223E6111C18FFDA0A0A7643A213DE9525AE138814C4183BF03A26A36F +EE9199821464C845A746945413629DC53F5A2B0D8CE9282B580ED662F2F07398D6A8B7093CFCC6F5 +E0F5A7926D2862AD1CCACB84D85902038551EE3EAED02AC7754E3B65818C530A0252C049A68862DC +A459DDD937F7BA64DB16AC86885B68AF46422D7C4923070E20CBAAC9F14E43979C5D5AC4C9321016 +7CCC52E7DA272146D68D8F61DB4D60063E74F6673B41ACB601DEEB1DF73517A8C5388F00E8A9D236 +9C85DBFE4C1E9864AB52E09F465EE98C194151E66CB98E6981EFFCADBC48532E9795290CF745FDA9 +CB7FD40BB77C148A8B90C0CA50176103E2ECCAA57030F7C0882F1E891F9EEBA077AA4992FAE38C75 +5470A4C35454EBAB45271DD76E4DBB2D9147817F7D3FB800EA136D3F27C84B4D45ACEAD13D3C91EE +BD6836AC04F95E578D1B7B8CE5B718E42FD1BBE91EF9A7873F0C6DC59AD231D08CEB4AE312F83F1A +9310155D2C4F216A6FC72385C899B5390EBADE7CF7BEB028F73DD76EDEEF639E9EDE034ACB25BA57 +8C7BEC3581FEE0B221F7340570489596FC60EC805405E0D2ACF0687A62A75358B3878972D4C039D9 +07D868DD00C5F7F3342384C09B01F1926F7D37C2B862FC516361253CBBDAB354898B31B1FE58F773 +61517F2C2E106708AB659D95CE3E9E7777B7327DE01AE2D1E0C84B9EE3887C094C149700CB095D5D +A5FEAF1AA9027AF257576A7370D79FF4DB98511AA27C5C083FA0CA60A3A5E66B8DA9A22FE5DD3DDF +C529BEA71E83881D8B010D140AD686DBEC9AF4B331086F6556B695CAB14BF24B5FE64382E6F9BC21 +5E9EC40C0914B1E27BC25F43E6F555B551726A8D9CD590D5AD3732777EF3B00CBAA89F8E8E0E0347 +7D45B00181A7B196FD4919F110C0F2C0F1B41231051AB5BC8F8025ED00C10F2C2F51E97B622A4E84 +E6AADA59F896F83EFADE779B37FACC56BDCA1892A3BD965B65D51B55AC1D73ABCD16D0EADE55C0BD +3C1BE9FDB323E9FBC9835C63F757051E29E773D3491706DEEBAA0F1182F0E02D0CB701661B30770D +94E240E1358195781006E18CBFC2D83F229A89C3066E35CAE1384A0266D5A37824A089E855F11209 +9F723AF03BC1C8B1C0BCFFDEBE3EF73A40BF83F5E038B63267DE5413B88D30155E62EDCFA35C0047 +0178E5558CDA2B30C4EE2A9854C93E0E484D4363E3614E5BE829FAEAE51935386D20DBFC00B42952 +7F56FB045EC4D97B3D649415045337AF44BCF4AD9B9F9BF3EA72151DB616FF8F6B13EF66516D9640 +67460FF123C7EA525A97F1D04BDE9D3D495602620659F6E5DCF1AFC5360D1C371BDF9984C4A7B462 +180A3CAA7098E0FB0BDCE694806BA466883BD28D77DB4CFB6635BB7DB45B4D83AAD4260A4CA0D411 +0E251AE7476A95327BD6AC1AC88F85CCB705FBD09993B9E2990D51C37F1110F78B887C54E4EFDA80 +4ADAE5D81477913B6938FE1B39913C6582021A1ACA834500D9D75C9942CE2375D0A2A73805751EC0 +970D6FA62D4354337A43D85DEA6C6F3334F40221FC473DD79344D028FAC689645963B371A55CDA92 +F6BC989F4F1880AC11D8A056DF7A0EE60471800126526488B95B785698D2AC488CC027D31190ECE2 +54F80757DC9B4FF18171409C457F5FC58DD1D43E8D1EE08A6AA2F374B7C245B7A21287DC333BCB1E +EB498A2BD723EE6BB30B76E574773F70A61F1E163A25941531C049ADEDDB59AE75B7A6725D997752 +10ED356DD93D0F0AD7EE6495F07869C570125125BC84946F6AA1152CA18FCAD3B68004A7F7AFC6E0 +9EE6E1B365A4DA15DA95AB980A566DEC7394F385FE041B3B7F46D62424F4726B55DCB4BD3625CA68 +1221CE01DAE78E24F8045EF21F85C13D27D1F0F1B589F936F62F699B93EF05930C6F5730B0AFDB7A +7A829F2ECBF0DD196ED66C7E4E4E7E05B565BB98385F017D01B1305856DB747C3634BF05DAB08836 +029674ED3A4053CC3DC696F758F86970F94034B4F0DFEAA4DBDE449800DB040B55E7FC83E6B5584F +A00F7C70ED18524037CCB48A22A5A69506A825DED81D98FE93177DEEFD42B485013D4C4184CD690D +714530B56E355FB01BC92DD90A7AE8095748A872F79121A28E965E6149F37C9D5F4DF64574F605E1 +B929174AE0CF533F77EBA0E10862BBAC46BEBF583B951BD0BFC5128B08CD998DE897033E7CA8B198 +625D865701394543845CDB7A45BF82DD8B6319658E28B34FD319E38E650869742BD2672623ED9810 +8DF14CE5C911AE0AF2035B4F9CC0D1D84176CF3AEBC4834E8BBF07B7720521C4E6C081A962FE29E0 +700C4F4ECFE92C39BEDD64C3DDF52959A4102CC242C35F56139643F22613D675F970CFDF8C6A57BE +9D168C9CDF93915F66A5CB37DDB9B8B729F8131391F9D6EADC8BDD5C13D22A0EF967622F3F7C08DC +C422E3D41B3BDA6B4520C98FD08262303E042DF37B9911C1447F3DC8A854973323E1C380A02DACDF +8A53A0D1EDE9BF34A50E8B76C5AD5B15F8E25B2783BCF4B1247309E9B70CC951CF3D98C1A25E9CB7 +11235352F3BA91FABA828F2D7D91F0FFC50852860C531C20A5FAAFBCE1197CA367F0F84DEB86A8FF +A9FF4C252EB2633AA2BDAB30F2094721F482CF926DA3299452177B79251B311AA60D4CC82F5A9F50 +E942703877AF1C10CD92DCFD16CF19BC7314FDA5A85284BDE964DE2BEE782F4D52D17FD2084E0A95 +59EBD5AADCC74A6DE64C1F799385F5EC2E2F5F869F78F7289A26B03A9FD906934C3A6BA4A7B36E7C +3B77A7581BE9CD62B49C34572A870053CBA85DCDB9FDDE407B29CB3D02AD1C752B54DBB995DF0F8F +CB117CF8500B97849275A4625EF9937AFD7C8751B9B021E778F7DE9A9B191BFC470823FB8EA919BA +DB8B68755DD83C6905B118FA18FAAE216E2494FDEE9C1125C3941092C592DEC7A5B0C763E7E0D3CF +DA02AF9FFCD234A01D75C661603820C37E9A681356A6DB424F5F991FACCFF78EAE3518C0747C35E0 +8EDEA2E108CBBFFA0B2D3BFD612B5743AC95CC4A0580A6739BE4EDE6CB1E8B2F4CB5C6FA4572329A +06080E0085748067462F3EAEBCAD734DDA18BF206EAEFE9F882807694B80A63AF2F40625E98DF55F +BE08AEEEC2C1BFBC16F1BB4D391B17122EFB5FB539005A613EF5C9F154BD50F05862F813F2083CEA +149FEDC651191259BA4FAA658A42AF151B03A7B553AA79726A44AF9175A724E0D65CE84F41F3B7B0 +E0B684656EA56B4E7E654946AEFABDABCC4F3876B3C3A67373F4133FA8498DCFEBDC27476FBB28C4 +003FBFB063267FEAB2B2BB8DC647345803B2723DBA8905AB0741137C43768B434CE118954AE55DD6 +61AAA1BB60B87ADE97D4197211A0C70CDD7855783B7C570FD742AE5A5940A3D90F9EFF687C4F1E4A +D3C4F5C3B9FF20B61C0076B9FF060EB99860F31C41B5AEC0D2C4DE626C6059678DFA35BAC5F2F171 +A3BD00065AB2007EABA499E4E7F30EB994F8BA757FF9BB0C9A2E3E384BC1DD4B62036E2D70819AD0 +A535816761800CFEA50681AFBF0057E69A0CDBB4BAAFB8B15F7727BE1169BDD4FAF692F9CEC12893 +E4E4425DE4CB20F330951EB5A7FBB0FC10DE78A7F9B0EF6FA629CA13E8C2F616A1BD42B1E26E2A0B +533DEA701AB7BA93526E2439755FB9BD5CB076C3309E73807A5935AF6CDBBDABD5DD7B036324130B +8BC40163FA0999364553CFBE351509F8A5167F205E228ECD66EC9375D0E0713563AE75B6C23423AE +63EB67167F2F4512BEFFE96B90913E6920F1F8B7139F1CAC9E38482B6CD26576776A01103FDEB164 +A176023370D08906E2EF27E1E8B6F6C27EC67A86EA36A6C82B681385F3A60AD53A8512E0880D7ACB +5567F2654731CCC1796C47E18DD6CCE30F65E27DDC5A3E56BFA0460DFC3F9FF1E98B7BDA9DDCC615 +718D7C6CD8DC1270E70FDD4973B287396E2B85ADFCC83C71DBEBB97346E858CFDA78713C0EDEFEF6 +B84984D719C4729C0A3F2A7422DFFBB2AA5FE61891D3D16CDC1BA4A84E7A74B0076FEBE0C2C74F4B +B9314E5246D7E67DE23466D47C8AA93AC4859B347D8CE31FCFB4D41137B51C41BF19D626A59D0999 +FF2A4FA5FE6FA60E029494EF99C8B00700E6E752F4F9ED52F2AF5845563ED8AA5D4E19F82DC0F87E +255ADA53AC62E3D7BC788EAA135431DFF49F2D3ACB61798353B27409D149FD635690F8AD324804DE +A99D12B02F15D9C6DAA01BE2C1512BB8DBE86EB31D7034866C10558C008D69DAD8830745F2BEFC2F +FCD957D0FEC30BFEC54F3C440F3A99BFDD7C6D0D657402A064F2656694E5F5A5524CF4A7A2AD4625 +5DE9D2E9916DB9DC2C39986A221C31F89A1884ADBF7DD62D4EBD47957E7A359F2ACFD38E073E8502 +5F907941ED233EE3582AA955CEF67A8ECE6D8B301EF37B7D40ED84FA9DD604C74C8E870F9C26A2D4 +DEC8F03563D29E1DFB974CA191D4696D877A468082951B02A88884B9B760961D9C37154F32D54512 +4F0E4357B68547CAE9CDB571089752D7881613E7FD8DAA8CFB98CA9E930B48B78AE13523E43A3568 +7B42DD2F0A99034ECA1DD782DA692EFF6AC99D6734DF1AED3616B198E6C242EA7A9954B7337ABA3D +13EBF06B95E16F19047AB0EDBAB6A8928D81003E593C1F134B0E2B8C250EA251B59CD04905F57016 +1662514225C393C42BCC172DD23D8871908522CFA5CE113EC05F39E4583EBDEB5DA425E4627A4A2B +D5C511F9C9C155BC81D0EFAFB0D0F2E96BD49A5C942933336EDF9AE0CDCBB159761DFC50F6180FB5 +024D2E5C2A20233AFF282FD3B1AAE9B65D2989BB8176AA8C7A1F58E43A9AF3A6D0168CADB6930706 +C4F974282D4A23F71B0A41C75086DC1C45CB98ED68ED0E4FC62807EDEF13C6C85741B11FA957D791 +D92B750F3B7BDFCA7E148149E55EDED66700483C4D5BFC3973580F7199FD99CE6B358B508FFF5DF1 +78A5E495977D851B0B06DC7F6B38388D5C94BC8934584D8EE2F4E0CCD3332A737BC066F042B14931 +57BE93622E346FC6B293B8DA0D3EED02508AD2183454FD4D5D21235268834B257EA8B06117F67589 +3E0505E64709FDE03F2D5C82B163C29629EEBF5D408547AC363758D8D134AD7B9A55AD9C7D90B67E +6DF3AAE6867759D2A75993265118BF6C5A261C6D80EF039A0163BCF8E6B40E643D1BF87BD2592BFD +6A41EFDF9CFC2E6DDCA83FEC28B5EEEA2E363C20AFB4A13B5EEB2CA3BAEB2CA6F4824AF1A59E4CBD +884CA4C62852A095E4B13CD018669AF3898DFC4840C874B97408C811E431163887E5BB8CEAC12FA4 +A1EC50E8305137437441AE0FDF8FA4DFFFC77C05FCCC41696E40889A02DC4B1267D5B892647D6AFB +BA549F737543652D3C3A051E36BDB692DD7EA0D8964EEC27BCAE8EF5FA853C54D67A8ABEF7B01FB5 +AA473DF48CFBD3D697C9B55C852773A35B9A7C97908DB701AB66DCFB274A824B60E275E1CB341147 +36B26E50EFB1DF01F01688E09E096533E95B3AF5D09D7823DED38487C58B4F10D6AC76EB48731CED +78AB098C452AC83CCEDFE4E8E4AEB4A93A715306A096F262BFDE5036F38A3B733B1A0134904A3EE0 +8A9F7C2723FB5D0535C5B57CB80C29E292A49AF936DAC66CDE5C01640490109E679FBDC13F892438 +D70CAFB12909FD2ABFEAB23ABF6D129F5628B36FA00548ACCC39C8312030DBB87364DA44FACF3818 +D4C8ACFE3302B1487D5CFED16E17B05CE9889219C13C9DEA28C9BAE5D788578C309CB7781244E30B +7DFFFAF5A9F594B8781F849EB20B1F3A346C2D697CFFEA6AB4134DD46C86BD0F89AB3EE9DBB2F87E +988D906C21A43E5ADE58BFE82D4D4009A39EA3D1E779FC374FF21B86BE48AA4A33186DFA0F97BBB3 +218CE963643EF2A35788D613DFF934139B3EEA36377E67A713D20BD3DF04720AB49834E3FCD78908 +1FB726CF642A5B87D5D23609661F7D694EA0256F3EA0DBAB7C2CF79CF89CA0FC9D25281EE0FC16B0 +D089DC5B156462343A375F1EA2682A53F70A1F239D58080F4F884DBFFA68CC6D63365A8CC308DC5C +BC2387BF3D3107C95FF4DDC3A902B31C3F414355748B10518EBE00C92682CFA413FD071A16B8D129 +4021B0ECC5025E33F6116C89C7B983C6BFC31C5C8D7FB5E5E81D3AC500123CC05B3C8DE01357E192 +0DCFD172EB4B488CEB9E1ED5FA1D235C96FAD22B319239FDBA08ECA2C5C1192B4D7A797ECE135228 +6BBF1E59AB3B54B8886E67A82AD971DFD1EB21CC5E3512CA922F9B870A48E6DC94F94181E422D274 +2D3A14FCB3939FC8C1D62CAF79033D6EF4DCC93751BDABE588BF5D97B52AFC5084C5BC17246FF977 +7AA4D738BB9B15E534ABFD68848B879A9840EEF4774734F0BACED5E7B6177DFD430E0497E36D1077 +7654F351348BCEAAA18C3B362B2791A006782C25C9D544CF1594EA623BB4C782C6AABCA95F9CBB1A +8C86318834E1430376406D2B6CD5AB09644361B83AFF66C96CF549C2D309F7439254C6C3A5B210E8 +23F83647FF420BE66901C317349C1B305014EE7E9F90DDA917E3F853F1A8AF3DF1528A81C50B76A0 +F02E933229C2743BFA639003025697612BFD8575DCEA0BA5FFF805EEB4D9FBFA8D2014BC239E9D5C +4C87E36D1C83E010B92F43C06733976BC84AAF1C05C0A0CF45CA7746ED7E1DF5A12F2401C0FFBEAB +EFA199A7299E4BE5089C2CD83E7838F163F6284FC299B213513F803E93ABD8D759595DBF513D68BF +96031B9FB95A945B7C9153B0B315436C850FA5F1415AA2C9565F6FA39E9F5C5FB265CEEEA8C98E4D +00A72CE7F9F6677DCA7E58C1A8C111A9C6C44781867AA5FC71F36486AEE73FB81C03BF4EC728E43D +75564244AACA3D66B6D36DFD38332AD05F150D4972FD475FD087E13C9312D5A17A83411B45740153 +81CB568CF85BD66428FF9EA2C07E7BF8D0AF4469AA367DAC0230650036240634AB81766E832EBA8A +2D8BFA402DA804D264757E74B3465EE21A1EA1C92929444DAB2EC83050AD169F257B77D3F4B9BA61 +B11361F5DA6DD2DD933E101B64F9DC82945A2D421807F09F3E587D4B13BE0FDD6D7133CE890C3AC7 +1D0880418880362E27635986795E2E8426A0A7D7E8E5C41317209D957B53B6CB9E4EE7C3EEAF3315 +E006B7FD90E7A58FAE5289AE513D7751201459BE029563B58D967AD24E90DE5E96357D37E86CAEB1 +6059CD8593F92617AF636C7D32E2B074A40B6A1C40828313C8DF1BCBB002DF276D424519EEE2F234 +FF9B9B27126996834BEFB6E05A7BFE958B4AFC810E8B77F0EDDCD43E81549154F81E282276A7133C +23650ACB159EFEA53ABABAE1C1CCEF5642898A5605A285205DB40DF6C768029D8CAF85C520AA66CE +5BF1E0A0520CC94917FCC3118953403A1B16312096DBD56883F03E78A14315A5F97345E13C363C06 +3A01D49492349D60A9114A77BB9FD48FC0C3AC76D190204DC69C3ED4A265B8148F2C5F2E147A504E +4F373637C065FB894446031F78C4BDEA68088681E0C5099CAB1D13833FA87AB96E511013A9B3D806 +E71EF6E0A1442C91FC2A1795A13145ACBBF5D18880695EF11832ACD328BDE6E0A7308B12759D12C8 +6B558CDA038590787704BC1BF49EE8C788C41594332624D56082ED8627EC110233CA328D2A0BEDAE +3511719EDAA726F338D324D1577593948A8B9F0300F27FD4420638C6972EEE2D6248B87643275DB7 +69F72E8F86803184035F6A539A7CDF43A79886ECF110ECD7053FC04EB5E51B3C7625B3BF95C0F5EC +044FB7226281BC723988AC2498ACC0489DF0BFD1DA82D04FE3ACF6B63EB269BA9489F8D5D07DA9A3 +AD04BA924B99B9C1EA64AFE7BB2886513EA6730462D4FB5DD82659C7DB7687F4CD8E006581A15EA7 +715E274C9B89F66F1ACE9C2AE7698FCF7479A04F2208DEBA6DE801A6D184A8A9AF6BC1B0E37CEE3B +323DC4EF93EAA8219F946DB9F4D9C133C6CE0FCC6884F9C2F3A816C4ABEF44DD6256E7BC4574600E +1D825080660BF6858B415648258399839118F3C11410C1C29B3C208A3B54AD5D7484708DCFBCA04C +849F2AAB79E4D96328D990C63DE05DC8E804DDAE255F94FC3D56270BAFF6F86190796F91BFA018C4 +FE4FAEC3F1ABE8ADE43D0DA18E710BC1F419F77DEBAACD3BE011BB93E111B18CCEDA8EB0352934F9 +690F3E73D71655191F150BC3788677D1FE46070FDB354BCCAC8C179009553A7D67C87518131A4D8B +4FFF85FB9485C9F30F4CD31EECBC4A44CC267F6C57AA05A11C6FCC09B5CCC83F189F6A32F8EA56F2 +2D20DA4D4008F08EFB1487675CCAE22BC9494441682F4E46839F0F4D2D16AD58AD0886C60C925DB9 +C7D9AA1A7FF41C94B6289E1B72382789006F40B99B78B05ED1FB1F715CE4C0A1078AAC02EFBE6306 +F53F5F7E73DAD249995DAEBF17E5F55082CC6885A54F93F1A935E0389FE54E8B1B6C5ED19D483620 +A697873D5F18CE9A48E3C2C1C871FD4739A78782D8112602DDF8D4FC497C459067A6B118AA998740 +6C8DE97C2F09CB9D388D341EAEC0A5BB4BBBED92BE59B273C77F3D6965418669BFCE0C43D5C86275 +D8E658BE1893DA8E698DC858CA459711969B2CBF4CE294071EA572496575CC35CAF57ED49C2FF1AC +CC21E19D189B7C2A1ABB1AEAD7185675413C224CC4C0E1AF4EB76BA9F44148A95D8609838B967784 +2391DECB30BB0FEB92CC890F224FD2E9E9D34466D6091443CB69E845D4419F9A04664706FC8D2D15 +9002422367F39CA1B1CB1A6C32A65F46230CA2376C3E5125CDFD367514E087E59873EEE569B7F376 +227DB126060F063662F118C7BD01946BD04172147B601BABA952A01E0AD31AB1147D48FC2C3F52BB +75D9618E6F03F1F1EA393AF0E8474025F451616C4ED236ED831E14F40BEF5B86806B73ED64AFE7B1 +2A3C1F5036BB9AE79862EDAF13BDFFF06C94939AFDA1A749364BEE73449520111CF56181527F9568 +F3189652FA7FFDF4BA1086DC5992C6E0282B6F88D7CB73F485F8A27A77453C151B0BA40E294653A9 +73298EBECE8132B440ED4B4437283356B79CADA8198512A45044A7AF04CD02CD4DF7F47D5D1E7FE9 +52C346B01D03D1F69904D1AB5E8C433B0615E88CF4D01B3C96361F82B5CF7CB4D92FF3971E44F0C3 +317D3C5B0BC8DF4BCD4DC63474D0E0B5BEFF3177E2722D4AD4AC4B4AB6269EE948BBAB6019ECF2F5 +846A3D215F6C0D999D489215D4328875DE21F2CA243CF184280B229ECA4B8A9C5290973503AE5883 +03C67DDECC577F12B41F0D4DA266772867F9D93E1863BF76C6AEA5DE3FC6567EECE93D96F717E39E +DF536ABDFEC14DF6748DC90A2CDF6066246DF69D2745D2944123AB3A6ADCFBE7C74EA8E8D712AE86 +F76B3059178E78FB2FBE8D1F25831C70F58FB6B5922B371A27501E7463E01C844A2226CBA263B570 +4E5C4D3E50FE31435437E1ED39E6E3BF47B4E2C4588274F044B3294E7B2BFE302E76EFA3CB74108D +A6CFBBBF383F5C456128ADB5E667E1F7ECB4C3E00AB8937769E5A2830520E9FC0A1DA1662F881ECC +DD7967647B5841D8FDE1DF7C9F5475523F236005EEC0DF307BFCEF379355C30A83EDC96D6086E224 +388DC7B5E951B819347AC5A1F9FBE7EF1907726EE7E972AA1DDECBF7F72658C20FDE99FEE686D7E5 +01A7759DEF55169938F34978A6BD4DB49E494883F67E868A9AB177FA8E6F81157A95A03B4D9DB572 +EC1CFF33B450BC13E00830BBA20AFF928CCE04B4F79F3795DB54A4A8B5A2F3CB323194990050CBBB +C7CD32103E0911160FF4DFF135A77DD0CC15867B994CC88E1EC10E3A097D329DBB90FBB62981FF61 +C2521F9AB4B9393C6764E5B4361D0FBB1938456CE437142F0AAD9341588BD15EA0F6EDDACF12A62E +C025F3294AB1AC45719C5EFEE94067390D579AED4D1D36041D358CF1A24446176DCC808CE2D6CE02 +7A2C2F6E517A5ADAC722EE94A1710BF61254DB4693B30225C12B9C4F856E1D24075327017D6B288B +B52EDE713B3710778A565EFF6C89656BE3C5F590F6ECA600390C1BFDE9B0EEBC2E4FBB9E0E2F405B +39738F7969F64E8228494B298C3FFF4C7DED00B0EEC336B7EFEAA892C4A80CE9ABAAB4318FB34348 +93AAE6A90FF00B892D1DEE254DACDB268A6308E91FB628A98989956958C9634896B878CF93F4E0AB +A0170C1B7BE2A0C4A0D514D7BBBC4CA114349D4D4985E96DB7E2ABB752C7828A9E36D9B0B4551DCD +D878C06C3C68D2C214EC8121F6675D8D03545606B582B09B76B6D8608DFCED5C4A721F7008FC2014 +1D877353E8BA5DEB1CB61F7C956D4A9F8CFFC8C4FF81B2660AE4BE45F7A63141BAEDEA05C43CAC2F +A04163ACECAEF90F61E0473E5CBF1F1994076B6A72CB5C33B17DD57E2632F7C6DEF7837F8A939055 +CF357795865D86C7745DE54C6079C791850B20C0C7349472FB6018521DD5924ED1505A1B8C8F9CF4 +C892CB40795C4ADBA3CC11C8A52A1DCFA8FD334D7F3C344CB4057E80A4B66AF6A97799F8DE817CDD +0202870BBF42E76C9BABD2D9B66D10F1A68388AF1A511887FFC50EC7D07581D4C4FC3F6C4F7EFCA9 +4799D74132B5EA25DF0C9557902C7EF1E04E612D9E40DBA459513E584C3A3EE5614ACEBA165E07A7 +CA3394969C2CF1FFF28B1C7DA85451270DF0FB71DE22A03FC2F17531FD59B12B55DEA7F5F56B0DF9 +34C96E26124342571BD04FAE6A12C6EB0E21F06275605FABE91C6EDCF55B298BC4CC52891DD90360 +AA5FDC150004BAE65225FFC42D13026F9C6FE343D7CE2F52229B4846F6E23BB2BBDB6DCF60F07A74 +8F19F74A1168DC5C67BEF840A3C68CA7A4D8CE7F94610F4CEE989459D0CDF1B194C63A2B82479746 +03A89150C4C6AC67AE3A1341F9516887C6BA254F81C5B552C527765A52ED5C4FC45D575F606E465F +7C2EDD2F5927319BE737D48099C333BBA84486F5F8CC0B32052DB6E57DC55A68019788DEABF8D649 +A531C1880D07E425D55D4DD4F3966B2FBD2A0B55E5C429051DCF0E3B9CB1DE6A5B3DA05DDBBDD3CC +1C81877AED2BD272FC7A10707C07DAA54FD6CD37E15C247E3100A1A0C527727B73D45C8E02798C44 +1864A2D1D30FAF94121F0CADA24753221C85DD5B43E5F00FCAF73A1E531D9453307581C6FA28BB5C +54D93F149D3871D2E017E6E7FFF7B0BEC71B83AD12AF353CD13311D3A6F16C51938986C9B6A24EAA +06B8BE6DF27A5090B3B120D1D1E064C6C1745536C6B0AE5C899C3DCA91BC38B7E900D9614F291B9D +BAA85AFBBBB57D58C3E1FA8713CCA1BF4EED469773EB4B9605125C08A8F7E998E37BD893F3533232 +ECDF47D26E8B2A0437220FAA760DC8E90FCBEF59AF6C1C55FE1A28A4C98E2A67DD5A7E55BD4FE272 +15533A56561F0D80989BFE15B321976CDEF26FD6530EF7A368A7239CC55D7AE2B8F0E980DF63CFE6 +F562F3ADD0AB906B60682BA447CE4A86E6D5538E13C6847791D8A16F5BA29E5840847A7E33AFF57E +BBEC1A5B329A461FD0E858DE5163A2120BA12839C3A216C44F364452A2D6401EB549791012C4B65F +4FEECA2B73B2D88CA49B44493802B01A23321470A2593A8F8ADE3F88D87247851561372137E11D10 +11A733C671C71D33EC939B05060C73697EE577A8F2BAE08309585887E5F314BCC642BA2715B51E0B +4D093F6B11CD37BD9728EE90A0C92D15BD1105637052F89B417F6F36340588601C9C2BE9526D01B2 +E88EEAFA300E38B0EB5E2B54341533B31DA1193588974DC054FFBDF374960D28F0C8C1AB8505CF5C +64988DB86E17213EF0D9D6D52ADB1BCEBCD02B5E16F0866D21D7C0FE108D551E695CEAFBB83AADC7 +362727C47BF24C482EAD6F122F1F35923DE5D6A248BB36433D044F73C944E6CE4D9FBDF0417ED53C +8F56B6D389519E7A539D6BE9444A4747957FEABCFFDCA5FA54BFF46F637B3A3299988929CDE008E9 +E3C4CCA97054A822C4AAD01ECF9861AF6238E6643358B0EA141B0E161C6ABCB45F38740B344D4112 +9D4E898DAEA8F2065263D68D97966FA24BF88E61BD86CF2C7BFD1F058FCF04AEB88F3A30C9D446C6 +3611112CCF30F163C103D6C7C5AF946ADD33B50A58FCD8EC612268F7E119BDF387104F22E4C2CAE2 +DAC407F206186F12D93BA87711FB05E6E96F17DE333305196FA7C33DC06255828744B590FA0E67CC +E4B0375276FC7AB9B324978B15FC228DAC17F955C7B3D441C540192145FBD002EE20FBDF6F397F95 +336C0A056609E28430E123A432EE91594E20A8D9E5774FE8768C84CC040A706D8D3590BBC9AFE373 +4A5536162846B6B7BB7B248924F1DAFD768B9546BD2A2CFA1203D6A3FF45C8EBDE2355F01744484C +DA9FC337CF7D9D54106407F54FEEA81B77BFEBEE088F344CA2E537644B615D8D6B6A79D03F6CBD9B +573FBA87EB00410B5251A29007CFB60E711F642C19847F58333B48F66B6758E4ABE524A4671B0635 +C491341B3CDEE650CB9F774A5B6FB92AA70FEC7D9A057084214D81EA5A36A7F8EBE9922A70F2B102 +121736E0BFB178A08ADC0A58E2A9DB347FB9B0BE707C038CC19A5519C3FA9AAEF660653086191E59 +320D0E696218CE1E8EA7DB5FB3318EEC98C130F3F1C45D0D2401223421FF99BD6E1546873C6F12C6 +F45D2E1C3EE41634F5A415FC8338A18EF2299EFCECEE00F9025E79610168548BF2A52623A479EEAE +CC55BE5172B0CF07F9B04E2B2AC08A2BC839DFBA9680F2BB2E438519BF3B434C71B4AD9E64262C76 +9F6C1AD174FCFF3F41B5BD7652AB296C543F323F0A16E88C6D1FD3025C33794551DCAED303B57A87 +CD1E7FA46E16ED357CE0FEBAAD2678A4D84E4D6B1635F412465C0F3E7246407BDDF934F0E2E0F5D3 +EFE318D7D63A7B6BD0CD5556B6DA811D521408EF336CCE2D2B6777AA472A9EE0DB9FE0D6914059FE +25EFF5D7E3D2A6EB96B23669118B9EFFEE5B7FB8F1EEEA355998BB48430156F14766FD77605BBF80 +CDEF19879E8F8C07B6998AF145B0AED86FA94A952F2F49D2891D41AB0184EFA8616B139E640A3A9B +D808BDF79E283B0CC4686935D0D96630D590A5F4A7C71C05E110BF3CDB5150D8CAC418AB25419BCF +DD5EF0A2015305561CA26494E267BA89892AD21E0BFF44D48E330694A1CE12183B9A7E4E25D78EA3 +498EDF9A22DD7718ABD06DE2C28D7762F609A1E9A5C40A878FB8AB33A60383152A119B9FA077B109 +90AF19C261CE43AFC116593C30BC27EE4D8CBCA0C0298BB84327FDBDD93F073B1E06F71933C0323A +6E7FD2AABA783E9BC995C4AED621434B82B34424B768B4427EE65228E612581B0B8A7AAC3149788D +FDD106A6AB93E01771802AD93B63EC386B057690E5C34A409421E532C6614EC61A0197C13EAEE438 +35ED9BB38CF811E39CF8F154684E3D8B12E3B673152B82DD9B15A2A68A6163D2CCD72D3117F7C24C +F1575671832ECC4AC6B912882C0231050D60ACDC7D6F36C6BB4E32B6019B32D1DA08C7ACFC1DF451 +3A338FACC16D297C56C6138FB02FC7FB5BF7B9DE4C61B63C6B37B0F9CB42E6FF86693BAE1CEBB60C +9C15CB6222F547E0D0776BC5545A73A2ED3C7799F0CA3C2D5EE17849DFB15C6ECF7C2846AD10870A +00E0810F35A57770EEE9D49D05B54500DF164A02FFC324CCFDB5F828AF7307DDFBBE647E98909C73 +A3CC6BFB360042823C678EE6ACA0D658C12776F2A573656073E4F40505F5CB4A3D340B034B0FBC29 +C3B6B055D23F0BD47E44B441D430B8703883AF8EBA79081D528AF5646340A27291472B8E1F19C8BB +B4AD17C7EA1FCFCC7B52E6EBAE0BC8204AA52C08B3A63B2F07FBFF20092139143A24130191C41D2D +69077D71FC204C5FD41275DCEBEF7E5701BFF6C0A4217F6F60C2E37697C7F1C35D2451B040BA0D28 +0C9D23AAEF592BFFB436165C314C3CB75223D15694B6EF312CBCE8035A1A9172365FCCD119CD5DCC +569B84C6BBC5AC9CAB6942096034523671156FAE2012F6A24A001DCB2F35A8A031A2366CA98F1E52 +944B58FBF1852710CEE0116BD2C7D68DB956B15FB6AAA147155E9F179E67357F231F8252D728AF12 +49DAFCF6AB4EBC8637E1BA10D27555D2FAAC9EEE5E51C8BBC793ECC6011C4FEDDF7116E719147927 +0BC11D5EDD9215A4E8087A6A16A591BF7ADFDB69C4A03361C0DD078017DC5851BBF60E06A86C6C0B +E08087C99F4F9002ED5206534913353AE16C4F358BC1564A442CAE506A107D1FBC0B9ED99AFC6633 +209BEDBBB681CCE475645E92155285C00FD6985216CCE60064946F94778F7AA85ED87F5762C20FE9 +DC007954281BD6FCA8554D2A0CA5B76A3ED42EE5F44F3B276E574F64B20E1AD489753903ECD20B4B +EC88ABD1E1CF5D06AA1815AB771E350EB6D04078EC04616B977CDA8CE88C483DDEE9F28D58366D3C +224C41D19E550B5ECB9775F569C2D391F61C4667A9BD11C69A88473AA7884B823F762195CC403823 +690A32087893C29C63100A5935842F6B612C95EC9B5F07459608786310C8AE65DBBDCFED21B43191 +874E20D08F12E1384DCE1A990CA5F07DE36BD012DC9EC558FE7CC44494F48CA3BCBF1F1F11BB98BA +EBBF8691F8590F84AD849923E656860EFC0EC27496FE6D6C185791E3261027DEEE4C57032547F94E +7D593F7885526AAF054BB850C02E863D831ECFEE61A781B89867139889A362F95F48A837ADB955C9 +939F609D2EBBD56775151D2EA4B09D38FC1D824A952EE7E52849260DE61F07333076CF887A3AC2F4 +CD088C29E47715C5242E2366CB493B2FEB38C19FC159EC50EAE88409CF0A30C0A6823C45D0532C2A +72E45A17916F6CEEB475C4D4A19372AE271326697CCCAFBB43D92C25A052797186FE8314FB41FD94 +2A4B24548866BAC19A83BCD2E6979FB3C7B70B075DCDAB3EF6B6181A00A98AE73B6D968EE2DDEF07 +503A92E4FE1E0B67A90A2F351D600DF960101A15808AA99B3C680A8F50D5CBBC96D98A3A2AD5F14C +43857F4CB9DF9372FE74B5D6CA9CD801667399E778B56EF702A56F0F393137B20BF11BCFF9DFC0F0 +4E67649D07A2A5F4C42C9A929231D5BACFB6B53210E9FE311642D8BAA7358E6A7370B6CE921765B3 +68A354B42C8877E59227146409DA83E407657BEB475329F228CDFDD11BC73123234649AEF0E2E9DA +76C12AF91713828368FB778905A6B7150258695D4D9DF6111E1B28A9462002D7C476FE44A9B13F32 +9FF84930D213787932A1BA01EA608ABE7054FFDAAE2176EB960005E5407D7C1D39AEF8EAD8683A50 +D93398C584312EE4A12C07E9D55AE9981D7EF57D66499CA93EA653EDDA1BECB494662E54CD7ED8A3 +0B2A8522CAB12B2751F7E9B3B66CA0B5C8905E0F3A51F68C96E9C02F10FE515FD6133D3ED298D15E +8B1649F3D13341BDADDA7FCB838720E8D0D9DD92D0A241A0CD8E25D7B313DDAA2F25B543BB0E7965 +402ED0F24AD146E49919ABD9604ECFEA5A7A49E58664DCEFDC893F5D722CF24A44D26369F5D86569 +9632141348086A80AE528EDAFFF9D9986D5665DBCD375DF221D5EF1757D79361E5A5BCBE333B6C9C +1CF46794A7C7C776477023BB298C970F6DFF9AE6C7ADDA8CEBE73B07117BFED6CED2A36548081C79 +BDA9A70C8FC5FA16D0EFD3E9F869DD5DBDF6E70CDA4217935FEFE577B64DA1DDBADB9A092B9D1E3C +E1FD3B6E0117DDED155313A5DB7D8742C3409FC18B9743F09ADEC49BFF2FDBBEF9D5FA7110266287 +7C65E3A1421BA56E258A49D76C436C97AE2116F772CA5EEA5726BF17AD5D5CE37DC5F45235730E90 +A1A1E3087132C820EB9E0E311500F2CA193C72E2ACCB4D77ADFA34E268B014FFAB5DD1BE7187251A +A69B7BB3A517796BACEFB9ACE0114FAAEFB0D9BCA028A52F5037291232A04C2353B9663BFCBEC2D9 +30CB007954B8C6396003214262AA9CA9FA876B4191313FD1831D664863C4A19946AEB8F4E21C468B +9C94B8CAA407A74AF418DFB60D46BEE5029C884950D3BE8A58023DA864E9AB34005337D335B0B35A +91DDEB53A54C3233150E27225B0800C841E489E9EA6C12F5D95112BB723C3E88AAEDA3A942D06242 +2CD80B04DDF024ED79224E166086C5770EB10C389D0BF0327B2F753358D9BD552C04EA52BA154EEE +5A84C51FBBFC79055AD0F1243E489F82FD3D1A3D2CCB24A02DB3F306767564A2451DA405BAFFED98 +20241A82C6F4F6E1D2A36FD954540EF3C091247120F5E1B362D1EBCBF80951A3158B1547E7A0CCFE +40C03F992BAD00496C32BBE9B0A06EE9554EA3FAA247A7399A37D05329CADB006F679B58F2E5969B +13A5516A9F6949505A64B7B3FE5E748B9B9662C05E6C5CB79D64FD72C54F557ADE72880B3F9D8718 +58D5EA3FEF2BD3FCFD670794AEA6144D13782BA89648C98E7CF5160089DB9798E49BE2DEBC2669C1 +0C42AE1AD7C1FF4921EF465300977E057C0AEE61579460F56E51B6EAFC1F7F41D669ADE9610EE777 +055F927444F971121CD76A55A273CEBB481B89D6B78D0066ECE31BE3EEF65CE9FD22D22EFD6E3ED4 +536E6439782AD53550CEF1A903125F228A3E2F1AA3342B0551C59924149358F8E941969125F6E54C +8B2C068F57FE0DF91912CD71BE9492768191F4F6B70BA45C72409D4AC6E9619E8A34398E6A66E984 +55F1793D8A2C0DF30EABE2B19679318AE09014262DFBB9AED5D637653FBA1C10821908ED6E088910 +AA033E2E0798A630966D29F84845A9C937C27A268CAB8BA1AE9B32E12B52EE4B64BE5388AD32035C +7F98904F052B31D7C4819E27BCBC597E8503A5614E0DC2BBE5C51922980E3F492B61BEEB169C3EB6 +AB9F1DA82EA6BCFBCC16199923C8399B0495EE9A9E1749DAD9FB289FF3FCCF34F55DF7D94F91EF31 +B3B4C8074C567C4FAB337A337BCC2F459075244F665B079C159AAB83781E465F5259D41313183EC5 +F5F53BFB4797942F93EAD6CBF9255F9B4DD0748A3BC6BF36ACBE0127AF68EA6566B65430D0595FD2 +A7A2FF74055BF2E70BFFF2B79131F1871CEDEFB495FF914B88770654F9E5556AF535E1B9AF812004 +99288AA39D1388ACCB5B11B13596B550F2746B2A83B076F4F606F7580156E54FBF6976AA4CFC9581 +0A7FAC41A1635FDCFD6F7CD6BF738190D7F9FEAAB8C0B7CE38DD1459E2465C3B75625C8BAFE3B60A +F66ED183965AB9681A8174C44311D8EE36E468A8FFE2035B7C5AB6A372FE37FF627F4697C0D19F7C +8A1E356F829BBF2B8F4A95A49F85CA16ADDCA5C0817D6A4F7C4EAEE908DA13E0C89C9AEFF6D1D7B5 +BCD1BBF672B46C4960720CD1C74E70C78784CBFA8930576AD4067D406A0FCE9248DCE6D610D7EF0E +97F3F9CEA1D08DDA90DFF0C484DD32265FD13A2571513F361DE3061F2EA76886112AC7589B290220 +E34610277CF81535CD628CA688CA812275D7B9909757DD519F1FC89FE4D0AFE5FDB999323A470C6A +A0D9BA9CC92BAC24514E7CB3A3EAD2A70271EA8B02B2DDFEC6CE803F1B761D9BB7099FFCBF918D8E +B602946FB0DC14F0FD1289037B15A4A96A4605BBE53BCEA9112BF9746F3BDDC06CCCD808C62F2B41 +D4F508EEFB03AD22E2E154888DC63C6BEC6A21D1851A5C82397FA49BD163BA8A72527827E4B6F50F +585325219FAA9B3A2CE14A0134C19DAE50373A0F9E6DDC8205467242D11A3989D17730C8169964B9 +CC9549BE20A84FD9137DD9C9F7DEBAC3A41345DFEB0AEDCD7ED408A909000FE8D9CAC85D93052256 +7A2C9312769DC85F902D4A5F5766EA3C561549F1F2B4C5269276946809ECA26B6F51DB4CBDA9E668 +BE1023D8962C0DBCACD5BBC9E5F61C459B825036E1322737C0F196C0DF93DA76011DF2CA06F7B383 +8C672A802EA24A474ACF7A51F2DE867ECAF5674B1053CD5419F5FAC20584A3F7565D7CE584CD395B +1968B622FE3C68DAD2F0E33274DFDF03B5A8EA047B077DA1316DF487C91ECEA84E9B417EA25EC9CF +1F1CEDD7A1C2CB0D51A58BD8F9772FAED8D553141ADAB148AFDA200479CD04C0FFD1478EBC618303 +5437A5BC1AEE3218E9B27D21656EB9F31BD4E7D3186C89DF251207E8B67265585083111BC1AFD4D6 +A2773629147A29CBB4BBC3935B83392487858E0D18FFC96E57C83C4C6744C8E0DBF001DFD64B660C +CC8064907AA4BECC12376A1EB55EDF655CBBB4744C1A6166590B9572073A2AB577EF446B80567241 +389F990AE6C90B286EB48454166BBF264422FF2A387FA0B413F2295B6B188A64927DF702C232CCAE +59A2CCD1D109840A464BAC74A45B865A6667C901D86F771C4A36421308551F532497990BC15DA648 +6E322566C210C517DAADDBC24DACB39CA41611B9F961E4696D1FEC46E71C608DFDEEF19ECDD88724 +24E1BEF7176B0AFA4888BDB4C56C8690AFD03428F32740DFBC4BE22B7583DC47BBA42DF4E83C14AA +29F4E79397BBDCD2EC43338BA1F0D2CA9DA6E64A065FCB0073ACD0D86E46EEBF1454C9C172C6BAA5 +0F37FA19756B05405763387237794E9FF74E6749BF6CE5EE9145413950D342DBE5B0EFDE57163127 +2A8D060E935547E1FB0FB1FD60400FF856D027671CCAECFF7E215BE61E8A77E9BF5C72C2C1E4501A +A11B2F8574BD823574EC9598D579A9C5C525867F4BAAAA78DDA0E5BD7AC832DEA41328A507874A85 +90B7F133E743471D4FA27DFAC39C6F99E233C913183B2A039CBEB5CB3BF8825A92D83D266246D5B3 +CC7B11469E611E260C6ED16D17C9693B13B78E3F0DE2F0ABBE73FD6AE1ED25F57B4894254FFDB332 +0E65ADA53669B95CA28BB4BD166507E9D8F12727E46D2B9593186C090764FE8A95F1594291FD551C +A96E4CBE1D6FD42852B2B65E7F10C4F17707F930DD934E2A2ACBDFA40E04EABC1E54632D67AB7D5C +00DC103A3D11DCF78B6771D98ABD5CCA0B253283C67B0863C80D1A78FE6D5422568207509FDB1946 +92706C7A211B29955F6354092C9732DB2ABA8CDAF407FF25B40BF9D73317D5985E19E6C12B6AB5F5 +DD59328905F822E1EBEB87C4E386EF20CEB7EAF842700F09BDC50D7AE6442D1C93804D56FE194785 +968373A154E1F426BF76692CE3E4474360ACB9FEBD3191B8EE909E7C224EF90EEF36CD660AC9A642 +4DB5BB20B8835D365D35A442ECB2444F30466C3323001A087639B73848E3EE275406CFFB495ECDB4 +52F2A357F45D2D32BB22CAF9F9C2C44741A5341B29BB6C4322287A2A3891E1E853B976E17DD9306F +D98BDE8A0C97ABDCC7C708BD1BF49B524CD0DCECB40DDC557E9C90A1EDDEE57BBABC4C338F08A625 +E03C1C1A20DEA709051EB1A3264D7002D6DD2BB7B622AF93C7DF54F49EFA5FBA58F115A049A91875 +A2476C19F9133D0BE1B07C8102746163CEA0A98F9B62EA59C9CED7AD808DD52DDF8687933AE52A7D +9D7081150A812801D3FA78F90C4933E5DF09C991325324DEC6ED364ADF73DFC7B78953B51FBA2F81 +F264C2A94139289CEBF7ECD6D8FEE9E579BE231FE1ABBCC07B4BF1884CABDCEBFC56610A5E2B7510 +37FE804511FB5443F7B21290E38855F6DE5EE38960E02481DC57F83CFCB87C8FF1CB196CDC19B2B4 +6C7C72B64D7D45C678851ED7E2860DE7DB772BE7B33C84ADF7E6F9B2063D1263CDF55E6220753ACD +67C4701EBDC0799AF47AC58A0CCE796384A50DE6A814DD994B372630E64E5FDFF57393522F689DF7 +81C44599B21AB1C214D4ACF94F07CFEE79C628C85378B96D9007ACD4225E14DAD8C70984DC596DF1 +96BC814E7346217C94F172FA40B3DFC73C30E6E530DDE4A91F6A5166AE19EAA3D2CC3D9D6917BFD3 +1EFAC19C236463AF8D7FB7D9B3A4D6FB6D962C59B296E988561957A3C3D11F33ACF69F5768A2DA30 +462BA9AFE67D3C41A1E8368099361F50D4F6368963A48C75F1590804E7918A02EB9DA5F60F49828C +95AC60E9D86DEB7699C35037669C02D408269D6BF481EC745E4EC630F68FF5168BE5E0BDF875EEC1 +5EB9CAA9CBED1CE2A0EB4CE97C14E10114087DCBE5DE1DB6A070CBC6B68EE141B7D62ED320F7B74C +07D9762E0F5C8AF0779D38B7677ED65B5DD2F83ED06F041B5701228EFEAA0FFC031E44D6D68B274A +45FF9EB62FDA007CDC98B86831E9A668098364B421E1FE2A45D85824612A521777C6177316F0C6DB +D9847A2F61326E74A3114EAC3ABAEE456156DF125E4EDAD6BDB66E7DA6370C90ADC4AF4EC1958170 +C32D5AAF3B45BF749EE1DFAD8A5D0C03973B7C1589EAE4E67F6C87213C721E4A33466F3F54253545 +5014417CFFC9AF461CF695F5E1D7A37E4C7680A5624AA11EEA65C59BB38A96734E4A4A238C636638 +9EB8083D5AD753FA7F74EDF10054315EDD53DE61D48846F70AA9272626E23BA3DAB7CCEE819B0A88 +9CE775AA7F5205C95A19AAF475729D2C0BCAD9AB5459380A5F034C108A64B80621820D779582A198 +14058DFDCC6C2D6461AC6F98C64AABA53A2EF77CEF612EA766FE15498F56F54106D70D0F8DD4134C +8C64B282E79A96F15D4BBE0297885ACF775BA5009006315637D60AD86D25A3CA6AC5BF5B4DB95B1A +672A8C589D89101809D838236560F7690E329784C1D335203BFED3A258CD79467D16B6DA06A282BC +4B9669986CB50C54DADE3D5B20FD5CD9FDDE60AF4B5D8D9C50E77CF50DF3B36F37F381FE7E28A719 +91C8199D18258C09BD0440F5E258A5D2E22C6CFBFDC5F91228992E86532F4C0A50067BCB2D4387B2 +9FEFB8043D7BC44A322FD3629D7D92B6EEBA21B035DAC884110BDC6B22CF59B08C195BBA1C682E5F +8CF32F479937D329FE8EC6E9A3A3AA63AE95EEB766E0EACEEAD4DCF46617888AE687009112732A7A +8FA8419A4652075EDDF83E291613B66BA793D3858CEA093C79B89B0C93E11CAAB86AD1980C401713 +0B6A02545DE484FDA6E4DFBCEBBC848751B2A8821CB3F7AC96D2EA9B83B575AB60CECA41EA567EE0 +8ADAC8F1060255057527485D6B12A26D2E7EF6892865FD65FEF28F8B46249C4F19341089D59DAF82 +582CAD1A3B53C763A0E57134A57C4A24AB4FD358592ADB01BE8F1D9FAE9CA97A3BC3A0E2939913E0 +62960CC1D29ECEF9E61BAC20E92F13C49078E7F1562C9D7C01C2B300ECD6ADCAC9AA0C1F1BA30401 +0573F79D158C66D91A8D987C5239C9D4FEED1DC5C9586C4129C33E7C737C624EE9BD1EDE38E9F72A +78DC19E144B5AABF3B0FB72216815E371A5D6452684965CB7208B87CE5A27E444820E03F80AD2DF4 +E280D25D9BDE41E719BB2C939E25B7965DB162CA8665CBFE65DFDC7992A508D54FE4EE8454C11482 +7186A280D3D9EDF397640A809E3646675AB6621B9CDF42808E2F19859AC975CF70F41D2B3D22F8E0 +C180126F4A12122B207A150BC8E1819962DAEBB821DE59B7EEF8FF9219474597AF859E353B4B713F +5F1350F4049DCE99627492E396038B10A2F8E82AB679F65BE14A166E4502921BA44CCFE04E5DD3FE +B04BA47C3F7A3E7DBF7D55328AD1E96092C73EDB16C3325537295DF768E2633D01304EA0B01379AA +DAFE6CCA2AB3E246768C5AC841A458A2F69141A9A9D716D129B26643F1BBC95D8CD0ED44148F7C6A +F370201E454F4AFF7C11A8080508FEDE242343E7ADDD5A8AAF079C50765A79BD25FBBDC59EDF980F +FE0B60435692C49D20AC22F8BD1FCA3F3D8200CA26D61A30212558B54671E63BC09776A3AE7A906F +CA63281F080A00500C42C02B8F82357A3EBF572CFC4BEBA3FE86537DDDF23A861C240A31778A131E +F638C1DBB7E87A45487C092D23FD9FB2C162C3253636ED263B141178FCA9F2D5BE2D81F99B2872C4 +B3C08749CE18C9C00E75DA6B3E4C6A6DD79EBA731618EF5B5E767BB40429D8FEEC6ABFE9975746FB +3A82A03A07B7D0DA8BAECFD1F72AFE17EB0C0CF100A2D48F4449A42C482BB1D64C19F8FEA73F5BA1 +8FC9BFEE3F640C39C081669A9B0EE3FF6B2BDC0A726301EF0E2259E65BE59275C76E7A3F1C76C3A3 +3AD0E2F79198DCA39C482B4E1196238DBA937692CF319436830BBF441C0A8A04161DC0814B5DF049 +83099439EF421B6D37D351D4A988A8DFE93D796B2E8B2564C602F79E6162F56F933196A0DCE91051 +600BAFFD9D439A91F17C20CD6A9104B553D823A0317E3C8344E9F0B2560AD583BF876AE307892500 +2177AF61BDBD745CEC2B2A7931D27423D2667584AE0D6CAA2B281EB9271ADE86C493791AC9A2265B +8324F764D20DE65F6267439F1574DB02C600E771D3C743D420FA6F8BF01A977B91AF035E0D5412AB +0B85D6ED3ED9D0345ED434F9B95FD911A9D3828CD162686E6ECCD2B6A5B1104F0E6838AAC7FB3FC7 +09F08F8E82B4BFCB55D8984771F9F4D339EE7FF391448C7807A436A78B6A487D3A5A86F314B302FA +C5BE1C1DB9844F975619D615D1C7A20EC2B144797E0648CF5C044C8DD1699EEA3AC9D7E3BAA54A85 +11A932623D5ED3F0A9C3028CA439AC395F58DEAF1C0354A169D9AC7F380900D9828C3ECBB975F6FE +6BD79EA4BEA9B71F3A9B1D2EAF8F1E475B4FB99758192EBCDA21B47EA33F57C58E904DA260C801AE +CF457C84592B81CFA96C10E448D705D24871F3D1AD1FE004406C8070A54FA3747788C5B55E9462E6 +F51378BF3F848360542CAD2D5FF9EDAC84C164DFEC115A2F3D873760EAE58CC8F361B37E6CE076EF +325A1C54DFF84DB95DB7DB5B56C48ED15C5426E6153D8A94B1A35B22EAB1D7B871097DF12C093BA5 +538957AB7D0AB2E39A2D1AECB91F0A693B8F6A00601929B6C55AAE8A227CAB6404FEBCC8BC4EEEE0 +ADD4CFD7DEC225170A0063457918B9875AD7F022A8F9932ADE316E4126EAB75C1D0B2B9F44E85F1C +54755D1301345665EA630C8E885A8D9AB069DEA2CC6D12E4A0BF6E80C3AE12BC7ABE507422A5D92B +65F70B4A472DD945EBB960880EC4C34E4C206C260FDF86A997D7D399A0219A51E6F8BC1189EC0ED0 +B8686F0243BFAFD829979747442AB1DA8282F10F4C37C4E6C88D231460DA3BF34C23A4755E2F8F21 +F6D138C86B6091CB3BCE5ED170242C4CC87C010FE63DA9A2ECBDD85311DA8572AD67E40F744D2EC9 +6607701D9790574F051C859EF29291AFA301C809E0A5513DF9A7FC2DB1776DBD4A2CB622BD17811B +C0E584A8D89D4BEB17C2D0AA8BF31CD7E2B36C0E1888409788E30EAC2E46AFA1CFE457D3A19C28C5 +80669CB82CF36BF40DFAFED78F99A5D5DF189CE293413FFBA9E8D2457986C68483242AD767D5F026 +1CE303153C35D5DEB1789448088B51C48A9B8E903BBC69ED7FB0129CCE33A0337198F11DBA94FDAE +AD74BBC5E519F559094E15B03AF3EFA89DC38B4278C68D2AEEEBE4B28B351D7B72F52D94480D8CBC +06544645F20800B8284A4E7C8FAD59D0AA8EC8EC0551912CBC62694A5DD15C469BBE614FB187C084 +838D676E5A1CC8DFA8676758EB7D53FD2BA8F1C434F4F70AED8F2CE27EED2F6A82E20E30EACF9BF0 +CE28B4BF7D556815A887D777B7D75F60D2C410AA2D378B7BFAA6C3A5BF0A5EF80D3E35A0CF393A5E +BC27A895D712C6F004F1A03F9FCF493973F33E6FB106407DFD992AB0E9E36EF395663A6EEFFD71BB +2DAD9DFE6AA4685F307B8FD69BB2F74E672666414A71FA479B37D3DEF6AEAF80FA14821C65F7ABBE +5CC6DD49002216E23B3D22C282F3DE0077EA81017E79D8C3BDB61EC031CFB13FA981120A6C518F4B +4C39C9DD5AC6EDA29ABA527C9948BC3162EF65E8251C9D4E3494C6A51A41D489F8BC89250128EBD7 +0EFD01B9F03C40B6E0384364F2571F7D969016A959E4243D7AB728F0F030B8E2FB456D8E47A85898 +313B0E91C68C7A8A7226603427AC6DCB5C69924FD026E90CB0EE89AC42D874BB15AFC981079E9DC7 +1271C3E461265AF327D4AAB4AEFAB6A9DC3F84DCE7C7868D4719006344B9055C8BA952A2250B8041 +E5EF519BB788201124BE90AECAC2293A310D9565E1EA4AEB99F7ED7106649169E8EBF3DCB210706A +F2FA65158D3059DFBD7AB5B00DBB06B016F73FEDB3AE1C1CC03BC2D94B143BFBD759338EB181B1F6 +841F7B539D8D126FC5B31B244A3A00ABBB121A98F73314D1F1683F513C3CCC9A0C2180824ACE5D45 +E454062CE1217F7AFBDC60A6022B0134EDA6C5D787DE8A5925BEB374F64D612329B9AC17B6EC03F8 +56CFEE502C1FC3AAC7B6F251E8DE4147DCB1580185C406F38E6B729307EADFF6D7A0E824C9830093 +F0C4FECEEFC7FF839306FEFEB780FFBD8879F22AFDADCA4C0767B8EEAE5DB869D7BD91355F0255E1 +CAC68A81A276967F233624DE0D2082B89E2C2D1DB0F8BE0B2BD7051C4DE9B1564AA6CBA03E50386F +D685943D1EDDF5BE0EB34418C48E5EA645CBA552A0444B254E82E9E84A5B7BD0064D5EA87B1716C1 +4EF7FD14E2187FCE16FF6ECBC0A6588B30B4329626F024BDBA65457028668BC6750A4DD668D017CC +EF35CD9CF45EC73885FC91B8AD78920919B4747A710D25BB850B558C5CCF7170C20012DD0F2874A6 +699DF53EDC6C75716A5B6B06C98F4904BAD22B18C77B3EEF32DE3F45A8AC12383DA16DF6F06CD923 +D344CFC2253ECF97A52F2DC6A22539231E29A324F851265BA82BE566E42167247CEBD914EBE42EAB +E189E74FE1FF17ADA8A5F47DC9866CF86694DEE28EED333B0A8AE380557820E3F1D32B05AE27FFE1 +68267FADD310C4EE550F71704EF71F4C669952F30E485AF37561884066C0E3425C748BBAC77CC7A9 +87EC336B8BEBA44358BEA4ECFEA32494A8006E9852C4BFCB1C0F00ACC247F1F8E3F3B34539C67638 +64527F9F885132DCACBFCB1DC80EE3B2A711145DDA1D3B5F83144E2CD698D43A02B0DEB706C78D75 +A24FA39B9374E1155969FAD7D5FB477F4C3C7440DBFE1BD1DC877360E8690A6D3A64EF0A1313A520 +C49320295302227CE5625E134EA442A537505D206EE46E7E218BDA38F7B6BA124ACA0E949725CEEB +961EF8B0727E3A78287E61E65A84AC14D1014A213259A48F04C634C1F04C73B4110D0DB491250CCD +7DAE323CC8BD29BEF605DD92AA5480009DEAD1256E5C9FFB18362D63B022C2A378D15ADE2C6AE603 +1DF385CF090226F0AF889464584A9EA63B884453DE231058C5661C4F7DCF7505D7B1E48C78AA5799 +8FF39084FFF1CD18CB2989D867F2E085B291FE52367B4E8667E5CDA4F41DDBC7129DA5BDC39549E0 +8B67D9C9E4C332D91FE261728521245CBF51870F24C42F5814F393719A9E126C5693C0E776E4D8F3 +0F0288537B8E9A7C5DA4F931FC83F96A1950B1DF26C0448B646D3BF42C0429E2BD0164703FC71833 +19DDEA75CE65D9DFFE8369787FE664306D843421C2C0C3A5B210E823F8366161A96CA88D95FD6486 +5F9E5B0D53DCEE4A98AC10A8FF1BC34A46DB6016E973C9FA298D3F58228E3D9FCCCF9632556CE2E7 +F9C81E05FDB0FC1071E69A4C158E742D0B8939CA3DE33A4BE8D01D679C81C6BA9CF396A6768CA626 +05D796AA5C323E3A6208F2DA5000FC4462ED81AD0044D9959E40E4764562ADA76E33EC63271966F1 +7A13AD376A54FFA40FA247896A22C1C4A4CE51094CA1892A0B9904EB762839AAE1EDB5A0A5A69343 +CCA45F88F61926B23E6C85688862B1D10F1ED827FCCE2A427E49D960DBEE0D39EDE08D2565C6F5AD +66CA83DAC1467C38F742132F715DA7E9757A5D067FDB4A8859D148473F302BF6ECB9B7EA5C0DF851 +8F58D4D076625B92BC8201028064950D70CD40492DA83B98FFD79BD3DCD9CEE95178B6DEA9AB10B3 +4C61A74B49C3697CF714F56A9B1E366B04500C9A67704AF6F721851EA4566B96E220E7B526873F94 +E6013EA8C489639D291167BCAEFB661C96C27DC7BCD5B317C1F101CD8DF2FB29F6162B5ECE903C0D +5570C8C6325F05218850E4A5B5F94C7CE334BADDFC5DB98EF5333B4A92129F41D046D0F5EB6F342C +F362BC8E45511FCF328E2CE2D4C579516307AEC400BA207071C887F5185AF536A6827307D7698095 +E8A6F8C19812A11C32AD207FBC353172C8DF626C5C05CD24C171B3C8DAB270A74AC48E35F0A8849C +E0934B93D56C93599F5235EC441B5232257C4C6767C7B5A35830010E60E56AFBE9199B42E725A216 +C49D45A3C554767DF192F04D1A192D5CE196831EB7A56201A4A96CD44DD084729774334F698E1902 +614405347A37A4C753C0211D7F24D5265CF033E3C4D30E61886CF781D2AC30385E6021A892AB116D +1F5505635BF5C915D0300ACA8AC32CAA0F3639550C4AEB390DA7B86E53B6BB0E4819626757BA9986 +BCA4B4B18F6BF3706577A3BE146F2585025D5A36EB14E587C5469EEEB622D31FD32EBFA812B9CCDC +CFF7D17D00D9F21BF8871661F20E89A25A4543068EC509D0DF7DEA2A24FF68957943BE0FC7BD319D +92A575E12E6FB8112D72A100FEF3EE85972304BBE07FC1026CCC068E8A414F641116E51F76009C5A +F9E664BCCF93C943CFF2115235BB3290F935AA3FAB4F2E73FCDB9FA5E1866EFE278FFE7EA9DD6F89 +38CD5E5F4F31F6C659AF7EFF5B291AFB86521678B42C99275024EDAD04E5929D201A36F4A6C4DCD7 +2E349D6B9A1F90B123DEDE3DA50EDF929F9285747CD504C8F4A73D522F312D623BD65A35419C0729 +30976129B2D99B32D1DEDD81D64F7879CEDDFF04BBBF1286E07BCE651E2DEC190DFB9D25F3C1EEC8 +D7277752BB7CCC313A0FEEBF0EFFA2A189861AD4EA13AD4FDBD5160DC273F12525815F0D693C1413 +AFE4FBE09BCBD71E16C33E6CF8D18732447FFDCC2E4AF9E270D725C1D262D96E72538CA3309BCAF2 +35A3FAFAB27D265C583E6F6F062B555C97DFD89AC46E6154670ADCA13FD99F7A4B9B8BB224D43764 +8CC9DB76E177F562862C912D8CBC248A4C628FF2D0C9688611CED3DFB89064B988F16655633B7CC7 +AFAE34B2937528EA0814ED245D6B0D2AEF87A5B63E2BD7E4F7D9CFE372C295A0891F97C3855C97EC +C03C7C2A231704BED419612255F8B2C9262D48CB4FB46D63CC9697A210FA9D7BFC3BAB7E46172D3F +52A4AF9C4114BC72A5C7CBA042FA633AFD5E404F29408D4485837E55E6F9702F04C7AB410C351039 +6A78C8672F8EAD53BB9CBCED63FB9E72E7238CC88FB4E7C48C3DE3E4B80E277B952727916A4127A2 +5CC1413C390F4DAFD5253B07BC96DAE8CF4DA08330DEE580CBC1E12B75A661819E96B018D47A8B71 +B6BFAFC5E3CBFE68E5193417B6E730E6A2820838D22049BE6BB64B74AA13779D46519965ED80D5FC +30B0A6F73D26DEBD8150B3D27B3F135F608D59BB1632AD9C2E11177FAF54CBD1C4E58D58C395BAE8 +AD7C7AEEB0E1C3F0C0B7A5E7142E9A1DCCC8B4EF56C319D4A4F750857D2FD180F871772B9CC69FB9 +B222F83C3ACCB66125AF6848B2EFDCE3D2284FA5844641FB32F701FBF32F1D2F2E2233B66E36CCD1 +49FCB3FCDB6EA04367D11624717D73D9128EA7D9AABB8658BE9E9986E532 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +cleartomark{restore}if + +%%EndFont +%%EndResource +11.52 /Mathematica1 Msf +0.75 10.5 m +(p) N +P +[1 0 0 1 -61.69 -151.566 ] concat +1 w +[ ] 0 setdash +P +P +[ ] 0 setdash +p +0 setlinecap +70.6 105.842 m +73.497 105.842 L +s +P +p +np 52 98 m +52 113 L +69 113 L +69 98 L +cp +clip np +p +1 w +0 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +[1 0 0 1 53.44 99.467 ] concat +1 w +[ ] 0 setdash +p +np -2.44 -2.467 m +-2.44 14.533 L +16.56 14.533 L +16.56 -2.467 L +cp +clip np +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +11.52 /Times-Roman-MISO Msf +0 10.5 m +(2) N +11.52 /Mathematica1 Msf +9 10.5 m +(p) N +P +[1 0 0 1 -53.44 -99.467 ] concat +1 w +[ ] 0 setdash +P +P +[ ] 0 setdash +p +0 setlinecap +70.6 53.742 m +73.497 53.742 L +s +P +p +np 52 46 m +52 61 L +69 61 L +69 46 L +cp +clip np +p +1 w +0 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +[1 0 0 1 53.44 47.367 ] concat +1 w +[ ] 0 setdash +p +np -2.44 -2.367 m +-2.44 14.633 L +16.56 14.633 L +16.56 -2.367 L +cp +clip np +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +11.52 /Times-Roman-MISO Msf +0 10.5 m +(3) N +11.52 /Mathematica1 Msf +9 10.5 m +(p) N +P +[1 0 0 1 -53.44 -47.367 ] concat +1 w +[ ] 0 setdash +P +P +1 g +[ ] 0 setdash +p +0 setlinecap +78.19 2.952 m +78.19 5.849 L +s +P +p +0 setlinecap +92.764 2.952 m +92.764 4.69 L +s +P +p +0 setlinecap +107.338 2.952 m +107.338 4.69 L +s +P +p +0 setlinecap +121.911 2.952 m +121.911 4.69 L +s +P +p +0 setlinecap +136.485 2.952 m +136.485 4.69 L +s +P +p +0 setlinecap +151.058 2.952 m +151.058 5.849 L +s +P +p +0 setlinecap +165.632 2.952 m +165.632 4.69 L +s +P +p +0 setlinecap +180.205 2.952 m +180.205 4.69 L +s +P +p +0 setlinecap +194.779 2.952 m +194.779 4.69 L +s +P +p +0 setlinecap +209.353 2.952 m +209.353 4.69 L +s +P +p +0 setlinecap +223.926 2.952 m +223.926 5.849 L +s +P +p +0 setlinecap +238.5 2.952 m +238.5 4.69 L +s +P +p +0 setlinecap +253.073 2.952 m +253.073 4.69 L +s +P +p +0 setlinecap +267.647 2.952 m +267.647 4.69 L +s +P +p +0 setlinecap +282.22 2.952 m +282.22 4.69 L +s +P +p +0 setlinecap +296.794 2.952 m +296.794 5.849 L +s +P +p +0 setlinecap +311.367 2.952 m +311.367 4.69 L +s +P +p +0 setlinecap +325.941 2.952 m +325.941 4.69 L +s +P +p +0 setlinecap +340.515 2.952 m +340.515 4.69 L +s +P +p +0 setlinecap +355.088 2.952 m +355.088 4.69 L +s +P +p +0 setlinecap +369.662 2.952 m +369.662 5.849 L +s +P +p +0 setlinecap +384.235 2.952 m +384.235 4.69 L +s +P +p +0 setlinecap +398.809 2.952 m +398.809 4.69 L +s +P +p +0 setlinecap +413.382 2.952 m +413.382 4.69 L +s +P +p +0 setlinecap +427.956 2.952 m +427.956 4.69 L +s +P +p +0 setlinecap +442.53 2.952 m +442.53 5.849 L +s +P +p +0 setlinecap +450.12 210.041 m +447.223 210.041 L +s +P +p +np 451 203 m +451 217 L +459 217 L +459 203 L +cp +clip np +p +1 w +1 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +[1 0 0 1 452.28 203.666 ] concat +1 w +[ ] 0 setdash +p +np -2.28 -1.666 m +-2.28 14.334 L +7.72 14.334 L +7.72 -1.666 L +cp +clip np +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +11.52 /Times-Roman-MISO Msf +1 g +0 10.5 m +(0) N +P +[1 0 0 1 -452.28 -203.666 ] concat +1 w +[ ] 0 setdash +P +P +[ ] 0 setdash +p +0 setlinecap +450.12 157.941 m +447.223 157.941 L +s +P +p +np 451 151 m +451 165 L +460 165 L +460 151 L +cp +clip np +p +1 w +1 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +[1 0 0 1 452.28 151.566 ] concat +1 w +[ ] 0 setdash +p +np -2.28 -1.566 m +-2.28 14.434 L +8.72 14.434 L +8.72 -1.566 L +cp +clip np +11.52 /Mathematica1 Msf +1 g +0.75 10.5 m +(p) N +P +[1 0 0 1 -452.28 -151.566 ] concat +1 w +[ ] 0 setdash +P +P +[ ] 0 setdash +p +0 setlinecap +450.12 105.842 m +447.223 105.842 L +s +P +p +np 451 98 m +451 113 L +468 113 L +468 98 L +cp +clip np +p +1 w +1 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +[1 0 0 1 452.28 99.467 ] concat +1 w +[ ] 0 setdash +p +np -2.28 -2.467 m +-2.28 14.533 L +16.72 14.533 L +16.72 -2.467 L +cp +clip np +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +11.52 /Times-Roman-MISO Msf +1 g +0 10.5 m +(2) N +11.52 /Mathematica1 Msf +9 10.5 m +(p) N +P +[1 0 0 1 -452.28 -99.467 ] concat +1 w +[ ] 0 setdash +P +P +[ ] 0 setdash +p +0 setlinecap +450.12 53.742 m +447.223 53.742 L +s +P +p +np 451 46 m +451 61 L +468 61 L +468 46 L +cp +clip np +p +1 w +1 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +[1 0 0 1 452.28 47.367 ] concat +1 w +[ ] 0 setdash +p +np -2.28 -2.367 m +-2.28 14.633 L +16.72 14.633 L +16.72 -2.367 L +cp +clip np +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +11.52 /Times-Roman-MISO Msf +1 g +0 10.5 m +(3) N +11.52 /Mathematica1 Msf +9 10.5 m +(p) N +P +[1 0 0 1 -452.28 -47.367 ] concat +1 w +[ ] 0 setdash +P +P +p +np 210 257 m +210 272 L +310 272 L +310 257 L +cp +clip np +p +1 w +1 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +[1 0 0 1 211.235 257.578 ] concat +1 w +[ ] 0 setdash +p +np -2.235 -1.578 m +-2.235 15.422 L +99.765 15.422 L +99.765 -1.578 L +cp +clip np +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +10.08 /Times-Roman-MISO Msf +p +0 9 m +(I) N +P +p +3.75 9 m +(m) N +P +p +12.75 9 m +(p) N +P +p +19.5 9 m +(a) N +P +p +24.75 9 m +(c) N +P +p +30 9 m +(t) N +P +p +36.75 9 m +(p) N +P +p +43.5 9 m +(a) N +P +p +48.75 9 m +(r) N +P +p +53.25 9 m +(a) N +P +p +58.5 9 m +(m) N +P +p +67.5 9 m +(e) N +P +p +72.75 9 m +(t) N +P +p +76.5 9 m +(e) N +P +p +81.75 9 m +(r) N +P +86.25 9 m +(,) N +92.25 9 m +(b) N +P +[1 0 0 1 -211.235 -257.578 ] concat +1 w +[ ] 0 setdash +P +P +p +np 34 75 m +34 165 L +49 165 L +49 75 L +cp +clip np +p +1 w +1 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +[0 -1 1 0 35.28 164.105 ] concat +1 w +[ ] 0 setdash +p +np -1.895 -2.28 m +-1.895 14.72 L +90.105 14.72 L +90.105 -2.28 L +cp +clip np +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +10.08 /Times-Roman-MISO Msf +p +0 9 m +(S) N +P +p +6 9 m +(p) N +P +p +12.75 9 m +(a) N +P +p +18 9 m +(t) N +P +p +21.75 9 m +(i) N +P +p +24.75 9 m +(a) N +P +p +30 9 m +(l) N +P +p +36 9 m +(r) N +P +p +40.5 9 m +(o) N +P +p +46.5 9 m +(t) N +P +p +50.25 9 m +(a) N +P +p +55.5 9 m +(t) N +P +p +59.25 9 m +(i) N +P +p +62.25 9 m +(o) N +P +p +68.25 9 m +(n) N +P +75 9 m +(,) N +10.08 /Mathematica1 Msf +81.75 9 m +(c) N +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +10.08 /Times-Roman-MISO Msf +P +[0 1 -1 0 164.105 -35.28 ] concat +1 w +[ ] 0 setdash +P +P +p +np 70 3 m +70 238 L +450 238 L +450 3 L +cp +clip np +p +np 117 136 m +117 152 L +155 152 L +155 136 L +cp +clip np +p +1 w +1 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +[1 0 0 1 118.485 136.705 ] concat +1 w +[ ] 0 setdash +p +np -2.485 -1.705 m +-2.485 16.295 L +37.515 16.295 L +37.515 -1.705 L +cp +clip np +p +np -0.485 0.295 m +-0.485 13.295 L +35.515 13.295 L +35.515 0.295 L +cp +clip np +[1 0 0 1 0 0 ] concat +1 w +[ ] 0 setdash +p +np -2.485 -1.705 m +-2.485 15.295 L +37.515 15.295 L +37.515 -1.705 L +cp +clip np +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +9.72 /Times-Roman-MISO Msf +%%BeginResource: font Mathematica2 +%%BeginFont: Mathematica2 +%!PS-AdobeFont-1.0: Mathematica2 001.000 +%%CreationDate: 8/28/01 at 12:01 AM +%%VMusage: 1024 29061 +% Mathematica typeface design by Andre Kuzniarek. Copyright \(c\) 1996-2001 Wolfram Research, Inc. [http://www.wolfram.com]. All rights reserved. [Font version 2.00] +% ADL: 800 200 0 +%%EndComments +FontDirectory/Mathematica2 known{/Mathematica2 findfont dup/UniqueID known{dup +/UniqueID get 5095653 eq exch/FontType get 1 eq and}{pop false}ifelse +{save true}{false}ifelse}{false}ifelse +20 dict begin +/FontInfo 16 dict dup begin + /version (001.000) readonly def + /FullName (Mathematica2) readonly def + /FamilyName (Mathematica2) readonly def + /Weight (Medium) readonly def + /ItalicAngle 0 def + /isFixedPitch false def + /UnderlinePosition -133 def + /UnderlineThickness 20 def + /Notice (Mathematica typeface design by Andre Kuzniarek. Copyright \(c\) 1996-2001 Wolfram Research, Inc. [http://www.wolfram.com]. All rights reserved. [Font version 2.00]) readonly def + /em 1000 def + /ascent 800 def + /descent 200 def +end readonly def +/FontName /Mathematica2 def +/Encoding 256 array +dup 0/NUL put +dup 1/Eth put +dup 2/eth put +dup 3/Lslash put +dup 4/lslash put +dup 5/Scaron put +dup 6/scaron put +dup 7/Yacute put +dup 8/yacute put +dup 9/HT put +dup 10/LF put +dup 11/Thorn put +dup 12/thorn put +dup 13/CR put +dup 14/Zcaron put +dup 15/zcaron put +dup 16/DLE put +dup 17/DC1 put +dup 18/DC2 put +dup 19/DC3 put +dup 20/DC4 put +dup 21/onehalf put +dup 22/onequarter put +dup 23/onesuperior put +dup 24/threequarters put +dup 25/threesuperior put +dup 26/twosuperior put +dup 27/brokenbar put +dup 28/minus put +dup 29/multiply put +dup 30/RS put +dup 31/US put +dup 32/Space put +dup 33/Radical1Extens put +dup 34/Radical2 put +dup 35/Radical2Extens put +dup 36/Radical3 put +dup 37/Radical3Extens put +dup 38/Radical4 put +dup 39/Radical4Extens put +dup 40/Radical5 put +dup 41/Radical5VertExtens put +dup 42/Radical5Top put +dup 43/Radical5Extens put +dup 44/FixedFreeRadical1 put +dup 45/FixedFreeRadical2 put +dup 46/FixedFreeRadical3 put +dup 47/FixedFreeRadical4 put +dup 48/TexRad1 put +dup 49/TexRad2 put +dup 50/TexRad3 put +dup 51/TexRad4 put +dup 52/TexRad5 put +dup 53/TexRad5VertExt put +dup 54/TexRad5Top put +dup 55/TexRadExtens put +dup 56/LBrace1 put +dup 57/LBrace2 put +dup 58/LBrace3 put +dup 59/LBrace4 put +dup 60/RBrace1 put +dup 61/RBrace2 put +dup 62/RBrace3 put +dup 63/RBrace4 put +dup 64/LBracket1 put +dup 65/LBracket2 put +dup 66/LBracket3 put +dup 67/LBracket4 put +dup 68/RBracket1 put +dup 69/RBracket2 put +dup 70/RBracket3 put +dup 71/RBracket4 put +dup 72/LParen1 put +dup 73/LParen2 put +dup 74/LParen3 put +dup 75/LParen4 put +dup 76/RParen1 put +dup 77/RParen2 put +dup 78/RParen3 put +dup 79/RParen4 put +dup 80/DblLBracket1 put +dup 81/DblLBracket2 put +dup 82/DblLBracket3 put +dup 83/DblLBracket4 put +dup 84/DblRBracket1 put +dup 85/DblRBracket2 put +dup 86/DblRBracket3 put +dup 87/DblRBracket4 put +dup 88/LAngleBracket1 put +dup 89/LAngleBracket2 put +dup 90/LAngleBracket3 put +dup 91/LAngleBracket4 put +dup 92/RAngleBracket1 put +dup 93/RAngleBracket2 put +dup 94/RAngleBracket3 put +dup 95/RAngleBracket4 put +dup 96/LCeiling1 put +dup 97/LCeiling2 put +dup 98/LCeiling3 put +dup 99/LCeiling4 put +dup 100/LFloor1 put +dup 101/LFloor2 put +dup 102/LFloor3 put +dup 103/LFloor4 put +dup 104/LFlrClngExtens put +dup 105/LParenTop put +dup 106/LParenExtens put +dup 107/LParenBottom put +dup 108/LBraceTop put +dup 109/LBraceMiddle put +dup 110/LBraceBottom put +dup 111/BraceExtens put +dup 112/RCeiling1 put +dup 113/RCeiling2 put +dup 114/RCeiling3 put +dup 115/RCeiling4 put +dup 116/RFloor1 put +dup 117/RFloor2 put +dup 118/RFloor3 put +dup 119/RFloor4 put +dup 120/RFlrClngExtens put +dup 121/RParenTop put +dup 122/RParenExtens put +dup 123/RParenBottom put +dup 124/RBraceTop put +dup 125/RBraceMiddle put +dup 126/RBraceBottom put +dup 127/DEL put +dup 128/LBracketTop put +dup 129/LBracketExtens put +dup 130/LBracketBottom put +dup 131/RBracketTop put +dup 132/RBracketExtens put +dup 133/RBracketBottom put +dup 134/DblLBracketBottom put +dup 135/DblLBracketExtens put +dup 136/DblLBracketTop put +dup 137/DblRBracketBottom put +dup 138/DblRBracketExtens put +dup 139/DblRBracketTop put +dup 140/LeftHook put +dup 141/HookExt put +dup 142/RightHook put +dup 143/Radical1 put +dup 144/Slash1 put +dup 145/Slash2 put +dup 146/Slash3 put +dup 147/Slash4 put +dup 148/BackSlash1 put +dup 149/BackSlash2 put +dup 150/BackSlash3 put +dup 151/BackSlash4 put +dup 152/ContourIntegral put +dup 153/DblContInteg put +dup 154/CntrClckwContInteg put +dup 155/ClckwContInteg put +dup 156/SquareContInteg put +dup 157/UnionPlus put +dup 158/SquareIntersection put +dup 159/SquareUnion put +dup 160/LBracketBar1 put +dup 161/LBracketBar2 put +dup 162/LBracketBar3 put +dup 163/LBracketBar4 put +dup 164/RBracketBar1 put +dup 165/RBracketBar2 put +dup 166/RBracketBar3 put +dup 167/RBracketBar4 put +dup 168/ContourIntegral2 put +dup 169/DblContInteg2 put +dup 170/CntrClckwContInteg2 put +dup 171/ClckwContInteg2 put +dup 172/SquareContInteg2 put +dup 173/UnionPlus2 put +dup 174/SquareIntersection2 put +dup 175/SquareUnion2 put +dup 176/DblLBracketBar1 put +dup 177/DblLBracketBar2 put +dup 178/DblLBracketBar3 put +dup 179/DblLBracketBar4 put +dup 180/DblRBracketBar1 put +dup 181/DblRBracketBar2 put +dup 182/DblRBracketBar3 put +dup 183/DblRBracketBar4 put +dup 184/ContourIntegral3 put +dup 185/DblContInteg3 put +dup 186/CntrClckwContInteg3 put +dup 187/ClckwContInteg3 put +dup 188/SquareContInteg3 put +dup 189/UnionPlus3 put +dup 190/SquareIntersection3 put +dup 191/SquareUnion3 put +dup 192/DblBar1 put +dup 193/DblBar2 put +dup 194/DblBar3 put +dup 195/DblBar4 put +dup 196/BarExt put +dup 197/DblBarExt put +dup 198/OverCircle put +dup 199/Hacek put +dup 200/VertBar1 put +dup 201/VertBar2 put +dup 202/Nbspace put +dup 203/VertBar3 put +dup 204/VertBar4 put +dup 205/FIntegral put +dup 206/FIntegral2 put +dup 207/FIntegral3 put +dup 208/OverDoubleDot put +dup 209/OverTripleDot put +dup 210/OverLVector put +dup 211/OverRVector put +dup 212/OverLRVector put +dup 213/OverLArrow put +dup 214/OverArrowVectExt put +dup 215/OverRArrow put +dup 216/OverLRArrow put +dup 217/Integral put +dup 218/Summation put +dup 219/Product put +dup 220/Intersection put +dup 221/Union put +dup 222/LogicalOr put +dup 223/LogicalAnd put +dup 224/Integral1 put +dup 225/Integral2 put +dup 226/Sum1 put +dup 227/Sum2 put +dup 228/Product1 put +dup 229/Product2 put +dup 230/Union1 put +dup 231/Union2 put +dup 232/Intersect1 put +dup 233/Intersect2 put +dup 234/Or1 put +dup 235/Or2 put +dup 236/And1 put +dup 237/And2 put +dup 238/SmallVee put +dup 239/SmallWedge put +dup 240/DoubleGrave put +dup 241/Breve put +dup 242/DownBreve put +dup 243/OverTilde put +dup 244/Tilde2 put +dup 245/Tilde3 put +dup 246/Tilde4 put +dup 247/BackQuote put +dup 248/DblBackQuote put +dup 249/Quote put +dup 250/DblQuote put +dup 251/VertBar put +dup 252/DblVertBar put +dup 253/VertBarExten put +dup 254/DblVertBarExten put +dup 255/Coproduct put + readonly def +/PaintType 0 def +/FontType 1 def +/StrokeWidth 0 def +/FontMatrix[0.001 0 0 0.001 0 0]readonly def +/UniqueID 5095653 def +/FontBBox{-13 -4075 2499 2436}readonly def +currentdict end +currentfile eexec +D8061D93A8246509E76A3EC656E953B7C22E43117F5A3BC2421790057C314DAE3EFBFF49F45DD7CD +91B890E4155C4895C5126A36B01A58FDB2004471266DA05A0931953736AD8B3DEB3BCB2A24BC816A +C1C90A1577C96B9096D6F51F9E21E625ADF6C3A49867A632A605C117E6325C820121799F412E226B +EFE61F2813676F172CBD7EC10FF1EFBB92DF3A88E9378921BBD00E6024CC08EF057CECD09B824E0A +CCDAA4644296DE34D19D779A21C30666026829D38FB35A2284CAED23C8B913E7B28BB3DA7C8CE390 +4C0BAE30B0287680CCCAB2E6D4CAB2E7D786ABF54068028FD7D94FAC236094761B62B7E76F68D2BE +58C23AF85001950EFC1A9C1BB71520B78DDF6AA0058D25D041E86D01878DF56A5C48D74DCB2BBD68 +D75C94A3CE878484D28049331CE3D4364B40FAA2C754E8F443D244C5BC44B1C7868E36EAF4F7EF1F +6CB81E6CF63FABD65C29A991EB7D724DA06535AE43F3D0E2D04F6113B493C15463B4CEBFB72AB879 +7E4645F9CC0BB17E02A9626BEA4B4259F798B53B18DF2ACCF2B86BF2209CF0265DE0A46869333F98 +CCF70BF2C9239A0ABD2E97923AA5695BAFEA31E27B8F532BAA45F2980A11D069265A5312A260A627 +A765C4A08897E5C500990AE6FDA4CD6D575905468417297380EB6400CB2CF001C4B8EB79811CD8D7 +C173A337922B99DAB1048D5D03C78F78F36FEE31673D8C5FF8AD689A63AEA055CA705DB47D3AF965 +73571985E62F63866018C96EC4CA7E735C9294D8C81C03806D23CB87C0C08F86F5FA68CFC9AE48F6 +958AE016DCE4D60EB64AEAAD59D8A2592BC398BCA479FBC2F0C20C3E7F730481494C88781A6A9E0E +4F47A94619A3841FAC76A4FB252EB6FB43628AE1A4944539B1DFF672940AA5E93FFACFAC04624EF6 +7ED9C691788F0004DB7FFD1C995F2C52C0042F02F5C789F85D9E51716F3B4EDB21D4B9E660E4A892 +B747201EEC6DD6A8881FA3039664061094D1892108A2AD068D7F0251BFA72D874ECB2F42D27CC343 +052156F6A3A66D2CA6DAEF046A433FD54FEB4410315690971D0F43363EC0119B21F4BE3DFDC8C28D +BF5D68F145D3AC932EE62C32DFDEB1C48C2455392193268C893093BF911645986607DD13D8285895 +1854A7FF81FC98ADD44742907818B3C8E3187371BD9FE6EF5B4315E82C359BF2EA91D2894EE7FD9A +734BF2745D7FE8D08D29DA2A03176C992E11F1AADCE219D5E33F325BCFF4521D6D04E61B913B6C41 +740AF8BD9EA83F3AE7C4E5402366A812B1724431EE78D2028317B975E91941B591CC6C97740C453C +C7D7AB3CE97AE2F4DFAB6B9C8810A52A276BEAABD687BDA0971EE623A40B7AD6A8E69ED8BE63959D +3DCF8799E2505AC7F7B0E2FFECB0B08027A6266B7F96311B0AD78B7B6C78392AA062A73FDF179FEC +7F748929D060289F899FE417D4028FF332204FE04146BB130EF05FB57AF4BF9337EF71094DC5922E +3EF2D6A9F8257AF242019C349B65C2A3972ACA842D14EAB6A8D287456C9D7D295198F4AB7632EE43 +7D006B8124A80BBF26C1B902379D7F90080B51F982630E27B6031CE20930C273EA5D7FF0FC7E996E +67B072796CD96A7739444D21FE10DE7B57D143E4155EEE1B89F32EBCBF4C64D6D3FA1C46E06C9E9F +F99BC9BBCC61A400C7DBF812C42AAED863FE9EE3B02E731D1809F3CAB941252DE486BFE641F60F60 +C788F68519A6B04A4D6F50F02F93C6B8774B960C1FE893373D2AC2D865C487CFFE7669E1F1E73630 +7D34C15835F0453C8B0C1AE352CE1F27065F1082E6C84F86330F76B39C246315D6996AB69F81A020 +30D92CCB4C2A5AA4F4B3CAC88B2C8C9C621294A5EAB6AC3778DB99BD2F411735DC1421861417B4FD +399B365AEA45185A3D9D687546E36BB73994FB7FA3EE890AE3734BD9381B0E7AE514E8C517B87268 +7364C38D0A8379039F33336799205F2F54BBF7C2E9B30B27BCFB9FF2CD64F5D700F2455EE66B6252 +6E79ED2B0E5FF9732281CA50D27A93F259B6D4B5C7F856BB7D4F2E0F7741FA2419BBAF86C372E34D +59BC7AABC4CEF4F47EE40E118AB95A4863E16C55824D34002D59844D1F51B5DC6FB6BB5D595C4404 +1E05A84FD453A129279F894D726F6CD53BA3E234518324C5F715DAE6E7B5695326FC0C9B6CA2B53D +B25EC76BE9662388058629E70DC7BD861E188F1FF32A754A455195163CB4754D116D24E6A6300B67 +1862625E260442DEA2505E36D5F7AA4AD1FEB3B42632E382959C7E84569B2A790A0D0A208C2D4816 +AD28046B42C7A4797D424277AD9425C04DB87DCF112AE431CFFF6E4FFA979E947502AE5E1755C112 +0AE2361888B956F3F513A5975680E6E8374D8BF26C32AADC826D729E9026B14A68BC3D065E11C697 +D4D474CF963AFE083DD7D9278A0C27447E25AD70DD40B2EBAB8040164E11CD75AE3125C29806DEF4 +AD1B989F7001E227685DEF6EBE3287DE43BBA5FE2123A0EC835AECF879C13F7CFDC409901F291E89 +06C26E42B189862AFAE029F03D86D35E44E318FE16537E2B73E4F39F1E6945A3A6432438DCB6D2B2 +09814B5228D08165568617C279499ECA1B88C90300F1C88C45D4BE3DC726A59E24B46C5B2FF228C6 +E6645819C6F1D5B05737BE7353F4787EE52A21DC47A44F3C44406E79BBFDDC164682B02F4C39300D +12EF37A58E317FC1B8CE58E04BE666ED5DA75DBF752BEDDA4C7491E4D6922BCCA9CF421CE6751002 +8638EF643119841F423626D6B19A5D2CFB193B093D7646913F64614C098E5F5FF9422EBA75FA9AA8 +4F8ED114AEAB011E6F0727FB96F26BECBBAFE3AA8D0ABC5A8E9906B6CBB9E03F8CC4FCA97C884B83 +7CC33C619CD3195C55633B72D3F2D45561CD226F42B859B8099812D591886FA851107A185169FA7C +944248DE28642FA3043FF3B60236BFD781257C6FE4D56174AD16ABBF9659C05F08673A70496A0787 +C187D4367CB0CF48BD9A4FE0E481273E4909A1092626A13917DCBDE920028B06E094F5B28887B990 +32521E1720B75EB284AA6FFE53FA5CD5B903F951FCF7B33CC981FE7BCC4BDF4907ACC3AA60B69969 +A9AF204C84EC8C0F5DCB8A85E39EA9F2D4B67095A44CA0C8B072D7A61F3015D502B1A0F660C22221 +3231986D5E8C04AECBAFE999D1735A80051C06CA279D0FF6215633FB7A706454DA7236DB17AD72EE +1F6044A26A0EB77AB3BCE823E3F5E0DD31ACB029A1D17665FF16E5D1ACDDFD83CAEE1D48666D7BC6 +DADC34D317C335855D118892CBD32412F5870C3D2E599A46AA997A5E2BBDD3001C2957D81345DBED +583B72C4FB356F0C872A31A35087775EF18601930C0874EEA1ACB3ED3690EF447926439CC383087C +C9D5C6EB21EDF5941CB4E99FDA434A91676D76DC1A1BD801EECA6B0A88370B7005D41A1253CF8217 +1285986DC302B51123DBA9733BDEF0361AE0580FE6FBA5F29CF1438801586559D7436436CFE33E6A +D6EFA850BB8C9382E1A068246F370388186DC278F31F770C2C96881AC6E40823B24D6D536514A2C7 +AF3D159621080442592CAC03D6967BCBDB38FCA1A45F76F1A10027F1DCC076533C6AFC097FBCF0DA +A0078BE0828247F938AF76A87EFC14D9F5444CBCDCE637E2325D86B9D99D1ED70F44194E19F6C7A9 +9E415DC8A6E484DAAE52AAC1307A5353E8F649A35214B3F43DB5F3DB3ED06580A570E60B3E52679F +F90A3B00D4EB4DFBCF0D2F9C5545A6DE10BCC849A0BA9E18F29C6F09ED0F0DD48AD37B7925654433 +A6D02965A3813BA2EAB2E6C2004ADD216DAE99471EE518BD0DA0F534F1512A8E26286B07FEDE71E6 +0A5A057A22AEF095A8B4752F54C04CB8BC170F3D6B725B83A6780176194B21BA906E37B7923E2548 +604F8DB18E0A3E1B5FF04D00898C29C6033DAC54637CF5B068291559D8526D5201F3503FBA4EE12D +D7A6CF6271618F41FE08384521CD771FA80364D747430A071EE3D3ABDB5400DD36A0285430D537FA +F6EF8ACAF85C250D6652F327B2BD3B29E1C64E6E66C788FF1D9C3AC6DD38691CDECD0F3FF4079BAD +A2BC0CBE14AA3FCC38E3F31B3298A6995C87B34A7245ABA2C968F908D8337860507569C370654635 +570615F987531551414B5CCAF7F4D0B38F701619C553E746BD90655294270560046A925A021C98F9 +3EA8FF5B5B8A0D05AD483E6DDC5257635308C6C0FE9182D0E4FB011A00981A7B95DB5BF5A82F8B1E +B68E8822F8B1B7CF01AF11302B44307F3A71D5EB3465F793CAEB1E72D2C63E3D264380A75FF1DDA5 +00B5F82B04179EA9DAC10731FDEDF5913EFDEDDF5799D2A86EF2D16C0B52D99FCEAD392E9226AA6D +3D11D29054130C8602F703CB1EBDAAA089A02C0EBD53343A7B297836CB63E4B2C33C8760ECEB15E5 +6B59D4B296B8B724244D37651C3CB862C7135D62B2692F5A27B9374C5C3C5399E5C4DCCD76572294 +F742B1F545B736BF4C82D8F4E2941CD52C0B944261DD4CCF8A968B646662F3D187557206FF165F3C +0D3D5CA1E428D61D7936E1D00C5377A047EE80E0A5612F7FDEBB8B224270ED23A031A049E8676516 +BF66EBAFCF3F9D4975B0F212FB7A914EE45640972B61AE8E60E602DC7C20758BC07A159B08862F16 +6302D8CBEF03C4B0C73BD8504EB5B14DBC64FBDDC867FE51F76099769A7BD4FA4CF4096EAAAFD55F +9A20F6D4B84D8FD139112A43204026F15F9FF5AB6729537CCDA60369C24D7EFF4B6B971EBF0BD277 +A9AD1BF1066508A0A7DD9A8D45447A39B92D6B0F7DA4BEC2689D25F35C8C490891F053F90DEE5E2D +8C9D7FD1E23D0F1C5F57921BDB13BC9B8C3CED4FC42C4DDBF0706985A0DDABCC683FF5EA8416C225 +ABD219024432E3972C3314C30A672FD21523C83D93B2AC8D1DF023EEB1BD74E825FCD19873E63A45 +F6935E6685CF5EF472191B976F9EED2A4765E1B21B46EE1C4CB90AE89DA48E52BC4EDBAC2C855A67 +CB0BE9160F3126151CD171081192D0D6CB27E4EB2D725F31AE95FB283149F53F22BD8E414354D4BB +56724057601FE4BF34A5B188C00B0E550639CD796CC66EF895AA5315BEAD49B5639EF0878CDF2CA4 +271027678693EA212D0C11A6EA52F748AD0F62A0336BEC8497EE933EEC461E461CCD2F5291B980E2 +8B7D66690B10EEBE22B092179396EEF5D00E42E6CB73BAD4485F2063AEA6B6207E136ABB925332C2 +60F12D8B60B211A9BB15F37F42F53AC2559F5A8397DDD491D314B6DB0B50E41F0AA0A42FFDD5B9F3 +FBD8EFB7E343C06F793DA6BBEE4FAAFB233C31EAA3AD701B1F1C4F2FB05A7647439D19CC856C7D98 +EB3375B3ED2255FA33D9ACB87C1937E0B7F34C9B299C8D2A7F85D41141C598F9505C72B5AC2DE9BD +E24CDAE1DEE416786B93D4EE713E437D2C4A3251A296B785C81A8232F98ADD04B3D2B41394F8BDEA +7B602A555EDBD51A088C2277D8E86B08A0D05CB6142E33E973BB3F2CE841D323ABE6FBBF83B84272 +220F569DE23264AB672C2590D4527A29510E7F289DC2193E66FF23D83703E27E9E81572E7534B1DA +510BB846576E8A39D9CF44483F297C92317ED8E46237B3D73844B3B19D37831B44EC116CBAC3F75B +B67928C4D4E741EC95E96FAD74D852220F4F1A8FDCD273E0F6E77F09EFD5723CCA1398A021FAE947 +9CAC5922DAC8E2F46704BC216C7BCC1575A455CCE2C2A080B9FDCD0758D9D921EEB6DF96C64A31D1 +C9BEA80F48461857ED7DB635A3BABB3BB6155E835E605B09E06A2AAF6BF3EA70B8C0E098CD1A818E +30B9A4AADC284EE2B87E945B717FA73AFF5FB788E51827F6FBE319ADDD059614B493ECCE718789A2 +EB0F117EC811EC38A3F4EDEACA660612BD247425A3FB2E6022CC14FDF69B6660B37FCD4359F1BA54 +D12B1F478D76CF898824762C25A026B01C94752F6F3724C31AE788CFE992D9CA152902EEBC4AD8B7 +A5F0E68A5A0408A2F0BA71CE0D94B4A905B35F2781D7E7A2712DC62E87518BFE72A5BC4A9F36A4B3 +B1494B0C4C14705203762E0CD0B28BE31234449C7655B5D6165D7CC4A16431F7A8ECA58D25711E98 +4FF2CE123C05AF9A65D478B73739715DE62A199D47BAC65785EE1DD25AF91868F91D037C0AD754BA +CE3DC4B67F1FDCA8FD9FA39796EFA9C975DBFAA99DB70624B3563408D0048E3AAC6B4F228DC0AC08 +B9C2B63657EEDB53B46D157426A3B4B4B8CC5B4F30BC24CF9BED442DB51F3C7A0656DFBEFA401E1E +0823065499C69D51C477360FD13ACA8896A8117789C4561F3D85F3A80D18E39F1D6BF76C7876922A +1038ADAFD53F2D092369B356D0CA3FE6A27D7B9BD3985C78424C21E60F6BB46408013DFD7A30D320 +EAD9AC6E5FD36655AC6706666A76F1E426640C4B0BE692E4879991EA9EDF4596C0DDF43D4E370360 +D91E8B2839D368DA2A910AA6092337E2E20DEECF43D583CF164881079ED5A492B5EFCC1CAF91512E +0FEA8140CA3E2553733D6F743728ACAC3E643394015967DAC8839D5A804503A45DBC539FB8656D75 +2F00EECF73E7EC8746CB13F438CAFD554C01150048F758573903B0B3260AEDD78BC2EE87D201E219 +486315A4C01D95DAAB54335A4F2CAFC3F43F12A9574CD2DECCBC1858406C701EE62C281A55B729DC +EBBE74FDFF275A0A7B8B22C7490187D1839F4FF271723C140095F28221C4145C9061F9A5B3EDF8D2 +9E0DA04D9A8AF6ECD42DB897DD5C9318D636FAB698554BD9EF9B0902BFD8C96CB958773A3C4A5FCE +8A334C673206C39277E45AB50DA2661F89D621AF057CF1A7ECDE344DC7658514B4C655937E7BE010 +B0694B069FF64D5582E3A4B7F6AF6C96D056ABB20CC883AB25A9BEABB18A84F0258CA3E4F33FFB77 +9841F5970DB447969FE9C6BFDB066ACBC040648D74F553EE434BADC353450A3792EEF9CFDB2FBCD6 +07153F2EF73C1BCCE3784609F26C80193BAEF766E7CC7C33A4CAB862E6E01FC1CDF11E2FBF25FE1D +308CFF9CD924893861BABF78F762F3CADD3E0BEB38F6157CD08F1B8767606427C4A631AFC9488E6D +4D1A8F4B51ED48582BCD3089BE037ECFF18DF6175EC317EA56D4FDE37288F089532C13F7B3C1EF7D +333E7FAF8B49D95F535F60889CD7245E5CB0BEBFDAE8F7A0AC1AB7DA18F2BC06267B27403F1BAD9F +DF5F13254E96C294C4568EC7154479570E514A55208D19A4538959F7C5B2A0C9CFE4B4A40300F248 +5943C6AAB753F3F0E551727B8DA8E75305A9CE623757B36FB7D34D13CB14EE561C404CDB2D88F375 +2BBFD9FDBCC92CF110D6C35629E3040D995CD25B90BED2CE79BBDC846EAA321B1BC46DFF7845380F +BF08782D6A31EC7D41F251786FDE403A39626D6052D5189CFBB3DCFF09E81C09D0CE7D571F979509 +79B26AA4F6D07F97A33522306AD692D4D960CEF1CEA3D251A841E2A23C7AE3EA44B3F31E79808F22 +B6ED20DEE4186927394624E22D37E873B660BB8DE6FFAE058DD5817A3BBD68963D055D406F253701 +D940B5E58DAB01FDFF1C626D0D35E8E7995D37057DD07F6D4D45F152A141269A7FB81433652209B2 +B23D69BB5D8D367D95D4A94B2C2924FB83F50F651458CABCB65009912F00F485A924A61A0008DB44 +D478CAFDB7D9524204947703B822755A1301FE163A8248C8AED7073362D918D097597B24A3B579DF +FE00F47776428D2B992E1F5FAD6190ADD1C789BB9A913BB1B938EDE357BB436F734477F7BF332E36 +7C380D049AED8687B4C2AB6EB813E719718C9CE62296C24F783B16E9635A7E4402840BD26D3A0DA5 +78050C49E6D8239EBE9E053719BE94CF6D8C7942AE1660F28B21B3C1E6E15459C1FEEA4FAAE64AA7 +165824F7B939E28E51009FB778E370C6001B3F546EBB76454912D730A3F8C7F6F9EC01B9F90A2E5E +58EFF9EA99BE57A0154147C2B7A7C7E493E37C9BD0ECDEAD4AA4DBFF95D7E451246C9D4C30E71F4D +76441A297A1223FD2F8E017B10C108B0F0F67385060E9C18133A6264AB2B445F6DBCE86CA803357D +749244A6FFD8FF8AD37EBAF3787F3702764C5EE2CA7547D7A9FED5AECDD2064F7C767078579DE13C +F135CB05561B15BD9803646611422353774984D386BAD640C5EED157569356A17BB6233EB298960B +8E34209562AE170A08D15F3A29967DE067F6AD183BA1EB49A99F4899031A01410D7311BB9B7A984E +BD6A303D44CF42B40F12769D44160583BCD68C68F823DDC0D73150083404B12AAA68E97206053C6D +23FF0620231D3570A089520E928E980F56A273092DF94EB3A99FBFD877B58860231B2A761DC91A41 +A427778B06F07D4F78924FF986F837C1437B44EAD5E7C56B9CE9CCFC0F6ABDBFDBDE4A32E3FFF336 +7F7194DA20D038CC44C4413B2CAC15C05B22758569D1008EA057DCDCF4A324C924021B35B10ED632 +BBE921BE2E34795951DDA394FABF3EDCEB99B3CA15D6579559F0BBECF8DF6E6DAE427DF75657AEDC +FE180A88DDA445A5A5E239B364B8884714B0ECE259F32F1742DBAC0BFA9A1052E2B14E632B56A474 +F2C9DCA9B5FD8D62A39227CA8C208DC69E5F543A745A913641950AE0DCCE02D20D374B652E2CC41B +F0417F99C2EFCE1C23204261FD1BCED5A1E8AD4736C5F23E14482D766390B1C62A320F751CA13454 +8DBA0B08E4BA0A0CA5F6DC765F9520D15D895792BE580133B92EF3691B95331DC76A551C4AE9AB10 +24D7EFC4A02B5654057224C3433A2AD6859E3E4C40F8F0B089C846002C75ABD667C68606D7300B7D +0569753AC074BE6943AD20018835A6EA28B99C983BE3BEA9B742A76F2D7A2A26B35664D24FFBF656 +EA28D525A78298C898C0BC2DDB56FA37151AF5A08B28226CE6BF09726C37F1B0BD39DB144CBB5494 +5DC48C374BA8716F6C9A4626C95B6993DB2CCD59A7430E3A3B2E6CCAB9A801760B8548C8447D129A +01EDF187435162EC13A65C943CE9EA547C3694F88F9706AF29F5357EE59500EC080E7FB844E8021D +907EE02C344DDCB78559AD7FDA31A3031D5CA80C004DBC04BE54B38752D49DFD19F1124C059ED68F +6E85E1A3A848F98707D7413ED3DEEEA823D958CCE720B85303CF208AEBB9B799653EBE4DD16186CB +F8C0301AAC6271EF9E2CF6732A6CB8548B7CAF2399287D6AEBD5ACC7C9D0DEB85BE38150072A0184 +51D3F1A8ECD784AF8149BF932E0422EDFC608B20B46D80D3EB68D746E1EF40423CD6FA218C9F569A +3442B0E70A2D464DC59CAEBC9607333D7B8FB90349676207AACEEE5ACE8E0E9F9C5896751ED4DA00 +95D68C421D8754D665D3D58C682AAB1DD72EF9050894EB680110C3E7F02C3551D73C63CDE8B45E5C +453BC9AC1FB3145CB6F0141B8E4928351FCE66F2A5AD534E5DD8BD901CEBFEB963DE2787095D7755 +81E588D3A165BD55B51F039992567B85FD3AE92C7526E33B44B8149E57BF7E57579E37611AA29DC5 +9EC94F583181201638BD4BBEEA23BB9EF067CFEC2E436D726F401EBA897480AEF7E38B9798C6CD42 +182C43B2BFCA7D8B6B696544F6B00C7B7D0D2C70D955304A4FC8D97E317C01113404129D480AF8E8 +EC0075A94859D5A79DF5F3FDC2EEF4F0BC1113D2C92DAB9859E9944DFAF557DF43AAF42B4FADE1BB +F5AD6728F884F0D4E7671787F1A3500B00E62929147C72FED37CC222EE991630EC9AF614160872D1 +BF4666DF3B682373AB1CE36FB87C42597FF1F96D3D7B07DC8755C2304AE69B955FD2547D316E16C0 +458BEEAD37B904BC27DE764240E67A68ED5FB57BA1F9C7C4C8F2BFF745F3E6FC732FD5E37CC1DED3 +6EDE20B06FD832673AC78DFB7655D7358CA03332A18241D96BB0A45D16BF2A2B80D0A68C74C8DAB3 +F18936EF73085EEACA9B24B18EB7DFFA75C707C947E17736EB7B608C4AB90ABB53A53F44D8661485 +5D60E36CA31704053CC453F2A50B878AFCE0361EC30444F5D6009ACB5D9673E5536B11A02B659252 +A64923E738F494D6264824392234FCED4D66E0342D03189778D41AEFD907272A919AAF40066A304C +6D7831F90B347CB8EACCAC6A726B40BE4671D6A0A591DC36A30ABBF91F9E780137D80EAD43BD49AF +690A3789F39D3EBFEA9CC64B82D601B88805B6FDAC3C84C61638DFF1E391DC74FE4D08A0683BC5D4 +E6634F82F4DA357742764FFB2B8D264275F82052921F7647BD8709857BB1C98C205D13EE51C14E9A +DAD1324562267D1931B5143A2ABD173C745B7272A6FECD532B5F189C8749DE0ECD3A6B1799C1834A +414554EA6972309C48DAB44A9DC41D8B28361E89CCE4DE8AD6058469D2F603E7AA62631E80C01535 +539580E124A24E9387E3E0E58A63AFB29944207BE5929455A150AA58E27EC885CCF019CABE1B8769 +0AA7FD1F4166DF820A324FA0FE3B59F8B767BFE029A7E3ECED513A6CC622AA8CE96563219EE328CE +BD649EE99E5F108FD57646926CBA30BE3AA8E00EB4CCA282AA35C0742410477E2E5771DAB74E4181 +D91DBCF25DF36BDBDFC5AB6C73A982A390416A23C8DA10655906878AF714C3478C8A0C7534F6022B +80925A069F63834539B18D9CBE67844520A195019C15F8F858E91CC50DE001EDB52C89F06035473A +022A718893BF7F6FC0B2E6CD4C1CB26E98C1A191EA5429BAE831F464971180F5EC2CC6E6F8F9EDB8 +2E2A7CA8C5656BFBDD618F7D31635A23C73F330EC76F4543C9795600F8EA45DF62BF4E071FFE3758 +2DADBF252F2A3EB399F61BEAE10BE0FEA537C272CE850026872F4BDFE5921245147B71DAFDC8EE88 +C509B6D8AC249557725FC5D14198A2DC889A4A9ED045870F767906A226826AC93FF1E09D75B4DF79 +8FD690C5146175EF2CBED8F03C9DEEBD95AABA69E98E25A98CC96820CF1C684F02E7739F525B12C2 +72613012143FC26919B800342903624AB29219E6266716E451C9D60A4FA010B8D26B56A4C91AE1C2 +ED778E35E66B49C4DE64021894C2B39E7C883518B06E04D198B7D056A24C3E65BC9E30BF2F73F2DE +21E676A37E2AFD625220831F598E93BCBE098AD73FB6EA5CBD9D17EFBE6EE35FE4EE93BD3A75A2F7 +118EACBCCB82216DF70F56C2E82F77F072093824C6ADB800C66F0F26BF7AE513A490AC3DCF648DF8 +2E54567ECB9D6FE66E908748B7D5090910EC99EB9B222E92B058F3EF34A11918D6FCDDBE2B9C27D7 +DB19AD215E7B327689E0597963E6EC907A23A0EBFCDF86ACDC349CD8983EE83144B5B8489545AE2D +ACCDC8E553FF4A1601F42CF82A90D571E36193BDF4A7893B2637DDC0C73EC0C21BDC4BE1D02BD257 +F4C240DD6AC53A321E13FD2EF4343B11B9C8152EC02EA6C4DBF7F66C9356647A948CA9E26672BD7F +9B828FE109600B1638806DBB95DA6AD0F78050FB13AA580139C7198B1673D4AF9BB610A83A709D3B +7D7B01AFFC0A740F03A5E2E3EB7AF145E3338D46D03A83FB82DD6487A52F9494A89717FB500A26AB +C949C51FE25DEE8F78E199AA53EC1DDF9D767D8FDA77FA32F19200BDC539F00A23DEF166D97F0DF6 +64489D932D115523CED7460212BB35D887FC3507C2592ECF622FEA49AE2F04299A547ACEF75EB0C8 +8ABDFA7A042D5EE4C88D716B00E79C40173A3F7044546D093B988463623DC1649FC6CD645D01E102 +1AAD11911190D0B07C0A66AE7F9F9CDCD0D841A976A8298C26A0850FF4FD42EDECC37B97A19F7240 +3413098A81025E4451850EAF180299667A392B7D2E96C4068CE110CC3CE15C6E58CBB11CE21A3E9D +FDC88ECF14A8F2D422E1CFCDDEA320DF5CAF93E6F9AFACBADCAEFBF542775D07EBF09A96F0162438 +62662AB782A464DC7A96BAC2B0F0F043E83690C3B24432F61293A1C5B3699605EEE8339AB079BA1B +A7C65ED392B6E94FF817CC25AD32E89C95A0667F124F26B11AF5B45A9AEDE4F443429ED30130D7C4 +68C940A7C538ACBDEEF77BC084F8A24FD0060BB9CC12A710DB9DF03CD381FB6E76F79D3DE40DEA4D +FEC56ECAADEAD68DF4492DBAE69EF1663E2CF90614871094BF6F0E1C9FA0EBB2D34923A19A557BE9 +54D914F35BA044FC800D822D88B5E70CAC27D6D56C66AD6CC3C7647DC679C8D3E1D39AA8282BCD27 +982428F5FAAB76EB16BCD26A1685C044E3C7B87B3A1685279DED690D76C0F1C52B76FD13C419165E +754BDD7FEA75E26DFE2B916DD0CD40301CCC945683C8E1F49A03A0DCE1974A76B754BF04D36C2693 +969FE4C6C39D60D995738F1DE0ED6A7E0B80B40BC14B440B6B8F1085E83995E224BFF4EEC6F67EAB +103B4BB6D21F9741932DFFBE85C0BA3D2AF925D670318D1157FACAE9C09B3AAB5B1FCFC889348207 +8D5A3F7787C699C420C9BF0883D3B8B3D7753E9A146175245CA9E2EE04FBE258B6E42334EF141A41 +D68ABA286864E72F0E4ADF41C1C96E60E69320E79211984A734392C870D72B8C236AD631672AB9F0 +FE48EF2611740799DF5B3339BD49697C4DFC0557C1022AAF15C24FDC54FBDEE2129EC70473A17EEF +D202EE43A1B5C7B78A299B6EC8BC7595FDA6BD0BD22E025E8FFD89115448D99FD27BAEB680A22C59 +7295E33201199E9E1E38AF099926344D1B7CA626166CFFBA2F3D1C15AD63F0C6035A5B9BC5AD644B +3D5636C2FF3B9403AFFC3AF0460B328C390D3B416C7880A0DFF10BF512BBB933081FAF4B2E06C093 +E80950F08BDEF07D56BD042433CB0A0C72E1F17692C9F5C7AA97C31AFEFA39233C62D5430F11DD31 +478E86A36A8AD3817B0AB397C8D6935960D905994ECD2AA8299D248AA274AE0FD1F1377F0443B37E +67DE63151184DB5EDDB4DEB9CCAC76896BEBE32E30E0F3C2557429FBD4B85ADE7829428C5CC95CBE +018C17BF38FE4B26B0AB736FEF35F6E3DACF0BEBB3B795D7982075B75D87324AC28D7E5B446F04F1 +0A001FF191A5FDD10B4729E57578FC42C26D473F22C70D5629AE05FC33E50A4EBA2C5D4D63B1D147 +9ED7B8FD7A0D824413D06437118C788543A21520653572608F9172CB1D1AC529280AADAEBB5A4E30 +AF99A58EDF2952BEEA29F366FB6FE7A804DFB1D116B73B45033E9E7E9767A9F41F2FAA76F97411D6 +420FB211B4BECF6C785FFEEBD90AB932E82EB0AEC7ABFA4A7AEE53E2482617576EB28BB2A3C7044E +15F0B6521F3B073021C3CE55890951E041EFA38937F2C0683BAD1AF255CF3747AF2F0B8A92BBE44D +88F7768D35B8F4EAEF0AADA3A42E26E3E3EC25E286C40808665B80C6265716DEEFAE3A86C9B54D34 +74285F3BA2946302A065B800EC7A9694B0B715BC86D3EEB649FAB8A47D170550D9213E8B8E9367CD +FC8527955263AB2AA55FB7ADB7DA9A4E727E3E69D9C7946369CC078DD7751DCEA1C0601C57F4B5E4 +48BAD7F5F8A919632178C77B7B5F95E402DD808AD59EDC020D82399DBD3A9D9F3FD089B0909C171A +940673E361F5728A89DB3E2CD0AE2009A6D64FD85ACEF62F8B42F009BBE11EA0AC14525C2ED72E03 +0DDF4F670D18B94C07C027509F281F7B59D854A5E46F4DC544BB320C427642D84B914A2E5043B1B6 +FC94802BE925FF260775F6D17A5C55C5A5D5931F88E3D7E8485D8026545CDED1DC96D1ED7E0088CA +ECBFEB99F110A5CCDF7EF3B4190F3DA6ADCD5A46DB27C0F076B558667A1B9ED967363799307E77B0 +9859909B4E86A27639DF3A8C0B193502FD22C0298AE0398E7D33C3039D7878922AA9997C93F29655 +5F5D7BF3A34D46BA5592FE2DAC5A32DD9945852962457B81DE4B6B9050660EEE1A0D95785D824A5B +DEABACAC8A8A90E7303093F0DFE57ACDF0EF2843DD7497B1B80AE7E883735D9BD689C84A61DE8127 +3E2DCA2F64B00B62F0FA3D3B5359241525434847763059927565F4D98CB8AD1842E31488E4C1DC58 +4BEEAFFE1D3E76AA2E6C81CE2DA9F00DD32841412695C8EE17EA60499E99B97D30C32DDB0B9E473C +E65C259949129A4682DDE5DEAC0611464650236934D7C57D1EF7E8B5D9E5D7458F0FCA9795853710 +F37B5C24E39D7EE92B2D4066D533A662AE2B063B741559B24AACF24DAB6FB6786F639ABD8B34C7E7 +AF20E5FC999BA74AD93CD821B545C2531C506719605A64FC06DA8907550087A4599EFA621DDFEC17 +B904B6115BF94AAFDC56F3570065D75DADA1AB177F4C333A04A0119A89BD209DB0CDBC5DA0C8B99F +EFF54B2F4FB4BF95AC573EBE6D5CC8110E6387365CCECA5630F5105C887DD5803DC1376986456634 +C3B3BBC235A72AF168CD5B350E0A8BBC303A2CFC37FF627F4697C0D19BEAE28FC3996E967CEAC4FC +8D9D309E2FA65172E899285BAD3F8B45B38C9C2BCE94C31911079850A040C08789EE377B9E652A10 +01EE4F44420757358E183D48EED67C3008E6F05C3971C732B98ABC24271527B267D8B10735CB1FBE +773E33FA51B5B472E402676E3590C7BE28BFFDE77AC34544718A20833C9891A176AA3A62D686E072 +7AB2150A1E77FAD5012D0299593B0222CA38CED2B9953B1E5893F176132F1197609D04F2F1D647B6 +F44B2EB0AD94211733F226B570E9D963AF9A6DF04FDFA26C0BDF31EDC41DA521F9D0090A9FA5DD13 +B9D977329F6412815A8C52C3290DD42EDBD312592DACBE0BFDEA209F389DE8E4B5D8ED51B46F1557 +C2B50098C2262D3DB298E12C0AC3E03B82CD2807CE04E109ADD00EB181D701E4BC3622DE8A86E977 +3D6C4AEB830F3283BCCEA663AFAB740B546C3577E9182EFE660AB380F0504590CEEC89313A608A29 +9F9DFFE22DA6296EA3E39857D7229885C78F097E7E7845E6C908A0570D4ED0AE320DFADB7AF87E5D +F85AFCD1B271B672813C0A0E2EFBAC5275807ACD3A2F09EAB95DE6F571E3F3C827FB3EA9DE89DEB5 +4B8B14770305B23EDE569571D0BB8BAF4811E12A0DD5BA4809818D2FE088DC1CD4BE72EECB36C819 +AC25B41BADFA27D5839D548CEED7DD18F5F2BF69EFCAC0ECD4FD942995E930C147E1A7AD93628180 +E62F20F3779824324C5A1C35ECEF68DE30BF5DFDB5DDEBF66CBC459B2C7FBCF0ADC0274D137BE67E +B22FA117C85CF7D52BBBB4CA5F9A6F73AFC23BF2E23B4B1EEACD33DAA3187F1D104843876EB44322 +67EDDDED02B6A507D13E3B9F012FCB8C9F0D14D951415BCFB20B3211B5B9860B0C6826BE597F2F9C +94DA2788E65107C5CC77CE1265E33DDE9378AF9019E7E68522997470A52088253FDCA09AF9F071C2 +988CEBDB46B7F7C8D08B5467A1B3FA0EFC552C5E20D4B9D565AFEF9B520FA2F544E802EB8E8E0C76 +21FF63F4A5C0C59F94E9E1731D8F3C80C772805DE264C7501E705BB21EC37A1379BEF8B8A9E50EB5 +6FE9CF9C10C9D25CBDC68124D2133B2DB6348175537EF872CCB8B1787330A5ACFEA87E2BE6615DFE +442EC74BBED30021A0437ED3E9DBA6EC49A824F0374B446271DE6E1B16AC74816F6216BAB7329725 +8CFBA83C178F5EC009C57404391898BCC3314411F129F12D68218AB6D0BCCE2E5AA9AA1D5FEE1E2F +0AFAA4BCC3D226C5512B456CA8F28DE54858F18DE2B30AB4FA02840859988BDE7ECECB4EB0002523 +C6EC40BAC2E7ABC411329F803DE2DCE1EEB354E4E6771E4328ADEE4E713AD248BF4F91108C52B169 +140F33D5C56F1EA2240E7E182C060187E29020139C373B4A6CC4D2156F7C15590D3C07C98535853F +4DF901EA9F2C66510C190D9456EE037DCDAA428D433CC2231B2B627CE2B5304B6A4630576BC48984 +66D7A8BB75D53ECA10C74D434A4E50B1A706ED6C7BA274A9CAD5D929B9BB8A631825A9C32A8F468D +578507DF2291DEAB6338ECC92CE8664D4B1C211A4CCE186679B6C71ACD5655B97ED8E552B09C1C85 +387749406C549057DEFC059CC85639203160B8FF05A48F7D5C4F452B111891846A521674C0E2734D +50B8C7E7B5D9F438C58DB139A6509DE3495388E0D7AD24F64FE73707C7BFB8CB06FA0E0C41346B98 +220E007E28515428C1874AC996819F16CB152C16F89CCDB3F9C83070AD90337F1823AC0A48B72749 +C6C29A8FDE1EC2E76B0D29FF711891EC81D0ED0B3349E9FDC413047731D70C33E57D2C4B637C8FCA +B027CADCB3E11F94F61CF3A56E4D90E8550F456BB90638DB6118229C9B74C9533508F343C0EB422F +87627EFB562C7730E1A804E3E4DC80FC0F199CE210045ECB1E3313C3364F78A500A8ACBFCAE0F7D6 +56FDC8B1BB95262A32ED7562A62EE5CF989235D1E641D726F34D215242D44A946662EE94E765A3C8 +75557732FB4DE1CC2699202802D4A5D99C621478C1C6D583FEE8CBDAF54C73C8C17BC73F1B414EEA +BD901409B83E98D62749F9E742FCA7C632C176D323E72FAB241D143950B87AFCA5B7B75936FC6638 +1FD0E537C30D744E970A08636D27AE7A277F3838BEB7D1BF821F331D483FCEE4EF9FF98F350B5B3E +CF2D6A5BBE95862FD5DEA6D3A5322DE6723B5201FF81EB1D1BC5BD0F77CC1737837655BE23E0662E +AFDAB16BC0635F40DA516BEBA8128C414D6EB5F5AF5F98B8C0129606FCF536181E7A8ECA563BBFDF +0AC65F1932F1DF20DDD6739F7B1EFEFFE282FB6DF35222E8148FB5968BC7E40A582D7B146E374270 +D3D014849E898E91997288BE44220B6B6E431B7AE3F2F7C5BF3E3444F5088F9F42B7F676EA14671B +C70A84B77BC275E82516040F7B9DDC582C0FE335852A83C31BE3B3F716F17253AE57372D14951A2B +58F69C2DF7B93052823311E4208A72C10D0625869BC5F3808D231E86CD259824D7E6C7669013CC55 +B61E4C20C0041C35BBD7F1C291EE7A3CAE016A8C90C56F22C515375252FC3E188B80940816EA5117 +88A2FC7AEEEEDAB9E0A33F2C82D886F9BE029BFA1348DAD16874751460DC149CAB5189D061E7C804 +1939D80A03BB529E3580A235F8C37EE25C503BECB9C31CB91904BFF4460837A1165A7474C83B5773 +5945BE04F3FAC3381310E4BEF8D8D4A7343B75D23BEFC58060C48BCEB52566A021C197ADCE5FA025 +1AD31CF2F90CF6A72122C38FEEACE6BE36176B1A990DBC42A33F0BC0090799C2F6C8AE6990725562 +B07725B3DD15C9011205C28700DF82AE4F00F9842DDEA3BB5C15D3A4CDCD18E692427505D7B24CEB +40CD7AE0D81A4C83A0F9ED579F924FCB19D9D017E60C6500CC64572E0161EBA57EBC11A5932F24FE +9F1AF444B3C657AD162BD39682D23D6355EF5D84440A124138CEAC85C926BDF484AD7B976D9A44AC +6015C25354DCD72A889474F31B8BD3CB7371B95A9729FF0E46EA3644477AA4C11FF5913D917B7742 +065F0593482B6E6EEC9EE63633A6A963819F3E6A2920136B17C982353F1F071B3D585DD24B22DE9E +EFB2B34F776DA85F85E9E107D16960AD67046476ADEC509FCFC64E8AAA6427935FC231C817A21C71 +6DCCE088EA4186DFF0A3A7A1C367615B8E7462DA176C9F9EA893DD04E29DFBF88679991AAB79A172 +48C06E2BCF3B91C108E09331FB57D94BE85EDCC66DA8225FF4B38E12F8563398E62622EBD2EAB098 +691EDED4D5D7AFC360AD6F263C043DAF483DA05CF70DD8BA8F96D2A5A87043DFACFBBBB3F8A378E2 +A896897DD48D8B13888A023AE6AD778DE5FA991907E731E5C5B0A3DABDC360D77CC71C59C34506C6 +39C21BA9FF7A9CF322C21B457D62F20448BA19CB765C4C0AE7CAD9A972F60ED60A21C92AB665537F +EAC8738AF8A27D3946F759162731F62C0A657CED40C66B8A9941EC2559074279CE0F6E10BE3F44C1 +D517E10D85EDA6BB6D097F4DF55A3DB7D50679675A781FA1FFFD6F1A8349B2870C8114A05F5F7645 +3B38446D57ED63FF8731661F0FEA79033E4C8B5CFA29CEC43355780C5E2EE86CCD449577EBDC0140 +47AA5CEC980CEA8200867212DDDAC234BEFC9FDFFDB43DD32F44883EC6F2963D4D28171E19E144FE +1BE2B8FCE99016691A00E4EA594F94E973E899D14DC44486BA6B4278DCB292FA5C7E6D73068A3BA5 +1557C3F072547E7F2F869D4E9AC03514276EBDB0920FA04E67E2934A250B1A502A8D06A25037CE59 +920D0E136C02D5DDEE2EDBE31A38BA32C4122AF89F295ADDF579FBFC72391283DC1914E9322A63E9 +44A280ABE7CEFA54ED2EF42B79FA97EF21EE83EF20CE34850FB66C378EC7C08B2BAB924F58FB8123 +FEFB43A385BC1EB922AD8360750FC1B0D8A303AD19286308B7A39A5086A50A8FDF7D60188342A9F6 +42286540945790524174800F8C44ED71306ACC3437FB49D8FC43FBF8E88103A76B4A92D95DB9B45A +FA067E31EAEFE6BC818D11D7CB8566BAB418B596A7494FC7326AB3CC029D010917B305CE585B194B +C5415088BC7AC7852A6D52EABD223E2634DCB29080217F6755B023C591F08C7E5D72267664136639 +9766EDF511FA744675D473AB37BED0ABD92E04049AA9008014C5EEC1B0443C6C86302CF6A3C38BDC +B8D9E0538E349BD930707DFB002700B5EB427192AD6105E01B8C2FE488CF617E9EACE73EFE3BAFD0 +F87CB57E02AD31627E6439188006655D6B992B393F4858254C2106FE9A3F0EF7347347C66C94A999 +D49527A2A177EE20A08BF594FF1E08CB091D22A8C1569320EB5145FE4A2674151750620B5EEC822F +A48C5F8B565DE0E18AD05F99827FF24D3BE03B007774F25284844D0F1F8F95643646960F303A831D +4C2C4ED9E0664C1D705137C157671D62179B47FA4A6441DAE99C2F7C8765C4C931EF345CD8F92D11 +E290B2FDEB1B0FAB4BA661A4511F75768808AC1DF2FE79BC285B976D364ED25C64EDEE62E8E035A4 +B79344D55B1E7E2B43AF1CF94ABFC8D0CA5E89240EEA231464449B831F1B3F9EF01AD07B38F0B402 +712A0346892A1DBBBCDBCC827220CE7F492CD7471FAD35B43E71CA14F1F1A9CEA740C4E1A98337B1 +5EB97B10AD57DAA9E9ED134CBB4614321D548C6A71D8ED95900E7947A7E4331D7DF3EF367F6DE8F3 +113A7DDBEA0F741F9C189B8B586B83671475A492AAF9994D884FEF3A646ED4F272668DDDB05EA230 +399223AE63088D636AE6AC7CE2DA06CA6AADE9272FECE86D0EEA8290B927B17450DA6F34A3D566E2 +096300CD8D5A34139489228ECFEB104714FF907A6E1D3DE35BC0FCCF45A2781AFC5562CCDB627E06 +F23DDBEBD4212F36C332C4A5A9498032213DA7C3FD03FC4832D1F2AC9EFEE3B840BF8356A16E14CE +989C37E6234CAC7A215DAE7C4DE2E2B6D9A876F709422113B503556A4BBD0ADC107B6B639F1BAC9C +6FAC7F4092D23C04EB8684C9D0A5F184160CB660CF6E8672ABE1AFA596EA86890DD22D0A406B2118 +9BB626943F378227132475A25710B75E5B3BB2ED7DC0412A0A079E2AC311ED55AD8E7B2A1A55FC84 +E62D61398511B70877F3DDDFEE5D033A9ACB66899021951378EAFB9E9A799AC9686FBC2E9E9B3A51 +6DA9DECFDE87FA4BC042A5D26C2117E29AEE8840B18361B7B38B21493401E931B431EAB1A3371628 +EF13BE5A0C64A3B9F8B6A29D209884706D2A9AC85B86E3839706269366EC7E53F31BA4219F741E55 +21E42F0A10B7B29E839B924AD90861FDFE3A3D446D1E32C06E66A5D7187A63E590000D1356718648 +7C99BC31088356C9ED29BD80C61E442B81E15657AB191E90EE77A6804C762C45D3C1937EA17454CB +D76D781A0C96A0914B9DE3D3984BAF6075D3A25AC69BEB34CC413D26C39824B83F853DF864C269F6 +8443970933FEF93208BAE4DB3BBE90DD3CABF6EAAD2F6CE664CFA05999FB1CC406A3502DAA6C8145 +3C69CD218B18BF0B9654FC3637EBAB8007A2EEA6ABDD11FB338E89FEC84B344857804D028F849E44 +5982E294384A442390AD36D7C4182EDD7A05BE6744FCBD3BBE6FAF4796063CF42499F2DEC302AEA7 +B64FEF6DD74F278FB5C2897CFBB87FE03538B2739E25EDEB806142E0030F7413018EC1833840BF37 +269E21DDFF67B8059BDC83DE9C6461F3EC2BC2224D2585AFA2AABEFE7D3B2A899C3E08F00AF2A707 +55C145C6BFFAC8F96B54EE682C3C8CE01BB44EB574E1C721974F236E8A2AA28DF0A4AD285EC4DE58 +DBD3A2FAC8A20173AE84CBF877559ECCEC64D9448F8CA0FE5272BEA6543738D5EDD54B73AED3C4CD +172F91C4F70616B36D37B1252D355820DA88536C829B1542C1EF4F76375360E7123525744F55001E +71F5AB1E5B39A5248CCC6789647F1FAE5E989A8A8ECAA2A9116ED69DC9B9AC25A743F70AC4B62D72 +5F120D94431528EF8C74611F7529BE325AF84663989C219B70274584D1EC4485E11AEFFE4A29F534 +6912577C010FC753DB47204BFD9E504027B335EEBD952FD299E5562407234C5DBF0B839D1010AE10 +5D56766F87910E44AC7968842833A302882AB481FE0AD444911F7EB8555DBB9F3D062E9E9FF3B529 +4E9A3B3AED4AECE34C816BE7FBCDAEBA33FDC491C725F13801A6BE162F7F8E99491E8BF77F2D2010 +D9FDD78BA2606A28810CB5D88CE00218D49609C62E96BBD36110DD611C3573EA341FD2AF6FE0C932 +58565D4A6C88CDA3951E287168A478F5EE074BAA9676EF5911D8EDF8D66A7E8F3BED1BB786F480F4 +423C3D3CDED2E80AB76CF5CE5A53B092A44FE52806D8EA72033BD3E7BCF1DA9C870108F32D8987FC +25E7D873985C3C4882A5CDFE7A8B51F3754842FD6F1FF6235DBB88F04989BB2F2816A476B513C10F +AB6F81CF115EF5044D3366A4E192EF68D385B6B6F4BDA7D14D9627F40843035CA80DE49F9DB52CD8 +714F769DF97F73E3152E8DE34D8C37163D485750F8F4E37AE8A3C3BF54D97BC3B2978985B557F9E2 +9F0537CB743EBFA0B7864BBEA9C126F13C02CECFDA50A8019F90900F409B6D700CBB9EEE18FD1952 +D496DBFDBAC800FB83B37C705367F182D91B21C7F6C242D8735A75343C84DBFFE583337DE2A95890 +660584B513C5BEB7A0926BCA7B7DC3ED4D080CC3F1264A4215ACD35DCC62D896B4354F2F7254444A +7235E0E3D53D02583710DBFF2CD55AE5E61D25ED1B3C3B6708E5BB308A3D658F043C26B881C949C1 +0940AF6BDFD2DB0D544DE119BC7F7B03451E61FE18845000D350AD6D04A09D8E3E999E6DAC6AB73F +818A11EAD345EAED03BA083A6EEE7E9CA8CFB760FCBC88B8DBE0887F79AB430913604F15272F9C73 +DAD19D591B40CB7863414A8FAB21C41F80A4BB0A3AFD9D4B1322487429149470DE62F305906F1244 +2AE20521BE034F159A7E7EA211A2FC6193AF59CBDD4B43207BCDE8697DD515459F80F8EDB982C97C +05ED3996E03891DD7EEAD505F6A71A924CC1CEF29053ABC8F0B5F56D0DA1249F317406822C225863 +ECEED46BE0072EDDFDF5F63DC8E94FC119087A66E394A653D5AC774407B006B35C406E7EE4385565 +78290F8CB8B131B88BD78CB87A11CDA44C5A199BC71388A81F2F30E2C003094E793969673E8D0906 +1F4A3FAB9B14C52EC89BACA1C52703F000A967EEC445E5423D3BCB9253D91AA64BB26727C8461FA7 +FF61022B4C6A9E793901D3407487B4962A16B564CAC93D7AA28A22C28318F69770E12DF9D6CFFF17 +09EE0604890191217696AA52630231FE11153761310A72D60E6925AD6B9D63A66047F32B9425C91E +57505CFFE42A90185451297C2CAD408B0CA4F8E923EC26A3D5D66448550AFA3CE3BE9296C8149878 +F853F2A7C3B2E98899C8F9B47B1405F96D2B22E9F1CD62A2945AB62F67AB0297982809A829826BC0 +F24A7777508EE0A71BA7588663D8118E3BAC936A61FF4A628EE96C0B9AE05072A5A4307E68EF2C3E +97A46EB31A2A7D4A33CE9C44E1111D73D9D3C6A0F22F50D8C22153C2CBB5BE187C0F2F37708237D6 +FEBC445843CF88F4C3A249B39DC971CA003A78028F8A2CB3BFBD2C26CFE457A9561350AF93E60295 +D21E1C2024312B1F2F76F2EAEB822CA72412F860F5A87DF705C2F82E681AB9AF45A19023E02538B6 +9E0F273BB4811F07D153029BF988D3EB66358D987895B96B5EC4C24F3409C1EE1B5978B1EC8F3E2E +75FDF2BEDB0AF0CC66481FA98ADBA8DF4D8C8EB800F88C7776BACEE6F61095FC2CA891574F309E1C +0C27E37D8B03472DB3FB8D6668E286501118F7DADBF1106687AEC6DC4C162D22E3BD0BD42DBED782 +BA4707ED5181DAA9ACED58FB358DA0AA9B63AB4394D42360C3F5082A6F168CF41D381073A1D99CA3 +3BD97F62446D62059BF4A8616A8809147B739400362748EDCF39FFD2BF2C16D4632C06A5D43B48D5 +0D0B98E4449B4F1D39659DCCE8AC72A2E8F32487FF8686E550299F37A6353A8E558D4A8B074C2F5B +864DBC8FA3391E3B5135FC738E4C13868D67234489B6AE382792FD5214D5F9E5249AD65C433C22A4 +D63FA7A36A48A339F443AB39C23D2025741186C8B18AAE9952D41E25E930D6905B29F85A4589E9D3 +95FF040E3F72FBF29650D4DA2B6FA27F60DAC4169DC9764021F4E7E094FA25F6B5AF25602C593266 +ADED528EAE6C967E66F0BA05F258E34CF6AA5488D3F7406C2AA9D9FD9C533E827F26862D348B5223 +A690E40953F337352C8245F1861A19E5326490F2A9742917B5546884E8036DE0874363F812CF6FF9 +574DFD5BA77A1DD7C5778B2B9A2E22F2482744E2CE9323E590C60FF02412CC7AB0EC30D0EC857D27 +A4E3D8B35FD69FE28287B2160AC0BCF645A0654403D26B05041654B17D82928044BBAC40871BC3FD +D8EFC3207928BDE5D66926ED199017B223AAEBA563F2723AFFAB737F6482DD269F44ECCA3B32FA03 +FFCE3ED882B449BEE196F59E6616EF1A2F08B42B1A184727D5BD96DF83972BE1B5F8CF098F61B84A +B5BBCBF231E099CFC07D4748D43F129D123FD8051628564931E43A70BC09BF20AE2C0ABB009014AF +89753F91ACB574C5A218A47A02DA3AE44D3F688F9D96076AED9EDE7388B2935C01FD400BA7EC9574 +96E317C6931E3ED7078A53CB4CEE4E56311F4D8A368AE981606AD7E9DB0EA2A10E079476D9881596 +8C9675D9CF15E29B9328600FECCC02B484D8749B4154D69CF90997AD650D881735AA71289AE93FB5 +8C56686C1F9FB0E696CC0285A1A870373E5DCAC285A1B4FE903CC30B8ACAD2E4613873ED77D813D2 +9FA4984A7530F5B046A71011D97CDE4BAE9648AD54537A1D87A5AF1B92560DD7064F3EDD3CCFA7A4 +FBD6166D067945F103C13B3019540C3FE706804A7A00E1D28A0C26A40AC5A8845E39631A00099CE9 +88C3F12C8954EA84BF268D99E2E13726BF9C63474A5FC874CBF723BD48A5461177789E11B4F1CC63 +0FF4D60DE4F01422C1029E664782232A8BEFC38CD058135C79E015A55BA933AD8D446A81051D956E +429779863DBA60F4258DFC62D1DC3CC3862C5D310579417FEF4D7642ACBA8BA5284DC5833F581150 +ACF91709D6B3A41395960197AB43E63B8C6C2F745DEB4647E298341F3E3023D7DA22509340E28140 +97A0C193493711E60C5DA99C464D8DFC83A61291BD0E13AB6A42C81253C0F1B37E71E7706BF2D662 +76C60A3A7DECCC58E56524A200F8C6C0512FAD2FEB51F5C24109E284FADFFD8484A7A053E8EA544F +AFC1C7BA21E4824866090E542B8BB0BE603060A36D8A8CD64EC92D6037B438EA6A7F3A23E9608F29 +02E8DB10F2854D89E2CE6F093E6804299305BFF3D1601C2830F793B92CC2542A6CB0E9DA602E00FF +DEF234702D0DEFCD270F2984642F13B818F65BD407B61227A94AB11E7ACE8D40849808AB3A7E6EFE +B2D4F3B9FCD233B8497B35299DF28F651B0B2960B4545BF2C05952229EB1CF676DA761995413051E +885A529957538A8B2C6BBDCEDB2A3F4104004B880624C2F55B544EEE8DD29231386492598C2BE995 +6E7BA78FA75FAEBED43807FAF072839BAA02333D38BF4A59B1F3ACEA5C7BC188C0BE8A8BCF2069BB +E36BDB2203EAC19D249C4ACFBF8F9717111B7F4637D631D058EAE0CD4E4E8A9F0ACE1BE19B3A241C +9C6DCE2513690473D8F4A59E1A7FCC926885CC324086981FE0C6AADB8F48116822C59B1E93F53829 +77CC88B82FEEDD2B4CC6095691FFA1419D5A6850D3576C4E705C676850D0BCAB84D52791355DCC7D +70A7F5CF603B4D0D7F0CF4F25AEF44F21A2D627D45D306DE0BE1C794AB90DD1EECAB2D61A115D3D4 +AFAD1914E808B16BC868FD48208E1F915B0E8ECFD59AA5895CD7ACF95E0DCE87DD8B12F683C8EFD9 +625CD388337C262013626A06ED60556FA70A8D425D36B48E430758AB4CAD34A656F457A60E4DF933 +07C4D5B2698501E6D1F270CFF70E47DE38A5FCA2B04D7BEC3A2945EB93C49F1D366835581B42F43C +C99D71F13F45A9FF8D12E26C43E1B994BE5AB44E5309B0F936D78C93169D666DDE6D18E33A5E016F +32278897FD7E76BAFE39498C6A849F4A6D882D109C40B42488059554CC95530FBBAB2591DCFADED7 +3EE5F2F2BBF17F4A131B8126F9E0AEB4B379CEE4EAD92A1BB29E3789EC19671E77558B4DE961629F +28B49DB4D8FAAF541D23205844EAA801FEA468D26F32BF9CAC30BCA244246A55F600BFBB61C5E8C4 +10CA07319DD094770DFFC1CB700DF67097F61C46036353C8AB3A5E5198445A194BF189E20490E970 +7D2C03C1A003BC782A66841AE5DDEED2297BB6DD019C98A66A8F279748DA39C85CE2082D09210EAF +CA995591A1A3DCA52EFC9A752DAE0CFB125127DA2932AAAAD7E9850AD78D48304260B4C270EFF12B +160DEF2C2B8E30E8C137975AD20046F37A72F1355F31D878334D96313D330C24EE7350D4042AAE2F +A345EDCEB133121D4B39645B1D6114D0597C3301B4CA56DA2B4A457D7A51BD13B7AC61FE6E1CD451 +6253F606FD4B57E9F4895CAC93691EEBC2AC992CC5D122DD3FC6A9EC8FD337CD402F03F901CE7986 +2F4F4E4500617DA0F913E357BED3ED04F49FD61FD1C66606CB231C3B7A5042C7C07EAB2E02BE8CF6 +AEE5E16B4AB725B5FB5D01EAD4887E365BC2ACA579BD80E0AA686E4A08DFFC70F99132353E3D5898 +5205807271753BA3DB7264C4567DF5FE999514F28E1DD6D3E966D8810978B140F8DD9BB259078A47 +013BCF247C37F543C0899B532F34843CA56F18F688B42A12DDE2A90CA457860540B6FA138F753DAB +E7331188ED6F535480FBFE934F68EFB1C9C16D4F11EDB35F944EAE63751101928EDD0E7AFE64D7C8 +5E9CAFCBA88450DEF9122A245FC1ECCF9EF8DD94EE6A70CF16ECAB39B52597AB1E8C47B6DA4FF0DE +C7D0FABC84DDCC8C652DD7C941DB3FDCC5F0542A8F433AF9FDF4D393E123884E1DD5D359D46DAC61 +0694020BAE84B3BD4C068E3BC871BE21DA13571BB61387E207926769236776B5B31A4A462902966C +DC3D92BE171F10EF8395D2402F0C492A3FE55979CB903CFF2CD2319CE4B46481489E798A131635CB +2E70147193FE3C8F4570FD01BE10E004B17341C4DB8B029BCBBC45D31227A684E5F38F5D6F0821C3 +ED13D31DBCFF51BD759C84A98145FC86D82F871D2D83F43C3DD7FE9A064120338A7BC63A2C60667E +25B50EA1C267174B334F4437856295A6B826F54C3EA9ED39CA6909A0F6D9669F1E75A7A05CFBE7B4 +2C330668E311872177F0BE3A9B3EAE611EB48721AAC2F10C3CCD897CEA8A136E5E10C2337BC5EEB2 +FBC1A3646A6B6792CA3946BA5D4D135D929547042A2F0D0A202A4D86E3F7098C823E7AE4331CEC6B +607F6AA434180B4153F6B10DCC914A92D6D0934551BC9DDB3C78065B2177B264216AF5524D798AE6 +2A90D00A70CB36C5B9950499163C2C1B04339FA76D28E03A4D0C80FCF7BF29B8A188C67EAB6A4BE7 +8C07713C7EE09043301B5BFD60222DD0D0943180AFB286D2953A8A12661986A4812E2C0DE5B3E703 +DAB34AF0E9306A5711D286AD09A3C6AB80841491BD0E5A1D1ABE1D600CB494BC17EC4F74B45870F6 +AC41EFE16BB6C87F382DFA4B2B8DDC9C2E912FD139A2FFD5C92D836F3D749EEB985C62A376849751 +A6AC56B1F679A85FDAD9448DC7A4CFE323AFB540408547C53297DB6FE9A0B08901BC285997934A2A +1772090FBA175CF4660764B87A21A738519D5B619840D15F45DF3589E8B80A6DDF1F395B65345869 +58C7060DC131700DFF6E25962494583085E6F8BAEA557A5666E6634E4704D0C07BB0A2EB228A7BEF +EB890B4EEC638303B8005BCCE922CF3A7AE627206F2946A142B0095FF960BB8B8F9C975B6FF07479 +2D5C3DFA125B7BE7A8356D8B44E264AF6AA582DB84BA09D2FFDC2213903FE8FE16DE5EF61E518DE0 +6A29D98E217038A4CA4D219E4F114858CA493AEF0CD6495A7C5EF1ADA06AB543051B1A5213952D46 +648BE06D15B1728768BB853CE32943AB0988D172227780CE82D1A1D297D0D6ECC51B290E156645B6 +9BD54699940AB17EBE10EDF258BBA6BFEA39F4F0B066FF6B3FA16C7C72F2565CC028F249BAA4B488 +B48A2513DCC5D1E205FB874BCFE45612DF4EDAF815CDD53CBB80842B429B1AFA32D35EA58E17F4E7 +252C2C9A737AAECFC25FD8CA5520D3EA38AF71C61B88F31FB53A7F5369305D63495ADABA455C3C4C +35D9FE423A00CFBB278CD482D3FD33BEEAC1F359AD9B6AA17D60CC46FAB670ABFB3B2B4161B9EB9D +949A06CC3B734F63DE821FE0B8EA065B6F79C0601E46E8CEB6E2DE0C052771E0EC7012063F1AC46C +3FC454767469225AA266784DD77256C6FDE25D7D857FCEF2562AEBE38A9A47063AEF91449723E680 +B36D824BB95BE95C9802F7AD4DF1AF37B4777A1E116A7EEF770F0A499BC9F9675A775503091D4EBD +F55118782E3E54AEBC67A0545E8D75BA5A482C6CEC50595D45AF041664689AA4338C1428870CDC15 +BFEEF788C1D1E87B3389103225E2619120B129FDF048DF3F5DDAFF1CE87428E6BFA591B91D82720C +E4A72FBB952403435248657ECD5456CA814FA0ECBE70BC3D391AEA0A195AE8FBE92D054AD0F3E549 +841ACDCE59DCAA9DAC20348A1D05DF7B4127C75F4C6607EF8501F741CBC96AD8D429A4CA8034CA52 +9AB673EE706F1FF51DD93F45802031EEBF8F3AD29D2A74888B1CB344F88ACEB9B4DEA13ECAE0A3B7 +1FF5CAA38D0DC484B96E90251D56732B85DB8A8DBF10E0A5921121CFDFDB6EA9CA45B98584401C3F +346BD026DA2A17E75CEEB74E48667F9BF5C538623E88021F0C24EC7D082C3E1FFDE5A6F68F0F3F6D +2B61547C4C14614118F7942851B090D6C8D80BA06D9139CB5AEB0EF77DEF2376C0BF602FB1083178 +27E86DDCC00622438FD7A268C0252CA2E20DA887A9D5ED251FD5CCE811E514D702206E413DEE7528 +3A6AEF793F5E3E3B0B10E59226102DF2A7347A95B96E39C6B6ABD1FB4B7CDC0813D7390E2819EE50 +7E5458E06D43CC3BF16E40CEC4E64909615CBFCD233B5D316BC8B8B46243CDB7F2FBECA2F208D0A7 +985048E88A5E685A9EE8C3A351FFCFB522C1EE41A8E4EF0A080C0D110D2A0D8A980AF1F604D1CD52 +3CF41D08A45EB809AF11F530C138F256FFD49BC20F77005D004AC85FD563E8E8BA5F79CC60FDE714 +1416F4C14FFF281ECE2BE1D167B7B1ECE17790454F795B056CE4DF1D08F25F0E5E2A16CFA066AF97 +F3A80015068FA2A1D65F329A5CF7856114A77EE7295C7929CA27796D8C51B31347CBC7C4EEF1E75D +12237C558BE5B65DCAA4CDDCB419E543B1785DF8B225C2E9778839123E6F85E53D925C6D2FC0327A +EF9CA13D1F2F9B3E510A1A4190D3057227621788AFB6567132238BE86559BCA006B85AFBB8AFE5D7 +A8CE58AF731F2550108C6B8CD63632184B1E218F01881CB94CEBFFC310F263565A39C83C874AE474 +AA213F7DD9CB3B8446A3E47E81BACF7B16E4A80899BF2D30C28F9DE0678DF364589DA6A454398E30 +21A92AD1D8B0DC494D96A06C7568E34547F0E68829E5D15F6500ECD7403B40B5CC2A479D0F8CE3E8 +709861608AED046339BE055BAED1A6BD2311CF918E74378D893710D42A769671326E947F108A38C2 +3F92EF5C6A50EFE36E858671F17151C719B9C7D60E8E429F088616D616080DC676760BE83A3F5229 +6C4B13CA3818E3FEB56D51DB5979F28063F7D537C15493D57CAA1E55438C01C794336D9F21520484 +FE5B5BAEAD7121E3CCC5086E2F2191DBEE9527CA61CE85CC0A4D99EA29169B17A10B3D4372EA493D +48CF572E570CF48B3B7512268A9AC4CC161F97695D19412C36F1D67522E272B1C18B6122A355B43C +37636E71462503C43C1AEF5ACE34A6442075B59892BA54E9B5A99B9733BAF64161450F8ECF4FB2B2 +DA6F9AAEBC827CD9AEF94BB463935C26E1DD5DDCA5BA87E0EFB62D9D3226DC28427EC097B68C9EE1 +E47D125F884F8656C8AD55D625A8F7F1A306383A5036A12E63B6FAC4A215AC88725611EBA74B6770 +B20F45356879DB807E9C9105D14C83104B2DCB4F274A2F37152425935B3F2D1633E4444540F7411B +24C17055850C9528D912F9DD40984CA1B3BE277F82198BC99B80233B8AAB674A44B42B9123E886B7 +B3161D48B4AA24970BB75A983569690BFD4B92E6ECB410DDCA14A3BF59057397FF1AF159BE230216 +FF2F7009C3A3DDD81F2BD1F5C10C2C2F30A8095D7371427AC9D527AC6794CF8593303F786F21CCBE +36DFBE01B0ADD78DB3C9483D9DB09A9E2577A3A4296E7BD09C41F5C91B29C9D7E69EF06B5BDB66E0 +853C3DB133769BC8858121A350CADC1D61C77C1A313833D077938AB2E10EF970590256479B1549B0 +401A9C5E97F12A269A305B372F0EFC035B06AE3E2187D6E3A62DE3B4E8075F0ECF5BE32A5B97A4AC +23A7335C4AB29917129C08250DBD1D5BC123C92E821BBB1A7598E32DDDF1876C6FBB7B858FD317D7 +6022955595338AAD2BFB3B17DA11380E7473A5F566C6329E0F38D9A67E68FD4B8CFCC82FC0BD7BA3 +9A25D5BD0952CC71CF0BD7B5EE184A8E62FBB366D95AB051BC3A80E9F6C27EC100E00C4A002291B0 +4D758A9683657FCB07A2AA8B07DF585CD4205B4DC55330E8A2A367CBE966E84618ACFCAAF81C8A9D +3A3165FE5A623720A0C11CBDD5CA200100DD2C970A09B124D98987D6A2CA7CBB40DA5B585B86FCB3 +8E96F54C64A921D7A5D2F805C67339DC4FC026FB2EE533BB9700F66F4AD58949B3DB75D770C4D7C5 +C23DC720D78124A7ABF30CDFF10C708219903431C7B1A19317341CEA22AA11A588F8AF9BFA4AAC40 +31EF22F13BA597BD1E5958CEA741274197113CB0B7975424C17F73733ED30BDC0170CD0084BB7DC1 +8F031BEF2A6C44D0EA0EBB84E31D5B4C50B63DF0AF96AAF33E3C986D4B82D161E2F9049DE9710EF8 +A11BA0E08266A3547F20567E582EDB47633772D37FCCD119AF5B11F338098F185D5B055975F56092 +CC6979FF49487D69E08A4E8754FD51D29410F56E0F3EFB9C3B86253B3B0A39E9D217604F664CC696 +634D216524F976D066034DDE8EDF5E8F9644337C50C7D8E2230B38E0EE88C53DEEDB3363477E32CB +88B3ACB6931B9717FC93F8D1A9DDDA3A7D8A56783F2B651A1DE216493C34DCD17A7635D21CEC0770 +751424B599B00CE950E60D8A8B3444F1629220DF073137E2ADE1B6243C1C69BD5E10450B948BFCBA +46A841B98BCE7C86E120789C73C87E581868021E68F78CB903AA6D494331174CBF944221DEA9E567 +A2542BD399C5E471D972FAB7E8950AEFF3D91A1296E685B0BFF91367C2703DCAB10AB236DE603E3E +993C4C9020EEBFE89726AB9FB92AF9D371D7188448CAB9FD2704506C39F0842E36EB8B9AAFB1F26F +CD366E66725AD28B19FA57537757EC71B04B451F056C3AEBFA04D1C0CABC9492B6B8D239EEC36776 +D6B515ED43A66AB4342BE4C8B2027F2D008EA231A24B472DA8352A05DDEE31CBC3577E5814DD2D4E +C17A216A7C8FFB27012346C9ED12F7819B96A5B135B6196E888C9AC73D7D4B7DC370E2FBFA17FD74 +0BF516CFF69294493900BFD63721A537BEFB31C5262567103F9CEA4E8DB02964B983E1AF190ECCEF +41F552C45E9B94E29AE3F129687EC35719F591C1987A08DCED3B822344DF81A70AE78E14A81EF1A1 +A77FD5D19F7D35B7C12A473EE11C655E15DC5D3C94F226CBDA85377338BFCEA18359176CA7EED622 +84F9015F2D592E27F1037C95570CFDCA3B9B90D35DB8C341434BBF04C0E692D4C2C3F59EF386CD1C +5A8C783198EBE42C89E3B64C662F7875325982E9299C18DBD1FD2257DD964F9F9DDEEBFE56E4AE9E +8163E8C58581BFD5818BF396CCDE3A66F58E17BDD262D63E5D9AE0D0E43C304CCAC4776B87D40F6B +5AD7E625B2065FAABA81AAF2E2D32E0ACAB12DB2A9FE9C6160FBA7DE5AF019810AD9C64B2E6567B0 +F0108E8EDEC635F4BA88BDEBD3561CDBBB9063B4D19C493E0CA4F551255A7DF6BCE96C17A5DD4877 +7F654F4F114CF29ECDB9779F63EECDC04E1FA06E48701547A8F96483B4195C0DE90B0FD1B95B5F12 +5C43BB973D0B6414A994595359289B5FFEE4A08D684C2E7E3F417585581318D54DF2EEAE7CF36E2C +A1A70EA76154B88C1E4FFDF5EBC28ABE264B40583F2DE1F761DC25DF242396AE502CC63EFD6EE284 +DB37B0DF36A8833ED3EA5A1DB372C8E1F3203E6E945A53D83B87250CD72C851F68A602E7BCF92DDC +E600D518069F8900F3BCA434D21694229572D55F307E0FAFA3DAEA864BAA19F227097963CE83882D +22FB7F1AA3FE558A3669BB7FA37C0A591B4BF3E2A2FF85BFEDE5E424E0AE337EABDFD67BBF38E160 +09A687D2E7C1882DB79304D722EACA233EFA489B10E8D4D404D12A5A4683FDE377A9A952CCAB257E +ABB408D75FF130206DC3447F26E74D1D00354313E340878917177DBD2AA5A2A70E2087D551DA5181 +6FAD07F6E826DB0BF21560BB26906D3100E12AA3801D4A8BDCBF1A0A8D58F1054EE2A0DB04ADDF3F +EAF1FD6E322BBEE274A4995EFFEAAD0F24D9FB45730F6BA0F42D88BE4AEBE9777F8AF508DED61024 +EF955B26ACEC51AF5C21BAD7AD93CC0C9DBE03C0FE9637A3099E5EF329051C87FFF70042D788F21F +4DE645FEBF58374F7E38A9AFE3DE4D2888DD807A09169DA8516DFE37591C122A4798343C1A8121C7 +430F244EE5B19A21897A4423E21CE0492E75C9320E37BD65F1EACA7FC6FE032842E4D985E666E633 +AE5CC62B3449404672B284EA5C6A01E927787104ECCE1354D1C0E5AA2452B7B12937B946B74EFA98 +8C5C79EEE5ACDCFC994CAA853AFA08EB9E180C5E898FDDF8903EB0863E98A4FA537207C154CE5B98 +EF4E97FB6A1CBB07C45D34221EED26998EC864475D231FF76E830A7C0900C4B5FCB980E3F67F4EAE +3DD8086CFA1874E65C424646C7A8F84272DAB04A5984FCE3F4B89380B3A5C6F04EA3B683CC224913 +9209136336AC9349AA89690B5DE0D93E92F996BA7E346B043EBD45A35FA297DB70E9A6250B138674 +FDDFA609BE11EBA8106EEE3923B4E2657CF7A82443C25022A5DED862E8E3A5BFA7B8AC1C1B804B23 +C08A7D8FE594140E8432C1A5E183FE361B6B8C763054458798B756A6CD2535FF4667C634DF78AFBC +C87D40DCD56FFFA12CFC6EDC6A8AF41AF657E0137320624F1895D9AA84AABAC5F3653E977B054C52 +92B06FEAAAC0E5C7FD45B6654D0D9CCDF292A8489E1E6CD929F0AF25B9604CE33BD25662133CEE99 +CDBBD00F865431193767480700CA019D694B38D695CC29F732B5B39B6CE654F1AA18AC3223B60E55 +3FC3C3E114E6A2E59617BFD58AD8E429200B59E035DB7D67C8DC6C72001D005924670ECF7A06FF5F +7B3DD5556DDDE1BE5163F7CD6FC969033EBBAD85856522ECA91F2A200A75BDDA69070240D86C2D7D +959F1DBE45D488A96F308269E8262327A410D057446F596418DF4A12267A7A3FF5ADEA0846896D3A +EFE3D5C72387F7EEEE809BCCD23D1126B86C45A0F66404FAF617D03379A2E44865051E92B4C835F7 +21492147DE3DCCE47EAD192D3F10A5DD459634D6C253F4D09DD98E7DDC836EED8DE08A78A6F6FB93 +84565CF6DA8D4C948144272D5F8787643B9B550F96E42A8CFC0F1C1F2B14D83201199E9E1F5BC0E6 +51E39E16A744930F4409C61CDF9F456C7EAC5C62BD22CE0DDCCDF3755DC670FDC8FEBF09F241BF95 +1A1694BD70B9695A15653F719DF4374AFC6C27F58DD144253BDF86FC1BB3D4FEAEEB9196BCEC7168 +AF1488AB7072751FA24C6642B87DCADF4B2427631E7D7FA39D126410189CD8E24CF0A490FDC7045A +A9A83D02CAB57B9C27211FE1805080FBCEF23B86CDB19885A574C589BDB15C4CB3651FA3D2D6B619 +4449B16D927047E376A84F9423562CD548D192AD0A57E0D5B41010D1C7D87929DB6F456B0A073DF9 +A8220BEB3D4DA01518B5C85C82ABCC821BEEC1965283DABF6AF3AC55ABDDAEF1B53E6119DBB4A114 +44FB1769F9891B5DC931ADFEC8ECEFFA179427FCB08C1B149EDA70717C5E9322F3CE9405438481F3 +90968A38061EDAA2223147D6143877E4C4E645EC0A9803A933116D610491FDC639DF69B418156772 +E14A428864982D3230EFFAA1D2D3388B0F70D8FE202CDD6CB0E97B3290ECCF4A1A69D93C11D3D735 +FF0B5A9A161A86CA4F16B7C231B8BF71D5083697B2F24C0BDAA6E83E5DD2222DA248D4ED3B5509CC +7CA40D8D5A2507A1D40FC1AE9486343CA2B2C65B6CED9B1F4C0535ADF7BECCE45E1DB74C7417B06D +897C6ECDD05F068857D931B3D960103628675BE2FB82DA774ED3786670D8C2BA4ECC36C203C7F7E0 +9C97A09E3B2E2C3EC30B53A8825519B664D09F149AB73F183A4A22C8F20E2052F76649AB881BA28C +6C3C3950EA9B3961F87F6AEFF24DD7B4E10DE28C15DCB27F593F98CBC9CDE19360C5531B2A0C6DC1 +8FAE2832AF49BF9522C068F3036516F711AADEE496EE4E3EFA2F55EA4891DEC6D8A868E0B0017076 +3040CA4D42A73A71057DFE315FF8625BBD74F41E5CA77B7DF096C2F4F0D51B1184CA9F2C8517FCB3 +956C44873D630E94EAA1D2D1451B332770172B2D7A21ECAC864C612235C0B39ADF55EF074F2073FA +D3B54A66B07AEA1FB495A9F7269BD1C07692B0B762DA6881EE6B265ACED0BF0794C0397F8D8B13FF +275BE77561067E2C1FA536131184682BFD32384C6488012D29E8E55838E5A5AA7C40C20AB6B03BFD +BF4EFD2001A612100D585BAC1C77C1CB1ADAF2B000E09686091AB7D1AB6ADE395A03580BD78E961D +14D052E7D4A61227534B55FACAFC4E8F9326DE35BA53A463F7D94B705698300771185DB19E78FABC +D0AE4FCE005B79C795B692F2D9C00B6A61D4B343C35E417BBA169EE82A2E4AE204A126B08A94191C +6E5B5E8328A147BD6ED5A5AD5C9143A50C47789DCFA699720336AFFBD6B1646D8C35139B0DC34340 +C76C7E4FD72DABF80BF64BA04742D07B380E20A678EBCB19057F2346FEC653F1302992279DCCD2E8 +902B2B8F78435AF3400DAE319E94E3148BA88C056701D524DD67FF368C85EC6366F31689A62FFC03 +4BE436588ECBB8B41E8C43112F3B65F50D20A5EC51A26FE899E74731B01C7771F75B76070DC0B223 +1845BE9C09670E65C4DF54C0FB36511B735251AEEBD13FDC0FCFC3134D8DA826E4100521CFEAB202 +B83267EB3F69AEEA25FDE1E9C86407E38AB4CA2D1B91607EFC96DDC5BB10FCD46DEAA5FFED196959 +12302ED55DFACFDC6F22C1528AE3A9902B75F46A489352C87B0F5056FD149DDE67219A3C3D1DD875 +BAD81AD443E0F90DC79D979E10B4262DD20B255B04BBBE5C988B23667135CC61D988928F5F07753A +C76807203942F6B62A178A1E5CBBFBBAEBE735D09B747BF00C360F2E2B6C9F2261F7DB018EDF40B1 +3DB4B7962D4D2F858E1FA6376F21ED9CEA4BEE07FFE27F136BF60352AFB71CDBFF7E65F6B4624E16 +C6E5AB7FF60B4711A178FEE691DD8D362B14175A69070FBC5B9EB15248E4DFDA3C9453335D0E1EB2 +7714E4624C7215A73B53402B02CF7AA05A14CE1E5AE161B75F218BF0EE1215D3CD925D5ACB7DBD2E +BD8E4405433F432C491999794C814D5B384B7A1C0AB28A11CBD0A6EA12678508CF86232309B0BBF7 +EEA929FB7951F5A6B367C5AC57DD7D3B3C1E2188DD4664D14FBC32B1A1EB53D7EE7F55F4D5C2D014 +528EBB7F0E595F7618721451EE6B83EB240A6C4D33377893D4EF542F47EB2845A09759D5554C74DC +5E9109FFC8C929CF1AC446D8149957720EE4FB670D3CA61378549DB992126B23618CF49361D6D4B1 +C73C3D37E4A4465ABB349CFA34E9351D1192E366267EDF02DE432ABC80792B0CFD41FFD0AAA42E63 +3F5B2177A351D33477C636CA573CB02C07F7F7A41C9F1BC4C112BD6459DD130757D2BD6F47495C3F +92E99522871DAC2865 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +cleartomark{restore}if + +%%EndFont +%%EndResource +9.72 /Mathematica2 Msf +0 9 m +(\310) N +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +9.72 /Times-Roman-MISO Msf +2.25 9 m +(q) N +9.72 /Mathematica2 Msf +7.5 9 m +(\310) N +9.72 /Mathematica1 Msf +12 9 m +(=) N +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +9.72 /Times-Roman-MISO Msf +p +20.25 9 m +(0) N +P +p +24.75 9 m +(.) N +P +p +27 9 m +(0) N +P +p +31.5 9 m +(2) N +P +P +[1 0 0 1 0 0 ] concat +1 w +[ ] 0 setdash +1 w +0 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +P +P +[1 0 0 1 -118.485 -136.705 ] concat +1 w +[ ] 0 setdash +P +P +p +np 181 96 m +181 112 L +219 112 L +219 96 L +cp +clip np +p +1 w +1 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +[1 0 0 1 181.505 96.904 ] concat +1 w +[ ] 0 setdash +p +np -1.505 -1.904 m +-1.505 16.096 L +38.495 16.096 L +38.495 -1.904 L +cp +clip np +p +np 0.495 0.0956 m +0.495 13.096 L +37.495 13.096 L +37.495 0.0956 L +cp +clip np +[1 0 0 1 0 0 ] concat +1 w +[ ] 0 setdash +p +np -1.505 -0.904 m +-1.505 15.096 L +38.495 15.096 L +38.495 -0.904 L +cp +clip np +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +9.72 /Times-Roman-MISO Msf +9.72 /Mathematica2 Msf +0 9 m +(\310) N +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +9.72 /Times-Roman-MISO Msf +2.25 9 m +(q) N +9.72 /Mathematica2 Msf +7.5 9 m +(\310) N +9.72 /Mathematica1 Msf +12 9 m +(=) N +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +9.72 /Times-Roman-MISO Msf +p +20.25 9 m +(0) N +P +p +24.75 9 m +(.) N +P +p +27 9 m +(0) N +P +p +31.5 9 m +(5) N +P +P +[1 0 0 1 0 0 ] concat +1 w +[ ] 0 setdash +1 w +0 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +P +P +[1 0 0 1 -181.505 -96.904 ] concat +1 w +[ ] 0 setdash +P +P +p +np 267 3 m +267 19 L +305 19 L +305 3 L +cp +clip np +p +1 w +1 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +[1 0 0 1 267.864 4.035 ] concat +1 w +[ ] 0 setdash +p +np -1.864 -2.035 m +-1.864 15.965 L +38.136 15.965 L +38.136 -2.035 L +cp +clip np +p +np 0.136 -0.0353 m +0.136 12.965 L +36.136 12.965 L +36.136 -0.0353 L +cp +clip np +[1 0 0 1 0 0 ] concat +1 w +[ ] 0 setdash +p +np -1.864 -1.035 m +-1.864 14.965 L +38.136 14.965 L +38.136 -1.035 L +cp +clip np +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +9.72 /Times-Roman-MISO Msf +9.72 /Mathematica2 Msf +0 9 m +(\310) N +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +9.72 /Times-Roman-MISO Msf +2.25 9 m +(q) N +9.72 /Mathematica2 Msf +7.5 9 m +(\310) N +9.72 /Mathematica1 Msf +12 9 m +(=) N +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +9.72 /Times-Roman-MISO Msf +p +20.25 9 m +(0) N +P +p +24.75 9 m +(.) N +P +p +27 9 m +(0) N +P +p +31.5 9 m +(7) N +P +P +[1 0 0 1 0 0 ] concat +1 w +[ ] 0 setdash +1 w +0 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +P +P +[1 0 0 1 -267.864 -4.035 ] concat +1 w +[ ] 0 setdash +P +P +p +np 295 86 m +295 102 L +328 102 L +328 86 L +cp +clip np +p +1 w +1 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +[1 0 0 1 295.617 86.954 ] concat +1 w +[ ] 0 setdash +p +np -1.617 -1.954 m +-1.617 16.046 L +33.383 16.046 L +33.383 -1.954 L +cp +clip np +p +np 0.383 0.0458 m +0.383 13.046 L +32.383 13.046 L +32.383 0.0458 L +cp +clip np +[1 0 0 1 0 0 ] concat +1 w +[ ] 0 setdash +p +np -1.617 -0.954 m +-1.617 15.046 L +33.383 15.046 L +33.383 -0.954 L +cp +clip np +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +9.72 /Times-Roman-MISO Msf +9.72 /Mathematica2 Msf +0 9 m +(\310) N +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +9.72 /Times-Roman-MISO Msf +2.25 9 m +(q) N +9.72 /Mathematica2 Msf +7.5 9 m +(\310) N +9.72 /Mathematica1 Msf +12 9 m +(=) N +%%IncludeResource: font Times-Roman-MISO +%%IncludeFont: Times-Roman-MISO +9.72 /Times-Roman-MISO Msf +p +20.25 9 m +(0) N +P +p +24.75 9 m +(.) N +P +p +27 9 m +(1) N +P +P +[1 0 0 1 0 0 ] concat +1 w +[ ] 0 setdash +1 w +0 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +P +P +[1 0 0 1 -295.617 -86.954 ] concat +1 w +[ ] 0 setdash +P +P +P +P +P +1 w +0 g +0 g +[ ] 0 setdash +2 setlinecap +0 setlinejoin +10 setmiterlimit +%Trailer +%EOF diff --git a/services/clsi/test/acceptance/fixtures/examples/latex_compiler/main.tex b/services/clsi/test/acceptance/fixtures/examples/latex_compiler/main.tex new file mode 100644 index 0000000000..76fd8e5f4c --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/latex_compiler/main.tex @@ -0,0 +1,9 @@ +\documentclass[a4paper]{article} + +\usepackage{graphicx} + +\begin{document} + +\includegraphics[width=\textwidth]{image.eps} + +\end{document} diff --git a/services/clsi/test/acceptance/fixtures/examples/latex_compiler/options.json b/services/clsi/test/acceptance/fixtures/examples/latex_compiler/options.json new file mode 100644 index 0000000000..a280541cfe --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/latex_compiler/options.json @@ -0,0 +1,3 @@ +{ + "compiler": "latex" +} diff --git a/services/clsi/test/acceptance/fixtures/examples/latex_compiler/output.dvi b/services/clsi/test/acceptance/fixtures/examples/latex_compiler/output.dvi new file mode 100644 index 0000000000..84888d7dd6 Binary files /dev/null and b/services/clsi/test/acceptance/fixtures/examples/latex_compiler/output.dvi differ diff --git a/services/clsi/test/acceptance/fixtures/examples/latex_compiler/output.pdf b/services/clsi/test/acceptance/fixtures/examples/latex_compiler/output.pdf new file mode 100644 index 0000000000..78e2440fa9 Binary files /dev/null and b/services/clsi/test/acceptance/fixtures/examples/latex_compiler/output.pdf differ diff --git a/services/clsi/test/acceptance/fixtures/examples/lualatex_compiler/main.tex b/services/clsi/test/acceptance/fixtures/examples/lualatex_compiler/main.tex new file mode 100644 index 0000000000..28da61efd3 --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/lualatex_compiler/main.tex @@ -0,0 +1,8 @@ +\documentclass{article} +\usepackage{luacode} + +\begin{document} +\begin{luacode} +tex.print("Hello world") +\end{luacode} +\end{document} \ No newline at end of file diff --git a/services/clsi/test/acceptance/fixtures/examples/lualatex_compiler/options.json b/services/clsi/test/acceptance/fixtures/examples/lualatex_compiler/options.json new file mode 100644 index 0000000000..96a05433b3 --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/lualatex_compiler/options.json @@ -0,0 +1,3 @@ +{ + "compiler": "lualatex" +} diff --git a/services/clsi/test/acceptance/fixtures/examples/lualatex_compiler/output.pdf b/services/clsi/test/acceptance/fixtures/examples/lualatex_compiler/output.pdf new file mode 100644 index 0000000000..3dae1ad270 Binary files /dev/null and b/services/clsi/test/acceptance/fixtures/examples/lualatex_compiler/output.pdf differ diff --git a/services/clsi/test/acceptance/fixtures/examples/makeindex-custom-style/main.tex b/services/clsi/test/acceptance/fixtures/examples/makeindex-custom-style/main.tex new file mode 100644 index 0000000000..fce282624c --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/makeindex-custom-style/main.tex @@ -0,0 +1,12 @@ +\documentclass{article} + +\usepackage{makeidx} +\makeindex + +\begin{document} + +To solve various problems in Physics \index{Physics} it can useful to express any arbitrary piecewise-smooth function as a Fourier Series \index{Fourier Series} composed of multiple sine and cosine funcions. + +\printindex + +\end{document} diff --git a/services/clsi/test/acceptance/fixtures/examples/makeindex-custom-style/output.pdf b/services/clsi/test/acceptance/fixtures/examples/makeindex-custom-style/output.pdf new file mode 100644 index 0000000000..d7c812de82 Binary files /dev/null and b/services/clsi/test/acceptance/fixtures/examples/makeindex-custom-style/output.pdf differ diff --git a/services/clsi/test/acceptance/fixtures/examples/makeindex-custom-style/style.ist b/services/clsi/test/acceptance/fixtures/examples/makeindex-custom-style/style.ist new file mode 100644 index 0000000000..bdae874015 --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/makeindex-custom-style/style.ist @@ -0,0 +1,7 @@ +heading_prefix "{\\bfseries\\hfil " +heading_suffix "\\hfil}\\nopagebreak\n" +headings_flag 1 +delim_0 "\\dotfill" +delim_1 "\\dotfill" +delim_2 "\\dotfill" + diff --git a/services/clsi/test/acceptance/fixtures/examples/makeindex/main.tex b/services/clsi/test/acceptance/fixtures/examples/makeindex/main.tex new file mode 100644 index 0000000000..fce282624c --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/makeindex/main.tex @@ -0,0 +1,12 @@ +\documentclass{article} + +\usepackage{makeidx} +\makeindex + +\begin{document} + +To solve various problems in Physics \index{Physics} it can useful to express any arbitrary piecewise-smooth function as a Fourier Series \index{Fourier Series} composed of multiple sine and cosine funcions. + +\printindex + +\end{document} diff --git a/services/clsi/test/acceptance/fixtures/examples/makeindex/output.pdf b/services/clsi/test/acceptance/fixtures/examples/makeindex/output.pdf new file mode 100644 index 0000000000..451f166af8 Binary files /dev/null and b/services/clsi/test/acceptance/fixtures/examples/makeindex/output.pdf differ diff --git a/services/clsi/test/acceptance/fixtures/examples/minted/main.tex b/services/clsi/test/acceptance/fixtures/examples/minted/main.tex new file mode 100644 index 0000000000..633abf72a5 --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/minted/main.tex @@ -0,0 +1,10 @@ +\documentclass{article} +\usepackage{minted} +\begin{document} +\begin{minted}{c} +int main() { + printf("hello, world"); + return 0; +} +\end{minted} +\end{document} \ No newline at end of file diff --git a/services/clsi/test/acceptance/fixtures/examples/minted/output.pdf b/services/clsi/test/acceptance/fixtures/examples/minted/output.pdf new file mode 100644 index 0000000000..968569f004 Binary files /dev/null and b/services/clsi/test/acceptance/fixtures/examples/minted/output.pdf differ diff --git a/services/clsi/test/acceptance/fixtures/examples/multibib_bibliography/bibliography.bib b/services/clsi/test/acceptance/fixtures/examples/multibib_bibliography/bibliography.bib new file mode 100644 index 0000000000..29728ba8ae --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/multibib_bibliography/bibliography.bib @@ -0,0 +1,15 @@ +@book{DouglasAdams, + title={The Hitchhiker's Guide to the Galaxy}, + author={Adams, Douglas}, + isbn={9781417642595}, + url={http://books.google.com/books?id=W-xMPgAACAAJ}, + year={1995}, + publisher={San Val} +} + +@book{Tolkien, + title={The Hobbit}, + author={Tolkien, J. R. R.}, + year={1904?} +} + diff --git a/services/clsi/test/acceptance/fixtures/examples/multibib_bibliography/main.tex b/services/clsi/test/acceptance/fixtures/examples/multibib_bibliography/main.tex new file mode 100644 index 0000000000..ff93b69371 --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/multibib_bibliography/main.tex @@ -0,0 +1,23 @@ +\documentclass{report} + +\usepackage{multibib} +\newcites{one}{First references} + +\begin{document} + +\chapter{First chapter} + +The answer to life the universe and everything is 42 \citeone{DouglasAdams} + +\bibliographystyleone{plain} +\bibliographyone{bibliography} + +\chapter{Second chapter} + +All that glitters is not gold \cite{Tolkien} + +\bibliographystyle{plain} +\bibliography{bibliography} + +\end{document} + diff --git a/services/clsi/test/acceptance/fixtures/examples/multibib_bibliography/one.bbl b/services/clsi/test/acceptance/fixtures/examples/multibib_bibliography/one.bbl new file mode 100644 index 0000000000..3c63a37c7b --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/multibib_bibliography/one.bbl @@ -0,0 +1,8 @@ +\begin{thebibliography}{1} + +\bibitem{DouglasAdams} +Douglas Adams. +\newblock {\em The Hitchhiker's Guide to the Galaxy}. +\newblock San Val, 1995. + +\end{thebibliography} diff --git a/services/clsi/test/acceptance/fixtures/examples/multibib_bibliography/output.bbl b/services/clsi/test/acceptance/fixtures/examples/multibib_bibliography/output.bbl new file mode 100644 index 0000000000..df4ff8751b --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/multibib_bibliography/output.bbl @@ -0,0 +1,8 @@ +\begin{thebibliography}{1} + +\bibitem{Tolkien} +J.~R.~R. Tolkien. +\newblock {\em The Hobbit}. +\newblock 1904? + +\end{thebibliography} diff --git a/services/clsi/test/acceptance/fixtures/examples/multibib_bibliography/output.pdf b/services/clsi/test/acceptance/fixtures/examples/multibib_bibliography/output.pdf new file mode 100644 index 0000000000..e666964ea0 Binary files /dev/null and b/services/clsi/test/acceptance/fixtures/examples/multibib_bibliography/output.pdf differ diff --git a/services/clsi/test/acceptance/fixtures/examples/nomenclature/main.tex b/services/clsi/test/acceptance/fixtures/examples/nomenclature/main.tex new file mode 100644 index 0000000000..3fb928cc89 --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/nomenclature/main.tex @@ -0,0 +1,25 @@ +\documentclass{article} + +\usepackage{nomencl} +\makenomenclature + +\begin{document} + +\section*{Main equations} + +\begin{equation} +a=\frac{N}{A} +\end{equation}% + +\nomenclature{$a$}{The number of angels per unit area}% +\nomenclature{$N$}{The number of angels per needle point}% +\nomenclature{$A$}{The area of the needle point}% + +The equation $\sigma = m a$% +\nomenclature{$\sigma$}{The total mass of angels per unit area}% +\nomenclature{$m$}{The mass of one angel} +follows easily. + +\printnomenclature + +\end{document} diff --git a/services/clsi/test/acceptance/fixtures/examples/nomenclature/output.pdf b/services/clsi/test/acceptance/fixtures/examples/nomenclature/output.pdf new file mode 100644 index 0000000000..828349615d Binary files /dev/null and b/services/clsi/test/acceptance/fixtures/examples/nomenclature/output.pdf differ diff --git a/services/clsi/test/acceptance/fixtures/examples/references_in_include/chapter1.tex b/services/clsi/test/acceptance/fixtures/examples/references_in_include/chapter1.tex new file mode 100644 index 0000000000..ded9bb4864 --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/references_in_include/chapter1.tex @@ -0,0 +1 @@ +\ref{two} \ No newline at end of file diff --git a/services/clsi/test/acceptance/fixtures/examples/references_in_include/chapter2.tex b/services/clsi/test/acceptance/fixtures/examples/references_in_include/chapter2.tex new file mode 100644 index 0000000000..993a780a38 --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/references_in_include/chapter2.tex @@ -0,0 +1,2 @@ +\section{Two} +\label{two} \ No newline at end of file diff --git a/services/clsi/test/acceptance/fixtures/examples/references_in_include/main.tex b/services/clsi/test/acceptance/fixtures/examples/references_in_include/main.tex new file mode 100644 index 0000000000..0956f98e27 --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/references_in_include/main.tex @@ -0,0 +1,8 @@ +\documentclass{article} + +\begin{document} + +\include{chapter1} +\include{chapter2} + +\end{document} diff --git a/services/clsi/test/acceptance/fixtures/examples/references_in_include/output.pdf b/services/clsi/test/acceptance/fixtures/examples/references_in_include/output.pdf new file mode 100644 index 0000000000..bc3c8db14c Binary files /dev/null and b/services/clsi/test/acceptance/fixtures/examples/references_in_include/output.pdf differ diff --git a/services/clsi/test/acceptance/fixtures/examples/simple_bibliography/bibliography.bib b/services/clsi/test/acceptance/fixtures/examples/simple_bibliography/bibliography.bib new file mode 100644 index 0000000000..5e796e057f --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/simple_bibliography/bibliography.bib @@ -0,0 +1,9 @@ +@book{DouglasAdams, + title={The Hitchhiker's Guide to the Galaxy}, + author={Adams, Douglas}, + isbn={9781417642595}, + url={http://books.google.com/books?id=W-xMPgAACAAJ}, + year={1995}, + publisher={San Val} +} + diff --git a/services/clsi/test/acceptance/fixtures/examples/simple_bibliography/main.tex b/services/clsi/test/acceptance/fixtures/examples/simple_bibliography/main.tex new file mode 100644 index 0000000000..33030bd667 --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/simple_bibliography/main.tex @@ -0,0 +1,10 @@ +\documentclass{article} + +\begin{document} + +The meaning of life, the universe and everything is 42 \cite{DouglasAdams} + +\bibliographystyle{plain} +\bibliography{bibliography} + +\end{document} diff --git a/services/clsi/test/acceptance/fixtures/examples/simple_bibliography/output.bbl b/services/clsi/test/acceptance/fixtures/examples/simple_bibliography/output.bbl new file mode 100644 index 0000000000..3c63a37c7b --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/simple_bibliography/output.bbl @@ -0,0 +1,8 @@ +\begin{thebibliography}{1} + +\bibitem{DouglasAdams} +Douglas Adams. +\newblock {\em The Hitchhiker's Guide to the Galaxy}. +\newblock San Val, 1995. + +\end{thebibliography} diff --git a/services/clsi/test/acceptance/fixtures/examples/simple_bibliography/output.pdf b/services/clsi/test/acceptance/fixtures/examples/simple_bibliography/output.pdf new file mode 100644 index 0000000000..1a5e1f8a82 Binary files /dev/null and b/services/clsi/test/acceptance/fixtures/examples/simple_bibliography/output.pdf differ diff --git a/services/clsi/test/acceptance/fixtures/examples/subdirectories/chapter2.tex b/services/clsi/test/acceptance/fixtures/examples/subdirectories/chapter2.tex new file mode 100644 index 0000000000..13a22d2b72 --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/subdirectories/chapter2.tex @@ -0,0 +1 @@ +This is chapter2.tex, included from main.tex. It's not in the same directory but can still be found. diff --git a/services/clsi/test/acceptance/fixtures/examples/subdirectories/output.pdf b/services/clsi/test/acceptance/fixtures/examples/subdirectories/output.pdf new file mode 100644 index 0000000000..d8f5cf5a71 Binary files /dev/null and b/services/clsi/test/acceptance/fixtures/examples/subdirectories/output.pdf differ diff --git a/services/clsi/test/acceptance/fixtures/examples/subdirectories/subdirectory/bibliography.bib b/services/clsi/test/acceptance/fixtures/examples/subdirectories/subdirectory/bibliography.bib new file mode 100644 index 0000000000..5654dbd22f --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/subdirectories/subdirectory/bibliography.bib @@ -0,0 +1,10 @@ +@book{DouglasAdams, + title={The Hitchhiker's Guide to the Galaxy}, + author={Adams, Douglas}, + isbn={9781417642595}, + url={http://books.google.com/books?id=W-xMPgAACAAJ}, + year={1995}, + publisher={San Val} +} + + diff --git a/services/clsi/test/acceptance/fixtures/examples/subdirectories/subdirectory/chapter1.tex b/services/clsi/test/acceptance/fixtures/examples/subdirectories/subdirectory/chapter1.tex new file mode 100644 index 0000000000..3056c071e2 --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/subdirectories/subdirectory/chapter1.tex @@ -0,0 +1 @@ +This is chapter1.tex, included from main.tex diff --git a/services/clsi/test/acceptance/fixtures/examples/subdirectories/subdirectory/image.png b/services/clsi/test/acceptance/fixtures/examples/subdirectories/subdirectory/image.png new file mode 100644 index 0000000000..8660218b7b Binary files /dev/null and b/services/clsi/test/acceptance/fixtures/examples/subdirectories/subdirectory/image.png differ diff --git a/services/clsi/test/acceptance/fixtures/examples/subdirectories/subdirectory/main.tex b/services/clsi/test/acceptance/fixtures/examples/subdirectories/subdirectory/main.tex new file mode 100644 index 0000000000..9972cde543 --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/subdirectories/subdirectory/main.tex @@ -0,0 +1,19 @@ +\documentclass{article} + +\usepackage{graphicx} + +\begin{document} + +Hello world, I'm in a subdirectory \cite{DouglasAdams} + +\input{chapter1.tex} +\input{chapter2.tex} + +\begin{centering} +\includegraphics[width=0.5\textwidth]{image.png} +\end{centering} + +\bibliographystyle{plain} +\bibliography{bibliography} + +\end{document} diff --git a/services/clsi/test/acceptance/fixtures/examples/tikz_feynman/main.tex b/services/clsi/test/acceptance/fixtures/examples/tikz_feynman/main.tex new file mode 100644 index 0000000000..6071bc26f0 --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/tikz_feynman/main.tex @@ -0,0 +1,66 @@ +\RequirePackage{luatex85} +\documentclass[tikz]{standalone} + +\usepackage[compat=1.1.0]{tikz-feynman} + +\begin{document} +\feynmandiagram [horizontal=a to b] { + i1 -- [fermion] a -- [fermion] i2, + a -- [photon] b, + f1 -- [fermion] b -- [fermion] f2, +}; + +\feynmandiagram [horizontal=a to b] { + i1 [particle=\(e^{-}\)] -- [fermion] a -- [fermion] i2 [particle=\(e^{+}\)], + a -- [photon, edge label=\(\gamma\), momentum'=\(k\)] b, + f1 [particle=\(\mu^{+}\)] -- [fermion] b -- [fermion] f2 [particle=\(\mu^{-}\)], +}; + +\feynmandiagram [large, vertical=e to f] { + a -- [fermion] b -- [photon, momentum=\(k\)] c -- [fermion] d, + b -- [fermion, momentum'=\(p_{1}\)] e -- [fermion, momentum'=\(p_{2}\)] c, + e -- [gluon] f, + h -- [fermion] f -- [fermion] i, +}; + +\begin{tikzpicture} + \begin{feynman} + \vertex (a1) {\(\overline b\)}; + \vertex[right=1cm of a1] (a2); + \vertex[right=1cm of a2] (a3); + \vertex[right=1cm of a3] (a4) {\(b\)}; + \vertex[right=1cm of a4] (a5); + \vertex[right=2cm of a5] (a6) {\(u\)}; + + \vertex[below=2em of a1] (b1) {\(d\)}; + \vertex[right=1cm of b1] (b2); + \vertex[right=1cm of b2] (b3); + \vertex[right=1cm of b3] (b4) {\(\overline d\)}; + \vertex[below=2em of a6] (b5) {\(\overline d\)}; + + \vertex[above=of a6] (c1) {\(\overline u\)}; + \vertex[above=2em of c1] (c3) {\(d\)}; + \vertex at ($(c1)!0.5!(c3) - (1cm, 0)$) (c2); + + \diagram* { + {[edges=fermion] + (b1) -- (b2) -- (a2) -- (a1), + (b5) -- (b4) -- (b3) -- (a3) -- (a4) -- (a5) -- (a6), + }, + (a2) -- [boson, edge label=\(W\)] (a3), + (b2) -- [boson, edge label'=\(W\)] (b3), + + (c1) -- [fermion, out=180, in=-45] (c2) -- [fermion, out=45, in=180] (c3), + (a5) -- [boson, bend left, edge label=\(W^{-}\)] (c2), + }; + + \draw [decoration={brace}, decorate] (b1.south west) -- (a1.north west) + node [pos=0.5, left] {\(B^{0}\)}; + \draw [decoration={brace}, decorate] (c3.north east) -- (c1.south east) + node [pos=0.5, right] {\(\pi^{-}\)}; + \draw [decoration={brace}, decorate] (a6.north east) -- (b5.south east) + node [pos=0.5, right] {\(\pi^{+}\)}; + \end{feynman} +\end{tikzpicture} + +\end{document} diff --git a/services/clsi/test/acceptance/fixtures/examples/tikz_feynman/options.json b/services/clsi/test/acceptance/fixtures/examples/tikz_feynman/options.json new file mode 100644 index 0000000000..96a05433b3 --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/tikz_feynman/options.json @@ -0,0 +1,3 @@ +{ + "compiler": "lualatex" +} diff --git a/services/clsi/test/acceptance/fixtures/examples/tikz_feynman/output.pdf b/services/clsi/test/acceptance/fixtures/examples/tikz_feynman/output.pdf new file mode 100644 index 0000000000..367b0d0cae Binary files /dev/null and b/services/clsi/test/acceptance/fixtures/examples/tikz_feynman/output.pdf differ diff --git a/services/clsi/test/acceptance/fixtures/examples/xelatex_compiler/Zapfino.ttf b/services/clsi/test/acceptance/fixtures/examples/xelatex_compiler/Zapfino.ttf new file mode 100644 index 0000000000..b68328074e Binary files /dev/null and b/services/clsi/test/acceptance/fixtures/examples/xelatex_compiler/Zapfino.ttf differ diff --git a/services/clsi/test/acceptance/fixtures/examples/xelatex_compiler/main.tex b/services/clsi/test/acceptance/fixtures/examples/xelatex_compiler/main.tex new file mode 100644 index 0000000000..ad9438af53 --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/xelatex_compiler/main.tex @@ -0,0 +1,7 @@ +\documentclass[11pt]{article} +\usepackage{fontspec} +\setmainfont[Ligatures=TeX]{Zapfino.ttf} +\begin{document} +The quick brown fox jumps over the lazy dog +\end{document} + diff --git a/services/clsi/test/acceptance/fixtures/examples/xelatex_compiler/options.json b/services/clsi/test/acceptance/fixtures/examples/xelatex_compiler/options.json new file mode 100644 index 0000000000..a2e0c09897 --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/examples/xelatex_compiler/options.json @@ -0,0 +1,3 @@ +{ + "compiler": "xelatex" +} diff --git a/services/clsi/test/acceptance/fixtures/examples/xelatex_compiler/output.pdf b/services/clsi/test/acceptance/fixtures/examples/xelatex_compiler/output.pdf new file mode 100644 index 0000000000..85e84adf86 Binary files /dev/null and b/services/clsi/test/acceptance/fixtures/examples/xelatex_compiler/output.pdf differ diff --git a/services/clsi/test/acceptance/fixtures/lion.png b/services/clsi/test/acceptance/fixtures/lion.png new file mode 100644 index 0000000000..64eb549922 Binary files /dev/null and b/services/clsi/test/acceptance/fixtures/lion.png differ diff --git a/services/clsi/test/acceptance/fixtures/minimal.pdf b/services/clsi/test/acceptance/fixtures/minimal.pdf new file mode 100644 index 0000000000..d578e90567 Binary files /dev/null and b/services/clsi/test/acceptance/fixtures/minimal.pdf differ diff --git a/services/clsi/test/acceptance/fixtures/naugty_strings.txt b/services/clsi/test/acceptance/fixtures/naugty_strings.txt new file mode 100644 index 0000000000..92eb1ddce6 --- /dev/null +++ b/services/clsi/test/acceptance/fixtures/naugty_strings.txt @@ -0,0 +1,626 @@ +\documentclass{article} +\usepackage[utf8]{inputenc} + +\title{eee} +\author{henry.oswald } +\date{September 2015} + +\usepackage{natbib} +\usepackage{graphicx} + +\begin{document} + +\maketitle + +\section{Introduction} + +Encoding: utf8 + +# Reserved Strings +# +# Strings which may be used elsewhere in code + +undefined +undef +null +NULL +(null) +nil +NIL +true +false +True +False +None +\ +\\ + +# Numeric Strings +# +# Strings which can be interpreted as numeric + +0 +1 +1.00 +$1.00 +1/2 +1E2 +1E02 +1E+02 +-1 +-1.00 +-$1.00 +-1/2 +-1E2 +-1E02 +-1E+02 +1/0 +0/0 +-2147483648/-1 +-9223372036854775808/-1 +0.00 +0..0 +. +0.0.0 +0,00 +0,,0 +, +0,0,0 +0.0/0 +1.0/0.0 +0.0/0.0 +1,0/0,0 +0,0/0,0 +--1 +- +-. +-, +999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 +NaN +Infinity +-Infinity +0x0 +0xffffffff +0xffffffffffffffff +0xabad1dea +123456789012345678901234567890123456789 +1,000.00 +1 000.00 +1'000.00 +1,000,000.00 +1 000 000.00 +1'000'000.00 +1.000,00 +1 000,00 +1'000,00 +1.000.000,00 +1 000 000,00 +1'000'000,00 +01000 +08 +09 +2.2250738585072011e-308 + +# Special Characters +# +# Strings which contain common special ASCII characters (may need to be escaped) + +,./;'[]\-= +<>?:"{}|_+ +!@#$%^&*()`~ + +# Unicode Symbols +# +# Strings which contain common unicode symbols (e.g. smart quotes) + +Ω≈ç√∫˜µ≤≥÷ +åß∂ƒ©˙∆˚¬…æ +œ∑´®†¥¨ˆøπ“‘ +¡™£¢∞§¶•ªº–≠ +¸˛Ç◊ı˜Â¯˘¿ +ÅÍÎÏ˝ÓÔÒÚÆ☃ +Œ„´‰ˇÁ¨ˆØ∏”’ +`⁄€‹›fifl‡°·‚—± +⅛⅜⅝⅞ +ЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя +٠١٢٣٤٥٦٧٨٩ + +# Unicode Subscript/Superscript +# +# Strings which contain unicode subscripts/superscripts; can cause rendering issues + +⁰⁴⁵ +₀₁₂ +⁰⁴⁵₀₁₂ + +# Quotation Marks +# +# Strings which contain misplaced quotation marks; can cause encoding errors + +' +" +'' +"" +'"' +"''''"'" +"'"'"''''" + +# Two-Byte Characters +# +# Strings which contain two-byte characters: can cause rendering issues or character-length issues + +田中さんにあげて下さい +パーティーへ行かないか +和製漢語 +部落格 +사회과학원 어학연구소 +찦차를 타고 온 펲시맨과 쑛다리 똠방각하 +社會科學院語學研究所 +울란바토르 +𠜎𠜱𠝹𠱓𠱸𠲖𠳏 + +# Japanese Emoticons +# +# Strings which consists of Japanese-style emoticons which are popular on the web + +ヽ༼ຈل͜ຈ༽ノ ヽ༼ຈل͜ຈ༽ノ +(。◕ ∀ ◕。) +`ィ(´∀`∩ +__ロ(,_,*) +・( ̄∀ ̄)・:*: +゚・✿ヾ╲(。◕‿◕。)╱✿・゚ +,。・:*:・゜’( ☻ ω ☻ )。・:*:・゜’ +(╯°□°)╯︵ ┻━┻) +(ノಥ益ಥ)ノ ┻━┻ +( ͡° ͜ʖ ͡°) + +# Emoji +# +# Strings which contain Emoji; should be the same behavior as two-byte characters, but not always + +😍 +👩🏽 +👾 🙇 💁 🙅 🙆 🙋 🙎 🙍 +🐵 🙈 🙉 🙊 +❤️ 💔 💌 💕 💞 💓 💗 💖 💘 💝 💟 💜 💛 💚 💙 +✋🏿 💪🏿 👐🏿 🙌🏿 👏🏿 🙏🏿 +🚾 🆒 🆓 🆕 🆖 🆗 🆙 🏧 +0️⃣ 1️⃣ 2️⃣ 3️⃣ 4️⃣ 5️⃣ 6️⃣ 7️⃣ 8️⃣ 9️⃣ 🔟 + +# Unicode Numbers +# +# Strings which contain unicode numbers; if the code is localized, it should see the input as numeric + +123 +١٢٣ + +# Right-To-Left Strings +# +# Strings which contain text that should be rendered RTL if possible (e.g. Arabic, Hebrew) + +ثم نفس سقطت وبالتحديد،, جزيرتي باستخدام أن دنو. إذ هنا؟ الستار وتنصيب كان. أهّل ايطاليا، بريطانيا-فرنسا قد أخذ. سليمان، إتفاقية بين ما, يذكر الحدود أي بعد, معاملة بولندا، الإطلاق عل إيو. +בְּרֵאשִׁית, בָּרָא אֱלֹהִים, אֵת הַשָּׁמַיִם, וְאֵת הָאָרֶץ +הָיְתָהtestالصفحات التّحول +﷽ +ﷺ + +# Unicode Spaces +# +# Strings which contain unicode space characters with special properties (c.f. https://www.cs.tut.fi/~jkorpela/chars/spaces.html) + + + + + + +␣ +␢ +␡ + +# Trick Unicode +# +# Strings which contain unicode with unusual properties (e.g. Right-to-left override) (c.f. http://www.unicode.org/charts/PDF/U2000.pdf) + +test +test + test +testtest +test + +# Zalgo Text +# +# Strings which contain "corrupted" text. The corruption will not appear in non-HTML text, however. (via http://www.eeemo.net) + +Ṱ̺̺̕o͞ ̷i̲̬͇̪͙n̝̗͕v̟̜̘̦͟o̶̙̰̠kè͚̮̺̪̹̱̤ ̖t̝͕̳̣̻̪͞h̼͓̲̦̳̘̲e͇̣̰̦̬͎ ̢̼̻̱̘h͚͎͙̜̣̲ͅi̦̲̣̰̤v̻͍e̺̭̳̪̰-m̢iͅn̖̺̞̲̯̰d̵̼̟͙̩̼̘̳ ̞̥̱̳̭r̛̗̘e͙p͠r̼̞̻̭̗e̺̠̣͟s̘͇̳͍̝͉e͉̥̯̞̲͚̬͜ǹ̬͎͎̟̖͇̤t͍̬̤͓̼̭͘ͅi̪̱n͠g̴͉ ͏͉ͅc̬̟h͡a̫̻̯͘o̫̟̖͍̙̝͉s̗̦̲.̨̹͈̣ +̡͓̞ͅI̗̘̦͝n͇͇͙v̮̫ok̲̫̙͈i̖͙̭̹̠̞n̡̻̮̣̺g̲͈͙̭͙̬͎ ̰t͔̦h̞̲e̢̤ ͍̬̲͖f̴̘͕̣è͖ẹ̥̩l͖͔͚i͓͚̦͠n͖͍̗͓̳̮g͍ ̨o͚̪͡f̘̣̬ ̖̘͖̟͙̮c҉͔̫͖͓͇͖ͅh̵̤̣͚͔á̗̼͕ͅo̼̣̥s̱͈̺̖̦̻͢.̛̖̞̠̫̰ +̗̺͖̹̯͓Ṯ̤͍̥͇͈h̲́e͏͓̼̗̙̼̣͔ ͇̜̱̠͓͍ͅN͕͠e̗̱z̘̝̜̺͙p̤̺̹͍̯͚e̠̻̠͜r̨̤͍̺̖͔̖̖d̠̟̭̬̝͟i̦͖̩͓͔̤a̠̗̬͉̙n͚͜ ̻̞̰͚ͅh̵͉i̳̞v̢͇ḙ͎͟-҉̭̩̼͔m̤̭̫i͕͇̝̦n̗͙ḍ̟ ̯̲͕͞ǫ̟̯̰̲͙̻̝f ̪̰̰̗̖̭̘͘c̦͍̲̞͍̩̙ḥ͚a̮͎̟̙͜ơ̩̹͎s̤.̝̝ ҉Z̡̖̜͖̰̣͉̜a͖̰͙̬͡l̲̫̳͍̩g̡̟̼̱͚̞̬ͅo̗͜.̟ +̦H̬̤̗̤͝e͜ ̜̥̝̻͍̟́w̕h̖̯͓o̝͙̖͎̱̮ ҉̺̙̞̟͈W̷̼̭a̺̪͍į͈͕̭͙̯̜t̶̼̮s̘͙͖̕ ̠̫̠B̻͍͙͉̳ͅe̵h̵̬͇̫͙i̹͓̳̳̮͎̫̕n͟d̴̪̜̖ ̰͉̩͇͙̲͞ͅT͖̼͓̪͢h͏͓̮̻e̬̝̟ͅ ̤̹̝W͙̞̝͔͇͝ͅa͏͓͔̹̼̣l̴͔̰̤̟͔ḽ̫.͕ +Z̮̞̠͙͔ͅḀ̗̞͈̻̗Ḷ͙͎̯̹̞͓G̻O̭̗̮ + +# Unicode Upsidedown +# +# Strings which contain unicode with an "upsidedown" effect (via http://www.upsidedowntext.com) + +˙ɐnbᴉlɐ ɐuƃɐɯ ǝɹolop ʇǝ ǝɹoqɐl ʇn ʇunpᴉpᴉɔuᴉ ɹodɯǝʇ poɯsnᴉǝ op pǝs 'ʇᴉlǝ ƃuᴉɔsᴉdᴉpɐ ɹnʇǝʇɔǝsuoɔ 'ʇǝɯɐ ʇᴉs ɹolop ɯnsdᴉ ɯǝɹo˥ +00˙Ɩ$- + +# Unicode font +# +# Strings which contain bold/italic/etc. versions of normal characters + +The quick brown fox jumps over the lazy dog +𝐓𝐡𝐞 𝐪𝐮𝐢𝐜𝐤 𝐛𝐫𝐨𝐰𝐧 𝐟𝐨𝐱 𝐣𝐮𝐦𝐩𝐬 𝐨𝐯𝐞𝐫 𝐭𝐡𝐞 𝐥𝐚𝐳𝐲 𝐝𝐨𝐠 +𝕿𝖍𝖊 𝖖𝖚𝖎𝖈𝖐 𝖇𝖗𝖔𝖜𝖓 𝖋𝖔𝖝 𝖏𝖚𝖒𝖕𝖘 𝖔𝖛𝖊𝖗 𝖙𝖍𝖊 𝖑𝖆𝖟𝖞 𝖉𝖔𝖌 +𝑻𝒉𝒆 𝒒𝒖𝒊𝒄𝒌 𝒃𝒓𝒐𝒘𝒏 𝒇𝒐𝒙 𝒋𝒖𝒎𝒑𝒔 𝒐𝒗𝒆𝒓 𝒕𝒉𝒆 𝒍𝒂𝒛𝒚 𝒅𝒐𝒈 +𝓣𝓱𝓮 𝓺𝓾𝓲𝓬𝓴 𝓫𝓻𝓸𝔀𝓷 𝓯𝓸𝔁 𝓳𝓾𝓶𝓹𝓼 𝓸𝓿𝓮𝓻 𝓽𝓱𝓮 𝓵𝓪𝔃𝔂 𝓭𝓸𝓰 +𝕋𝕙𝕖 𝕢𝕦𝕚𝕔𝕜 𝕓𝕣𝕠𝕨𝕟 𝕗𝕠𝕩 𝕛𝕦𝕞𝕡𝕤 𝕠𝕧𝕖𝕣 𝕥𝕙𝕖 𝕝𝕒𝕫𝕪 𝕕𝕠𝕘 +𝚃𝚑𝚎 𝚚𝚞𝚒𝚌𝚔 𝚋𝚛𝚘𝚠𝚗 𝚏𝚘𝚡 𝚓𝚞𝚖𝚙𝚜 𝚘𝚟𝚎𝚛 𝚝𝚑𝚎 𝚕𝚊𝚣𝚢 𝚍𝚘𝚐 +⒯⒣⒠ ⒬⒰⒤⒞⒦ ⒝⒭⒪⒲⒩ ⒡⒪⒳ ⒥⒰⒨⒫⒮ ⒪⒱⒠⒭ ⒯⒣⒠ ⒧⒜⒵⒴ ⒟⒪⒢ + +# Script Injection +# +# Strings which attempt to invoke a benign script injection; shows vulnerability to XSS + + +<script>alert('123');</script> + + +"> +'> +> + +< / script >< script >alert(123)< / script > + onfocus=JaVaSCript:alert(123) autofocus +" onfocus=JaVaSCript:alert(123) autofocus +' onfocus=JaVaSCript:alert(123) autofocus +<script>alert(123)</script> +ript>alert(123)ript> +--> +";alert(123);t=" +';alert(123);t=' +JavaSCript:alert(123) +;alert(123); +src=JaVaSCript:prompt(132) +">javascript:alert(1); + + + + + + +'`"><\x3Cscript>javascript:alert(1) +'`"><\x00script>javascript:alert(1) +ABCDEF +ABCDEF +ABCDEF +ABCDEF +ABCDEF +ABCDEF +ABCDEF +ABCDEF +ABCDEF +ABCDEF +ABCDEF +ABCDEF +ABCDEF +ABCDEF +ABCDEF +ABCDEF +ABCDEF +ABCDEF +ABCDEF +ABCDEF +ABCDEF +ABCDEF +ABCDEF +ABCDEF +ABCDEF +ABCDEF +ABCDEF +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +test +`"'> +`"'> +`"'> +`"'> +`"'> +`"'> +`"'> +`"'> +`"'> +`"'> +"`'> +"`'> +"`'> +"`'> +"`'> +"`'> +"`'> +"`'> +"`'> +"`'> +"`'> +"`'> +"`'> +"`'> +"`'> +"`'> +"`'> +"`'> +"`'> +"`'> +"`'> +"`'> +"`'> +"`'> +"`'> +"`'> +"`'> +"`'> +"`'> +"`'> +"`'> +"`'> +"`'> +"`'> +"`'> +"`'> +"`'> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +XXX + + + + + + + + +"> + + + + + + + + + + + +perl -e 'print "";' > out + + + + +< +