diff --git a/Cargo.toml b/Cargo.toml index 6127547..1d38d1c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,16 @@ crossterm = "0.29" regex = "1.11" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0.141" +serde_yaml = "0.9" notify = "8.1.0" get_if_addrs = "0.5" +actix-web = "4" +actix-files = "0.6" +tokio = { version = "1", features = ["full"] } +clap = { version = "4.4", features = ["derive"] } +log = { version = "0.4", features = ["std"] } +daemonize = "0.5.0" +num-rational = "0.4" +num-traits = "0.2" + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 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 General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is 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. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + 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. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + 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 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. Use with the GNU Affero General Public License. + + 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 Affero 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 special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU 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 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 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 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 General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + 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 GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/README.md b/README.md index beea897..5f94e52 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,16 @@ -ο»Ώ# πŸ•°οΈ NTP Timeturner (alpha) +ο»Ώ# Fetch | Hachi (alpha) -**An LTC-driven NTP server for Raspberry Pi, built with broadcast precision and a hint of magic.** +**An LTC-driven NTP server for Raspberry Pi, built with broadcast precision** -Inspired by the TimeTurner in the Harry Potter series, this project synchronises timecode-locked systems by decoding incoming LTC (Linear Time Code) and broadcasting it as NTP β€” with precision as Hermione would insist upon. +Hachi synchronises timecode-locked systems by decoding incoming LTC (Linear Time Code) and broadcasting it as NTP/PTP β€” with the dedication our namesake would insist upon. + +Created by Chris Frankland-Wright and Chaos Rogers --- ## πŸ“¦ Hardware Requirements -- Raspberry Pi 5 (Dev Platform) but should be supported by Pi v3 (or better) +- Raspberry Pi 5 2GB (Dev Platform) but should be supported by Pi v3 (or better) - Debian Bookworm (64-bit recommended) - Teensy 4.0 - https://thepihut.com/products/teensy-4-0-headers - Audio Adapter Board for Teensy 4.0 (Rev D) - https://thepihut.com/products/audio-adapter-board-for-teensy-4-0 @@ -22,27 +24,103 @@ Inspired by the TimeTurner in the Harry Potter series, this project synchronises - Reads SMPTE LTC from Audio Interface (3.5mm TRS but adaptable to BNC/XLR) - Converts LTC into NTP-synced time - Broadcasts time via local NTP server -- Supports configurable time offsets (hours, minutes, seconds, milliseconds) +- Supports configurable time offsets (hours, minutes, seconds, frames or milliseconds) - Systemd service support for headless operation -- Optional splash screen branding at boot +- Web-based UI for monitoring and control when running as a daemon --- -## πŸš€ Installation (to update) +## πŸ–₯️ Web Interface & API +When running as a background daemon, Hachi provides a web interface for monitoring and configuration. -For Rust install you can do -```bash -cargo install --git https://github.com/cjfranko/NTP-Timeturner -``` -Clone and run the installer: +- **Access**: The web UI is available at `http://:8080`. +- **Functionality**: You can view the real-time sync status, see logs, and change all configuration options directly from your browser. +- **API**: A JSON API is also exposed for programmatic access. See `docs/api.md` for full details. + +--- + +## πŸ› οΈ Known Issues + +- Supported Frame Rates: 24/25fps +- Non Supported Frame Rates: 23.98/30/59.94/60 +- Fractional framerates have drift or wrong wall clock sync issues + +--- + +## πŸš€ Installation + +The `setup.sh` script compiles and installs the Hachi application. You can run it by cloning the repository with `git` or by using the `curl` command below for a git-free installation. + +### Prerequisites + +- **Internet Connection**: To download dependencies. +- **Curl and Unzip**: The script requires `curl` to download files and `unzip` for the git-free method. The setup script will attempt to install these if they are missing. + +### Running the Installer (Recommended) + +This command downloads the latest version, unpacks it, and runs the setup script. Paste it into your Raspberry Pi terminal: ```bash -wget https://raw.githubusercontent.com/cjfranko/NTP-Timeturner/master/setup.sh -chmod +x setup.sh +curl -L https://github.com/cjfranko/NTP-Timeturner/archive/refs/heads/main.zip -o NTP-Timeturner.zip && \ +unzip NTP-Timeturner.zip && \ +cd NTP-Timeturner-main && \ +chmod +x setup.sh && \ ./setup.sh ``` +### What the Script Does + +The installation script automates the following steps: + +1. **Installs Dependencies**: Installs `git`, `curl`, `unzip`, and necessary build tools. +2. **Compiles the Binary**: Runs `cargo build --release` to create an optimised executable. +3. **Creates Directories**: Creates `/opt/timeturner` to store the application files. +4. **Installs Files**: + - The compiled binary is copied to `/opt/timeturner/timeturner`. + - The web interface assets from the `static/` directory are copied to `/opt/timeturner/static`. + - A symbolic link is created from `/usr/local/bin/timeturner` to the binary, allowing it to be run from any location. +5. **Sets up Systemd Service**: + - Copies the `timeturner.service` file to `/etc/systemd/system/`. + - Enables the service to start automatically on system boot. + +After installation is complete, the script will provide instructions to start the service manually or to run the application in its interactive terminal mode. + +```bash +The working directory is /opt/timeturner. +Default 'config.yml' installed to /opt/timeturner. + +To start the service, run: + sudo systemctl start timeturner.service + +To view live logs, run: + journalctl -u timeturner.service -f + +To run the interactive TUI instead, simply run from the project directory: + cargo run +Or from anywhere after installation: + timeturner +``` + +--- + +## πŸ”„ Updating + +If you installed Hachi by cloning the repository with `git`, you can use the `update.sh` script to easily update to the latest version. + +**Note**: This script will not work if you used the `curl` one-line command for installation, as that method does not create a Git repository. + +To run the update script, navigate to the `NTP-Timeturner-main` directory and run: +```bash +chmod +x update.sh && ./update.sh +``` + +The update script automates the following: +1. Pulls the latest code from the `main` branch on GitHub. +2. Rebuilds the application binary. +3. Copies the new binary to `/opt/timeturner/`. +4. Restarts the `timeturner` service to apply the changes. + --- ## πŸ•°οΈ Chrony NTP ```bash @@ -51,10 +129,10 @@ chronyc tracking | NTP Tracking sudo nano /etc/chrony/chrony.conf | Default Chrony Conf File Add to top: -# Serve the system clock as a reference at stratumβ€―10 +# Serve the system clock as a reference at stratumβ€―1 server 127.127.1.0 allow 127.0.0.0/8 -local stratum 10 +local stratum 1 Add to bottom: # Allow LAN clients diff --git a/SECURITY.MD b/SECURITY.MD new file mode 100644 index 0000000..14b8058 --- /dev/null +++ b/SECURITY.MD @@ -0,0 +1,9 @@ +Reporting Security Issues + +The TimeTurner team and community take security bugs in TimeTurner seriously. We appreciate your efforts to responsibly disclose your findings, and will make every effort to acknowledge your contributions. + +To report a security issue, please use the GitHub Security Advisory "Report a Vulnerability" tab. + +The TimeTurner team will send a response indicating the next steps in handling your report. After the initial reply to your report, the security team will keep you informed of the progress towards a fix and full announcement, and may ask for additional information or guidance. + +Report security bugs in third-party modules to the person or team maintaining the module. diff --git a/config.json b/config.json deleted file mode 100644 index 5ba71c3..0000000 --- a/config.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "hardware_offset_ms": 20 -} diff --git a/config.yml b/config.yml new file mode 100644 index 0000000..bc552ee --- /dev/null +++ b/config.yml @@ -0,0 +1,19 @@ +# Hardware offset in milliseconds for correcting capture latency. +hardwareOffsetMs: 55 + +# Enable automatic clock synchronization. +# When enabled, the system will perform an initial full sync, then periodically +# nudge the clock to keep it aligned with the LTC source. +autoSyncEnabled: true + +# Default nudge in milliseconds for adjtimex control. +defaultNudgeMs: 2 + +# Time-turning offsets. All values are added to the incoming LTC time. +# These can be positive or negative. +timeturnerOffset: + hours: 0 + minutes: 0 + seconds: 0 + frames: 0 + milliseconds: 0 diff --git a/docs/api.md b/docs/api.md new file mode 100644 index 0000000..6657028 --- /dev/null +++ b/docs/api.md @@ -0,0 +1,196 @@ +# NTP Timeturner API + +This document describes the HTTP API for the NTP Timeturner application. + +## Endpoints + +### Status and Logs + +- **`GET /api/status`** + + Retrieves the real-time status of the LTC reader and system clock synchronization. The `ltc_timecode` field uses `:` as a separator for non-drop-frame timecode, and `;` for drop-frame timecode between seconds and frames (e.g., `10:20:30;00`). + + **Possible values for status fields:** + - `ltc_status`: `"LOCK"`, `"FREE"`, or `"(waiting)"` + - `sync_status`: `"IN SYNC"`, `"CLOCK AHEAD"`, `"CLOCK BEHIND"`, `"TIMETURNING"` + - `jitter_status`: `"GOOD"`, `"AVERAGE"`, `"BAD"` + + **Example Response:** + ```json + { + "ltc_status": "LOCK", + "ltc_timecode": "10:20:30;00", + "frame_rate": "25.00fps", + "system_clock": "10:20:30.005", + "system_date": "2025-07-30", + "timecode_delta_ms": 5, + "timecode_delta_frames": 0, + "sync_status": "IN SYNC", + "jitter_status": "GOOD", + "lock_ratio": 99.5, + "ntp_active": true, + "interfaces": ["192.168.1.100"], + "hardware_offset_ms": 20 + } + ``` + +- **`GET /api/logs`** + + Retrieves the last 100 log entries from the application. + + **Example Response:** + ```json + [ + "2025-08-07 10:00:00 [INFO] Starting TimeTurner daemon...", + "2025-08-07 10:00:01 [INFO] Found serial port: /dev/ttyACM0" + ] + ``` + +### System Clock Control + +- **`POST /api/sync`** + + Triggers a manual synchronization of the system clock to the current LTC timecode. This requires the application to have `sudo` privileges to execute the `date` command. + + **Request Body:** None + + **Success Response (200 OK):** + ```json + { + "status": "success", + "message": "Sync command issued." + } + ``` + + **Error Response (400 Bad Request):** + ```json + { + "status": "error", + "message": "No LTC timecode available to sync to." + } + ``` + **Error Response (500 Internal Server Error):** + ```json + { + "status": "error", + "message": "Sync command failed." + } + ``` + +- **`POST /api/nudge_clock`** + + Nudges the system clock by a specified number of microseconds. This requires `sudo` privileges to run `adjtimex`. + + **Example Request:** + ```json + { + "microseconds": -2000 + } + ``` + **Success Response (200 OK):** + ```json + { + "status": "success", + "message": "Clock nudge command issued." + } + ``` + **Error Response (500 Internal Server Error):** + ```json + { + "status": "error", + "message": "Clock nudge command failed." + } + ``` + + +- **`POST /api/set_date`** + + Sets the system date. This is useful as LTC does not contain date information. Requires `sudo` privileges. + + **Example Request:** + ```json + { + "date": "2025-07-30" + } + ``` + + **Success Response (200 OK):** + ```json + { + "status": "success", + "message": "Date update command issued." + } + ``` + + **Error Response (500 Internal Server Error):** + ```json + { + "status": "error", + "message": "Date update command failed." + } + ``` + +### Configuration + +- **`GET /api/config`** + + Retrieves the current application configuration from `config.yml`. + + **Example Response (200 OK):** + ```json + { + "hardwareOffsetMs": 20, + "timeturnerOffset": { + "hours": 0, + "minutes": 0, + "seconds": 0, + "frames": 0, + "milliseconds": 0 + }, + "defaultNudgeMs": 2, + "autoSyncEnabled": false + } + ``` + +- **`POST /api/config`** + + Updates the application configuration. The new configuration is persisted to `config.yml` and takes effect immediately. + + **Example Request:** + ```json + { + "hardwareOffsetMs": 55, + "timeturnerOffset": { + "hours": 1, + "minutes": 2, + "seconds": 3, + "frames": 4, + "milliseconds": 5 + }, + "defaultNudgeMs": 2, + "autoSyncEnabled": true + } + ``` + + **Success Response (200 OK):** (Returns the updated configuration) + ```json + { + "hardwareOffsetMs": 55, + "timeturnerOffset": { + "hours": 1, + "minutes": 2, + "seconds": 3, + "frames": 4, + "milliseconds": 5 + }, + "defaultNudgeMs": 2, + "autoSyncEnabled": true + } + ``` + **Error Response (500 Internal Server Error):** + ```json + { + "status": "error", + "message": "Failed to write config.yml" + } + ``` diff --git a/firmware/ltc_audiohat_lock.ino b/firmware/ltc_audiohat_lock.ino new file mode 100644 index 0000000..4218dd9 --- /dev/null +++ b/firmware/ltc_audiohat_lock.ino @@ -0,0 +1,180 @@ +/* Linear Timecode for Audio Library for Teensy 3.x / 4.x + Copyright (c) 2019, Frank BΓΆsing, f.boesing (at) gmx.de + + Development of this audio library was funded by PJRC.COM, LLC by sales of + Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop + open source software by purchasing Teensy or other PJRC products. + + 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, development funding 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. +*/ + +/* + + https://forum.pjrc.com/threads/41584-Audio-Library-for-Linear-Timecode-(LTC) + + LTC example audio at: https://www.youtube.com/watch?v=uzje8fDyrgg + + Adapted by Chris Frankland-Wright 2025 for Teensy Audio Shield Input with autodetect FPS for the NTP-TimeTurner Project + +*/ + +#include +#include +#include "analyze_ltc.h" + +// β€”β€” Configuration β€”β€” +// 0.0 β†’ auto-detect; or force 24.0, 25.0, 29.97 +const float FORCE_FPS = 0.0f; +// frame-delay compensation (in frames) +const int FRAME_OFFSET = 4; +// how many frame-periods to wait before declaring β€œlost” +const float LOSS_THRESHOLD_FRAMES = 1.5f; +// Blink periods (ms) for NO_LTC, ACTIVE, LOST +const unsigned long BLINK_PERIOD[3] = { 2000, 100, 500 }; + +AudioInputI2S i2s1; +AudioAnalyzeLTC ltc1; +AudioControlSGTL5000 sgtl5000; +AudioConnection patchCord(i2s1, 0, ltc1, 0); + +enum State { NO_LTC = 0, LTC_ACTIVE, LTC_LOST }; +State ltcState = NO_LTC; +bool ledOn = false; +unsigned long lastDecode = 0; +unsigned long lastBlink = 0; + +// auto-detect vars +float currentFps = 25.0f; +float periodMs = 0; +const float SMOOTH_ALPHA = 0.1f; +unsigned long lastDetectTs = 0; + +// free-run tracking +long freeAbsFrame = 0; +unsigned long lastFreeRun = 0; + +void setup() { + Serial.begin(115200); + // while (!Serial); + AudioMemory(12); + sgtl5000.enable(); + sgtl5000.inputSelect(AUDIO_INPUT_LINEIN); + pinMode(LED_BUILTIN, OUTPUT); +} + +void loop() { + unsigned long now = millis(); + // compute dynamic framePeriod (ms) from last known fps + unsigned long framePeriod = (unsigned long)(1000.0f/currentFps + 0.5f); + + if (ltc1.available()) { + // β€”β€” LOCKED β€”β€” read a frame + ltcframe_t frame = ltc1.read(); + int h = ltc1.hour(&frame), + m = ltc1.minute(&frame), + s = ltc1.second(&frame), + f = ltc1.frame(&frame); + + // β€”β€” FPS detect or force β€”β€” + if (FORCE_FPS > 0.0f) { + currentFps = FORCE_FPS; + } else { + if (lastDetectTs) { + float dt = now - lastDetectTs; + periodMs = periodMs==0 ? dt : (SMOOTH_ALPHA*dt + (1-SMOOTH_ALPHA)*periodMs); + float measured = 1000.0f/periodMs; + const float choices[3] = {24.0f,25.0f,29.97f}; + float bestD=1e6, pick=25.0f; + for (auto c: choices) { + float d = fabs(measured - c); + if (d < bestD) { bestD = d; pick = c; } + } + currentFps = pick; + } + lastDetectTs = now; + } + + // β€”β€” pack + offset + wrap β€”β€” + int nominal = (currentFps>29.5f)?30:int(currentFps+0.5f); + long dayFrames = 24L*3600L*nominal; + long absF = ((long)h*3600 + m*60 + s)*nominal + f + FRAME_OFFSET; + absF = (absF % dayFrames + dayFrames) % dayFrames; + + // save for free-run + freeAbsFrame = absF; + lastFreeRun = now; + + // unpack for display + long totSec = absF/nominal; + int outF = absF % nominal; + int outS = totSec % 60; + long totMin = totSec/60; + int outM = totMin % 60; + int outH = (totMin/60)%24; + + // dynamic drop-frame from bit 10 + bool isDF = ltc1.bit10(&frame); + char sep = isDF ? ';' : ':'; + + // print locked + Serial.printf("[LOCK] %02d:%02d:%02d%c%02d | %.2ffps\r\n", + outH,outM,outS,sep,outF,currentFps); + + // update state + ltcState = LTC_ACTIVE; + lastDecode = now; + } + else { + // β€”β€” NOT LOCKED β€”β€” check if we should switch to free-run + if (ltcState == LTC_ACTIVE) { + // only switch after losing more than LOSS_THRESHOLD_FRAMES + float elapsedFrames = float(now - lastDecode) / float(framePeriod); + if (elapsedFrames >= LOSS_THRESHOLD_FRAMES) { + ltcState = LTC_LOST; + // free-run will begin below + } + } + } + + // β€”β€” FREE-RUN β€”β€” when lost + if (ltcState == LTC_LOST) { + if ((now - lastFreeRun) >= framePeriod) { + freeAbsFrame = (freeAbsFrame + 1) % (24L*3600L*(int)(currentFps+0.5f)); + lastFreeRun += framePeriod; + + long totSec = freeAbsFrame/((int)(currentFps+0.5f)); + int outF = freeAbsFrame % (int)(currentFps+0.5f); + int outS = totSec % 60; + long totMin = totSec/60; + int outM = totMin % 60; + int outH = (totMin/60)%24; + + Serial.printf("[FREE] %02d:%02d:%02d:%02d | %.2ffps\r\n", + outH,outM,outS,outF,currentFps); + } + } + + // β€”β€” LED heartbeat β€”β€” non-blocking + unsigned long period = BLINK_PERIOD[ltcState]; + if (now - lastBlink >= period/2) { + ledOn = !ledOn; + digitalWrite(LED_BUILTIN, ledOn); + lastBlink = now; + } +} diff --git a/firmware/ltc_audiohat_lock.ino_v2.hex b/firmware/ltc_audiohat_lock.ino_v2.hex new file mode 100644 index 0000000..2b636bd --- /dev/null +++ b/firmware/ltc_audiohat_lock.ino_v2.hex @@ -0,0 +1,5895 @@ +:0200000460009A +:100000004643464200000156000000000103030081 +:1000100000000000000000000000000000000000E0 +:1000200000000000000000000000000000000000D0 +:1000300000000000000000000000000000000000C0 +:1000400000000000010408000000000000000000A3 +:100050000000200000000000000000000000000080 +:100060000000000000000000000000000000000090 +:100070000000000000000000000000000000000080 +:10008000EB04180A063204260000000000000000FD +:10009000050404240000000000000000000000002F +:1000A0000000000000000000000000000000000050 +:1000B0000604000000000000000000000000000036 +:1000C0000000000000000000000000000000000030 +:1000D00020041808000000000000000000000000DC +:1000E0000000000000000000000000000000000010 +:1000F0000000000000000000000000000000000000 +:10010000D8041808000000000000000000000000F3 +:100110000204180804200000000000000000000095 +:1001200000000000000000000000000000000000CF +:10013000600400000000000000000000000000005B +:1001400000000000000000000000000000000000AF +:10015000000000000000000000000000000000009F +:10016000000000000000000000000000000000008F +:10017000000000000000000000000000000000007F +:10018000000000000000000000000000000000006F +:10019000000000000000000000000000000000005F +:1001A000000000000000000000000000000000004F +:1001B000000000000000000000000000000000003F +:1001C000000100000010000001000000000000001D +:1001D000000001000000000000000000000000001E +:1001E000000000000000000000000000000000000F +:1001F00000000000000000000000000000000000FF +:10020000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE +:10021000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEE +:10022000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDE +:10023000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCE +:10024000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBE +:10025000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAE +:10026000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9E +:10027000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8E +:10028000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7E +:10029000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6E +:1002A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5E +:1002B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4E +:1002C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3E +:1002D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2E +:1002E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1E +:1002F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0E +:10030000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD +:10031000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED +:10032000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDD +:10033000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCD +:10034000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBD +:10035000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAD +:10036000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9D +:10037000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8D +:10038000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7D +:10039000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6D +:1003A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D +:1003B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4D +:1003C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3D +:1003D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2D +:1003E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1D +:1003F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0D +:10040000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC +:10041000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEC +:10042000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC +:10043000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCC +:10044000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBC +:10045000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAC +:10046000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9C +:10047000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8C +:10048000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7C +:10049000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C +:1004A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5C +:1004B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4C +:1004C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3C +:1004D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2C +:1004E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1C +:1004F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0C +:10050000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB +:10051000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEB +:10052000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDB +:10053000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCB +:10054000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBB +:10055000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAB +:10056000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9B +:10057000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8B +:10058000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7B +:10059000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6B +:1005A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5B +:1005B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4B +:1005C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3B +:1005D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2B +:1005E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1B +:1005F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0B +:10060000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA +:10061000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEA +:10062000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDA +:10063000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCA +:10064000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBA +:10065000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAA +:10066000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9A +:10067000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8A +:10068000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7A +:10069000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6A +:1006A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5A +:1006B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4A +:1006C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3A +:1006D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2A +:1006E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1A +:1006F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0A +:10070000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9 +:10071000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9 +:10072000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD9 +:10073000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC9 +:10074000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB9 +:10075000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA9 +:10076000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF99 +:10077000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF89 +:10078000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF79 +:10079000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF69 +:1007A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF59 +:1007B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF49 +:1007C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF39 +:1007D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF29 +:1007E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF19 +:1007F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF09 +:10080000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8 +:10081000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE8 +:10082000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD8 +:10083000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC8 +:10084000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB8 +:10085000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA8 +:10086000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF98 +:10087000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF88 +:10088000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF78 +:10089000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF68 +:1008A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF58 +:1008B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF48 +:1008C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF38 +:1008D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF28 +:1008E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF18 +:1008F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF08 +:10090000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7 +:10091000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE7 +:10092000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD7 +:10093000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7 +:10094000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB7 +:10095000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA7 +:10096000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF97 +:10097000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF87 +:10098000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF77 +:10099000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF67 +:1009A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF57 +:1009B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF47 +:1009C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF37 +:1009D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF27 +:1009E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF17 +:1009F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF07 +:100A0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6 +:100A1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE6 +:100A2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD6 +:100A3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC6 +:100A4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB6 +:100A5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA6 +:100A6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF96 +:100A7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF86 +:100A8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF76 +:100A9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF66 +:100AA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF56 +:100AB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF46 +:100AC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF36 +:100AD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF26 +:100AE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF16 +:100AF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF06 +:100B0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5 +:100B1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5 +:100B2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD5 +:100B3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC5 +:100B4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB5 +:100B5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA5 +:100B6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF95 +:100B7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF85 +:100B8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF75 +:100B9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF65 +:100BA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF55 +:100BB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF45 +:100BC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF35 +:100BD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF25 +:100BE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF15 +:100BF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF05 +:100C0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4 +:100C1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE4 +:100C2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD4 +:100C3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC4 +:100C4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB4 +:100C5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA4 +:100C6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF94 +:100C7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF84 +:100C8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF74 +:100C9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF64 +:100CA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF54 +:100CB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF44 +:100CC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF34 +:100CD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF24 +:100CE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF14 +:100CF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF04 +:100D0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3 +:100D1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE3 +:100D2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD3 +:100D3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC3 +:100D4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB3 +:100D5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA3 +:100D6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF93 +:100D7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF83 +:100D8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF73 +:100D9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF63 +:100DA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF53 +:100DB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF43 +:100DC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF33 +:100DD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF23 +:100DE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF13 +:100DF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF03 +:100E0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2 +:100E1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE2 +:100E2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD2 +:100E3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC2 +:100E4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB2 +:100E5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA2 +:100E6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF92 +:100E7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF82 +:100E8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF72 +:100E9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF62 +:100EA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +:100EB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF42 +:100EC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF32 +:100ED000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF22 +:100EE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF12 +:100EF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF02 +:100F0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1 +:100F1000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE1 +:100F2000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD1 +:100F3000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC1 +:100F4000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB1 +:100F5000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA1 +:100F6000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF91 +:100F7000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF81 +:100F8000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF71 +:100F9000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF61 +:100FA000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF51 +:100FB000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF41 +:100FC000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF31 +:100FD000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF21 +:100FE000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF11 +:100FF000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF01 +:10100000D1002043491600600000000000000000ED +:10101000201000600010006000640160000000000B +:10102000000000600070010000000000FFFFFFFFF3 +:10103000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0 +:10104000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB0 +:10105000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0 +:10106000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF90 +:10107000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80 +:10108000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF70 +:10109000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF60 +:1010A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF50 +:1010B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF40 +:1010C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF30 +:1010D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF20 +:1010E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF10 +:1010F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00 +:10110000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF +:10111000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDF +:10112000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCF +:10113000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBF +:10114000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAF +:10115000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9F +:10116000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F +:10117000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F +:10118000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6F +:10119000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5F +:1011A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4F +:1011B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F +:1011C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2F +:1011D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1F +:1011E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0F +:1011F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +:10120000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEE +:10121000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDE +:10122000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCE +:10123000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBE +:10124000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAE +:10125000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9E +:10126000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8E +:10127000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7E +:10128000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6E +:10129000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5E +:1012A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4E +:1012B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3E +:1012C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2E +:1012D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1E +:1012E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0E +:1012F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE +:10130000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED +:10131000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDD +:10132000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCD +:10133000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBD +:10134000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAD +:10135000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9D +:10136000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8D +:10137000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7D +:10138000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6D +:10139000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D +:1013A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4D +:1013B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3D +:1013C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2D +:1013D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1D +:1013E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0D +:1013F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD +:10140000814205D051F8043B40F8043B8242F9D8B0 +:10141000704700BF044A05494FF0000342F8043BFF +:101420009142FBD8704700BFC01E0020402C002016 +:101430002DE98848BFF34F8F00BF00BF00BF00BF3A +:1014400000F07AFA674B0822C3F8542100BF00BFAE +:1014500000BF00BF00BF00BF00BF00BF00BF00BF94 +:1014600000BF00BF00BF00BF00BF00BF5E4A5F49B2 +:101470005F48FFF7C5FF5F4A5F496048FFF7C0FF5D +:101480005F4CFFF7C7FF4FF470004FF0E0210023DF +:101490005C4AC1F8880D44F823200133B02BFAD1FF +:1014A000594B8021594A03F8011B9342FBD14FF05D +:1014B000E0254C4E4FF08039DFF880B1DFF880A195 +:1014C0004FF0FF31C5F8084D0027C6F80491C6F863 +:1014D00000B1C6F8F490C6F8F0A0D5F8243DDFF8C6 +:1014E000648143F4E0234A4AC5F8243DD8F81C300F +:1014F00023F07F0343F04003C8F81C30D8F82430B1 +:1015000023F07F0343F04003C8F824309166D1668E +:101510001167516700F018FA3E4B3F49A3633F4BF8 +:10152000E36363236B610323AF612B613C4BC5F81D +:10153000203DD5F8FC3D43F08073C5F8FC3D394BA8 +:101540001A6842F001021A605B680B6000F084FACE +:10155000C6F804913448C6F800B1C6F8F490C6F84D +:10156000F0A000F019FCD8F86C10304B304A41F470 +:101570004051C8F86C101F60C3F80871C3F81871A7 +:10158000C3F82871C3F83871936BDB0708D442F6AF +:101590001563284951651365936B43F00103936309 +:1015A000234A254C936843F00113936000F0B8FB85 +:1015B00000F0E6FB00F07EFA00F0C0F92368132B80 +:1015C000FCD900F00FFB2368B3F5967FFBD300F046 +:1015D000B9F900F0B5F900F0F3FB00F0E1FB30BF22 +:1015E000FDE700BF00800D4048230100402000605F +:1015F00000000000C01E00208C430160000000209D +:10160000001C002015AB000000E400E0A0E400E0B6 +:1016100000C00A4065A00000C02B002069A00000A7 +:1016200000002020001000E00046C32300400840D6 +:1016300000400D400000C056C42B00201B10182095 +:101640000C0D111300C00F40054B4FF42A01054A41 +:1016500005485A641864054A99639546FFF7E8FE01 +:1016600000C00A40BFAAAAAA0700200000800620E6 +:101670001BB9124B1B6F9B041ED400F03F000F4B95 +:1016800022F0604221F0604140F489101867C3F8ED +:101690008010C3F890201A6F22F480521A671A6FD4 +:1016A000002AFCDAD3F87011054A0A40C3F8702109 +:1016B0001A6F22F480321A67704700BF00800D4015 +:1016C000FF7F7FFF43690A4A03EB011010B4037ADE +:1016D000084C02EB0313D3E901321460C2681A60AC +:1016E00003690BB142691A605DF8044B704700BF93 +:1016F000E40B002061F801004369027E03EB021253 +:1017000092F808C08C451CD01A7AFF2A19D0914251 +:1017100010B5044616D01A7EFF2A06D00121D3E95F +:10172000002312681A4201D1217610BD064B052212 +:10173000204603EB0C135B681A60FFF7C3FF2176AA +:10174000F3E770470021EAE7E40B002043690A4A07 +:1017500003EB011010B490F82830084C02EB03138F +:10176000D3E901321460C26A1A60036B0BB1426B99 +:101770001A605DF8044B7047E40B002061F801002B +:101780004369427E03EB021292F828C08C451ED0BA +:1017900093F82820FF2A1AD0914210B5044617D09A +:1017A00093F83820FF2A06D00121D3E900231268DC +:1017B0001A4201D1617610BD064B0522204603EB8B +:1017C0000C135B681A60FFF7C1FF6176F3E770479F +:1017D0000021EAE7E40B0020164942698B6B23F4F1 +:1017E0007C0343F4802370B58B630446124DD2E929 +:1017F00000130A681A4303690A60022200211A6171 +:101800000E4A19619A6401225A629D624FF4303582 +:10181000DD624FF001159E6C1E6519629D651A61AF +:10182000017EFFF74FFF617E2046BDE87040FFF765 +:101830008DBF00BF00C00F40B80B05053B3728190E +:10184000B1F5607FF0B50E468DB028BF4FF46076DD +:101850000F46054672B62E4B0024702218602146B2 +:101860002C4B2D481C8000F0AFFACFB121462A48FE +:101870004FF0010C4A0901F01F03013150F82240DA +:101880000CFA03F38E4243EA040340F82230F1D805 +:10189000284600234380013300F582709E42F9D828 +:1018A0001E4C257815B162B60DB0F0BD082000F0D1 +:1018B0006FFA1B4B80220646009302A90693194B30 +:1018C0000271056008A8029300F06EFA06A9164A94 +:1018D000304600F06DFA069B08A8DB689847009B2D +:1018E00002A8DB6898472378002BDCD10F4B104A05 +:1018F000C3F858210F49D0204FF0E023402281F84F +:101900004600C3F808210123237062B60DB0F0BD74 +:1019100040260020E82B002048260020F92B00203C +:1019200040090020BD9A00001B100100001C00208F +:10193000C99A000000E400E0704700BF704700BF94 +:10194000704700BF00BF704710B44FF0E023002184 +:1019500010243148C3F8941DC3F89C4D1124C3F8DA +:10196000A00D2E48C3F89C4D1224C3F8A00D2C489E +:10197000C3F89C4D2B4AC3F8A00D2B4C42F0150226 +:101980002A48C3F89C4DC3F8A00D294C2948C3F838 +:101990009C4DC3F8A00D284CC3F89C2D2748284A1D +:1019A000C3F8A04DC3F89C0DC3F8A02D02F5A022EA +:1019B000244C0C322448C3F89C4DC3F8A02D234A74 +:1019C000C3F89C0D224CC3F8A02D02F14062C3F86D +:1019D0009C4D2048C3F8A02D0C32C3F89C0DC3F8D1 +:1019E000A02D00BF00BF00BF00BF00BF0122C3F891 +:1019F000942DBFF34F8FBFF36F8FC3F8501FBFF30A +:101A00004F8FBFF36F8FD3F8142D5DF8044B42F462 +:101A10004032C3F8142D70473F000010250008071E +:101A200009001000402C00201300200021000207B4 +:101A300014000020250008130900001016002020C3 +:101A400027000B1317000040180000602F000B0741 +:101A5000190000701A000080F0B4154A40274FF4B6 +:101A600080314FF480564FF400554FF4404443F218 +:101A70004200136913F0020F0ED113F4005F0FD070 +:101A800013F4805F0ED0002BF3DA13F4803F0BD1F8 +:101A90005B060BD5F0BC7047946151619061E8E73B +:101AA0005561E6E75661E4E79161E2E75761E0E7F7 +:101AB00000800D403F4A03203F49F3EE095AD2F817 +:101AC00080304FF0000C9FED3D6A23F001039FED45 +:101AD0003C5A30B4C2F88030C2F89000D1F8E0101F +:101AE000384DCBB2384C39482B6007EE903A0B0D8D +:101AF000C1F30B21F8EEE77A06EE903A07EE101AE2 +:101B0000334BB8EEC77A2160F8EEE66A314937EE1A +:101B1000C66A37EEC55A76EEC76A77EEE57A26EEE4 +:101B2000266AC3ED006A25EE265AD2F8803067EEA9 +:101B3000A64AC0ED007AC6EE275A274885EE276AE6 +:101B4000C4EEA76A75EE875AFCEEE55A36EE076AD0 +:101B500015EE904ABCEEC66A43EA045376EE877AE5 +:101B6000C2F8803016EE103AD2F89041FCEEE77AD7 +:101B700001EA0341214317EE903AC2F89011C3F3F2 +:101B80000B03D2F890110B431449C2F89031D2F8EC +:101B9000803043F00203C2F88030114B80F840C01F +:101BA000C1F840314FF0E023012230BCC3F80821D6 +:101BB000704700BF00810D4000441F400000AA4252 +:101BC0000000B442A42B0020A02B0020A82B002052 +:101BD000AC2B00200000FF0F00E400E0001C002000 +:101BE00001AD0000314B40F6617210B5C3F8202101 +:101BF00040F2044400F0E0F82D4A2E49D2F880303B +:101C00002D4843F00303C2F880302C4BC1F86041EB +:101C100002681A4203D1D1F8A8319A071BD0254A8D +:101C20004FF00041244B5963D2F8403143F0020396 +:101C3000C2F84031D2F840319B07FBD44FF400305A +:101C40004FF0E0211C4B4FF00042C1F88C021920EC +:101C50009A6300F099F8184A4FF08040154C002123 +:101C600090630A20164B11604FF42072C4F8A8014B +:101C7000184600F0A9F84FF4800203464FF48100A3 +:101C800040F243111860C4F858311A640D4B0E4AE3 +:101C9000C4F84811C3F804224FF0E0224FF4003199 +:101CA0000123C2F80C11C4F8403110BD00800D4072 +:101CB00000C00F4000002E4000900D40001C1E0090 +:101CC00000000020001C0020E9AE000008B50E4B0B +:101CD0001B6E9B0700D4FBBE72B60C4B00200C4A57 +:101CE000C3F8400103F160430A49A3F55F2311647F +:101CF0009D46BFF34F8F4FF400130748074ADB6937 +:101D000002609B68984700BF00441F4000002E40BF +:101D100000C00A400300200000802020000012EBD9 +:101D2000104BA020104AD96E41F4403110B4D9664E +:101D300040F23764D96E41F44071D96654649064BE +:101D4000936C1B06FCD4094A40F23761A02351640E +:101D50009364936C13F08003FBD1054A13705DF814 +:101D6000044B704700C00F4000400C4000800C4006 +:101D7000002C0020F8B500BFF8BC08BC9E46704798 +:101D80005FF800F0FDA900005FF800F0EDA500008D +:101D90005FF800F015A900005FF800F0FDA2000058 +:101DA0005FF800F0D1A700005FF800F0319B000061 +:101DB0005FF800F03DA100005FF800F059B60000A8 +:101DC0005FF800F075CF00005FF800F0FDCC000078 +:101DD000450000006D04000041050000E909000015 +:101DE0002D0C0000450C00005D0C0000750C00007F +:101DF0008D0C0000A50C0000BD0C0000D50C0000EF +:101E0000ED0C0000050D0000F90D0000110E0000A2 +:101E1000290E0000410E0000590E0000710E000056 +:101E2000890E0000A10E0000D50E0000050F000075 +:101E30001D0F0000350F00004D0F0000650F000062 +:081E40001922000041A200007C +:101E480080C00F40000000031900000010000000CF +:101E5800E8841F4001000000FF000000FF000000B0 +:101E68000000000000000000180000001000000042 +:101E7800E4841F4001000000FF000000FF00000094 +:101E880000000000000000001F000000B19A0000E0 +:101E980070C00F40000C000011000000110000008D +:101EA800E0841F400200000024000000120000002F +:101EB800E0841F4001000000100000001100000035 +:101EC800DC841F4002000000250000001200000012 +:101ED800DC841F40010000001E000000A59A0000DD +:101EE80070C00F40C0000000120000001300000086 +:101EF800D0841F4001000000FF000000FF00000028 +:101F080000000000000000001300000013000000A3 +:101F1800CC841F4001000000FF000000FF0000000B +:101F280000000000000000001C000000999A00005A +:101F3800160355005300420020005300650072004C +:101F4800690061006C00000018035400650065001A +:101F58006E00730079006400750069006E006F0000 +:101F68000403090409026200030100C032080B00DF +:101F78000202020100090400000102020100052416 +:101F880000100105240101010424020605240600AD +:101F9800010705820310001009040100020A00006D +:101FA80000070503024000000705840240000009FD +:101FB80004020002FF6AFF000705810240000107D2 +:101FC800050102400001000009026200030100C08F +:101FD80032080B000202020100090400000102029B +:101FE8000100052400100105240101010424020652 +:101FF80005240600010705820310000509040100F5 +:10200800020A000000070503020002000705840217 +:102018000002000904020002FF6AC70007058102E6 +:102028000002010705010200020100000A06000281 +:08203800EF020140010000006D +:102040000000000000000000000000000000000090 +:102050000000000000000000000000000000000080 +:102060000548064B1B1AD90F01EBA301491002D0FA +:10207000034B03B118477047C01E0020C01E00204C +:102080000000000008B5054B1BB105490548AFF33A +:102090000080BDE80840FFF7E3BF00BF000000007C +:1020A000382B0020007001602DE9F843214D40F2EB +:1020B000EE28214C214FDFF890902E680BF0D2FED5 +:1020C0002378E3B13B78DB0719D52B68D9F80020DA +:1020D0009B1A0E2B13D91A4C0C211A4812F04CF9EA +:1020E000204600F08FFB55222021204600F09AFA6E +:1020F00090B901210D20BDE8F8430AF051BB2B68CF +:1021000022789B1B2AB1B3F5FA6FE4D80BF0AAFE34 +:10211000D4E74345FAD9DEE7E2882421204642F09D +:10212000040200F07FFA01210D20BDE8F8430AF017 +:1021300037BB00BFC42B00200A2C0020092C002034 +:10214000B42B002000002020D42B00202DE9F04FDC +:10215000BD4B8BB0BD4F1C6897ED007A72B6BC4A80 +:10216000137FDBB262B6002B00F0A58072B60023AD +:10217000D2E90A60137762B6C0F30163C6F3026165 +:10218000DFF82483C0F3034503EB8302C0F302238B +:1021900001EB810900F00F0C03EB8303C6F301216F +:1021A00005EB4205C6F3034E01EB8101D8F8002090 +:1021B0000CEB430C06F00F030EEB490E03EB41034F +:1021C000002A40F09D8097ED007ADFEDA27AC8F8F2 +:1021D0000040B4EEE77AF1EE10FA00F3C580F6EEB7 +:1021E000007A9D4877EE277AFDEEE77A17EE901A8F +:1021F00001FB00F0C6F38022CCEB0C1CB7EEC77AD3 +:102200003A324FEA8C0C01924FF4616202FB05CC2A +:10221000924DF44401FB0C33043393FBF0F200FBCA +:102220001233034493FBF0F200FB12338C4A8D48C7 +:102230008DED047B13608C4A146093FBF1F201FB7B +:102240001233029380FB0213D1171344C1EB6311C5 +:1022500080FB0103C8170B44C0EB6310C0EB0013F5 +:10226000A1EB8303C1EB0111A2EB81027F49009234 +:1022700085FB0025C217C2EBA50202EB4202A0EBD0 +:10228000C2027B480AF04CF87A4A01217A4B11705D +:102290001C607A4D32222B68E31A93422DD3784B7F +:1022A0000D20197881F0010119700AF03DFA2C60B7 +:1022B0000BB0BDE8F08F9FED736AF6EE006A6D4DCE +:1022C000C6EE077A2B78012B77EEA67AFCEEE77A3A +:1022D0004DD0022B40F0B380634A17EE900A13688A +:1022E000E11A814264D2684B2A7853F822205208BE +:1022F000624D2B68E31A9342D1D20BB0BDE8F08F48 +:10230000A21A07EE902A614A92ED007AF8EE677AF7 +:10231000B5EE407AF1EE10FA3FD1DFED5A6A0DF1D9 +:102320001C0AC2ED007AB3EE097AC6EEA75A584AE3 +:102330009FED586A0DF1280BD14607CA8AE80700BD +:10234000F9EC016A75EEE67AF0EEE77AF4EEC67A19 +:10235000F1EE10FA03D5B0EE667AB0EE676ACB45BF +:10236000EED187ED007A30E74B481E2142E7424B21 +:10237000F8EE676AB7EE086A1B68E31A07EE103AD0 +:10238000B8EE477AC7EE265AF4EEC65AF1EE10FAC6 +:10239000FFF67FAF02232B709EE79FED406ADFEDD3 +:1023A000406A27EE067AA7EEA67AF0EE477AB4E7FF +:1023B000F6EE005A97ED007A0344294FB7EEC76A4C +:1023C000254E37EE257A1360DFF898C0DFF88CE0F1 +:1023D000FDEEC77A334926488DED026B17EE902A41 +:1023E0003B6802FB06F6013393FBF6F806FB183355 +:1023F0003B6093FBF2F702FB1733FE1701938CFB54 +:1024000007233B44C6EB63168CFB063CF317B4442E +:10241000C3EB6C138EFB032EDA17C2EBAE0202EB9A +:102420004202A3EBC202C3EB0313A6EB8303C6EB8A +:102430000616A7EB8607009709F072FF53E7124ACA +:1024400052F82320520853E7C42B00208C1A002096 +:10245000F82000200000EC4180510100ABAAAA2A1C +:102460000C2B002089888888342B0020640E0020E3 +:1024700020110020022C00202C2B0020282B0020D3 +:10248000012C002000007A44A8040020642B0020C6 +:102490007003002000247449008D27006666663FA3 +:1024A000CDCCCC3D8C0E0020302B002070B5264DBD +:1024B0000021264A82B0264E2B68166011611181D8 +:1024C000D160002B3CD019465B69002BFBD14A61DF +:1024D0000024204B1D48136054615460947200F036 +:1024E0005FFB1D494FF480702B680A46CC608C61FD +:1024F00042F8186B08810A6123B31A465B69002B06 +:10250000FBD15161154A0024154B0A600A22154D72 +:102510004C614C608C720C771D601A72124809F085 +:10252000DFFB224609490C4B00940F4809F04CFC94 +:102530000E4A0F490C4802B0BDE870400BF0FEBCDB +:102540002A60C5E72960DDE744260020102B002023 +:10255000DC060020E8060020F8200020F406002019 +:10256000B42B002098070020502B0020FC140020E2 +:102570003D9E000010B5044609F016FD204610BD32 +:10258000024A034903480BF0D9BC00BFFC140020E9 +:1025900035050000C4270020002070470020704748 +:1025A000F8B50127027A1E4C0D46BA40C1F3072147 +:1025B0000646204684F8A52084F8307184F82F71EF +:1025C00009F02CF8E9B2204609F028F8002120464D +:1025D00009F0FCF808B10020F8BD3B460222317A30 +:1025E000204609F073F90128F5D994F8A22094F84F +:1025F000A300824210D2531CA118DBB2897E9842FC +:102600004FEA012184F8A23006D923440232987E91 +:1026100084F8A2200843F8BD4FF0FF30F8BD00BF9A +:1026200030110020F8B50127037A144C242903FA4D +:1026300007F30D4608BFC2801646C1F307212046A6 +:1026400084F8A53084F8307184F82F7108F0E6FF23 +:10265000E9B2204608F0E2FFC6F30721204608F061 +:10266000DDFF2046F1B208F0D9FF3946204609F0D7 +:10267000ADF8B0FA80F04009F8BD00BF301100207D +:102680002DE9F0414FF001080F461546302144F284 +:10269000600280F804800446FFF7C4FF064610B9C4 +:1026A0003046BDE8F0816C2226212046FFF7BAFFB4 +:1026B0004FF4F97228212046FFF7B4FF40F622724A +:1026C0002C212046FFF7AEFF44F246423C21204633 +:1026D000FFF7A8FF40F2371224212046FFF7A2FFA0 +:1026E000002F6BD0454B342120469F428CBF424681 +:1026F0000022FFF797FF07EE905A9FED417A3221B3 +:10270000B8EE676A07EE907A2046F8EE676AB5FB86 +:10271000F7F2C6EE267A02F01F0206EE902AF8EED5 +:10272000E66A77EEE67A67EE877AFCEEE77A17EEEE +:10273000903AC3F30A0343EAC222FFF773FF44F25D +:10274000FF5230212046FFF76DFF73220221204601 +:10275000FFF768FF4FF4C87009F068FF41F61D529B +:102760002E212046FFF75EFF072204212046FFF7B7 +:1027700059FFB02206212046FFF754FF10220A21FC +:102780002046FFF74FFF00220E212046FFF74AFFA9 +:1027900043F63C4210212046FFF744FF47F67F7284 +:1027A00022212046FFF73EFF362224212046FFF754 +:1027B00039FF012330466372BDE8F08144F2FF0225 +:1027C00030212046FFF72EFF732202212046FFF71B +:1027D00029FF4FF4C87009F029FF41F61D522E2140 +:1027E0002046FFF71FFF042220461146FFF71AFF7D +:1027F000302206212046FFF715FFBFE740660301A0 +:102800000000004510B50446084811F0B1FD052050 +:1028100009F00CFF06212046FFF7C2FE2046044ABD +:102820000021BDE81040FFF72BBF00BF3011002092 +:102830000040C40A10B50446D1B1012901D00020DE +:1028400010BD40F273122A21FFF7ECFE0028F6D0EB +:10285000882220212046FFF7E5FE0028EFD0E288FD +:102860002046242122F00402BDE81040FFF7DABE22 +:1028700055222021FFF7D6FE0028E0D0E28820462E +:10288000242142F00402BDE81040FFF7CBBE00BF98 +:102890009FED1F7ADFED1F7AE0EE077A38B5054627 +:1028A000FCEEE77A17EE904A14B3802C0CD8C4F1F2 +:1028B00080042B7944EA042453B922462846222175 +:1028C000BDE83840FFF7AEBE2B790024002BF4D0D2 +:1028D000EA8800232421284622F010022B71FFF7FA +:1028E000A1FE224628462221BDE83840FFF79ABEC5 +:1028F000012347F67F7222210371FFF793FEEA88D6 +:102900002846242142F01002BDE83840FFF78ABE75 +:1029100000000143EE7CFF3E30B482B00C4602ABB7 +:1029200003E90600C37C002B30D072B6C37CDA0703 +:1029300008D54FF0E0214569D1F880212A40826214 +:10294000C1F880219D0708D54FF0E0218569D1F8B5 +:1029500084212A40C262C1F88421590708D54FF06A +:10296000E021C569D1F888212A400263C1F8882195 +:102970001A0708D54FF0E021056AD1F88C212A40CA +:102980004263C1F88C21DB062FD462B683689C4277 +:1029900035D0224B84609B69214AC3F30111C3F3F4 +:1029A000826352F821100133B1FBF3F2CCB19442AF +:1029B00027D8B2FBF4F3B2FBF3F294422CD3B3F575 +:1029C000817F20D3174CC460036803220020019943 +:1029D00018615A6201221C6419661A6102B030BC87 +:1029E00070479942EFD3531CE9E74FF0E022416A68 +:1029F000D2F890310B408363C2F89031C5E7C468C8 +:102A0000E2E70024DFE7022BFBD9023B5A0814025D +:102A100044EA02441C43D6E71A46E4E700C00F40EC +:102A200050090020FF7F7F00024A034903480BF052 +:102A300085BA00BFFC1400203505000040270020A7 +:102A4000294A2A4B2A4910B5146810792269C87797 +:102A50009A420BD2274A1278002A41D04FF0E02246 +:102A6000402103F5807EC2F8081202E09E46A3F5DD +:102A700080732149214A0968106881B378B3204CDA +:102A80002288402A2BD802F1020C403201EB4C0183 +:102A9000228000EB4C001A46BFF34F8F03F1200455 +:102AA00003F5807CA44534BF4FF0010C4FF0080CB7 +:102AB0004FF0E02403EB4C1CC4F85C2F203262453D +:102AC000FAD1BFF34F8FBFF36F8F33F9042B21F887 +:102AD000022B9E4533F9022C20F8022BF5D810BDAD +:102AE00003F5807EC5E700BFC8260020400D2020EA +:102AF00000800E40FA2B0020C0260020C4260020B3 +:102B0000EA2B0020F8B5064609F03CF8C0B10446AF +:102B100009F038F8054680B172B61E4B1A887F2A34 +:102B200017D81D490A6872B362B6204609F080F8CA +:102B30002846BDE8F84009F07BB8204609F078F84F +:102B400072B6144B1A887F2A01D862B6F8BD0025E8 +:102B50002C4611480022114907681A8004600C684D +:102B60000D6062B63946304609F08AF8384609F0F9 +:102B70005FF830462146012209F082F82046BDE880 +:102B8000F84009F055B80C6004491A80086062B634 +:102B9000F8BD00BFEA2B0020C0260020C42600207C +:102BA00038B5234C01210625204609F0A3F9002061 +:102BB00000F0D4F802221F4903201F4BC1F87C010A +:102BC000C3F894211D4923681D4859609A609A8270 +:102BD0004FF480721B49186000201961DA82217954 +:102BE000DA839D83A5F20625174AD8609D6142F8D5 +:102BF00021001648164B42F82100164AC3F88820D7 +:102C000009F056F92379144C0121144A207003F17C +:102C10001000134C02EB5312E37603F01F039200F3 +:102C2000104C9940104B43F82040116038BD00BF54 +:102C3000C826002000801F4000841F4000000101C2 +:102C4000A2403840400C202000C00E4013000080FD +:102C50000040384001000092FA2B00204038003834 +:102C600000800E40010A0000001C0020024A0349B7 +:102C700003480BF063B900BFFC14002035050000C9 +:102C8000C8260020024A034903480BF057B900BF89 +:102C9000FC14002035050000E0260020024A03490C +:102CA00003480BF04BB900BFFC14002035050000B1 +:102CB00048270020024A034903480BF03FB900BFF0 +:102CC000FC1400203505000050270020024A03496B +:102CD00003480BF033B900BFFC1400203505000099 +:102CE00068270020024A034903480BF027B900BFB8 +:102CF000FC14002035050000D0260020024A0349BC +:102D000003480BF01BB900BFFC1400203505000080 +:102D1000E8260020024A034903480BF00FB900BF20 +:102D2000FC1400203505000058270020024A034902 +:102D300003480BF003B900BFFC1400203505000068 +:102D4000D8260020024A034903480BF0F7B800BF19 +:102D5000FC14002035050000F0260020F8B52D4CAD +:102D600005462D4AE36F43F44023E3679368002B45 +:102D700046DBD2F88830002B42DB002342F210728F +:102D80004FF40C611C2011F0E7FAE369234A23F4A5 +:102D90004063234943F40063E361A36A1A40214B73 +:102DA00042F0CE02A2624A68134043F400234B6013 +:102DB0002DB91D4B0322C3F82021C3F824211A4E3C +:102DC0000327154B0124C6F8287100254FF48030E5 +:102DD0001649174A174E1D66DC601E6158619961DD +:102DE000DA61C3F8E050C3F88C4004F1E064C3F842 +:102DF0009040C3F89400C3F89810C3F89C20F8BD25 +:102E0000002DFCD1084B0322C3F82021C3F8242154 +:102E1000F8BD00BF00C00F400040384000FEFFFF7B +:102E200000C00A40F8FFF7FF00801F401B1F010091 +:102E3000001F1F1F01000047024A034903480BF00F +:102E40007DB800BFFC14002035050000F8260020E6 +:102E5000024A034903480BF071B800BFFC1400207C +:102E60003505000030270020024A034903480BF0D3 +:102E700065B800BFFC140020350500007027002055 +:102E8000024A034903480BF059B800BFFC14002064 +:102E90003505000078270020024A034903480BF05B +:102EA0004DB800BFFC140020350500009827002015 +:102EB000024A034903480BF041B800BFFC1400204C +:102EC0003505000000270020024A034903480BF0A3 +:102ED00035B800BFFC140020350500008027002015 +:102EE000024A034903480BF029B800BFFC14002034 +:102EF00035050000A027002010B5054C04F108009E +:102F000009F052F82046BDE8104009F04DB800BF66 +:102F10000827002010B5084C0021204608F0EAFFE1 +:102F200004F10800002108F0E5FF044A04490020EC +:102F3000BDE810400BF002B808270020FC14002068 +:102F4000B90E0000024A034903480AF0F7BF00BF68 +:102F5000FC1400203505000060270020024A0349C8 +:102F600003480AF0EBBF00BFFC1400203505000049 +:102F700088270020024A034903480AF0DFBF00BF48 +:102F8000FC1400203505000090270020024A034968 +:102F900003480AF0D3BF00BFFC1400203505000031 +:102FA00018270020024A034903480AF0C7BF00BFA0 +:102FB000FC14002035050000382700200020704751 +:102FC000704700BF036D0BB101207047406D0038A2 +:102FD00018BF0120704700BF10B50446806D18B1BE +:102FE0000AF0BAFF0023A365236D2BB104F118008A +:102FF000BDE8104005F0B4BD636D002BF6D110BDE7 +:1030000010B50446806D00B110BD4FF480700AF019 +:103010009BFFA065B0B10022236D02703BB1014659 +:103020004FF48072184605F0EBF9A06D10BD636D8A +:10303000002BE9D001464FF48072184602F08EFE54 +:10304000A06D10BD014B1846A36510BDFF2B0020DD +:1030500038B5056D6DB10BB1002038BD114628465D +:1030600003F00AFF0028F7D02846BDE8384004F0F6 +:10307000A5B8446D002CEFD0204601F0C1FA00281D +:10308000EAD02046BDE8384002F034B98A79A2F18E +:1030900050031B0622D402F26C72F0B54B7985B056 +:1030A000046D01330D798E784F78DBB209784CB11D +:1030B000204601960095CDE90271042104F012F832 +:1030C00005B0F0BD406D0028FAD001960095CDE91D +:1030D0000271042102F052F805B0F0BD00207047E3 +:1030E00010B50446006D80B1037813F0700F00D165 +:1030F00010BD002103F0C0FE606D0028F8D0002252 +:103100000023BDE8104001F07BBA606D0028EFD0CD +:1031100090F8313013F0500FEAD000220023BDE8C0 +:10312000104001F06DBA00BF036D10B50C4682B0BF +:103130002BB30DF1060201A9184603F043FA38B388 +:10314000BDF80430BDF8062053EA020120D0C2F3D6 +:10315000451C02F01F00D20AC3F34311400084F85B +:1031600001C0A2705A0A013903F01F0302F5EA6296 +:103170002070012061712371A27102B010BD406DF9 +:1031800030B10DF1060201A901F0E0F80028D7D115 +:10319000002002B010BD00BF036D10B50C4682B018 +:1031A0002BB30DF1060201A9184603F0FBF938B361 +:1031B000BDF80430BDF8062053EA020120D0C2F366 +:1031C000451C02F01F00D20AC3F34311400084F8EB +:1031D00001C0A2705A0A013903F01F0302F5EA6226 +:1031E0002070012061712371A27102B010BD406D89 +:1031F00030B10DF1060201A901F096F80028D7D1EF +:10320000002002B010BD00BF0369D3B10E4810B456 +:103210001C68E46884420FD1186D18B15DF8044B46 +:1032200004F006B8586D18B15DF8044B02F0D4B83C +:1032300000205DF8044B7047184623465DF8044BA8 +:1032400018470020704700BFD1140000006990B1FA +:103250000368154A1B69934225D1036D63B1187841 +:1032600010F0080007D0D8695B69C01A48BF6FF03A +:103270000040704718467047436D002BFAD093F812 +:10328000310010F00800F6D0186919685A69401A20 +:103290005B6862EB0303B0F1004F73F10003EAD304 +:1032A0006FF0004070471847CD150000036963B107 +:1032B0001A68074992698A4208D1186D08B103F06B +:1032C0000BBF586D08B101F0E3BD704718461047B9 +:1032D00051140000036973B11A68084952698A429F +:1032E00007D1186D08B103F053BC586D18B101F047 +:1032F00071B9184610474FF0FF307047A91300000E +:10330000036D13B1586900217047436D13B1D3E9C0 +:103310000001704718461946704700BF036D13B18E +:10332000D86900217047436D13B1D3E90401704798 +:1033300018461946704700BFF0B595B000224FF40B +:103340007A74244F1831054604A88DF80C20009794 +:10335000CDE90124CDE9122205F06EFC129B002B71 +:103360002DD05C20002609F0F5FA019B044646604A +:10337000C36004A9029B183040F8083C9DF80C304B +:1033800000F8043C144B40F8183C144B40F8103C37 +:1033900005F0A4FB124B4FF47A72A7602B606368B0 +:1033A000A66501336E602E73AA602C6163600D4BBD +:1033B00004A8009305F0D4FB284615B0F0BD139B7C +:1033C000002BCED1064A2B732A602B61C5E901344C +:1033D000EDE700BFE007002004080020600800209F +:1033E000B4070020B8060020036D13B1184603F09F +:1033F000CFBB406D08B101F0EDB84FF0FF30704722 +:10340000836C13B1184603F0C3BBC06C08B101F064 +:10341000E1B84FF0FF307047036D33B11B7813F004 +:10342000700F14BF012000207047406D30B190F83C +:10343000313013F0500F14BF01200020704700BF3F +:10344000036D13B1184603F0CFBA406D08B100F018 +:10345000F1BF4FF0FF307047836C00B583B063B1AC +:1034600001220DF10701184603F0BEFA01280CD124 +:103470009DF8070003B05DF804FBC06C28B1012281 +:103480000DF1070100F0D6FFF0E74FF0FF30F1E754 +:10349000036D13B1184603F01FBE406D08B101F073 +:1034A000F7BC7047836C13B1184603F015BEC06CAF +:1034B00008B101F0EDBC7047036923B31968134AE2 +:1034C00010B58C6882B0944214D1186D48B10122B5 +:1034D0000DF1070103F088FA90B19DF8070002B0E2 +:1034E00010BD586D0028F8D001220DF1070100F041 +:1034F000A1FFF1E701220DF107011846A047EBE714 +:103500004FF0FF30EBE74FF0FF3070470114000041 +:10351000036D13B1184603F08BBE406D08B101F086 +:103520005BBF7047836C13B1184603F081BEC06C5B +:1035300008B101F051BF704700B5836C83B08DF8BE +:10354000071043B101220DF10701184603F070FE88 +:1035500003B05DF804FBC06C0028F9D001220DF126 +:10356000070101F039FF03B05DF804FB8A79A2F18D +:1035700050031B0622D402F26C72F0B54B7985B071 +:10358000046D01330D798E784F78DBB209784CB138 +:10359000204601960095CDE90271022103F0A2FDBB +:1035A00005B0F0BD406D0028FAD001960095CDE938 +:1035B0000271022101F0E2FD05B0F0BD002070476C +:1035C000836C53B1187810F008000DD0D8695B698E +:1035D000C01A48BF6FF000407047C36CA3B193F8A6 +:1035E000310010F0080000D17047186919685A6955 +:1035F000401A5B6862EB0303B0F1004F73F1000304 +:10360000F2D36FF0004070471846EDE7036D53B1F9 +:10361000187810F008000DD0D8695B69C01A48BF4F +:103620006FF000407047436DA3B193F8310010F084 +:10363000080000D17047186919685A69401A5B6818 +:1036400062EB0303B0F1004F73F10003F2D36FF0AC +:10365000004070471846EDE700B5006983B08DF86B +:10366000071060B10368104ADB68934215D1036DFF +:1036700043B101220DF10701184603F0D9FD03B053 +:103680005DF804FB406D0028F9D001220DF107011F +:1036900001F0A2FE03B05DF804FB01220DF1070169 +:1036A000984703B05DF804FBD114000038B5044618 +:1036B0000C4B806D236018B10AF04EFC0023A3650B +:1036C000236D04F118054BB1284605F049FA064B65 +:1036D0002846A36005F044FA204638BD636D002BF0 +:1036E000F2D1F4E704080020B806002038B50446FB +:1036F0000E4B806D236018B10AF02EFC0023A365E9 +:10370000236D04F118056BB1284605F029FA084B22 +:103710002846A36005F024FA20465C2109F01CF934 +:10372000204638BD636D002BEED1F0E70408002081 +:10373000B806002030B4029C11469C4634B1012CDE +:103740001CD0022C0ED0002030BC7047056DF5B1A6 +:103750004FF0FF33934274EB0C04F4D3284630BC93 +:1037600003F08ABB026D0AB3D36959184CF1000308 +:10377000002BE8D1104630BC03F07EBB026D62B175 +:10378000536959184CF10003002BDCD1F2E7406D6E +:103790000028D8D030BC00F033BF406D0028D2D014 +:1037A000D0E900238A184CEB0303F3E7406D0028AF +:1037B000C9D0D0E9042330BC8A184CEB030300F0D5 +:1037C0001FBF00BF70B5244B044605690360002D80 +:1037D00032D06E68013E6E6076BB2B681F4ADB6A92 +:1037E00093422FD1A86D10B10AF0B6FBAE652B6DD8 +:1037F00023B305F1180005F0B3F92569E5B12B688D +:10380000174A5B68934224D1164BA86D2B6018B100 +:103810000AF0A2FB0023AB652B6D05F11806A3B1DE +:10382000304605F09DF9104B3046AB6005F098F935 +:103830005C21284609F090F8204670BD6B6D002B86 +:10384000D7D1DAE728469847D7E76B6D002BE7D149 +:10385000E9E728469847EFE7B4070020990F0000F2 +:10386000AD16000004080020B806002070B5264BF5 +:10387000044605690360002D32D06E68013E6E601B +:1038800076BB2B68214ADB6A934233D1A86D10B115 +:103890000AF062FBAE652B6D43B305F1180005F02D +:1038A0005FF92569E5B12B68194A5B68934228D115 +:1038B000184BA86D2B6018B10AF04EFB0023AB65C6 +:1038C0002B6D05F11806C3B1304605F049F9124BCE +:1038D0003046AB6005F044F95C21284609F03CF81D +:1038E0002046142109F038F8204670BD6B6D002B7E +:1038F000D3D1D6E728469847D3E76B6D002BE3D1A9 +:10390000E5E728469847EBE7B4070020990F000049 +:10391000AD16000004080020B806002090F81CC076 +:103920004160BCF1020FC26001D18368184708F002 +:1039300055BB00BFF0B4046840F201251E46256166 +:10394000A3B121B311F8015B013B6566256FAF0799 +:1039500007D41546013E676F1AB105F8017B2A4668 +:1039600004686569ED07F1D5002BEAD16EB10368F3 +:10397000196F8907FAD41146013E5B6F002AF5D012 +:1039800001F8013B0A46002EF1D1F0BC704790F8D7 +:103990003C50D9E7324B334930B5D3E91154207943 +:1039A000C8771A6C95F804C081F81CC0087752B12A +:1039B000B2F5004F23D32C4911442A4A1964D0761A +:1039C00082F81BC030BD19680F24D86C8C6540F29A +:1039D0000134CA610C614FF47C544C6103210468CA +:1039E000246883F83D10214B9C4226D1037F42601E +:1039F000022BC26026D18368BDE8304018472D688D +:103A0000E98B090422D492B2EA832168EC8BA4B238 +:103A1000EC82CC8B240405D5CC8BC2F3080204F4D1 +:103A20007E442243CA83CA8B92B2CA8200210D4AC5 +:103A30001964D07682F81BC030BD23461146BDE81C +:103A400030401847BDE8304008F0C8BAE98BC2F3EF +:103A5000080E92B201F47E4141EA0E01E983D4E7F7 +:103A6000D010002000800E400180FFFFDD18000014 +:103A700043682DE9F04FD3E90041814D4FF0B80A7A +:103A800022684FF0020822EA01027E492260AA69F8 +:103A900011407D4A0A43AA6190F810E07B4A03EB8B +:103AA0000E0603EB8E0E317C02EB01118968C1F822 +:103AB00000A090F811C003EB0C0503EB8C0C95F8FB +:103AC000201002EB01118968C1F800A0817C03EB92 +:103AD000010903EB810199F830B002EB0B1BDBF815 +:103AE00008B0CBF800A0D4F800A05F684AEA070A43 +:103AF000C4F800A0347CDEF814E002EB041464681F +:103B0000C4F800E095F82040DCF824C002EB04146F +:103B10006468C4F800C0496B99F8304002EB0412A5 +:103B200052681160DA6B99F838101160DA69317EE9 +:103B3000DB6A116095F828201A600F220368C3F829 +:103B400010809A65C27C002A31D072B6C37CDC0733 +:103B500008D54FF0E0214469D1F8802122408262EB +:103B6000C1F88021990708D54FF0E0218469D1F888 +:103B700084212240C262C1F884215A0708D54FF03F +:103B8000E021C469D1F8882122400263C1F888216C +:103B90001F0708D54FF0E021046AD1F88C2122409C +:103BA0004263C1F88C21DE0655D462B60368384CF6 +:103BB0008268A24259D0324A846092693549C2F380 +:103BC0000116C2F38262344D51F826100132B1FB66 +:103BD000F2F2AA4231D80022C260002403211C6103 +:103BE0000724596201211A641C661961C37C13B34E +:103BF000DD0704D5816A4FF0E022C2F800119C076E +:103C000004D5C16A4FF0E022C2F80411590704D567 +:103C1000016B4FF0E022C2F808111A0704D5416B7E +:103C20004FF0E022C2F80C11DB0604D5826B4FF096 +:103C3000E023C3F81021BDE8F08F1849A1FB025121 +:103C4000090DB2FBF1F2A24288BF0131B1F5817FCB +:103C50000DD3134AC0E74FF0E022416AD2F8903109 +:103C60000B408363C2F890319FE7C268B5E7022931 +:103C7000B1D902394C08220242EA04420A43ABE7B6 +:103C800000C00F40CFFFFFE310000008E40B00204E +:103C900000093D0050090020FF083D0083DE1B4362 +:103CA000FF7F7F000BB1FFF745BE70474368D3E944 +:103CB00000120968114200D1704710B5026804462D +:103CC000002005211061227C1344187C08F068FD57 +:103CD000627C63680521134493F8200008F060FDBE +:103CE0006368A27C05211344BDE8104093F83000BE +:103CF00008F056BD704700BF012BF0B5054695B0E2 +:103D00003DD0022B40F2022001F104010CBF03461A +:103D10000023684605F03EF8129B002B38D05C204B +:103D2000002608F017FE214B04AF0446C0E9003618 +:103D3000019B3946183040F80C3C1D4B40F8103CB4 +:103D4000029B40F8083C9DF80C3000F8043C04F05D +:103D5000C5FE184B4FF47A72A665A360164B6E60D1 +:103D60002B6063682E730133AA602C616360134B70 +:103D70003846009304F0F4FE284615B0F0BD44F236 +:103D800002230431684605F005F8129B002BC6D1CA +:103D9000139B002BC3D14FF47A71074A04AF2B73E6 +:103DA0002A602B61C5E90131E1E700BF040800206A +:103DB00060080020E0070020B4070020B8060020BB +:103DC00010B5D0F884448EB00A4644B10023214691 +:103DD0006846009302F0B4FD80B90EB010BDD0F873 +:103DE000881441B1234668460C9400F0C7FE50B9D0 +:103DF00000200EB010BD08460EB010BD684602F09F +:103E0000F3FF0EB010BD684600F076FF0028EFD03B +:103E1000E3E700BF70B5D0F884548EB016465DB1AC +:103E200005F5896500230A4668462946009302F095 +:103E300005FD90B90EB070BDD0F888040028F9D007 +:103E400000F589640A462B46684621460C9500F029 +:103E500019FE48B900200EB070BD324629466846AA +:103E600002F0CCFE0EB070BD32462146684601F02D +:103E700097F80028EED0DDE710B5D0F884448EB076 +:103E80000A464CB10020012321460090684602F00A +:103E900057FD80B90EB010BDD0F8881441B1012390 +:103EA00068460C9400F06AFE50B900200EB010BDB8 +:103EB00008460EB010BD684603F048FE0EB010BDB7 +:103EC000684600F0BFFE0028EFD0E3E730B5D0F839 +:103ED00084448FB00A464CB10025012304F5896162 +:103EE0006846009502F034FC0FB030BDD0F888046D +:103EF0000028F9D000F58961012368460C9401F08F +:103F0000D1F80FB030BD00BF10B5D0F884448EB0EA +:103F10000A463CB1002321466846009302F010FD9A +:103F20000EB010BDD0F8881431B1234668460C9409 +:103F300000F024FE0EB010BD08460EB010BD00BF4C +:103F4000F8B5054690F8D00408B90146F8BDD5F893 +:103F50008434002B4CD0DC69D5F89004013C002857 +:103F600054D00368DB6B9847E0B1D5F8900478B380 +:103F700003681B6C9847A8B9D5F8900440B3036850 +:103F800001215B6C9847074610B3D5F8840458BBF1 +:103F9000D5F8886433466EB9D5F8900490B90020FE +:103FA0000146D3E7D5F88404E8B9D5F88834002B66 +:103FB000F5D00746184602F049F906463FB1D5F854 +:103FC000900428B1036800215B6C984700B1A41BE2 +:103FD000D5F88434FBB19B794FF40071994089B2D4 +:103FE000A1FB0401F8BD002704F002FC0646E5E74A +:103FF000D5F88834D5F89004B3B1D3F8304400280C +:10400000AFD1184602F022F90646E0E7184604F060 +:10401000EFFB0646DBE7D5F88864002EBFD0D6F864 +:104020003C14A1FB0401F8BD0028B8D01C4698E759 +:1040300090F8D03463B1D0F8843463B19A794FF4F6 +:104040000070D9699040013980B2A0FB010170472E +:10405000184601467047D0F888040028F9D0D0F8F7 +:104060003C14D0F83004A1FB000170472DE9F04367 +:10407000D0F890548DB04DB198462B680446284630 +:10408000DB699847B0F5405F064604D80026304605 +:104090000DB0BDE8F0834FF4007009F055FF0746FE +:1040A0000028F3D00DF10409B6F1806F02464346B3 +:1040B000294648462ED901F095FB0646384609F0B8 +:1040C0004BFF002EE2D02B682846271D1B6A98471D +:1040D00094F8C034FF2B21D0D4F8C43404F594658F +:1040E00002932846D4F8C8340393B4F8C034ADF82A +:1040F000043099E80E0005F013FD94F8B134C4F8CB +:104100009054002BC3D10123294638461A4604F0A7 +:10411000CFFDBCE704F032F80646CFE704F2944541 +:1041200094F8CC14284606F043FB2846C4F8905473 +:1041300005F0A0FD0028AAD10123D4F89014384638 +:104140001A4604F0B5FDA2E7F0B5D0F8906485B04A +:104150000446002E42D090F8D05490F8D13485B166 +:10416000FE2B63D094F8D20427283DD933686946E2 +:1041700030469B6C98470546284684F8D05405B0D5 +:10418000F0BDFE2B26D090F8D204272849D994F808 +:10419000C034271DFF2B2DD0D4F8C43404F5946609 +:1041A000D4F8C82401933046B4F8C0340292ADF874 +:1041B00000306B460ECB05F0B3FC94F8B134C4F874 +:1041C000906463B90123314638461A4604F070FD05 +:1041D000054604E01F4B9B689B03D8D40025284666 +:1041E00084F8D05405B0F0BD08F0C8FA051E18BF19 +:1041F0000125F4E704F2944694F8CC14304606F016 +:10420000D7FA3046C4F8906405F034FD0028E6D1B2 +:104210000123D4F8901438461A4604F049FD0546A7 +:10422000DDE708F0ABFA0028B1D1D7E733683046B4 +:104230005B6D9847421C034694D00028CFD194F878 +:10424000D124FE2ACAD1032126201D4608F0A8FA4F +:10425000C5E700BF0080004218484FF0290C184AFB +:104260000023184910B4C0F89424072280F8B1C480 +:104270004FF0FF0CC0F8A8144FF47F41124CC0F867 +:10428000AC24124AA0F8D014A0F89C3480F8B534BD +:1042900080F8CC3480F8D2C40460C0F8A0240C4963 +:1042A0000C4A5DF8044BC0F88434C0F88834C0F878 +:1042B000903480F8BC3409F041BE00BF30210020AA +:1042C000D808002000093D008408002000070020D5 +:1042D000B51C0000FC14002070B500F1240384B06C +:1042E0008C46044601AD164693E8070085E80700B2 +:1042F0004FEA4C122946206A01F0C4FE012806D17B +:1043000032462946206A01F0A1FE04B070BD0020AB +:1043100004B070BD10B5044600F0BAFD002384F867 +:10432000313084F8333010BD38B514460D460022C4 +:1043300000F12401006A01F089FE034620B14289A0 +:1043400001202A801B89238038BD00BF38B5144660 +:104350000D46002200F12401006A01F077FE0346B9 +:1043600020B1C28901202A809B89238038BD00BFEB +:1043700038B50D4690F8311009B1002038BD38220B +:1043800004460AF0DBFC012340222562184684F82B +:10439000333084F8312038BDF0B40D460978202937 +:1043A00003D115F8014F202CFBD0156095602C78B7 +:1043B0002F2C11D084B16E1C3C2C1D4F35462AD8B1 +:1043C000212C12D804F1FF3CBCF11E0F16D800209E +:1043D000F0BC704715F8014F202CFBD02F2CF9D0E2 +:1043E0001D601146F0BC01F01FBDA4F1220C5FFA64 +:1043F0008CFC27FA0CFC1CF0010FE8D12E2C01D00C +:10440000202C0DD116F8014B002CE5D02F2CE3D039 +:104410003C2C3546D4D95C2CD9D003D97C2CD6D0B1 +:104420009660EFE73E3C012CFAD80020F0BC7047C4 +:10443000012100052DE9F04F90F8333083B0054697 +:10444000DC0774D558060F46904640F1B080D5E998 +:104450000023D5E9041018EB020443F10003A14244 +:1044600070EB0303C0F0A980B8F1000F5BD04646A3 +:1044700005F11809D5E90032D5F820A0DAF838445A +:104480001C40C4F3080B002C70D1134370D195F875 +:1044900031305A064CBFDAF83424EA69AA619AF836 +:1044A0004504023ADAF82C14630A824001EB5421E5 +:1044B0001144BBF1000F45D1B6F5007F42D3DAF8C5 +:1044C0001C2291423ED0B6F5806F58D34FF0010BBD +:1044D0000BFA00FBABEB030B730A9B4528BF9B4613 +:1044E00091424FEA4B240AD801EB0B039A4206D2C1 +:1044F0000AF50470019106F0B5FD0199B8B1DAF83A +:1045000014025B460268D2F814A03A46D04770B154 +:1045100023462744D5E900125B1842F10002361BFE +:10452000C5E90032A8D1404603B0BDE8F08F95F848 +:1045300032304FF0FF3043F0020385F8323003B0E1 +:10454000BDE8F08FCBF5007400220AF50470B44288 +:1045500028BF344606F0B2FD0028E8D000EB0B017E +:104560002246384608F05CF92346D2E7AA6996E766 +:1045700095F833305B060ED5AA6901328EE7DAF87A +:1045800014023A4603681B6998470028CFD04FF4BD +:1045900000731C46BDE74A465046A96901F0B4FDC8 +:1045A0000028C4DB0CD0D5F820A0AA6977E795F8DD +:1045B000313019077FF558AF49E7A1EB020853E7FF +:1045C00095F8313013F0500FB1D0A8EB06084046F3 +:1045D000AAE700BFF0B583B00122044685690DF15A +:1045E0000701D0E90067FFF725FF0128A5610CBF8F +:1045F0009DF807004FF0FF30C4E9006703B0F0BD3D +:104600002DE9F04F1F4690F8313083B00446D0F8C2 +:104610001880002B51D01646D0E9001CBC4508BFBD +:1046200091425CD056EA07024DD01D0704D5D0E96F +:104630000402B042BA4140D394F83320751ED4F836 +:1046400020A0019247F1FF309AF845240932D2B2F6 +:10465000C2F1200ED540A2F1200900FA0EFB20FA8B +:1046600009F045EA0B0505430198400633D4481E7E +:1046700020FA02F24CF1FF3051EA0C0C00FA0EFE67 +:1046800020FA09F042EA0E0242EA000201D0954205 +:1046900029D25B064CBFDAF83434E369A36104F134 +:1046A000180906E0A169013D206A01F02DFD0028EE +:1046B00003DD4A46002DF5D107E00020C4F818803C +:1046C00003B0BDE8F08F002383610120C4E90067D7 +:1046D00003B0BDE8F08FE3692B44A361F5E7012047 +:1046E00003B0BDE8F08FAD1AD9E700BF2DE9F04F58 +:1046F000174690F831208FB00546002A40F0D78049 +:104700008B4691F8311011F0500F00F0D08003F07B +:1047100003019A46032900F0CA80013103F0080022 +:1047200041EA00030293002F00F0CB80396901F1C8 +:104730000E08B649A1FB0818DBE900104FEAD808BB +:10474000014308F102085FFA88F805D00020002133 +:10475000CBF81820CBE900010024029B264643F049 +:1047600040030393202206A95846FFF763FE00B3D7 +:10477000202840F09C809DF918209DF81830002AD0 +:10478000C0F2A28034B9DBF80020A2F12009DBF8E6 +:1047900018200192444501D20134E4B2002B00F00C +:1047A0001381202206A958460026FFF743FE002861 +:1047B000DED11AF4007F7AD0029B9B0777D5002FB9 +:1047C00075D0444517D2DDF804A0202206A958462A +:1047D000FFF730FE631C002861D0202867D12CB978 +:1047E000DBF80020DBF818A0A2F12009DCB2A0451C +:1047F000EBD8CDF804A03822002128469BF833409E +:104800000AF09CFADBF82030C4F38014019A2B6282 +:104810000823002685F82C4085F831303B68C5E92F +:1048200009297B60BE81B8F1000F33D008F1FF3950 +:10483000B346DFF8DCA15FFA89F901225946284620 +:10484000FFF74AFD044690B390F90020002A2EDBC2 +:10485000202200210AF072FA002E00F0BC80BBF189 +:10486000010F00F0D780C123A3461E3404F81E3C7C +:10487000BB8938461BB9D7E901239A4205D006F017 +:1048800045FC2BF8020FA345F2D101365FFA86FBF7 +:10489000D845D2D8284600F0FBFA06460DE0584627 +:1048A000DBF8186000F024FB002840F09180002322 +:1048B0001E4685F8313085F8333030460FB0BDE8FC +:1048C000F08F4FF0030847E756BB444538BF00243C +:1048D000852B7FF447AF31463822284601260AF05F +:1048E0002DFA9DF81C209DF8193085F8303002F023 +:1048F0003703D20658BF43F0080385F83130DBF8A0 +:104900000030DBF82020203B2A62DBF81820C5E9C4 +:1049100009239BF83330C3F3801385F82C3021E74B +:10492000C02B28D0C12B7FF43CAF3A4606A92846BD +:1049300001F0EEF9E8B1BB89DBB9D7E901329A425F +:1049400017D11AF4006FB2D11AF4884F70D195F8CC +:10495000333098076CD41AF4806FA8D11AF4804FC2 +:10496000ABD02846D5E90423FFF74AFE0028A4D19E +:104970009DE70646F6E6029B85F833309DF8193030 +:104980009B0702D5039B85F833300B9BEB61DDE978 +:104990000823C5E90423DDE90C23C5E90223002F20 +:1049A000CFD04FF000033A69BB813B687B609DF834 +:1049B0001B309A427FF4F5AEBE8ABDF81C30F61A61 +:1049C000B6FA86F67609CDE6002F7FF4F2AE6EE7F2 +:1049D000CBF818600BE78523237085F8309084F8B6 +:1049E0000190DAF80030002B46D00DF113020DF1E2 +:1049F000160105A89847BDF814306381BDF816303C +:104A000023819DF8133023753FE700BF898888888C +:104A10003C260020C02384F801B02370029B63F081 +:104A20007F0385F833303B69E370BB8AA3802CE7B2 +:104A300095F83130D9063FF53AAF13F001017FF414 +:104A400036AF1AF4806F89D095F8332092077FF53E +:104A50002EAF002B3FF42BAFD5E90032134304D027 +:104A600000220023A961C5E90023284600F042FC8A +:104A700000283FF41CAF20E745F621236381E38142 +:104A8000638202E72DE9F043002597B0994690F83C +:104A9000313001921495ADF81450002B3ED191F8AD +:104AA00031300F4613F0500F38D0137804461646B5 +:104AB0002F2B37D04FF0000801AB02AA3146204619 +:104AC000FFF76AFC50B3019E3378002B3ED00023E1 +:104AD00002AA39462046FFF709FEF8B1A44608AD00 +:104AE00004F13007DCF800000CF1100C5CF80C1C31 +:104AF000AE465CF8082C10355CF8043CBC45AEE8CA +:104B00000F00EFD1DCF8000008AF2860204600F06D +:104B1000BFF984F8318084F83380CDE7002017B0E6 +:104B2000BDE8F08316F8011F2F29FBD00196B1B91B +:104B3000382220463D6A0AF001F90123402225620D +:104B4000184684F8333084F83120E8E74B4602AA4F +:104B500039462046FFF7CAFD17B0BDE8F08338227A +:104B6000002108A83D6A0AF0E9F8012308AF109572 +:104B70008DF8533040238DF851309BE719B101F582 +:104B80008961FFF77FBF0846704700BF90F831305A +:104B900063B991F8313013F0500F07D00B6813F060 +:104BA0001F0C03D113466246FFF7A0BD00207047DB +:104BB0008169F8B50446006A01B10131012201F0B2 +:104BC00069F90128054632D901230146206A1A46AF +:104BD00001F0C0F9064650B3A3695BB394F83320E3 +:104BE000510612D5591CA94218D022F04002E169A1 +:104BF00084F8332005E0206A01F0A8FA3946B0B104 +:104C0000A3694F1C99423A46F5D34FF0FF3229462B +:104C1000206A01F09BFA50B1A16911B93046A56133 +:104C2000F8BD2A46206A01F091FA0028F6D1002644 +:104C30003046F8BD94F8333043F0400384F8333005 +:104C4000ECE700BF90F833309A0736D5C16970B5EC +:104C50000546A1B90024214607E0037803F07F034D +:104C6000037095F830308B4229D301340122284655 +:104C7000FFF732FBE1B20028EFD1002070BD5B06E8 +:104C8000006A34D590F84534D5E902240933013A55 +:104C9000DBB244F1FF34C3F1200CDA40203B04FACC +:104CA0000CFC24FA03F342EA0C021A4300230132FB +:104CB00001F050F90028CDD1DFE700207047002334 +:104CC0002C6A85F83130204685F8333006F0CAF971 +:104CD0000028D2D004F5047006F0C4F90028CCD026 +:104CE000D4F840040368BDE870401B6A184701F01F +:104CF0004DFA0028AED1C0E790F83130DB0601D480 +:104D00000020704710B5002288B000230446FFF74A +:104D100077FC08E020281BD19DF900309DF8002089 +:104D2000002B15DB32B1202269462046FFF782FBBB +:104D30000028EFD194F833300822204643F00203D4 +:104D400084F8312084F83330FFF77CFF08B010BDC1 +:104D5000002008B010BD00BF2DE9F0414FF0000861 +:104D600082B04A4F06464446414600223046FFF78D +:104D7000B3FA054630B10178C02969D0C1292BD0DA +:104D8000852909D096F83230002043F0010386F8D7 +:104D9000323002B0BDE8F08196F8313003F03703CD +:104DA00083803B6883B10DF103020DF1060101A878 +:104DB0009847BDF80630AB812B82BDF80430EB81FB +:104DC0006B829DF803306B75326A92F8103243F0B3 +:104DD000010382F810322978A1F185000022B0FA8F +:104DE00080F0400901E00422A95CE303012A02F1FA +:104DF000010243EA540311FA83F39CB201D1002863 +:104E0000F1D11F2AF0D908F1010896F830305FFA85 +:104E100088F18B42A9D2012206F12401306A01F007 +:104E200015F90028AED0356A4480284606F01AF9F4 +:104E30000028A7D005F5047006F014F90028A1D0C9 +:104E4000D5F8400403681B6A98470028A1D199E768 +:104E500096F8333013F0400F437814BF43F0020349 +:104E600003F0FD034370D6E90401D6E90732C5E932 +:104E70000201D6E902016B61C5E9060192F8103220 +:104E800043F0010382F810322978A5E73C26002080 +:104E900038B590F8313043B390F93320044690F898 +:104EA0003330002A0CDB056A284606F0DBF878B9B7 +:104EB00094F83230002043F0010384F8323038BDDA +:104EC00003F07F0380F83330BDE83840FFF744BF7C +:104ED00005F5047006F0C6F80028E9D0D5F84004BE +:104EE00003681B6A98470028E2D0012038BD00BF44 +:104EF00070B590F8313005465A064CD480682B6A5C +:104F0000D3F83C341844B0F1806F01D3002070BD59 +:104F10002846FFF74DFE0028F8D0286A0024AE6925 +:104F200090F84534023E9E40D0F82C341E4431198E +:104F3000052200F50470013406F0C0F84FF4007249 +:104F400000210028E2D009F0F9FE286A012390F838 +:104F5000452493409C42EAD395F831305B0615D442 +:104F600095F8332062F07F02D5E9023185F83320CD +:104F7000D0F83C249B1841F10000AB60D5E9043126 +:104F8000E8609B1841F10001C5E904312846BDE8FD +:104F90007040FFF77DBF006A01F0FEF9AFE700BF88 +:104FA00070B5044690F831009CB0002310F0180F43 +:104FB0000C931A9303D0206A0B6A984202D0002007 +:104FC0001CB070BD40F601236846FFF75BFD00286A +:104FD000F5D0A44604F130060EADDCF800000CF16B +:104FE000100C5CF80C1CAE465CF8082C10355CF814 +:104FF000043CB445AEE80F00EFD1DCF8000009AA8C +:1050000004F1240328609DF8305007CA83E80700A4 +:1050100094F83330204684F8305063F07F0384F8EE +:105020003330FFF735FF0028C9D0002102220823C2 +:105030000EA815918DF86B208DF86930FFF702FEF0 +:10504000BEE700BF38B591F8313013F0500F02D1F0 +:105050000025284638BD40F602230446FFF746FBEC +:105060000028F5D01023204684F83130FFF740FFA8 +:1050700005460028ECD0A169002200232046E1610A +:10508000FFF7BEFAC12294F8313084F83320002BA8 +:10509000DFD04123204684F83330BDE83840FFF7A5 +:1050A0005BBE00BFF0B5002597B01F4690F83130C9 +:1050B0000192ADF814501495002B46D191F831307F +:1050C0000E4613F0500F40D01378044611462F2B94 +:1050D0003ED001AB02AA2046FFF75EF9002834D08B +:1050E000019B1B78002B41D0002302AA31462046A9 +:1050F000FFF7FCFA30B947B302AA31462046FFF762 +:10510000A1FF10B3A44608AD04F13006DCF800009E +:105110000CF1100C5CF80C1CAE465CF8082C103539 +:105120005CF8043CB445AEE80F00EFD1DCF80000B9 +:1051300008AE28602046FFF7EDF8019901AB02AAFE +:105140002046FFF729F90028CAD1002017B0F0BD8A +:10515000013101910B782F2BFAD0316A08A8FFF7A3 +:1051600007F90028F1D0019908AEB2E702AA31464A +:105170002046FFF767FF17B0F0BD00BF2DE9F04FE5 +:105180000E4690F8311083B009079DF830B09DF8B5 +:1051900034909DF838809DF83C7040F18580A2F2F3 +:1051A000BC7294B27F2C7FD85A1E0B2A7CD80BF18C +:1051B000FF321E2A78D8B8F13B0F98BFB9F1170F0C +:1051C0008CBF4FF0010A4FF0000A3B2F88BF4AF016 +:1051D000010ABAF1000F67D105460193FFF758FEA7 +:1051E000002861D0019B51464BEA431B7B0817F016 +:1051F00001074BEA4424D34643EA481818BF642702 +:10520000A4B248EAC92806F001091FFA88F800226A +:105210002846FFF761F8002846D090F800C0BCF19E +:10522000850F45D00CF14003DBB2012B3CD8ACF12B +:1052300085010023B1FA81F1490902E0042310F845 +:1052400003C04FEACB32012B03F1010342EA5B02B8 +:105250001CFA82F21FFA82FB01D10029EED11F2B2A +:10526000EDD90AF1010A95F830305FFA8AF18B42E4 +:10527000CDD2012205F12401286A00F0E7FE98B1A1 +:105280002C6AA0F802B0204605F0ECFE60B104F5EF +:10529000047005F0E7FE38B1D4F8400403681B6AD7 +:1052A00003B0BDE8F04F1847002003B0BDE8F08F11 +:1052B00095F831302A6A03F03703838092F8103270 +:1052C00043F0010382F81032B9F1000F02D0A0F8C8 +:1052D00010804482B20703D50775A0F80880448186 +:1052E000730703D54775A0F80C80C48190F800C0FF +:1052F0009DE700BF90F833309A0762D570B5C56955 +:1053000082B00446A5B313F0400634D0006AA26808 +:1053100090F845C4013AE1680CF1090C41F1FF3104 +:105320005FFA8CFCCCF1200E22FA0CF2ACF1200CCE +:1053300001FA0EFE21FA0CFCA16942EA0E0242EAD1 +:105340000C02013219B3013D6D1A01312A44019159 +:1053500072BB63F07F03204694ED007B84F833300A +:1053600084ED027B84ED047BFFF792FD02B070BDFB +:10537000012002B070BD816961B90195C161294602 +:10538000206A00F003FFC8B194F83330E1E70195DB +:10539000E161DDE701AA006A019600F0B5FE002890 +:1053A0000CDB10D1019D002DE9D194F83330D0E70A +:1053B0000023019900F0CEFD0028E5D1002002B0C5 +:1053C00070BD002070474FF0FF32A169206A00F0E5 +:1053D000BDFE0028E6D1F1E72DE9F04390F8333027 +:1053E00083B004469D0740F1A18091461A070E46FE +:1053F00000F19580B9F1000F00F0288123684D4637 +:10540000206AA169D0F8382402EA0308C8F3080723 +:10541000B8F1000F40F09480002900F0D48094F897 +:1054200033305B0640F1EC8090F845C4D4E9023299 +:105430000CF1090C013B5FFA8CFC42F1FF32CCF11C +:10544000200E23FA0CF3ACF1200C02FA0EFE22FA25 +:105450000CFCE26943EA0E0343EA0C03134499424D +:1054600080F0D5800131A16190F845240239D0F84F +:105470002C3491401944B5F5007FC0F08A80B5F511 +:10548000806FC0F0A680012393406A0AA3EB080353 +:10549000934228BF1346D0F81C228A424FEA432881 +:1054A00009D35F18BA4206D2002280F810224FF0CA +:1054B000FF32C0F81C22D0F8140232460768BF6AD7 +:1054C000B84798B343464644A5EB0805D4E90072B3 +:1054D000D4E90401DB1942F1000298429141C4E988 +:1054E000003207D294F8331061F07F01C4E904322E +:1054F00084F83310002D83D1D4E902019842914100 +:10550000C0F09680534B1B68002B00F09D8094F8F0 +:105510003330484663F07F0384F833300DE0D0E940 +:105520000423FFF76DF800287FF464AF94F832305D +:10553000002043F0010384F8323003B0BDE8F0836B +:1055400090F8452402394FEA5828D0F82C3491407D +:1055500041441944002F8ED0C7F50078012200F590 +:105560000470A84528BFA84605F0A8FD0028DDD096 +:10557000384447444246314607F052F9B7F5007FB8 +:10558000206A9FD100F5047005F06CFD002899D1C8 +:10559000CCE76268636900920193226923689342B1 +:1055A000DDE900239A4112D2012200F5047005F0D2 +:1055B00085FD0028BAD02A4631463844A84607F06F +:1055C0002FF92B467FE7E16949B3A1614CE705223A +:1055D000EBE7D0F81C328B4206D1002380F8103262 +:1055E0004FF0FF33C0F81C32D0F814023246036883 +:1055F0005B6A9847002899D04FF40073984662E799 +:1056000004F1180200F080FD00288FDB04D1204651 +:10561000FFF7CEFA002889D0A169206A24E7204646 +:10562000FFF7C6FA002881D0A169206AE1611BE773 +:1056300094F833104846C4E9023261F07F0384F8DD +:10564000333003B0BDE8F083484676E7D4E9003252 +:1056500052E700BF3C26002069B170B505460846F8 +:105660000C4609F02DFD2B680246214628465B6852 +:10567000BDE87040184770478368C3F3080383B1DF +:10568000002110B40269D1540133B3F5007FF9D180 +:105690000168D0E903321C681846636A5DF8044B60 +:1056A00018470120704700BF82680346006940F236 +:1056B000FF1CC2F3080281546245586801EB700177 +:1056C000986800F10100C3E9011001D00120704782 +:1056D000D868196810B404684A1C646A1A601A69A8 +:1056E00023465DF8044B184738B58368CAB20D46A7 +:1056F0000169C3F3080340F2FF1C0446CA54634522 +:10570000416802EB71024260826802F1010282602C +:1057100005D0290A2046BDE83840FFF7C5BF01681B +:10572000C0684A1C03685B6A2260226998470028A7 +:10573000EFD138BDF8B50023064601601D46C0E92B +:105740000133A8B205F0F6FDA842044607D0C1B265 +:105750003046FFF7A9FF00283BD10020F8BD6C1CA4 +:10576000B4F5803F04D12AE00134B4F5803F04D081 +:10577000A0B205F0DFFDA042F6D0671BB7F5007FB1 +:105780001DD34FF6FF713046FFF7AEFF0028E4D07F +:10579000B9B23046FFF7A8FF0028DED02546B5F5A0 +:1057A000803FCED13046BDE8F840FFF765BFC5F376 +:1057B000072130460135FFF777FF0028CDD0A542FD +:1057C000E9B23046EBD2FFF76FFF0028EFD100209F +:1057D000F8BDC4F307213046FFF766FF0028BCD0B0 +:1057E0000135DCE72DE9F04F1F4689B00B680D4607 +:1057F00004901446C16002610846DB699847B0F521 +:10580000801F0090C0F0D88000230122009E013349 +:105810005200DBB201D09642F9D81C2B009640F220 +:10582000B780A3F10B08012248FA02F1C8F3470838 +:105830008A4002910792013301225B109A4006923E +:1058400004229A400392022202FA03F30193009A7F +:105850000021039B2046029E4FF0010AD31A4FF409 +:1058600000724AF6552BF34003FA06F90593019EA0 +:1058700009F064FAFF2384F8BFA184F8C0A1B14401 +:1058800084F8C431224684F8C53107230021284614 +:1058900084F8C231FE23C4F8C66184F8C3312B6892 +:1058A000C4F8CA915B6AA4F8FEB19847002863D097 +:1058B0004FF400720021204609F040FA009B84F862 +:1058C0006D804FF000086366F421059B04F17800B9 +:1058D000069AE3652023266423726372A372EB2386 +:1058E000A665464623707623C4F8489063709023DB +:1058F00084F86EA0A3704523E370582323714623D8 +:1059000063714123A3715423E371042323664FF48D +:105910008073A4F86830092384F86C308023C4E9CC +:10592000142284F86F304FF4C37209F007FAA4F818 +:10593000FEB1A8F16A03012B06D9B8F1700F03D0AC +:1059400014F8083003EB760608F10108B8F5007F7B +:10595000EFD12B682246DDF8049028465B6A494661 +:10596000984748B12B684946224628465B6A0C3165 +:10597000CDF80490984740BB2FB13B680F22B8493F +:1059800038465B6898470026304609B0BDE8F08F7E +:105990001A2B4FF0080800F2A6814FF48043CDF88F +:1059A000088001934FF4004303934FF480730793EF +:1059B0004FF4005306934AE7002FE4D03B681522CA +:1059C000A84938465B689847D7E7424600212046F9 +:1059D00009F1010A09F0B2F94AF6552309F1090261 +:1059E00004F2FF19A4F8FE3100239346A04601E01B +:1059F00018F8013FC14503EB7606F9D12B68224622 +:105A0000514628465B6A98470028B5D02B68224645 +:105A10000AF10C0128465B6A98470028ACD00AF1CD +:105A200001039B4502D09A462378DFE74FF40072CA +:105A3000002120469B4609F081F900220AF1030A61 +:105A40001146234601E013F8011F984501EB760645 +:105A5000F9D12B682246594628465B6A98470028A8 +:105A60008AD02B6822460BF10C0128465B6A9847C6 +:105A7000002881D00BF101018A456AD1231F04F56A +:105A8000FE7243F8046F9A42FBD12B6822462846E7 +:105A90005B6A984700283FF46FAF2B680BF10D014C +:105AA000224628465B6A984700283FF465AF2FB12D +:105AB0003B680C226C4938465B689847069A00217F +:105AC000019B2046002613444FF400729946059B23 +:105AD0004FEA830809F032F923464FF0FF3208F20B +:105AE0000728F821B7F1000B4FEA582A03F8011BE9 +:105AF0004FEA9838C4F8012018BF4FF0010BDA6064 +:105B00005A609A60C3F80F2002E00136B24523D0F4 +:105B1000B6FBF8F308FB136343B9BBF1000F05D0E4 +:105B20003B680122514938465B6898472B6809EB6E +:105B30000601224628465B6A984700283FF41CAFBE +:105B4000002EE2D131464FF40072204609F0F6F8FB +:105B5000DBE78B46217874E7002F34D03B680222C4 +:105B6000434938465B689847059E079A0736F6080A +:105B700006F2FF13B2EB532F4FEA5329FFF4FDAEA9 +:105B80004FF400720021204609F0D8F80723237053 +:105B9000B9F1000F00F08A804FF0000808E0B8F17A +:105BA000000F01D184F8008008F10108C1457BD9BC +:105BB000039A28462B6802EB080122465B6A984745 +:105BC0000028ECD1D8E6059E079A0736F60806F2BB +:105BD000FF13B2EB532F4FEA5329FFF4D4AE4FF427 +:105BE00000723946204609F0A9F807232370B9F15D +:105BF000000FD1D1039B079A04989918FFF79AFDDB +:105C000000283FF4C0AE029A4FF400739340049A08 +:105C100092689A423FF6B7AE4FF00208029B4FF4EB +:105C20000072002108FA03F9039B2046994409F009 +:105C300085F881220323049909F1FF3984F8202093 +:105C40008222237084F84020C4E90D864A684FF010 +:105C50000108636562648B68A3650023E3650EE059 +:105C600038060020D4050020EC050020FC050020AB +:105C700014060020079B98453BD208F101082B68C9 +:105C800009EB0801224628465B6A98470646002829 +:105C90003FF472AEB8F1010FECD14FF40072002165 +:105CA000204609F04BF8E8E7002FA3D03B68162206 +:105CB000144938465B689847039B079A04989918DB +:105CC000FFF738FD00283FF458AE029A4FF40073F6 +:105CD0009340049A92689A423FF64FAE0A4938467A +:105CE000FFF7BAFC98E74FF48072CDF8088007926E +:105CF000A1E5002F3FF448AE04493846FFF7ACFC5D +:105D000042E600BF000600201806002028060020FA +:105D10002DE9F0410C46154601F11E08AB892846D5 +:105D200034F8027F1BB9D5E901239A420ED005F061 +:105D3000EDF905F0FFFA0646384605F0FBFA864213 +:105D400009D14445EAD10120BDE8F081B7FA87F0D6 +:105D50004009BDE8F0810020BDE8F0812DE9F04F59 +:105D600090F8313083B08846002B4FD090F8303017 +:105D70000746012B53D9013A0B464FF0020A002483 +:105D80008E18DFF8A0B00022514638460193FEF786 +:105D9000A3FA00283AD00278C12A37D1054600F18B +:105DA0001E09019B35F8020F24B300F5105292B280 +:105DB000B2F5806F2AD20BEA8424C0F30900204395 +:105DC00000F580301946324605F016FA0346E8B170 +:105DD00000244D45E6D10AF1010A97F830205FFA18 +:105DE0008AFA5245CFD2A3EB08009846002388F8E0 +:105DF00000300FE000F5205292B2B2F5006F02D3EE +:105E00000028DFD1EFE7B2F5806F06D300231846F4 +:105E100088F8003003B0BDE8F08F0446D9E70020D1 +:105E2000E4E700BF00FC0F0070B50C4600234FF6FE +:105E3000FF75226819461E46A3812361626017E040 +:105E400005F064F9A84222D005F074FA2369F20340 +:105E5000A189013342EA5602060A236152FA80F010 +:105E600083B2C0F34E0040EAC33016FA80F086B227 +:105E700020460029E4D1D4E901239A42E0D12069E7 +:105E8000A6820138FE288CBF0020012070BD0020B2 +:105E900070BD00BF2DE9F84F07468A46914600299C +:105EA00042D0A1F10208D7F83034434542D908F076 +:105EB00007030125C8F3C80B9D40EDB24646444692 +:105EC000D7F82C140022384601EB143105F0F6F80F +:105ED000E8B10BF1FF3B834400F2FF101BF8011FF8 +:105EE0000AE04A452BD0A04510D0D7F83054A5423F +:105EF00014D913F0FF050CD0013429424FEA4503B1 +:105F0000A4EB0602EDD0A0452646EED10120BDE867 +:105F1000F88F58454FF00105E0D101E000263446E6 +:105F200001254FF0000BCBE7D0F82084D7F83034B0 +:105F30004345BCD84FF000080125C346BEE7BAF17F +:105F4000000F04D1B9F1010F08BFC7F82064B01CDD +:105F5000BDE8F88F2DE9F8438046881E15461E4699 +:105F60008318D8F83024934237D8CEBBD8F82034E1 +:105F7000834288BFC8F8200400F007030124D8F842 +:105F80002C74C0F3C8099C4007EB1031E4B2012225 +:105F900040468F1805F092F8F8B109F1FF3E8644AB +:105FA00000F2FF101EF801CF1CEA040F8CEA040C6B +:105FB0004FEA440414BF01220022B2420DD0013D39 +:105FC0008EF800C018D014F0FF04EDD17045A14642 +:105FD0004FF00104E6D13946D9E70020BDE8F88347 +:105FE000D8F820148B42C7D98142C5D3934228BF29 +:105FF0000023C8F82034BFE70120BDE8F88300BFC4 +:10600000F8B5D0F8303401338B4201D20020F8BD0E +:1060100007460C4600F50476002505E0D7F8303435 +:1060200001350133A342F1D3D7F8241400223046BE +:1060300001EBD41105F042F8A4000028E6D0C4F327 +:1060400008040459631CE9D1681CF8BD38B50C4636 +:106050000B6890F845C400F50470D0F82812023B94 +:10606000656803FA0CF3294003EB5123D0F81C12A6 +:10607000194405F023F818B16368C3F30803184402 +:1060800038BD00BF2DE9F8430C46D0F838344968D4 +:106090000B4011446160134490F8451401F109026A +:1060A000D2B2D3402BB380465D1E00F5047905E0E3 +:1060B0002368013D03F1010323601AD3267A002EE1 +:1060C000F6D1D8F8303432462768484601339F422B +:1060D00012D8D8F8241401EBD71104F0EFFFBF0059 +:1060E00050B1C7F30807C3595A1C09D0013D2360BA +:1060F000E4D20120BDE8F8834FF0FF30BDE8F8831B +:106100003046BDE8F88300BF38B5D0F830340133ED +:106110008B4202D24FF0FF3038BD0C46D0F8241429 +:10612000154600F50470002201EBD41104F0C6FFFF +:106130000028EFD0A400C4F3080403595A1C02D06D +:1061400001202B6038BD002038BD00BF01291BD9BC +:1061500038B5D0F830340C4601338B4201D20020E0 +:1061600038BDD0F82414154600F50470012201EB67 +:10617000D41104F0A3FF03460028F0D0A4000120AE +:10618000C4F308041D5138BD00207047D0F83034E6 +:106190000133994201D9002070472DE9F04F05469F +:1061A00083B00C4600F504790F464FF00008D5F88F +:1061B0002414002248464FEAD41B01EBD41104F00A +:1061C0007DFF90B1A300C3F30803C2580193531C91 +:1061D00016BF16464FF0000A4FF0010A012C04D9F1 +:1061E000D5F830240132944203D9002003B0BDE831 +:1061F000F08FD5F8241401224846594404F05EFF7C +:106200000028F2D0019B40F80380BAF1000F12D0B1 +:106210000134B44208D00023E21B39462846FFF778 +:1062200099FE0028E1D03746D5F830340133B34227 +:10623000DBD33446BBE7621C534639462846D21BA3 +:1062400003B0BDE8F04FFFF785BE00BF2DE9F8436E +:1062500000250646D0F82C1400F504782C460022C0 +:1062600040464F1C04F02AFFA8B100F1FF3E04F5A0 +:106270008059D6F8300405E079B90834844209D24F +:106280004C4516D01EF8011FFF29F5D108340835FA +:106290008442F5D3401BBDE8F8830822012319424C +:1062A0004FEA430C18BF0135013A5FFA8CF3F6D17F +:1062B000E3E73946D3E700BFF8B500234FF0FF36D8 +:1062C00000F504771546C0F84014044641601A46AC +:1062D000C0F81412194680F844340370C66080F880 +:1062E0001032C0F81C62384604F0E8FE042D0DD8C8 +:1062F000064658B1BDB16B1E00EB031393F8BE21E7 +:1063000012F07F0202D193F8C2310BB90020F8BD20 +:1063100000EB05163846D6F8B651294604F0CEFEF5 +:1063200006460028F2D005221A49F01C08F058FD54 +:106330000028EBD196F86C30092BE7D1336D01467C +:106340002B44C4F82434736DC4F82834B36D2B4443 +:106350000125C4F82C34F36DC4F83034336EC4F81E +:10636000343496F86D20C4F82004204602F1090365 +:1063700084F8452405FA03F35A1EC4F83C34C4F8E3 +:1063800038242A46FFF786FD4023284684F8443403 +:10639000F8BD00BF4806002010B50446D0F83414FC +:1063A000FFF72EFE94F845340933DBB2984010BD58 +:1063B00070B590F9023082B00446002B0DDBA56861 +:1063C00005F1280004F04EFE00283BD16378002040 +:1063D00043F00103637002B070BD80680122A169BF +:1063E000283004F06BFE0028F0D0A58805F00F05DA +:1063F0006B0100EB4515C35CE52BE7D023781B0749 +:1064000001D5E369EB61236A15491A0C6B830E68A9 +:10641000AA8266B10DF103020DF1060101A8B04791 +:10642000BDF80430BDF806202B836B82EA82A37886 +:10643000A56803F07F0305F12800A37004F012FEA5 +:106440000028C3D005F50E7004F00CFE0028BDD066 +:10645000286803681B6A98470028B7D0BBE700BFCD +:106460003C260020024638B552F8105F044680688A +:10647000294602F021F950B155B123690135AB42EB +:10648000A37818BF03F0BF0363F07F03A37038BD88 +:10649000A37843F04003F7E7F8B5047814F020043C +:1064A00004D11A4B054642699A4202D30027384666 +:1064B000F8BDFFF7D7FF07460028F7D0A8682E6978 +:1064C0008279023E416996400E440179A9B1214684 +:1064D00006E008F033FCA868E1B202798A420BD9E1 +:1064E000314405222830013404F0E8FD4FF40072F5 +:1064F00000210028EDD1D9E782794FF40073696952 +:106500003846934011FA83F36B61F8BD00FE1F001B +:1065100010B5044680680A462830A16904F0CEFD13 +:1065200020B1A38803F00F0300EB431010BD00BFA0 +:1065300010B5037804462BB1FFF73AFF0023237010 +:10654000A37010BD002301202370A37010BD00BFF5 +:1065500038B5037805460C4613B1FFF729FFF0B1B3 +:10656000A8680022A969283004F0A8FDB8B1AA885B +:1065700002F00F0200EB421352015D6880589968E7 +:10658000DA6820606560A160E26018695D699969F8 +:10659000DA69206101206561A161E26138BD0020F6 +:1065A00038BD00BF30B589B00D4614466946FFF7C7 +:1065B000CFFF28B1BDF81020BDF80E302A8023800F +:1065C00009B030BD30B589B00D4614466946FFF7B5 +:1065D000BFFF28B1BDF81820BDF816302A802380EF +:1065E00009B030BD0B7813F0700F01D10020704757 +:1065F000F0B540F6022389B00D46044601F0F0F8EC +:1066000038B1012210232046A2702370FFF744FF07 +:1066100010B9002009B0F0BD2269237822626BB165 +:10662000636933B1A378002223F02003C4E9042274 +:10663000A3702046FFF7BCFE0028EAD0A068012224 +:10664000A169283004F03AFD0028E2D0B4F804C073 +:1066500010220CF00F0C4FEA4C1300EB4C1C8CF882 +:106660000B20C058A768236A97F806E09E1EDCF846 +:106670000410DCF80820DCF80C3006FA0EF6EE46C2 +:10668000AEE80F00DCF81000DCF81410DCF818207D +:10669000DCF81C30AEE80F007B6907F1280001220E +:1066A000F1184FF02033CDF80130CDF80530ADF8BA +:1066B000093004F003FD84460028AAD02E27EE46B8 +:1066C0008DF800707646BEE80F00CCF80000CCF8DC +:1066D0000410CCF80820CCF80C308DF80170BEE81E +:1066E0000F00CCF81000CCF81410CCF81820CCF81F +:1066F0001C302B6A1A0CADF81A30ADF814200FCEEE +:10670000CCF82000CCF82410CCF82820CCF82C3081 +:106710000FCECCF83000CCF83410CCF83820CCF8C0 +:106720003C30A46804F1280004F09CFC00283FF4ED +:1067300070AF04F50E7004F095FC00283FF469AFCB +:10674000206803681B6A09B0BDE8F040184700BF25 +:106750002DE9F041002694B0984603780192ADF8F7 +:1067600014600B96002B41D10B780D4613F0700F7F +:106770003CD01378044616462F2B3BD0002728E048 +:10678000019E3678002E50D001F02AF8034602AA66 +:10679000294620462BB9B8F1000F27D0FFF722FF7A +:1067A00020B3A6460DF12C0CBEE80F00ACE80F009C +:1067B000BEE80F00ACE80F00DEF80050204623785A +:1067C000CCF800500BB1FFF7F3FD019E0BAD277025 +:1067D000A770314601AB02AA204601F04DF90646EA +:1067E00002AA294600232046002EC9D1002014B059 +:1067F000BDE8F0810136019633782F2BFAD0AD68D1 +:10680000242200210BA808F099FA0D95EB79102BA2 +:1068100003D0202B0FD00C2BE8D120238DF82C3067 +:1068200001230BAD8DF82E30A8E702AAFFF7DAFEA0 +:1068300014B0BDE8F0814023F0E700BF2DE9F0413E +:10684000002594B09846037801920295ADF838502F +:10685000002B37D10B780E4613F0700F32D013781F +:10686000044615462F2B31D000271EE0019D2D78C0 +:10687000002D40D000F0B4FFA6460DF1080C08B37F +:1068800066462578BEE80F00ACE80F00BEE80F00B2 +:10689000ACE80F00DEF800302046CCF800300DB137 +:1068A000FFF786FD019D2770A770294601AB0BAA53 +:1068B000204601F0E1F805460BAA314600232046A8 +:1068C000002DD3D1002014B0BDE8F0810135019531 +:1068D00029782F29FAD0A9B9B5682422204608F0D2 +:1068E0002DFAA560EB79102B03D0202B22D00C2B96 +:1068F000E8D120221FE043460BAA00F071FF14B03C +:10690000BDE8F081B6682422002102A808F016FA3A +:106910000496F379102B03D0202B03D00C2BD1D16C +:10692000202300E040238DF80830012302AE8DF8CB +:106930000A3099E74022012322701846A370C2E76B +:1069400019B101F58961FFF779BF0846704700BFAB +:10695000CB6870B50D46044693B906780EB118465B +:1069600070BD8D682422314608F0E8F9A560EB7906 +:10697000102B18D0202B10D00C2B14D0304670BD0B +:106980002422002108F0DAF901201023A0702370DE +:10699000D5E90223A260236270BD40220123227048 +:1069A0001846A37070BD2022F8E700BF70B50578C7 +:1069B0000DB1002070BD0E4604462422294608F081 +:1069C000BDF9A660F379102B0BD0202B03D00C2B34 +:1069D00007D0284670BD4022012322701846A370BC +:1069E00070BD2022F8E700BF2DE9F04F2DED028B9E +:1069F000837883B00546DF0740F18C8088460178B4 +:106A000092460E0700F191808C0608D583685A895A +:106A10004369C3EB42139BB29A4528BF9A46BAF129 +:106A2000000F00F0AF806A6905F110038806564632 +:106A30004FF0000908EE103AAF68C2F3080B3DD5DD +:106A4000396A01EB5221BBF1000F51D1B6F5007F3D +:106A50004ED37A6B91424BD0B6F5806FC0F08280F6 +:106A60002878730A800605D43879A0EB09008342A0 +:106A700028BF034691424FEA43240CD8C8188242EB +:106A800009D207F12800CDE9001304F0EBFADDE9A3 +:106A9000001300283ED0F86A026857694246B8479A +:106AA000002837D06A69361BA04422446A6169D045 +:106AB0002978C2F3080BAF688806C1D497F805900F +:106AC00009EA5229BBF1000F36D1B9F1000F33D1D9 +:106AD000002A33D14A064CBF3A6A2A6A2A61023A2E +:106AE000B8797969824049441144BBF1000FADD0B7 +:106AF000CBF50074002207F12800B44228BF3446C9 +:106B000004F0DCFA30B100EB0B012246404605F000 +:106B100087FEC7E76B784FF0FF3043F002036B70DE +:106B200003B0BDEC028BBDE8F08FC36942699B1ACC +:106B30009A4528BF9A4672E72A69D0E70B0705D520 +:106B4000AA78540602D52A690132C7E718EE102A3E +:106B50003846296901F0FEFD0028DBDB0CD0AF6868 +:106B60002A69BCE7F86A424603681B69984700280F +:106B7000D0D04FF4007495E72B7813F0700FC9D084 +:106B8000AAEB060A504603B0BDEC028BBDE8F08FBD +:106B900070B582B0012204460DF10701D0E9045618 +:106BA000FFF722FF01280CBF9DF807004FF0FF30D0 +:106BB000C4E9045602B070BD436913F4F07F30B5E8 +:106BC000044683B0C3F3431509D0012907D120330C +:106BD0004361A068383000EB451003B030BD01229E +:106BE0000DF107012046FFF7FFFE40B2012803D157 +:106BF00063691F336361ECE70020EEE72DE9F041A4 +:106C000003789AB0002613F0180F0896119606D054 +:106C1000174683688A6804460D469A4203D00020CE +:106C20001AB0BDE8F081FFF7C3FBA6460DF1440C96 +:106C3000BEE80F00ACE80F00BEE80F00ACE80F00A4 +:106C4000DEF800303246A169CCF80030A36803F1C9 +:106C5000280004F033FA0028E1D0A288EC4694F82A +:106C6000008002F00F0200EB421E5201DEF8041019 +:106C70008058DEF80C30DEF80820ACE80F00DEF8B3 +:106C80001410DEF81820DEF81C30DEF81000ACE836 +:106C90000F0018F008033A46294640F09B8008A8E8 +:106CA000FFF756FD0028BAD0109EBDF8243000250D +:106CB0000E990122A3809DF82330A068E3700B9BFE +:106CC0002830A161E3608DF820508DF8225004F047 +:106CD000F5F90028A3D0A38803F00F0300EB4310BD +:106CE000DDF80D30C0F80D30DDF81130C0F811308E +:106CF000DDF81530C0F81530DDF81930C0F819305E +:106D0000BDF81D30A0F81D309DF81F30C3779DF8E9 +:106D10000B30C372002E3BD0A068B31E2A46817987 +:106D200028308B4050F8141C194404F0C7F905466C +:106D300000283FF474AF006A6F46696AAA6AEB6A7A +:106D40000FC7286B696BAA6BEB6B0FC73146A06846 +:106D500001F022FD00283FF462AFA068236A827927 +:106D60002830023B50F8141C93400122194404F0CF +:106D7000A5F9064600283FF452AF6D460FCD3062AC +:106D80007162B262F3620FCD30637163B263F36319 +:106D900000210222082311A819918DF846208DF8B0 +:106DA000443000F0D3FE00283FF439AFA46804F16A +:106DB000280004F057F900283FF431AF04F50E70B5 +:106DC00004F050F900283FF42AAF206803681B6ADA +:106DD000984725E740F601236046FFF72FFD00287E +:106DE0007FF463AF1BE700BF0378DA0601D400200D +:106DF0007047436930B5044683B033B183780022CD +:106E000023F02003C0E90422837000230FE06361B4 +:106E1000A3686A0138339A5C03EB4513EAB1E52AAB +:106E200004D02E2A02D0DB7A1B0722D5636913F423 +:106E3000F07FC3F3431503F12003E8D101220DF1E4 +:106E400007012046FFF7D0FD40B2012803D1636956 +:106E50001F336361DCE763785BB9A37808222046BF +:106E600043F002032270A37003B0BDE8304000F08D +:106E70006DBE002003B030BD2DE9F041037804461B +:106E80000769002B39D00D464169A94242D0002D37 +:106E900037D018072AD5E269AA422ED3D4F808C001 +:106EA0006E1EA2789CF8060012F0400F00F1090057 +:106EB000C0B226FA00F630D14A1EC24009B196424D +:106EC0002FD25B064CBFDCF82030236A236104F12B +:106ED000100806E02169013EA06801F03BFC002893 +:106EE0000BDD4246002EF5D1A2780CE09A06D5D5EE +:106EF000A3685B89B5EB431FF6D900202761BDE885 +:106F0000F0818278056122F0200201206561A27083 +:106F1000BDE8F0810120BDE8F081236A334423619C +:106F2000F1E7B61AD3E700BF2DE9F0410E4615464A +:106F300000212422044698469DF8187007F0FEFEB2 +:106F4000B068336A00F13802A58005F00F0502EB46 +:106F50004512C4E90203D17A0B0711D401F01701DD +:106F60002170D37A13F0180F02D141F0080121707B +:106F700008F00303E770012B38D0022B06D0F3B1E1 +:106F8000002318462370A370BDE8F0810323217805 +:106F9000CD06F5D4CE07F3D408F0080118F4806FBD +:106FA00043EA0103A370416B958AA161518B41EAC9 +:106FB000054112D019BB63F07F03A37010E018F4F1 +:106FC000806FDDD108F0080343F00103A370416B2B +:106FD000938AA161518B41EA03412162D369E36144 +:106FE00018F4804F04D10120BDE8F0810223CEE7E0 +:106FF000E1692046FFF740FF0028F4D1C0E701F027 +:10700000CBFB0028BCD0A378D5E700BF0378002BCA +:1070100045D12DE9F0470B7884B00C4613F0700F82 +:1070200030D04B6913F01F052CD106469046A94677 +:1070300001220DF10F012046C3F3431A5F09FFF748 +:10704000D3FC40B24FEA4A1201281BD16369A16800 +:107050001F3301F1380C63611CF802200CEB4A1C51 +:1070600082B12E2A12D0A2F1E500B0FA80F04009D8 +:1070700060B99CF80B1011F0080E12D00F2907D040 +:107080000546D5E7002004B0BDE8F0870025CFE72E +:107090005106CDD502F01F059CF80D90C8E70020E1 +:1070A000704785B10CF10A0101E01CF8012F4FEA8D +:1070B000CE13614543EA5E0352FA83F35FFA83FE1F +:1070C000F3D1CE45DED14346BAB2214630460095D3 +:1070D000FFF72AFFD7E700BF03780BB1FFF768B9C6 +:1070E000012070472DE9F0470E46017882B009076C +:1070F0009DF828709DF82C909DF830A09DF8348064 +:1071000018D5A2F2BC7294B27F2C13D85A1E0193E8 +:107110000B2A0FD87A1E1E2A0CD8BAF13B0F98BF43 +:10712000B9F1170F06D8B8F13B0F03D80546FFF7A2 +:107130003FF918B9002002B0BDE8F087A868012225 +:10714000A969283003F0BAFF0028F3D0019B4FEA69 +:107150005802A98847EA4313F70701F00F0142EAF2 +:107160004A1243EA442300EB41109BB242EAC9228F +:1071700048BF4382B40792B208D518F001080382D1 +:10718000C28118BF4FF0640880F80D80710701D5E7 +:107190000383C282AC6804F1280003F063FF002877 +:1071A000C8D004F50E7003F05DFF0028C2D020683F +:1071B00003681B6A02B0BDE8F047184783789B0755 +:1071C00027D5036A10B5044682B0ABB1016911BB83 +:1071D000019301621946A06801F0DEFAB0B1A3780C +:1071E000616963F07F032278E161A37022B12046D8 +:1071F000FFF7DEF802B010BD012002B010BD6FF045 +:1072000070422169A06801F0B7FA68B9002002B0A5 +:1072100010BD00207047002301AA8068019301F08F +:1072200099FA0028F2DBEAD1019B002BD7D0D1E7F5 +:107230002DE9F047837805469C0777D588461907DE +:10724000914600F1B5806B6913EB09026ED2B9F17A +:10725000000F40D04F464FF0000AA868C3F308065D +:107260002969447914EA53243FD1002E3DD10029E5 +:107270006ED0AA78520676D5EA699A4273D901315E +:10728000296102398279436991401944B7F5007F39 +:1072900053D3B7F5806F70D303797A0A1B1B9342DF +:1072A00028BF1346426B8A424FEA432407D35E1835 +:1072B000B24204D24FF0FF3280F828A04263C06A85 +:1072C00042460668B66AB04780B36B693F1BA0446C +:1072D00023446B61C1D1EA699A4276D2AA784846C2 +:1072E000EB6162F07F03AB7025E08279023943697C +:1072F000914019442144002EC8D0C6F500740122E3 +:10730000BC4228BF3C46283003F0D8FE70B1304460 +:1073100026442246414605F083FAB6F5007FA86868 +:10732000D3D1283003F09EFE0028CED16B78002008 +:1073300043F001036B70BDE8F087C6F500746A691D +:10734000EB69BC4228BF3C469A4205D30522DAE7E6 +:10735000296A21B3296194E7AB7813F0200F14BF99 +:1073600005220122CFE705F1100201F0F3F9002810 +:10737000DCDB24D0A868296983E7436B8B4204D106 +:107380004FF0FF3380F828A04363C06A4246036889 +:107390005B6A98470028C9D04FF4007495E72846E7 +:1073A000FFF760F80028C1D02969A868296268E75A +:1073B000C169FFF761FD00287FF445AFB6E72846B5 +:1073C000FFF750F80028D5D1B0E7054B1B682BB16B +:1073D000AB78484663F07F03AB70ACE74846AAE75A +:1073E0003C2600202DE9F04F84468DB014461568E8 +:1073F00098460646894603AF01934FF0000EBCE85D +:107400000F000FC7BCE80F000FC7DCF80030656045 +:107410003B604346A4F80CE0002B3FD04FF0010A3C +:10742000A9EB0A0103A889B24901FFF725FD50B372 +:10743000002103A8FFF7C0FB074620B300250DE09D +:1074400003F064FE8046584603F074FF83464046CE +:1074500003F070FF834516D10D2D18D0EAB23946DE +:107460003046013500F0E4FEA38983462046002B18 +:10747000E6D1D4E901329342E2D1BBFA8BF0400964 +:107480000DB0BDE8F08F00200DB0BDE8F08F0AF11F +:10749000010A019B5FFA8AFA5345C1D20120EFE746 +:1074A0002DE9F04F07468DB016469A460DF10C0CAB +:1074B00002F1150402F1200501914FF000090FCFF0 +:1074C000ACE80F000FCFACE80F003B68CCF8003001 +:1074D0004FEAC91314F8012F43EA5903A54252FA9F +:1074E00083F35FFA83F9F3D133684FF000087360D8 +:1074F000A6F80C80BAF1000F4ED00127019B03A81B +:10750000D91B89B24901FFF7B7FC002855D00021EB +:1075100003A8FFF751FB00284FD0059A574500F10B +:10752000010B4FF0010492F828304FF0000543F0B2 +:10753000010382F828304FF00F030CBF47F04002E0 +:107540003A46C3724FF00003027003734FF000031A +:1075500080F80D90438306E0ABF80000013401355C +:107560000BF1020BE4B2B08918B9D6E901239A42B3 +:1075700016D0304603F0CAFD042DEBB2ECD90A2B2D +:1075800002D8ABF80300E9E70D2CABF80500E5D114 +:107590000137FFB2BA45B1D201200DB0BDE8F08F7E +:1075A000B8F1000F06D008F101084FF6FF705FFA3E +:1075B00088F8E1E74FF00108DEE700200DB0BDE8F4 +:1075C000F08F00BF02464FF0203152F8163B2DE9F4 +:1075D000F043C0F81610864684685160C2F8071060 +:1075E0001A782E2A14BF0120002003D113F8012F8E +:1075F0002E2AFBD0611E99420BD90A4602E0934223 +:10760000114606D01146013A91F800C0BCF12E0F88 +:10761000F5D19C424FF0000540F2868007260827EE +:10762000A946A84606E001330A264FF008091027AC +:107630009C425BD91A782E2A08BF9942F3D0222A9D +:107640000DD07C2A0BD0A2F15B0CBCF1020F06D945 +:10765000A2F12A0CBCF1050F21D82D2A1FD002F06F +:10766000C002802A5DD04E452FD299422CBF002007 +:1076700001200A2E08BF40F00100002847D09EF8E4 +:107680001630202B40D09EF8143001207E2131226C +:1076900073448EF815009975DA75BDE8F083A2F190 +:1076A0003A0CBCF1050FDAD9A2F1210CBCF15D0F47 +:1076B000D5D84E45D9D3A2F1610CBCF1190F28D809 +:1076C000203A3D43D2B2EDB201E000205F2209F141 +:1076D000010CF144013389F816205FFA8CF2062A76 +:1076E000914698BF8EF814209C42A3D89EF816307D +:1076F000202B09D00028C6D018EA050F18BF022594 +:107700008EF81550BDE8F0830020BDE8F0830B46ED +:107710008EE7A2F1410CBCF1190F98BF47EA0808A7 +:10772000D5E70133002083E7A846DFE72DE9F84FCE +:107730004FF0620900250F460446DFF8A0B04FF075 +:107740007E0A91F8148001F11606B8F1030FDBF8F8 +:10775000003028BF4FF003082B449DB208F104030A +:10776000DBB205F00F02581E2D09092A02F137017C +:1077700098BF02F13001FA18C3B291759845F0D163 +:1077800007EB08030021204683F816A0FFF774FBDF +:1077900001212046FFF710FA03460B2230469BB129 +:1077A00093F800C01946BCF1000F13D0DB7A1B0719 +:1077B000EED407F017FA0028EAD109F1FF3919F0E1 +:1077C000FF09C2D1484603E06078B0FA80F0400972 +:1077D000BDE8F88F0120BDE8F88F00BFC42B002062 +:1077E0002DE9F04F2DED028B8BB0CDE902038B68B4 +:1077F00007930B7813F0700F53D0029B1B78002B6C +:107800004FD1136990469A4A0E460C33A2FB0323CC +:10781000C3F3870298F815309807049200F0A78008 +:10782000571CFFB20023304619461C460693FFF74B +:1078300023FB08F11603A346A146A24608EE103A20 +:107840000594756900213046FFF7B6F9C5F34F1569 +:10785000034620B30278E52A29D042B3BC4238BFA0 +:1078600000242E2A2BD090F80BC0BCF10F0F54D05F +:107870001CF0080C23D1B9F1000F40F0D5800B2289 +:1078800018EE101A07F0AEF90028DAD198F8153082 +:1078900013F0010300F0E48001230593D1E773782E +:1078A00083B100200BB0BDEC028BBDE8F08F002C43 +:1078B00008BFAA46BC4201D20134E4B212B14FF073 +:1078C0000009BEE7039B9A05EBD503F00303013BD8 +:1078D000012BE6D8002C08BFAA46BC4203D348E0DF +:1078E000DCB2A74245D000213046FFF765F9631CA2 +:1078F0000028F5D17378002BD3D1A74239D9079D41 +:1079000005E02B7904EB0314E4B2A74231D93046E9 +:10791000FEF7C2FD0028F4D1C3E7B9F1000F19D179 +:1079200002F01F0B049959458BD112F0400988D001 +:10793000437B89460693BBF1010F82D1691C4B46FC +:107940004246304689B2FFF74DFD002808BF4FF090 +:10795000000976E70BF1FF3B5FFA8BFB5A45AED18E +:10796000437B069A9342E6D04FF0000969E701276E +:1079700058E7059B2BB141463046FFF7D7FE00285C +:107980008FD0013F42463046FBB20AEB03051F464B +:10799000ADB22946FFF784FD002882D06901304648 +:1079A000FFF76AFA00283FF47CAF00213046FFF76A +:1079B00003F9044600283FF474AF2022002107F0A9 +:1079C000BDF9D8F81620D8F81A302260636098F80C +:1079D0002030B8F81E20A372228198F8153003F0E9 +:1079E00018032373234B1B68002B3BD00DF123029C +:1079F0000DF1260109A89847BDF824302382BDF86F +:107A00002630E3819DF823306373079A92F828307B +:107A100043F0010382F82830039B2A46314602983E +:107A20000097FFF781FA3DE7BBF1010F7FF439AF13 +:107A30000A3001E013F8012F4FEACC11984241EAD5 +:107A40005C0152FA81F25FFA82FCF3D1069B634536 +:107A50007FF427AF4F46039B19053FF522AFDBE7C5 +:107A60001F46F8E745F62123238223836382CCE770 +:107A70004FECC44E3C2600202DE9F0411F460B7808 +:107A800082B00C46202B154603D114F8013F202B61 +:107A9000FBD02C60237863B32F2B2AD04FF0000843 +:107AA000294E211D204601AA03F0F8FB044670B1BF +:107AB000019BB3F5803F40D27F2B08F1010831D8FC +:107AC0003C2BD9B229D8212905D81F2909D8002053 +:107AD00002B0BDE8F0812239C9B226FA01F1CA0725 +:107AE000F5D42E2B01D0202B1CD123780BB12F2BBA +:107AF000D7D12B69013BFE2BE9D82378202B03D16A +:107B000014F8013F202BFBD02F2BF9D028463C60E6 +:107B100002B0BDE8F041FFF755BD5C29D7D005D9CB +:107B20007C29D4D0C5F81080AC60DEE73E3901294D +:107B3000F8D8002002B0BDE8F08108F10208AC607E +:107B4000C5F81080D1E700BF01210005F0B5002382 +:107B50008BB0019383789A0724D5016A054619B141 +:107B6000806800F019FEE8B101212846FEF7D0FC3C +:107B7000C0B1421E00F10A0C0024E30112F8011FFB +:107B800043EA5403944551FA83F3DCB2F5D1E52678 +:107B900000230670AF682B7007F12800AB7003F06C +:107BA00061FA10B900200BB0F0BD07F50E7003F0BC +:107BB00059FA0028F6D0386803681B6A98470028ED +:107BC000F0D0EB78002BEED0294601A8FEF7C0FEDE +:107BD0000028E7D0EB78002BE4D0012721E001A8B2 +:107BE000FEF7EAFF7B1CF9B20028DBD0C27A0F2A2D +:107BF000D8D102785FFA83FC9FB202F01F038B4258 +:107C0000D0D1437BA342CDD10670A96891F828302A +:107C100043F0010381F8283053060DD4EB78634517 +:107C2000C0D3A98801A8C91B89B24901FFF724F96B +:107C300000210028D3D1B5E7AC6804F1280003F097 +:107C400011FA0028AED004F50E7003F00BFA0028EC +:107C5000A8D0206803681B6A9847A4E72DE9F84379 +:107C6000DDF82090A2B105460C469846571801E071 +:107C7000BC420DD02B68204649465E6AC04721466B +:107C8000024628460134B0470028F1D1BDE8F88308 +:107C90000120BDE8F88300BF486810B50C4630B13C +:107CA0000B894A8901339BB29A420B8101D9206822 +:107CB00010BD0368012203495B68984700232068D0 +:107CC000238110BDFC0500202DE9F04F054687B04B +:107CD0008846924600214FF40072406A07F02EF861 +:107CE000286A28B103680C223A495B689847286AD9 +:107CF0006B6A4FF00009EE690AF1FF32DFF8E0C06D +:107D0000E968ADF814904C1CCDE903304FEA5A13E2 +:107D1000ADF816303368DF6A674526D16AB301EBE8 +:107D20000A07DFF8C0A00AE02146039A3046013472 +:107D3000D84700283FD0A7421ED033680498D3F814 +:107D400024B00028F0D0BDF81430BDF8162001335F +:107D50009BB29A42ADF81430E6D80368514601222E +:107D60005B689847ADF81490DEE703AB21463046D8 +:107D70000093194BB847F0B1286A20B1036802227A +:107D800016495B689847B8F1100F4FF0F8016A6A1E +:107D90004FF001030CBF04200C201170FF216A6A10 +:107DA000D15401339842FAD1E8696A6A0368E968F4 +:107DB0005B6A984718B9002007B0BDE8F08FD5E995 +:107DC0000231E86919446A6A03685B6A984707B038 +:107DD000BDE8F08FEC050020595C0000140600207F +:107DE0001D5C0000FC05002038B5436A4FF40075A7 +:107DF000044600212A46184606F0A0FF4FF0203125 +:107E0000EB22A0F80B50C0F803100346C0F807108F +:107E100090210270762099700222587094F82B10ED +:107E200059734AF65521208D1A74F822D8815A7553 +:107E30002269DA61A269A3F8FE111A6238BD00BF97 +:107E400070B504464FF400720021406A06F076FFD8 +:107E5000656A2269216805F2BF1003F07DF9A36904 +:107E6000226905F2C31021681A44013A03F074F93B +:107E700094F82A204AF6552385F8C2212269E06940 +:107E8000C5F8C621626AA169A5F8FE310368C5F884 +:107E9000CA1100215B6ABDE87040184770B5466999 +:107EA0004FF4807390F82BE00446A6F58072456A83 +:107EB0004360B2FBFEF202F2011C4FEA1C214FEAC2 +:107EC000410C81600CF1A10098420ED98033F21A66 +:107ED000B2FBFEF202F20111090A4FEA410C0CF169 +:107EE000A1008342F2D3C4E901311B1AA2F6F57155 +:107EF00003F18000B1F5704F20614FD20CF1210CDD +:107F00008133204602FB0EC2E360B2F5803FA261DE +:107F100034BF0423062384F82A3001232385FFF786 +:107F20008FFF08B9002070BD2046FFF75DFF2922B2 +:107F3000A1684FF0203385F826204622C5F82F305F +:107F4000802085F836205422C5F82B30C5F8323011 +:107F5000312385F838203622E982412185F83930ED +:107F600085F837104FF4007185F8240085F83A2021 +:107F70000F4BE069C5F827300368A5F81110626A55 +:107F800021695B6A98470028CCD062682046E36884 +:107F90001021D21ABDE87040FFF796BE206A002873 +:107FA000C0D00368132203495B689847002070BD66 +:107FB00087D61200C0050020F8B546694FF400537B +:107FC00090F82BC04FF48042A6F58041036142F245 +:107FD000090E0446456A4260B1FBFCF101F18103E0 +:107FE000DB0983600EEB4300904240F2B68002F55D +:107FF0000052B11AB1FBFCF101F18103DB090EEB78 +:1080000043005F008242F2D3C4E901234FF6F473C8 +:10801000994240F2978001FB0C2CA2F500522046B9 +:10802000D21B92B202F5005322854D4AE360ACF5B3 +:108030000053944594BF4FF00B0C4FF00C0CA36110 +:1080400084F82AC0FFF7FCFE08B90020F8BD2046DE +:10805000FFF7CAFEA16829224FF020338020696211 +:1080600085F8422054214622C5F84B3085F840005F +:108070004120C5F84730C5F84E30022385F852201C +:10808000332285F85410322185F8552085F85300A5 +:1080900085F85610EB62E069324B334A2B63036874 +:1080A000C5F843205B6A626A216998470028CCD0F2 +:1080B000E069216903680631626A5B6A98470028B3 +:1080C000C3D04FF400720021606A06F037FEE06909 +:1080D000264A0368C5F8FC2121695B6A0231626A9D +:1080E00098470028B1D0E069216903680831626AC5 +:1080F0005B6A98470028A8D04FF0FF33E0691C4A1C +:10810000C5E97A331B4B2A60C5F8E431036821695D +:10811000626A5B6A01319847002896D0E06921695C +:108120000368626A07315B6A984700288DD0A268AD +:10813000204694F82B30202103EB4202BDE8F840A2 +:10814000FFF7C2BD206A00283FF47FAF0368132207 +:1081500009495B6898470020F8BD5F0056E700BFFB +:108160000004FB000100060087D61200000055AA9B +:108170005252614172724161C005002038B5044617 +:108180000D68C16108466262EA692362904700F2A5 +:10819000FF736061DB0A062B236024D9102B13D8F0 +:1081A0000223B0F5800F84F82B3020462ED2FFF743 +:1081B00075FE0546206A05B320B103680D221949F2 +:1081C0005B689847284638BD202B23D9402B23D9FC +:1081D000802B23D9B3F5806F22D9B3F5004F8CBF24 +:1081E00080234023DDE7206A20B1036814220E4972 +:1081F0005B6898470025284638BD0028FAD00368F8 +:108200000F220A495B689847284638BDFFF7D4FE1D +:108210000546CFE70423C4E70823C2E71023C0E7DD +:108220002023BEE7A005002088050020B00500201F +:10823000042A04D801EB4202B2F8010070470A2A6E +:1082400003D801EB4202908870470C2A03D801EB57 +:108250004201C88870470020704700BFF8B5047815 +:108260000E467CB114F06004174607D0012A09D9E4 +:108270002F22002301200A704B70F8BD2146FEF723 +:1082800047F918B9002318463370F8BD0346A446D1 +:10829000082111E0027B114203D00EF1200E5FFA9B +:1082A0008EFE651CBD42EDD20CF1010C06F804E017 +:1082B000ECB2BCF10C0F10D0BCF1080F11D013F8C8 +:1082C00001EBAEF14102192AE4D9BEF1200FE8D149 +:1082D0000CF1010CBCF10C0FEED1002320463355FC +:1082E000F8BD1A78202AF8D010214FF02E0ED8E7CA +:1082F0002DE9F04F00248BB0037889460194002BC0 +:1083000055D0C3780646002B58D0014601A89046A8 +:10831000FEF71EFB00284AD0F078002843D008F171 +:10832000FF38CB464FF0010AC844B18801A8A1EB41 +:108330000A0189B24901FEF79FFDC0B3002101A8DF +:10834000FEF73AFC98B3C37A0F2B30D103785FFA6B +:108350008AF103F01F038B4229D1471C0025042D0D +:10836000EBB23FD83B8874BB03F5205189B2B1F51D +:10837000006F3ED3A3B118465946424602F03CFF77 +:108380008346A0B10024013502370D2DE7D10AF153 +:10839000010AF1785FFA8AF31FFA8AFA9942C4D285 +:1083A000ABEB0900D946002389F8003003E0002335 +:1083B000184689F800300BB0BDE8F08FFFF74EFF8C +:1083C0000BB0BDE8F08F03F5105189B2B1F5806FA5 +:1083D000EDD20A4AC3F3090302EA8420184300F5E8 +:1083E0008030C9E70A2B94BFB7F80330B7F80530DF +:1083F000B9E7B1F5806FDAD21C46C4E700FC0F0084 +:10840000FFF776BF2DE9F843DDE90887C3B1814660 +:108410000C4615465E1802E0C047B44210D0D9F8A9 +:10842000003021462A4648461B69984703463A468B +:10843000204629460134002BEED11846BDE8F883CA +:1084400001231846BDE8F88310B41468B4F5807FA2 +:10845000A44628BF4FF4807C01EB4C00814207D238 +:1084600031F8023B13B95368013353608842F7D89F +:10847000A4EB0C0414605DF8044B704710B414684E +:10848000802CA44628BF4FF0800C01EB8C00814269 +:1084900007D251F8043B13B9536801335360884243 +:1084A000F7D8A4EB0C0414605DF8044B704700BFD0 +:1084B0002DE9F843C37904460D461746202B59D0C1 +:1084C000102B30D00C2B51D1027AC1F34E018369AD +:1084D00000F50E7911FA85F1A2F1020248468EB23A +:1084E000B2FA82F2C1F34621520901EB03085200AD +:1084F000414602F0E3FD002838D0C6F30806731C9D +:10850000865DB3F5007F23D018440378EA07E2695B +:1085100046EA03234CBF1B09C3F30B039A4240D224 +:108520000020BDE8F883027AC1F30721836900F5D2 +:108530000E70A2F102021944B2FA82F252095200FC +:1085400002F0BCFD90B16D0005F4FF75435B25E0C2 +:10855000227A08F101014846A2F10202B2FA82F23F +:108560005209520002F0AAFD0028CED14FF0FF3090 +:10857000BDE8F883027A816900F50E70A2F102026B +:1085800001EBD511B2FA82F25209520002F096FDC7 +:108590000028EBD0AD0005F4FE754359E2699A421C +:1085A000BED301203B60BDE8F88300BF2DE9F8434E +:1085B000C37905460C461646202B48D0102B2DD0EB +:1085C0000C2B41D1C1F34E01836900F50E7911FAEC +:1085D00084F11FFA81F8C1F34621CF18037A484687 +:1085E000022B394614BF0122032202F067FD58B363 +:1085F00014F00104C8F308033FD0C25C02F00F027C +:1086000042EA0612C2540133B3F5007F3AD0C6F3F2 +:108610000712034401201A70BDE8F883027AC1F3FF +:108620000721836900F50E70022A194414BF012244 +:10863000032202F043FD034630B16400012004F43C +:10864000FF741E53BDE8F8830020BDE8F883037A69 +:10865000816900F50E70022B01EBD41114BF0122C9 +:10866000032202F02BFD03460028EDD0A4000120D8 +:1086700004F4FE741E51BDE8F883C6540133B3F50B +:10868000007F15D12B7A791C4846022B14BF01229A +:10869000032202F013FD03460028D5D0C6F30712CB +:1086A000002CB7D1197821F00F0141EA1212B1E77D +:1086B000C6F307120344F5E72DE9F041C46882B020 +:1086C00005460E468C42904640D301270134EB69A3 +:1086D00001AA2846A34205D29FBBEC6801273C446F +:1086E000A3422ED3A64218BF012C214629D9FFF759 +:1086F000DFFE002825DBE9D0019B002BE6D107B186 +:10870000EC60EB69A3421CD36FF07042214628460F +:10871000FFF74CFF0746A0B13EB96B6A002B01DBA7 +:10872000013B6B62C8F800400CE0012E09D0EB69F8 +:108730009E4206D8314622462846FFF737FF0028DA +:10874000EBD10027384602B0BDE8F0810C46002787 +:10875000BCE700BF01290CD910B4C4698C4203D313 +:108760005DF8044BFFF7A4BE4FF0FF305DF8044BFB +:1087700070474FF0FF30704701290BD910B4C4691E +:108780008C4203D35DF8044BFFF710BF00205DF867 +:10879000044B70470020704770B5054682B00C4608 +:1087A0001DE0EB699C421FD8FFF782FE064621467A +:1087B0000022002E284617DBEB699C4214D8FFF7F5 +:1087C000F5FE621E80B16B6A002B03F10103A8BFA6 +:1087D0006B62EB68A342019C88BFEA602EB1012C5A +:1087E000214601AA2846DCD8002002B070BD00BF97 +:1087F0002DE9F0470646406A84B000281BDAF2797A +:108800000C2A1BD1F7697B1C022B40F2CD8002247D +:108810000025214602AA3046FFF74AFE002804F14F +:10882000010306DB57D1A7421C465CD0F269934294 +:10883000EFD94FF0FF3004B0BDE8F087F1690020B8 +:1088400096F8383201313469DB07CDE9021000F1C6 +:10885000858000214FF0FF33202A06F5127786F835 +:108860003812C6F8443242D0D6F800804F4BD8F8C0 +:108870000020D6F818A095699D4278D1002C00F010 +:1088800082800AEB0409136951463A4640469847EC +:108890000028CED00299B1F5807F8E4628BF4FF4D4 +:1088A000807E07EB4E0CBC450BD9039D3B46002256 +:1088B00033F8024B0CB9013502469C45F8D802B199 +:1088C00003950AF1010AA1EB0E01D14502915AD09C +:1088D000D8F80020D7E7029A002AA4D1A74205F1D0 +:1088E00001051C46A2D1284604B0BDE8F087D6F8A1 +:1088F00000A02E4BDAF80020D6F8189095699D421A +:1089000046D1002C3FD009EB0408136949463A468A +:108910005046984700288CD0DDF808C0BCF1800F85 +:10892000E64628BF4FF0800E07EB8E02BA420BD905 +:10893000039D3B46002153F8044B0CB90135014619 +:108940009A42F8D801B1039509F10109ACEB0E0385 +:10895000C845029317D0DAF80020D6E706F50E7066 +:1089600002F080FB00283FF464AFF27971E7234600 +:1089700002AC3A465146019440460D4C0094A8473B +:1089800000283FF456AF0398706204B0BDE8F0874A +:10899000234602AC3A46494601945046054C0094A1 +:1089A000A8470028EFD144E7002044E7C563000052 +:1089B000096400003D64000070B5002304461546BC +:1089C00001204FF0FF3204F128062160E371E060DE +:1089D000E162C4F83C1284F8283084F838326263CB +:1089E000C4F84422CDB1042D01D9002070BD1A462F +:1089F0001946304602F062FB6FF0704300F5DF72FB +:108A00002B441D0102EB03130028EED01979002935 +:108A1000EBD0525D5206E8D19D68002229463046CF +:108A200002F04CFB0028E0D0B0F80B30B3F5007F2B +:108A3000DBD1037C5A1E2372012AD6D8417B4B1E00 +:108A40000129217163714FF00003A37144D0012209 +:108A500052000133D2B2DBB2914204D0082BF7D1DD +:108A60000020A37170BD1E46A371C18A216109B99E +:108A7000416A2161C289B0F811302A4463815B01E7 +:108A8000A26190F810C003F2FF1301FB0C2202EB6D +:108A900053232262B0F81320636102B9026AED1A0F +:108AA000AB18F3405A1CE2614FF0FF32626240F6AD +:108AB000F47293420CD94FF6F47293420AD9C26A07 +:108AC000202322620120E3712163C4F8401270BDAB +:108AD0000C23F7E71023F5E71E46C6E7F8B5002696 +:108AE0008F6B0D460446C0E90E669FB101462420F7 +:108AF00000F0DCF8068086708446AD6BA0630FCD75 +:108B0000ACE80F000FCDACE80F002B68CCF80030BC +:108B10002046F8BDCB6B002BFAD00146382000F080 +:108B2000C5F880F8317047860246EB6BE06303F1CD +:108B300030071E68103353F80C5C103253F8080CE1 +:108B400053F8041CBB4242F8106C42F80C5C42F82B +:108B5000080C42F8041CECD11B6820461360F8BDD9 +:108B600010B50446806B10B1FDF7E2FC30B9E06B44 +:108B700010B1FBF7CFFB20B9002010BD0023A36389 +:108B800010BD0023E36310BD002952D02DE9F04150 +:108B90000446806B0D4617461E4610B1FDF7C8FC13 +:108BA000A0BBE06B10B1FBF7B5FBB8BBD5F8808478 +:108BB000B8F1000F11D02146242000F077F8334699 +:108BC00000263A4606808670A063D5F88014FDF72B +:108BD000B7FE58BBA063BDE8F081D5F8843493B1EB +:108BE0002146382000F062F8334680F831803A465A +:108BF000A0F83280E063D5F88414FBF7BFFFA8B972 +:108C0000E063BDE8F0810020BDE8F0810023D5F8E5 +:108C10008084A363B8F1000FCDD1DEE70023D5F83F +:108C20008084E363B8F1000FC5D1D6E70120BDE829 +:108C3000F0810020704700BFF8B50446806B0D46F8 +:108C4000174610B1FDF774FC38BBE06B10B1FBF7B1 +:108C500061FB38BBAE6B76B12146242000F026F8CC +:108C600000213A4601808170A063A96BFEF7CEF91E +:108C700088B9A063F8BDE86B0028FBD021463820F6 +:108C800000F014F83A4680F831604686E063E96BFC +:108C9000FBF77CFF20B10120F8BD0023A363D9E7D7 +:108CA000E063F8BD0023E363D4E700BF08467047E4 +:108CB0002DE9F041002604469846C0F88814C0F813 +:108CC000806401464FF490601746FFF7EFFF42467D +:108CD00080F84464054680F87964A0F87A64C4F8A2 +:108CE0008404D4F88814FDF7E7FAA0BB00262146D7 +:108CF00040F26C40C4F88464FFF7D8FF0223C671C9 +:108D00004246A0F84864054680F84A640372C4F8F5 +:108D10008004D4F88814FFF74FFE38B900231A4AAC +:108D200018461360C4F88034BDE8F08105F5896603 +:108D30003046FDF7FDFB29463046FDF737FE00289B +:108D4000ECD0124B1A68AAB91D600F4BAFB10120CD +:108D50001C60BDE8F08105F589663046FBF7DAFA5C +:108D600029463046FBF704FB0028BFD0084B1A68A1 +:108D7000002AE9D0044B002FE9D11A68002AE6D076 +:108D80000120BDE8F08100BFCC270020D0270020C3 +:108D9000BC26002070B500254FF47A760446456065 +:108DA00005738660C0E91255034D40F8105BFFF76C +:108DB000EBFE204670BD00BFE00700204FF0FF3003 +:108DC000704700BF407C7047007D7047407D704712 +:108DD00001207047007F70472DE9F0471E46C37C95 +:108DE00005460C46022B9146089F28D02B68214649 +:108DF00028461B6E984798B1AC61B9F1000F12D0AC +:108E000004EB090801E0A0450DD039462046B047E3 +:108E10002B6801462846DB6D013498470028F2D1C3 +:108E20000020BDE8F087AB69287F4B44AB61002888 +:108E3000F7D12B6828465B6EBDE8F0471847836979 +:108E40008B42D3D1D9E700BF704700BF043002F096 +:108E5000B5B800BF10B50446202103F07DFD2046C3 +:108E600010BD00BF2DE9F0411F46C37C05460E46EC +:108E7000022B144624D02B68314628461B6E984797 +:108E800078B1AE6187B1002601E0B7420CD02A6804 +:108E9000214628460136D26D04F50074904700281B +:108EA000F3D10020BDE8F081AB69287F3B44AB6182 +:108EB0000028F7D12B6828465B6EBDE8F0411847C3 +:108EC00083698B42D7D1DDE72DE9F041204E07467B +:108ED00000F10408356805F51675ADB203E0336896 +:108EE000EB1A1B0410D4404602F06CF8FF2804462D +:108EF000F5D1FD21404602F083F8BB7CCBB90023BD +:108F00000120FB74BDE8F0811E23B87C7B7400282F +:108F1000F8D0387C012102F009F8FF21404602F028 +:108F20006FF8404602F022F800231846BB74BDE8F3 +:108F3000F0810121387C01F0F9FF2146404602F022 +:108F40005FF8404602F012F80023BB74D7E700BF79 +:108F5000C42B00202DE9F041C37C012B35D0867C49 +:108F600004464EB1043002F02DF8B0F1FF0518BFF1 +:108F700001252846BDE8F081071D4FF0010838465D +:108F800001F0D6FF3146207C01F0D0FFFF213846AA +:108F900002F036F8384684F8128002F013F8A37C09 +:108FA000B0F1FF0518BF0125002BE2D04146207C1F +:108FB00001F0BCFFFF21384602F022F8384601F0EC +:108FC000D5FF2846A674BDE8F08100252846BDE8F7 +:108FD000F08100BF2DE9F843204F044688469146B2 +:108FE0003D68061D05F59675ADB203E03B68EB1ACA +:108FF0001B040DD4304601F0E5FFFF282075F5D0A5 +:10900000FE281AD01823A07C637430B9BDE8F88319 +:109010001D23A07C63740028F8D0207C012101F07E +:1090200085FFFF21304601F0EBFF304601F09EFF47 +:1090300000231846A374BDE8F8834A4641463046EB +:1090400001F0CCFF207538B9304601F0BBFF304647 +:1090500001F0B8FF0120D9E72523D4E7C42B002075 +:10906000F0B5002783B00C2104463A46C77400F0DF +:109070005BF8B0B9A67C1EB90126304603B0F0BD3E +:1090800005460121207C01F051FF201DFF210190A8 +:1090900001F0B6FF019801F069FF3046A57403B0F6 +:1090A000F0BD0923A67C6374002EE6D0251D207C2C +:1090B00001213E4601F03AFFFF21284601F0A0FFC2 +:1090C000284601F053FF3046A77403B0F0BD00BF3F +:1090D000C27C022A03D0012A04D001207047036811 +:1090E0005B6E1847FFF7BCBF38B503680D460D49E6 +:1090F00004461A6A8A420CD1C27C022A04D0012A90 +:109100000BD00120257738BD5B6E98470028F8D139 +:1091100038BD90470028FBD0F3E7FFF7A1FF0028F8 +:10912000F6D0EEE7917000002DE9F041036882B0BF +:109130000F463549019206461A6A8A425ED1C27CC0 +:10914000022A41D0012A5BD0B47C002C47D0351DC7 +:109150000C2F11D0DFF8B480D8F8004004F59674D5 +:10916000A4B204E0D8F80030E31A1A0434D4284634 +:1091700001F028FFFF28F5D10DF1040802AC47F0FB +:109180004001284601F03CFF14F8011D284601F07B +:1091900037FFA045F8D1002F28464FF00A040CBF36 +:1091A0009521872101F02CFF284601F00BFF28466E +:1091B000013C01F007FF0306A4B2307501D5002C75 +:1091C000F5D102B0BDE8F0815B6E98470028BBD1B5 +:1091D000FF2002B0BDE8F081002FCDD0F8E7351DAB +:1091E000284601F0A5FE2146307C01F09FFEFF21BC +:1091F000284601F005FF0123B374A9E79047E5E78E +:10920000FFF72EFFE2E700BF91700000C42B0020A3 +:109210002DE9F04788B005464FF00008174601AC2D +:109220002E1D85F8128085F8118085F8158084E858 +:109230000E009DF80400287401F074FE0121287CC2 +:1092400001F074FE6C490723C5E9021394E8070096 +:1092500005AB83E8070030460ECB01F073FEAC7C13 +:1092600085F81380002C67D00A240121287C01F0A6 +:109270005DFEFF21304601F0C3FE611E11F0FF04C8 +:10928000F7D121460A24287C01F050FE002228460E +:109290001146FFF749FF012804F1FF3304460AD0C5 +:1092A00013F0FF04F2D10123A87C6B74002851D184 +:1092B00008B0BDE8F0874FF4D57208212846FFF7C3 +:1092C00033FF420757D56C752B68DFF830A19B6DD3 +:1092D000534561D1687DA0F10204DFF82491B4FA0E +:1092E00084F4D9F80030640903F5FA68A4071FFA7A +:1092F00088F805E0D9F80030A8EB03031B0449D433 +:10930000372100222846FFF70FFF22462921284651 +:10931000FFF70AFF0028EDD12B689B6D534565D1FF +:10932000687D022849D0AB7CCBBB07230120C5E96F +:10933000027308B0BDE8F087304601F0F9FD214620 +:10934000287C01F0F3FDFF21304601F059FE012396 +:10935000AB7489E7287C012101F0E8FDFF2130464C +:1093600001F04EFE304601F001FE00231846AB74BA +:1093700008B0BDE8F087022304246B75304601F085 +:1093800021FE631E287513F0FF04F7D1AA289BD095 +:10939000062389E7172387E7284698479BE701219B +:1093A000287C01F0C3FDFF21304601F029FE304644 +:1093B00001F0DCFD0023AB74B7E700223A21284618 +:1093C000FFF7B2FEA8B9304601F0FCFD00F0C00086 +:1093D000C02801D103236B75304601F0F3FD304600 +:1093E00001F0F0FD304601F0EDFD9CE7284698477E +:1093F00097E7122358E700BF801A06008D6D000022 +:10940000C42B0020F8B500220D463A210646FFF78E +:109410008BFEE0B9371D2C1D384601F0D3FD04F852 +:10942000010DA542F8D1B47C14B901242046F8BD41 +:10943000307C012101F07AFDFF21384601F0E0FD8A +:10944000384601F093FD00232046B374F8BD122383 +:10945000B47C7374002CE9D0341D307C012101F000 +:1094600065FDFF21204601F0CBFD204601F07EFD89 +:1094700000231C46B3742046F8BD00BF70B51646E5 +:1094800082B000220446FFF74FFEB0B11B23637485 +:10949000A07C08B902B070BD251D207C012101F01F +:1094A00045FDFF21284601F0ABFD284601F05EFD99 +:1094B00000231846A37402B070BD05461022314641 +:1094C0002046FFF787FD0028E2D0A67C002EE1D0E1 +:1094D000207C012101F02AFD201DFF21019001F0D7 +:1094E0008FFD019801F042FD3046A57402B070BDB9 +:1094F0000368254ADB6C934200B585B00FD16A46FC +:109500000921FFF7BBFF38B19DF8003013F0C0030D +:1095100008D0402B27D0002005B05DF804FB694639 +:109520009847F0E79DF809309DF80A2003F00303FF +:109530009DF806109DF807005B0001F00301800014 +:109540009DF808C043EAD2139DF8052040EA812027 +:1095500002F00F0240EA9C1013440130073B984090 +:1095600005B05DF804FB9DF809009DF80730013057 +:109570009DF8082003F03F0300EB034000EB0220BE +:10958000800205B05DF804FB6D78000003680A46B0 +:1095900030B59B6D83B0164D0446AB4224D1407D5F +:1095A00003284FF01201204618BF5202FFF7BCFDFE +:1095B00020B901231846E37403B030BD0C23A07C0E +:1095C00063740028F8D0251D207C012101F0AEFC39 +:1095D000FF21284601F014FD284601F0C7FC0023B6 +:1095E0001846A37403B030BD01919847019AD7E79C +:1095F0008D6D0000F8B51446C27C06460D46012A62 +:109600001F4602D183698B4205D029463046FFF7B9 +:10961000BDFF80B1B56187B1002501E0AF420CD03C +:1096200021464FF400723046013504F50074FFF70F +:10963000D1FC0028F2D10020F8BDB369307F3B4453 +:10964000B3610028F8D13046BDE8F840FFF708BD07 +:109650002DE9F84F9B46C37C06460C46012B154668 +:10966000DDF82890DDF82C8002D183698B4205D08B +:1096700021463046FFF78AFFB0B1B461BBF1000F5D +:1096800015D004EB0B0A02E0C847A2450FD04FF4F7 +:10969000007229463046FFF79DFC074642462046A9 +:1096A00029460134002FEFD10020BDE8F88FB369BF +:1096B000307F5B44B3610028F7D13046BDE8F84FF6 +:1096C000FFF7CEBC03682DE9F0415F69164B9F425E +:1096D0001FD1C37C04460D461646012B02D1836977 +:1096E000994205D029462046FFF750FF70B1A56189 +:1096F0004FF4007231462046FFF76CFC30B1A3698D +:10970000207F0133A36148B1BDE8F0810020BDE8AE +:10971000F081BC460123BDE8F04160472046BDE82A +:10972000F041FFF79DBC00BFB575000003680A4615 +:1097300030B59B6D83B0164D0446AB4224D1407DBD +:1097400003284FF01901204618BF5202FFF7ECFC26 +:1097500020B902230120E37403B030BD0E23A07CA6 +:1097600063740028F8D0251D207C012101F0DEFB68 +:10977000FF21284601F044FC284601F0F7FB0023B6 +:109780001846A37403B030BD01919847019AD7E7FA +:109790008D6D000003682DE9F043DB6C1746414AEC +:1097A00085B004460E46934245D16A460921FFF72B +:1097B00065FE0546B5B19DF80A305A0618D5637D99 +:1097C000032B01D076027F02324620212046FFF78C +:1097D000ABFC28B93A4621212046FFF7A5FC70B31F +:1097E00026236374A57C9DB9284605B0BDE8F083A7 +:1097F00003F03F039DF80B205B0043EAD2137A1C71 +:1098000032431342DBD02723A57C6374002DEBD0B9 +:10981000251D207C012101F089FBFF21284601F054 +:10982000EFFB284601F0A2FB00231D46A374284647 +:1098300005B0BDE8F083694698470546BAE7024699 +:1098400026212046FFF770FC0028C9D1DFF8588098 +:1098500042F2107704F10409D8F800301F44BFB277 +:1098600004E0D8F80030FB1A1B0417D4484601F076 +:10987000A9FBFF280646F4D1A37C002BB4D001211C +:10988000207C1D4601F052FB3146484601F0B8FBF2 +:10989000484601F06BFB0023A374A5E728236374FB +:1098A000A0E700BF6D780000C42B002070B5002237 +:1098B00082B00E4609210446FFF736FCB0B11B23E7 +:1098C0006374A07C08B902B070BD251D207C012105 +:1098D00001F02CFBFF21284601F092FB284601F005 +:1098E00045FB00231846A37402B070BD0546102244 +:1098F00031462046FFF76EFB0028E2D0A67C002E02 +:10990000E1D0207C012101F011FB201DFF210190FD +:1099100001F076FB019801F029FB3046A57402B0F6 +:1099200070BD00BF70B5002282B00E460A21044609 +:10993000FFF7FAFBB0B11B236374A07C08B902B037 +:1099400070BD251D207C012101F0F0FAFF21284681 +:1099500001F056FB284601F009FB00231846A374CA +:1099600002B070BD0546102231462046FFF732FB9B +:109970000028E2D0A67C002EE1D0207C012101F05D +:10998000D5FA201DFF21019001F03AFB019801F06A +:10999000EDFA3046A57402B070BD00BF70B5051D6C +:1099A00016460446284601F02BFB4FF40072314660 +:1099B000284601F02FFBFF21284601F021FBFF2163 +:1099C000284601F01DFB284601F0FCFA00F01F03B9 +:1099D0002075052B04D02023A07C637410B970BDC2 +:1099E000012070BD207C012101F0A0FAFF21284652 +:1099F00001F006FB284601F0B9FA00231846A374CB +:109A000070BD00BF2DE9F041174D06460F4600F12D +:109A100004082C6804F51674A4B203E02B68E31A5A +:109A20001B040CD4404601F0CDFAFF28F6D13A468B +:109A3000FC213046FFF7B2FF18B1BDE8F0812423C6 +:109A40007374B07C0028F8D0307C012101F06EFAEC +:109A5000FF21404601F0D4FA404601F087FA002386 +:109A60001846B374BDE8F081C42B0020036870B5BC +:109A70009B6D1646224A82B004460D4693423CD165 +:109A8000407D03284FF01801204618BF6D022A467A +:109A9000FFF74AFB0546B0B10D236374A07C08B9FB +:109AA00002B070BD251D207C012101F03FFAFF218D +:109AB000284601F0A5FA284601F058FA0023184676 +:109AC000A37402B070BD3246FE212046FFF766FF48 +:109AD0000028E3D0A67C002EE2D0207C012101F0FA +:109AE00025FA201DFF21019001F08AFA019801F06A +:109AF0003DFA3046A57402B070BD9847C1E700BF7B +:109B00008D6D000010B4047F34B104680123A46A91 +:109B1000A4465DF8044B60475DF8044BFFF7A6BF11 +:109B200010B584B004460DF1040C8CE80E009CE8DE +:109B30000E00FFF76DFB20B19DF8053003F0010327 +:109B4000237704B010BD00BF00207047002070478D +:109B500000207047704700BF084B0021084A0948A1 +:109B600010B499631C6B146012685DF8044B1A639F +:109B70009A6C22F081029A640170704700002C40B8 +:109B800038260020F82B0020034B586A80F08070A4 +:109B9000C0F30060704700BF00002C40014B1878F4 +:109BA000704700BFF82B00202B4A2C4B526AD3F889 +:109BB00000312B49C2F3C22203F03F03013270B5DA +:109BC000284C4FF47A75A4FB034305FB00F09B0877 +:109BD000B1FBF3FEBEFBF2FEB0EB1E1F35D201233C +:109BE0001E465B001A01BEFBF2F2824201D9FF2B36 +:109BF000F6D9BEFBF3F2360290422AD24FEA430C6A +:109C0000012200E0A446154603EB0C040132BEFB22 +:109C1000FCF1814217D9102AF4D1F0254FF47A7360 +:109C20001149124A03FB0CFCBEFBFCF30B60104B0A +:109C3000D16A0B402B43334343F46023D362536A0E +:109C40001B07FCD570BD2D01E8E7724600260123F5 +:109C5000D2E79C460025E1E700C00F4000800D40A0 +:109C600000EC695EABAAAAAA0426002000002C40E2 +:109C70000F00F0FF014B1878704700BFF61A002064 +:109C8000014B1868704700BF3826002010B4074CFD +:109C90008C460FCCCCF800000120CCF80410CCF896 +:109CA0000820CCF80C305DF8044B70470C260020DF +:109CB00010B4074C8C460FCCCCF800000120CCF837 +:109CC0000410CCF80820CCF80C305DF8044B704739 +:109CD0001C260020024B01201B680B60704700BF50 +:109CE0002C260020704700BF10B504460C2102F05E +:109CF00033FE204610BD00BF044B1B7823B1044B3C +:109D000018780230C0B2704701207047F52B002050 +:109D1000F62B0020184B1A7812F0C0020FD0402A00 +:109D200001D000207047587ADA79197A013002F0B0 +:109D30003F0300EB034000EB0120800270475A7A9A +:109D40009979D87902F0030293F808C001F0030171 +:109D50008000520040EA812000B593F80AE040EA12 +:109D60009C105B7942EADE12013003F00F031344CA +:109D7000073B98405DF804FB1C260020404A052064 +:109D8000404938B5D2F800413F4B44F080043F4D84 +:109D9000C2F80041D2F8004124F03F04C2F800416B +:109DA000D2F8004144F01804C2F80041D2F8004152 +:109DB00024F08004C2F80041D3F8802042F00C0265 +:109DC000C3F880205A6A22F460525A62DA6942F477 +:109DD0008032DA615A6A42F400625A62C1F8CC01F8 +:109DE000C1F8D001C1F8BC01C1F8C001C1F8C4017B +:109DF000C1F8C801AA6C264B42F00042AA64EA6A84 +:109E00001343EB62EC6A14F08074FBD14FF4C8701A +:109E1000FFF7CAFE1B4B47F2B80241F2B801C3F884 +:109E2000CC411C48C3F8D041C3F8BC41C3F8C04181 +:109E3000C3F8C441C3F8C841C3F8BC23C3F8C02366 +:109E4000C3F8AC23C3F8B013C3F8B4231249C3F862 +:109E5000B823124B6863C1F8F8314FF0E0234FF498 +:109E600080420F49602081F86E00C3F80C21EB6A34 +:109E7000064A43F00063EB62D36A1B01FCD438BD91 +:109E800000800D4000801F4000C00F4000002C40AB +:109E9000008000010B007F11001C0020197B0000D6 +:109EA00000E400E02DE9F04102F014FC174E184DDB +:109EB0000746DFF8748004E002F00CFCC01B40454C +:109EC0001BD8346B2C40F7D0124A0021124B117072 +:109ED000326B1A601968114A31631B68134209D04A +:109EE0000F491F240F4B40F27A2200200C701A6099 +:109EF000BDE8F0810120BDE8F081064A064B1470F0 +:109F0000326B1A601B683363EAE700BF00002C4025 +:109F100002007F11F72B00203826002000007F115F +:109F2000F61A00200826002040420F002DE9F843D1 +:109F3000264C0F462378002B38D1254B5A6AD20580 +:109F40002BD5234DDFF89480AB6A43F48033AB62AA +:109F500002F0C0FB064604E002F0BCFB801B40455B +:109F60002AD86B6A13F48069F6D007F13C0C1848C4 +:109F700007F50F77436A5B05FCD5ACF1400353F856 +:109F8000042F9C450262FAD10CF1400CBC45F1D182 +:109F9000012318462370BDE8F8839A6A22F48032C0 +:109FA0009A629A6A42F400329A62CAE7FFF77AFF2D +:109FB0000028C2D1BDE8F88306492124064B4FF49E +:109FC0007E7248460C701A60BDE8F883F72B0020BB +:109FD00000002C40F61A00200826002040420F0006 +:109FE0002DE9F041074688461F4C02F073FB1F4ED7 +:109FF000054604E002F06EFB431BB34224D8636ABB +:10A00000D907F7D4BB02C4F8088020D427F0FF0397 +:10A01000154C174EE36002F05DFB144F054604E05B +:10A0200002F058FB401BB8420ED8236B3342F7D0E6 +:10A03000226B104B1A601A6822631A68D20703D584 +:10A040001B6813F4702F0BD00020BDE8F081A26CC8 +:10A05000FBB222F0FF02A264A26C1343A364D5E713 +:10A060000120BDE8F08100BF00002C4040420F00FD +:10A0700001000F0038260020154B30B50D4685B085 +:10A080001968FFF7ADFF08B3124B05F10F041A6909 +:10A0900000925969019199690291DB690393002348 +:10A0A00001E05EF8102C03F0030C01334FEACC0CF6 +:10A0B00023F0030E0F2B22FA0CF20EF1100104F81C +:10A0C000012D0DEB010EECD10023EB7305B030BD7B +:10A0D0003026002000002C4010B5037ADB0705D5A0 +:10A0E000154B1B68B3B1BDE810401847134B1B78E4 +:10A0F0003BB9134B5C6A84F08074C4F3006420465F +:10A1000010BD0F4B0F4C1B6B1C40B4FA84F4640958 +:10A11000204610BD0C4B1C78002CF0D00B4B0C488B +:10A120001968FFF75DFF0028E9D0054B1C6984F42E +:10A130008074C4F30024E2E734260020F72B0020CB +:10A1400000002C4002007F11F42B0020302600205C +:10A1500000001A0D08B5044B04481968FFF740FFCA +:10A1600008B1034B186908BD3026002000001A0D05 +:10A1700000002C4008B5074B07481968FFF730FF6F +:10A1800030B1064B186980F48070C0F3002008BD20 +:10A19000012008BD3026002000001A0D00002C40D0 +:10A1A0002DE9F047294B8946DFF8C0A0284ECAF8B0 +:10A1B000003002F08FFA274D0446DFF8B480264FB6 +:10A1C00006E002F087FA001BB84229D803F04AFEE5 +:10A1D00031682846FFF704FF0028F2D0D8F8103085 +:10A1E000DB05EED500234FF40072CAF80030D8F832 +:10A1F000283023F48033C8F82830184BC8F80420DE +:10A200001B78CBB149461648FFF7EAFE30B915492D +:10A210000E24154B40F257420C701A60BDE8F087CF +:10A22000104A0A210020104B117040F24B42CAF82C +:10A2300000001A60BDE8F0874FEA492908484946FE +:10A24000FFF7CEFE0028E9D1E1E700BF358100002D +:10A250003026002000001A0D40420F00F62B00208F +:10A2600020003A19F61A0020082600203426002083 +:10A2700000002C402DE9F041254C00212548A36A1F +:10A2800023F48033A362FFF7ABFE054648B92249A9 +:10A290000920224B40F23D2208701A602846BDE892 +:10A2A000F0811F4BDFF88080C8F8003002F012FA0E +:10A2B000636A0646D80118D41A4F04E003F0D2FDB1 +:10A2C000636AD90111D402F005FA831BBB42F5D9A8 +:10A2D000114A0A210025114B11704FF410722846C3 +:10A2E000C8F800501A60BDE8F0810022084BC8F899 +:10A2F00000205A6A9207D1D5586B9A6AD96A22F41B +:10A30000803241F08061D96258639A62C6E700BF2B +:10A3100000002C400000DB0CF61A0020082600206C +:10A32000497B000040420F00342600202DE9F04711 +:10A3300082468946364E02F0CDF9364D0446DFF8A6 +:10A340000081354F04E002F0C5F9031BBB4227D85A +:10A3500031682846FFF744FE0028F4D0D8F81030C2 +:10A36000DA05F0D501232D4D2D4F51462B700023DA +:10A370002C483B602C4BC8F80090C8F804302B4B9D +:10A38000C8F83830FFF72CFE0446A0B9284904204D +:10A39000284B40F29F12087020461A60BDE8F087F3 +:10A3A00023490A20234B4FF4CC72002408701A6012 +:10A3B0002046BDE8F087204BDFF88890C9F80030D0 +:10A3C00002F088F92B780646BBB1DFF84C8003E039 +:10A3D00003F048FD2B7883B102F07CF9831B4345E1 +:10A3E000F6D90023C9F8003011492520114B4FF44C +:10A3F000D172002408701A60DAE73B6800229B07DC +:10A40000C9F80020F0D53A680C4B1A42D0D0EBE7DF +:10A410003026002000001A0D40420F00F82B0020CB +:10A420003826002011003A064000010002007F118A +:10A43000F61A0020082600205D7B000000007F1136 +:10A4400000002C40342600202DE9F041324D144606 +:10A45000AB7A13F0400012D103F03F03EA7A5B00BD +:10A4600043EAD213621C0A43134208D02B49272423 +:10A470002B4B40F202320C701A60BDE8F081294B80 +:10A480001B780BB9490264022748FFF7A9FD40B9C0 +:10A4900022490F24224B40F20A320C701A60BDE8A8 +:10A4A000F08121462148FFF79BFD40B91B4910244C +:10A4B0001B4B40F20D320C701A60BDE8F081002198 +:10A4C0001B48FFF78DFD38B914491124144B4FF484 +:10A4D00044720C701A60E2E702F0FCF8154E164D5B +:10A4E0000446DFF85C80154F31682846FFF778FD99 +:10A4F00018B1D8F81030DB05D1D402F0EBF8001B0E +:10A50000B842F1D905492824054B40F21332002006 +:10A510000C701A60C3E700BF1C260020F61A00204A +:10A5200008260020F62B002000001A2000001A2127 +:10A5300000001B263026002000001A0D40420F00AC +:10A5400000002C402DE9F04F12F0030483B018BF37 +:10A55000012401900093002B08BF44F001045CB17A +:10A5600040492520404B40F2F512002408701A6043 +:10A57000204603B0BDE8F08F3C4B15463C4A0E46E2 +:10A58000DFF80C91136002F0A5F8DFF808810746A8 +:10A59000DFF804B1DFF8F0A006E002F09BF8C01B82 +:10A5A000504544D803F05EFCD9F800104046FFF750 +:10A5B00017FD0028F1D0DBF81030DA05EDD5009A50 +:10A5C0002C4B2B4903EA024300222B4F0A6043F431 +:10A5D00000730121DFF8C4803970C8F80020CBF87F +:10A5E0000050CBF80430254BCBF83830244B1B7887 +:10A5F00043B331460198FFF7F3FC81460028B7D0FA +:10A60000204B1B4A136002F065F83B780546DBB12E +:10A610001D4E03E003F026FC3B78ABB102F05AF884 +:10A62000401BB042F6D90023114A1360A0E70D4B3E +:10A630000A2200210E481A704FF4FC720A4B016086 +:10A640001A6095E77602D4E70023094A1360D8F828 +:10A6500000309B078CD5D8F800200C4B1A4208BF5D +:10A660004C4685E7F61A00200826002035810000B8 +:10A67000342600200000FF1FF82B002002007F116D +:10A68000F62B00205D7B000040420F0000007F1190 +:10A690003026002000001A0D00002C403826002033 +:10A6A000F8B50646007A0C461546C0071F4613D477 +:10A6B00083B10F4401E0BC420CD033682A462146E6 +:10A6C00030461B69013405F5007598470028F2D122 +:10A6D0000020F8BD0120F8BD900712D0002BF9D062 +:10A6E0000F4401E0BC42F5D033682A46214630468B +:10A6F0001B69013405F5007598470028F2D1002048 +:10A70000E7E70648FFF71EFF0028E3D104490C24C1 +:10A71000044B40F2A1320C701A60F8BD37003A12B7 +:10A72000F61A002008260020F8B50646007A0C46E6 +:10A730001546C0071F4613D483B10F4401E0BC4245 +:10A740000CD033682A46214630465B6A013405F551 +:10A75000007598470028F2D10020F8BD0120F8BD0F +:10A76000900712D0002BF9D00F4401E0BC42F5D085 +:10A7700033682A46214630465B6A013405F5007588 +:10A7800098470028F2D10020E7E70648FFF7DAFEF5 +:10A790000028E3D104490E24044B40F23D420C70E2 +:10A7A0001A60F8BD27003A19F61A00200826002082 +:10A7B0002DE9F04F0025DFF8C0929B4C91B0DFF8F7 +:10A7C000BC829A4E0172457289F80050257088F853 +:10A7D00000503570FFF7D2FA29462846FFF700FCF3 +:10A7E00050B90121924B40F28E22054621701A6029 +:10A7F000284611B0BDE8F08F03258E4F4FF4D57178 +:10A800003846FFF7EDFB00284ED1013DF6D13378F5 +:10A81000002B3DD0DFF868B201F05CFF864E0546A4 +:10A82000DFF860A2854F00213046FFF7D9FB50B911 +:10A83000002517217E4B4FF42A72284621701A609A +:10A8400011B0BDE8F08F59465046FFF7C9FB00280C +:10A85000EED001F03FFF401B794BB842E8D81A69AF +:10A86000002AE0DA1969774A11601B695A0002D59B +:10A87000012388F8003000217348FFF7B1FB05463B +:10A8800010BB02216A4B40F2B12221701A60AFE77F +:10A89000FFF774FA29462846FFF7A2FB3378002B0E +:10A8A000B8D14FF4401BB7E7654B1B69B3F5D57FB3 +:10A8B00007D006215E4B4FF42572002521701A60E7 +:10A8C00096E701233370A5E700216048FFF788FB76 +:10A8D000054630B90321564B4FF42D7221701A6092 +:10A8E00086E7574E5A4B32695A4F13405A495B48D4 +:10A8F0003B60FFF7C1FB054630B907214C4B40F2E6 +:10A90000B92221701A6073E755495648FFF7B4FB26 +:10A91000054630B90821464B4FF42F7221701A605A +:10A9200066E739685048FFF75BFB054630B90521FB +:10A930003F4B40F2BF2221701A6059E739683E4808 +:10A94000FFF74EFB38B91421394B40F2C3220025E2 +:10A9500021701A604CE702214448FFF741FB05468D +:10A960000028F0D0B36A69466FF07F4023F00603F9 +:10A97000B362B36A43F00203B3624FF0101373641F +:10A98000FFF7D4FC9DF80D309B0743D5002841D03C +:10A99000274E6946364894F800803768FFF7C6FCB2 +:10A9A0009DF8103003F00F03012B36D1A8B34CF201 +:10A9B0005030304C0523C4F8CC31C4F8D031C4F841 +:10A9C000BC31C4F8C031C4F8C431C4F8C831FFF791 +:10A9D000EBF8002347F2B802C4F8CC31C4F8D03108 +:10A9E000C4F8BC31C4F8C031C4F8C431C4F8C831AB +:10A9F00041F2B803C4F8BC23C4F8C023C4F8AC23A4 +:10AA0000C4F8B0330123C4F8B423C4F8B82389F8D8 +:10AA10000030EDE646F2A810CBE746F2A81084F825 +:10AA200000803760C5E700BFF61A0020F52B002034 +:10AA30000826002000001A0800001A3740420F00C4 +:10AA400000002C402C2600200000090200001A0300 +:10AA50000000FFFF302600201C260020000009090E +:10AA60000C2600200000090A00001B0700001A063F +:10AA7000F1FFFF8000801F40F42B0020F62B002008 +:10AA80000000304000000229374B5A6A92052DE938 +:10AA9000F0410F460DD49A6A22F480329A6272B65F +:10AAA0009A6A42F400329A629A6A42F480329A6256 +:10AAB00062B601F00FFE2C4EDFF8C480054604E0BC +:10AAC00001F008FE431B434537D8746A14F4006450 +:10AAD000F6D007F13C0C244807F50F77436A1B05B5 +:10AAE000FCD5ACF14003026A43F8042F9C45FAD12F +:10AAF0000CF1400C6745F1D101F0ECFD1A4F1B4DF4 +:10AB00000646DFF87C8004E001F0E4FD831B43454A +:10AB10001DD83C6B2C40F7D03B6B154A1360136873 +:10AB20003B63136813F002031BD01268114B1A42E7 +:10AB30000CBF01200020BDE8F0810F491A250F4B02 +:10AB400040F2563220460D701A60BDE8F0810A4985 +:10AB50001D250A4B40F2613220460D701A60BDE897 +:10AB6000F0811846BDE8F08100002C4002007F1102 +:10AB70003826002000007F11F61A00200826002049 +:10AB800040420F002DE9F047294B8946DFF8C0A06D +:10AB9000284ECAF8003001F09DFD274D0446DFF82D +:10ABA000B480264F06E001F095FD001BB84229D87D +:10ABB00003F058F931682846FFF712FA0028F2D05E +:10ABC000D8F81030DB05EED500234FF40072CAF838 +:10ABD0000030D8F8283043F48033C8F82830184BB8 +:10ABE000C8F804201B78CBB149461648FFF7F8F99E +:10ABF00030B915490C24154B40F2BD320C701A6067 +:10AC0000BDE8F087104A0A210020104B117040F275 +:10AC1000B132CAF800001A60BDE8F0874FEA49294E +:10AC200008484946FFF7DCF90028E9D1E1E700BF11 +:10AC3000358100003026002000001A0D40420F0030 +:10AC4000F62B002030003A12F61A002008260020C9 +:10AC50003426002000002C402DE9F04100221D4C3C +:10AC60000D4642721146A36A1B4823F48033A36247 +:10AC7000FFF7B6F940B919490924194B40F2D3320C +:10AC80000C701A60BDE8F081002DFBD0154B164EFC +:10AC9000336001F01FFD636A0746DA0116D4DFF85E +:10ACA0004C8004E003F0DEF8636ADB010ED401F0AF +:10ACB00011FDC01B4045F5D9084A0A210020084B68 +:10ACC000117040F2D73230601A60DBE7002328466B +:10ACD0003360D7E700002C400000DB0CF61A0020A0 +:10ACE00008260020497B00003426002040420F0047 +:10ACF0000A4B1B7810B504461BB9637A43B901208F +:10AD000010BDFFF7CFF80028FAD0637A002BF6D0F9 +:10AD100020460121BDE81040FFF79EBFF72B002021 +:10AD20002DE9F0410446007AADF5007D164610F09D +:10AD3000010513D093073CD0012338486A46FFF73A +:10AD400001FC00283AD04FF400726946304601F009 +:10AD500067FD28460DF5007DBDE8F081DFF8CC8069 +:10AD60000F4698F80030002B35D1637A012B39D08B +:10AD700022682B49126A8A424AD198F80020002A98 +:10AD800034D1002B39D139462046FFF7FBFEE8B11C +:10AD900001236760637231462046FFF775FEA8B154 +:10ADA000636805460133284663600DF5007DBDE804 +:10ADB000F08101231948FFF7C5FB38B919490B2069 +:10ADC000194B4FF45D72002508701A6028460DF586 +:10ADD000007DBDE8F081FFF765F80028F6D0637AC2 +:10ADE000012BC5D16268BA42C2D1D4E7FFF75AF845 +:10ADF0000028EBD0637A002BC5D001212046FFF755 +:10AE00002BFF0028BFD128460DF5007DBDE8F0815D +:10AE1000204690470028F6D0B5E700BF11003A1150 +:10AE2000B18C0000F61A002008260020F72B002025 +:10AE30002DE9F041047AADF5007D0F46904614F0FF +:10AE400001041DD012F0030F06D0684611464FF4DE +:10AE50000072804601F0E4FC0123424639462C484A +:10AE6000FFF770FB044630B92A490D202A4B40F207 +:10AE7000114208701A6020460DF5007DBDE8F08192 +:10AE8000264D06462B782BBB737A022B29D03268CD +:10AE90002349126A8A4236D12A7832BB002B2BD141 +:10AEA0003368394630461B6E98470028E3D00223AA +:10AEB00077607372336841463046DB6D98470028EF +:10AEC000D9D0736804460133204673600DF5007DC8 +:10AED000BDE8F081FEF7E6FF0028CCD0737A022BA4 +:10AEE000D5D17268BA42D2D1E4E7FEF7DBFF002881 +:10AEF000C1D0737A002BD3D001213046FFF7ACFECE +:10AF00000028B8D0CCE7304690470028B3D0C7E738 +:10AF100001003A18F61A002008260020F72B00201E +:10AF2000B18C0000012101F03BBC00BF01F0FCBB73 +:10AF300008B5034653F8040B93E80600F7F7ECFC5A +:10AF400008BD00BF84B00DF1100C0CE90E000246E4 +:10AF500023B11846136004B0F8F78ABD024B1846B7 +:10AF6000136004B0F8F784BDD01000200268D37CD1 +:10AF700013B3D80704D5906A4FF0E021C1F800015F +:10AF8000990704D5D06A4FF0E021C1F804015807B1 +:10AF900004D5106B4FF0E021C1F80801190704D562 +:10AFA000506B4FF0E021C1F80C01DB0604D5926B29 +:10AFB0004FF0E023C3F81021704700BF0068F8F796 +:10AFC00075BE00BF0268FF2312685366D36D13F489 +:10AFD000F81FFBD0506FC0B2704700BF30B50C46B1 +:10AFE00083B00546FF212046019203F0A7FE2868A2 +:10AFF000019B22462146F8F755FE002003B030BDE4 +:10B0000003681A685166D36D13F4F81FFBD0536FB1 +:10B01000704700BF531EB3F5007F30B51446ADF541 +:10B02000017D054611D36AB10368481E196882186C +:10B0300010F8013F4B66CB6D13F4F81FFBD0904224 +:10B040004B6FF5D10DF5017D30BD684601F0E8FB91 +:10B050006A46234628681146F8F724FE0DF5017D5F +:10B0600030BD00BF30B5037883B0DC071DD5044682 +:10B07000406804F110020368E16801925B6A984736 +:10B08000019A0546A8B12378990708D56068D4E9E4 +:10B090000231194403685B6A984750B1237823F062 +:10B0A00001032846237003B030BD0125284603B0B4 +:10B0B00030BD0025284603B030BD00BFF8B5436859 +:10B0C0000BB3C36804460F4615468B4206D110F8F1 +:10B0D000103B05F003052B432370F8BDFFF7C2FFBB +:10B0E00088B16B0705D504F1100630460023E760F0 +:10B0F000EFE7606804F110063946036832461B69C1 +:10B1000098470028F1D10020F8BD00BF10B50446D3 +:10B11000808982B018B10023A38102B010BDD4E9A8 +:10B1200001318B42F9D201AA184600F0B7F880B17C +:10B13000019B6060B3F5803F01D298B2EDE7980AB9 +:10B14000C3F30903A0F52150A3F5105380B2A381E6 +:10B15000E3E74FF6FF70E0E7B1F5807F21D81029D3 +:10B160002ED840234FF0200CB2FBF3F1B1F5806FE5 +:10B1700020D203FB112300B5B2FBFCFEB3FBFCF3B2 +:10B180000CFB1E224FEA910CDBB201322CF03F0C7B +:10B19000C9B2037042EA0C028170D2B242705DF80B +:10B1A00004FB3F239C46802910D9B1F5FC7F0FD8C2 +:10B1B0001B01D9E7FF21FE234170037081707047A6 +:10B1C000202916D880234FF0200CCDE7DB00CBE7F9 +:10B1D000B1F57C7F04D9B1F5FC6F03D89B01C3E7BF +:10B1E0005B01C1E7B1F57C6F94BFDB01C3EB0323C7 +:10B1F000BAE720239C46D6E77F28A2EB010205D8B8 +:10B2000012B10A4602F8010B10467047B0F5006F04 +:10B210000FD2012A40D94FEA901C00F03F030A46A2 +:10B220006CF03F0063F07F0302F8020B10464B7096 +:10B230007047B0F5803F16D2022A2DD9C0F3851C85 +:10B2400000F03F03CA1C63F07F0300B54FEA103ED5 +:10B250006CF07F008B706EF01F0E4870104681F806 +:10B2600000E05DF804FB032A16D94FEA904CC0F3C6 +:10B270000532C0F3851300F03F0062F07F026CF0EE +:10B280000F0C63F07F0360F07F004A700A1DC870E6 +:10B2900081F800C08B70B7E70022B5E788423DD245 +:10B2A000034610B490F900001C7800282DDA04F051 +:10B2B000E000C02834D004F0F000E02834D004F0DE +:10B2C000F800F02826D104F007040420184488422E +:10B2D00020D8013313F8011B01F0C00C01F03F012D +:10B2E000BCF1800F41EA841414D18342F2D1A4F15D +:10B2F00080010F4B99420DD8A4F55843B3F5006F68 +:10B3000008D314605DF8044B7047581C14605DF856 +:10B31000044B704700205DF8044B704700207047D5 +:10B3200004F01F040220D1E704F00F040320CDE74E +:10B330007FFF10007E283ED94FF0350C002330B43B +:10B34000284C04E034F82120824220D80B46ACEB94 +:10B350000302012A03EB5201F4D89BB234F82320F4 +:10B36000904216D24B2400231F4D04E035F82120D3 +:10B3700082421ED80B46E21A012A03EB5201F5D88D +:10B380009BB235F8232082421FD030BC70478C46D8 +:10B39000DDE704EB8304821AE3789A42E2DA94F957 +:10B3A0000230012B16D0D3B19BB2034430BC98B20B +:10B3B00070470C46DFE7A0F16103192B8CBF002317 +:10B3C0000123A0EB431398B2704705EB830568880F +:10B3D00030BC704702F00102831A98B2D5E74EF2F2 +:10B3E000A033E2E7B40400207C0300202DE9F04FF5 +:10B3F00083B00021824600F067FC019000284AD00B +:10B4000000F58273041DDFF8C0B147F6FF77684E80 +:10B41000684DDFF8B881DFF8B891009326E09B45CE +:10B42000B8BF9B46DAF8201032788B42D4BF002395 +:10B4300001239A4233702B681ED0D8F80020934223 +:10B440002CDA13EB4303D9F8002048BF0133012A5B +:10B450004FEA6303C8F8003002F1010362D0C9F873 +:10B46000003000232B60009B9C420AD034F9023B41 +:10B47000BB42D4DA1F46D5E701332B60009B9C42C8 +:10B48000F4D1019800F0D4FB17EB0B0748BF01374C +:10B490007F10CAF8207003B0BDE8F08F002B1A4669 +:10B4A000B8BF5A1C13EB62034FF0000248BF0133D0 +:10B4B000C9F800205B10C8F800303F4B19683F29DD +:10B4C00010DC3E4B3E4A1B78002B40D0136850687E +:10B4D0005B0843EAC07340080131C2E90030364BD3 +:10B4E0001960BEE736494BF6FC700B895B009BB2D6 +:10B4F00083420B81B5D1334B1868C86001F0EAF87C +:10B50000304B00222E490AF1280C18604FF0010E32 +:10B51000294B1A60294B1A700FC98CE80F008AF862 +:10B520001CE09EE7244B00221968C9F800203F293F +:10B5300012DC224B224A1B78002B31D0D2E900309A +:10B540005B0843EAC073400840F00040C4E713685A +:10B550005068DB184041BFE7194943F6FD700B897D +:10B560005B0043F001039BB283420B817FF479AF10 +:10B57000144B1868C86001F0ADF8124B00224FF070 +:10B58000010E0F4918600AF1280C0B4B1A600B4B87 +:10B5900083F800E00FC98CE80F008AF81CE060E730 +:10B5A00013685068DB1843F00103404194E700BF83 +:10B5B000FE2B0020E0270020D4270020F71A0020CF +:10B5C000E0200020D82700200080FFFFDC2700209B +:10B5D000E427002090F8A32090F8A200101A7047EA +:10B5E00090F8A23090F8A3209A4205D95A1C03443F +:10B5F00080F8A220987E70474FF0FF30704700BF60 +:10B6000090F8A23090F8A3209A4202D91844807E84 +:10B6100070474FF0FF307047704700BF0346B0F8E7 +:10B62000300178B193F82F21882A03D90122002014 +:10B630005A60704702F1010C01201A4483F82FC1AF +:10B6400082F8A510704700BF38B5B0F830410CB98A +:10B65000204638BD90F82F310546C3F18904A24237 +:10B660000DD8144605F1A5002246184401F0D8F87B +:10B6700095F82F312046234485F82F3138BD01221B +:10B680004260EFE72DE9F04FD0F814A01524017EB9 +:10B690008146437E83B00AEB0111384A0AEB03135B +:10B6A000374F097A93F8283002EB01150901E86851 +:10B6B00052F8018002EB0311D5F804B01B01CE68EB +:10B6C000D558CBF80040C8F88400D8F804304A6850 +:10B6D00003432C490192C8F804301460C5F8846013 +:10B6E0006B6833436B60284B4C683A68A3FB0232AB +:10B6F000920C02EB820252004B681B1B9A42FBD851 +:10B700004FF0090C1F4ADFF880E0D8F808300342F8 +:10B7100002D0AB6833422FD1C5F8886054683968CD +:10B72000AEFB0131890C01EB810153681B1B99426F +:10B73000FBD8C5F8846054683968AEFB0131890CC8 +:10B7400001EB810153681B1B9942FBD8BCF1010C32 +:10B75000DBD1604699F81830019A0AEB0313DB68D5 +:10B76000CBF8003099F819300AEB031ADAF82C30CC +:10B77000136003B0BDE8F08F0120EBE7E40B00207D +:10B78000CC100020001000E083DE1B430E4A10B5F1 +:10B790001168046905E0DB0107D413685B1A102BFC +:10B7A00008D8636913F0007FF5D14FF4FE43012000 +:10B7B000636110BDFFF766FF0028FAD04FF4FE4327 +:10B7C00001206361F5E700BFC42B00202DE9F0479D +:10B7D00090F82FA10569BAF1000F4FD08146884635 +:10B7E000FFF7D4FF002849D0374E0024376818E00F +:10B7F0006B69190551D4DA0455D4580559D4990404 +:10B8000041D43268D21B322A3DD8544507D9EA6D5B +:10B81000520704D19B0555D4B8F1000F52D002F065 +:10B8200021FB5445E4D8EA6D500702F00703DFD44A +:10B8300013E099F8A5200133022442F48062042B1E +:10B840002A661ED08A4503F1010309EB01020ED9D5 +:10B8500092F8A520042B2A66CAD00121002CE8D03A +:10B860002146013301348A4509EB0102F0D8B8F1D1 +:10B87000000FBDD04FF400732B66B9E70420BDE87C +:10B88000F0870124B4E72B694FF40072042043F4DD +:10B8900040732B612A66BDE8F0872B69042043F4CE +:10B8A00040732B61EBE72B69052043F440732B6158 +:10B8B000E5E72B694FF40072022043F440732B61DB +:10B8C0002A66DCE70020DAE7C42B00202DE9F84FD8 +:10B8D00083460C4615461F46D0F810A0FFF756FFCA +:10B8E000002800F09E806100012DDFF83C8140F2CD +:10B8F0000146CBB24FF0000138BF0125D8F80090C7 +:10B900000C461E43ABF8A21020E09BF8A330872B17 +:10B910003FD9DAF8142010055AD412F4105F70D110 +:10B92000D8F80030A3EB0903322B6AD89BF8A33078 +:10B93000AB4209D3022C07D9DAF85C30590703D19E +:10B9400093054BD4002F49D002F08CFA022CDCD89E +:10B95000DAF85C3003F007025B07D6D4681E224495 +:10B9600040F480704CB9CAF860600134131B032B9B +:10B97000CBD8022CC9D8002CF5D0012C37D01FB160 +:10B980004FF40073CAF860309BF8A3300324872B70 +:10B99000BFD8DAF85C2012F4E02FC2F3024CB8D022 +:10B9A000591C9C441933C9B25FFA8CFC5BFA83F3CF +:10B9B000DAF870004A1C61458BF8A310D1B203F885 +:10B9C000010FA6D08929F3D1DAF814201005A4D5E7 +:10B9D000DAF8103043F44073CAF81030DAF85C300B +:10B9E00013F4E02F06D19BF8A300BDE8F88FCAF846 +:10B9F0006000BAE7DAF8103043F40073CAF8103088 +:10BA0000F1E7DAF810304FF4007243F44073CAF8EB +:10BA10001030CAF86020DAF85C3013F4E02FE2D07E +:10BA2000E8E70420BDE8F88FC42B0020F8B50669CC +:10BA30000446D6F8145115F4706301D0C6F81431D9 +:10BA4000A8070BD5D6F8702111043DD5002301219C +:10BA500084F8A230234484F8A3109A76EA0710D51C +:10BA600094F83071F7B194F82E7194F82F31BB42ED +:10BA700026D97B1C274484F82E3197F8A530C6F8C8 +:10BA80006031AB050DD594F8A30018B1D4F83C3162 +:10BA900003B198470023A4F8A230A4F82E3184F80B +:10BAA0003031F8BDD4F8383103B19847002384F819 +:10BAB0002E31012384F8303194F82F31BB42D8D88D +:10BAC0000023C6F86031DCE794F8A330872BC5D893 +:10BAD000591CC9B2BEE700BF0148FFF7A7BF00BFAE +:10BAE000301100200148FFF7A1BF00BF70120020F5 +:10BAF0000148FFF79BBF00BFB01300204FF0E023C9 +:10BB00004022C3F808227047F8B5144B144D1C6846 +:10BB10006E689CB1237A20466BB123686F681B68FE +:10BB200098476B68E188DB1BC3F38F12B1EB931F5F +:10BB3000A28038BFE2806469002CEBD1084B094A2F +:10BB40005B6810889B1B084CC3F38F11B0EB931FED +:10BB5000218038BF1180BFF34F8FF8BD44260020ED +:10BB6000001000E0E62B0020E42B002003681847BB +:10BB70000B680360704700BF0B680360704700BF2D +:10BB8000704700BF30B472B6244D254C2A8804F1AA +:10BB9000700104EB82038B423CD204F16F01501C14 +:10BBA000C91A00EB910002E00132824232D09C4679 +:10BBB00053F8041B0029F7D0B1FA81F04FF000438D +:10BBC000C34021EA0301CCF8001001B90132154B42 +:10BBD0002A801A88013291B2198062B6ACEB040C4B +:10BBE00041F67C73C0EB00644FEAAC0CC0EB8410F0 +:10BBF00001240CEB8C1C03EBCC1303EB80030A48F1 +:10BC00000068C4541844094B1C88944230BC38BFA7 +:10BC10001980704762B6002030BC7047E82B0020C6 +:10BC200048260020E02B002040260020E22B0020A8 +:10BC3000428872B60378012B03D9013B037062B6C8 +:10BC40007047D14353090B484FF0004201F01F01E8 +:10BC5000CA4050F823100A430749B1F800C040F821 +:10BC600023209C45054A88BF0B801388013B138025 +:10BC700062B6704748260020E82B0020E02B002009 +:10BC8000C36813B91DE0DB68E3B1187A9042FAD1BA +:10BC900010B4586893F809C0006950F82C4054B1AA +:10BCA000DB682BB1187A9042F3D0DB68002BF9D116 +:10BCB0005DF8044B704740F82C100878013008708C +:10BCC000EEE77047704700BF437A8B4206D903699D +:10BCD000002253F8210043F82120704700207047CC +:10BCE00000220449C0E90022028102740A68086047 +:10BCF000C2607047B8260020037CFBB90368014688 +:10BD0000FBB14368EBB1427A5B7A9A421CD230B401 +:10BD100072B62B4B1C68ECB1E368C3B1486801E014 +:10BD2000DB68A3B15A688242FAD193F809C04A7A13 +:10BD30009445F5D162B6042030BC7047012062B64C +:10BD40007047032062B67047022062B6704764698C +:10BD5000002CE1D11B4C236843B1994202D10BE086 +:10BD6000994207D01A46DB68002BF9D1052062B64C +:10BD700030BC704702F10C040D68E868E8B1C36894 +:10BD80001BB908E0DA683AB1134681421846F9D186 +:10BD900062B60620D0E70346D960CB680020236056 +:10BDA0000123C860AA7A2B721A44AA724A68947A4C +:10BDB00013721C4494720B74D9E7E960EDE700BF7D +:10BDC00044260020B826002010B5047C9DF808E029 +:10BDD0000CB1012010BD027280F809E0C0E9001327 +:10BDE000BDE81040FFF788BF38B5037C002B36D084 +:10BDF00043680446427A5B7A9A4238D272B6016846 +:10BE0000CB68002B2DD0984233D01A46DB689C4279 +:10BE10002AD0002BF9D16268607A136953F82000A8 +:10BE200048B1FFF705FF72B662680025607A1369B2 +:10BE3000216843F820508B7A013BDBB28B7203B947 +:10BE40000B72937A013BDBB2937203B913720A4B04 +:10BE500000201A6820741C60E26062B638BD0120C0 +:10BE600038BD62B6032038BDE368D360D3E7022053 +:10BE700038BDC368CB60CEE7B826002010B50446B5 +:10BE8000FFF7B2FF094A136843B19C4202D108E0B0 +:10BE90009C4205D01A46DB68002BF9D1204610BD24 +:10BEA0000C32E3682046136010BD00BFB8260020A6 +:10BEB0000C4B1A789AB90C4A0C4910B4C2F85811B4 +:10BEC0000B48D02401224FF0E02180F84640402466 +:10BED0001046C1F808415DF8044B1A707047002005 +:10BEE000704700BFF92B0020001C0020C99A0000F9 +:10BEF00000E400E030B472B621B9036813B10279EE +:10BF00000F2A3BD9244C2188002341FA03F212F076 +:10BF1000010208D00133102BF7D162B60022037161 +:10BF2000026030BC70474FF0010C0CFA03FC41EA90 +:10BF30000C01218062B619495FFA83FC184C194440 +:10BF400080F804C04B01E16F41F0C001E16740F2AD +:10BF5000824414490C6081F81AC081F81EC081F82F +:10BF600018C081F81FC0036030BCC3E90022C3E9D8 +:10BF70000222C3E90422C3E906227047064C218845 +:10BF800041FA02F5ED07BFD5044D1544B3EB451F4B +:10BF9000BAD162B6C5E700BFEC2B00208074000266 +:10BFA00000C00F4000800E4003790F2B11D8094AC2 +:10BFB000937672B60849012290F804C00B8802FA01 +:10BFC0000CF223EA02030B8062B6102200230271F6 +:10BFD0000360704700800E40EC2B0020EFF31082CE +:10BFE00072B6437F5BB9017F012930B40BD00329BE +:10BFF00013D00123437702B962B630BC70470AB947 +:10C0000062B670477047124C2168B1B11149436163 +:10C010000B68086083615861EBE70F4D0F492C688E +:10C020008CB143610B68836158614FF0E0234FF09E +:10C0300080540860C3F8044DDBE7064B20601860AD +:10C04000C0E90511D5E7C0E905442860EDE700BF68 +:10C05000202700202C27002028270020242700202C +:10C0600070B5EFF3108272B60C4C206880B10C4EA4 +:10C0700000254369236073B19D6102B962B683688C +:10C0800045779847EFF3108272B620680028F0D108 +:10C0900002B962B670BD3360EFE700BF2827002009 +:10C0A00024270020FFF7DCBF0449054A4968054BF7 +:10C0B0001960136801331360704700BF001000E07F +:10C0C000C42B0020C02B0020704700BF704700BF6A +:10C0D000704700BF704700BF70B51A4C1A4D2368F7 +:10C0E000AB4202D0194AD16829BBA369AB4202D046 +:10C0F000164AD169C9B9236BAB4202D0134AD16A3F +:10C1000069B9A36CAB4209D0104AD16B31B101219E +:10C110001B680F48D163BDE87040184770BD01210E +:10C120001B680C48D1629847EBE701211B680A485D +:10C13000D1619847DFE701211B6804F10800D16055 +:10C140009847D2E7C01E002050060020004108405A +:10C15000101F0020F81E0020E01E002038B5064CFD +:10C16000A4F1600554F8083C2046183CDB68984769 +:10C17000AC42F7D138BD00BF101F002003682DE985 +:10C18000F041044688B01746002B4BD000229A603D +:10C190000122DA60304D04A8DFF8E0801D4451F838 +:10C1A000083B2D1102935B6805EB45069847F600A6 +:10C1B00006F1080058F806304044DB6801909847C3 +:10C1C000264A04A9DDE90103029248F806309B687B +:10C1D0009847029B04A8DB689847236803222048FD +:10C1E0001F609A601F4A23791F4C5355137851786A +:10C1F000C0F828428B4228BF0B469178D2788B42F8 +:10C2000028BF0B46934228BF1346184C4FF0E0223C +:10C210004FF08061012084F87A30C2F80C1108B028 +:10C22000BDE8F081124AD36E43F44053D366012235 +:10C23000104B1A60104A134602604032986800287A +:10C24000A8D0103393422360F8D10023184623600E +:10C2500008B0BDE8F08100BF00BFF7BF5006002066 +:10C26000001C0020F014002099A0000000E400E071 +:10C2700000C00F400040084000410840C01E0020A0 +:10C2800010B4064B0020064C064A1C609C611C63DF +:10C290009C6405495DF8044B01F050BEC01E0020AF +:10C2A00050060020FC1400201DA10000084601F0EB +:10C2B00045BD00BF2DE9F0410C46D1B1EAB1804641 +:10C2C0008E1800250E4F04E001F038FDB4420544FD +:10C2D0000CD0D8F8003014F8010B1B68BB42F3D027 +:10C2E000014640469847B4420544F2D12846BDE88D +:10C2F000F0810D462846BDE8F0811546F6E700BFFF +:10C300006DA20000054B022888BF034610B41C68CC +:10C31000184663685DF8044B184700BF20110020E1 +:10C320000EB400B582B003AA52F8041B019202F0C9 +:10C3300019FC02B05DF804EB03B07047A249A34BAF +:10C3400088422DE9F047A24C5E699A69D4F80C80C6 +:10C350001BD9A04B984240F20281C31A9E491B0A86 +:10C36000A1FB031340F22761DB0903EB830303EB1B +:10C37000830303F2E2438B4228BF0B46A3F54877C1 +:10C38000964BA3FB0737FF0804E0954FB8428CBFDC +:10C390000E2706278D4908F01F09D1F88030B945CE +:10C3A00043F0C003C1F880300CD228F01F08A1F57B +:10C3B000F82148EA0708C1F80C800B68002BFCDA6A +:10C3C00008F01F0916F0007324D186490C698649CC +:10C3D000A14300F0EA8082F4805134464FF4805546 +:10C3E00014F0605F04D026F060561E43774B5E6108 +:10C3F00011F4405F07D022F4405274492A438A6105 +:10C400008B6C1A07FCD446F00076704A5661936C28 +:10C410009B06FCD4754CA04200F2CE804FF0010C7C +:10C420000146634603FB011203F1010E0CF1010505 +:10C43000A24218D8BEF1080F4FF0010340F08D80E2 +:10C44000BCF1040F00F291800A18A24200F2A4800D +:10C4500005FB00F1AC4603F1010E03FB01120CF1E8 +:10C460000105A242E6D90CF1FF318C0286EA812156 +:10C470005F4810445F4A90427FD9DFF8A4A16C2244 +:10C480005D48584DB0FBFEF0D5F800E0B0FBFCF085 +:10C49000DFF890C10EEA0C0CD44509D042F40052EA +:10C4A0004FF4805CC5F800C02A602A68002AFCDAD4 +:10C4B000464A156905F007059D4203D01361936C48 +:10C4C000DD03FCD411F4E05F09D026F4E05604F457 +:10C4D000E0543E4A26435661936C9907FCD4474981 +:10C4E000474A014491423CD8464BC909A3FB01315C +:10C4F000090B4B1E1B0286EA030212F4407F06D092 +:10C5000026F4407603F44073304A334353612F4A94 +:10C51000536923F000735361936C9B06FCD43A4B30 +:10C520004F45A3FB00234FF0FF324FEA9343B0FB8C +:10C53000F1F1B2FBF3F3354A1060354A1160354A28 +:10C54000136008D228F01F08214A48EA0707D7607D +:10C550001368002BFCDABDE8F087734662E7122708 +:10C5600018E74FF440730421C5E70CF1FF31204870 +:10C5700007238C02104486EA8121274ADFF8A8A00D +:10C58000A2FB0020020D2548362A38BF362202FBC6 +:10C5900000F042EA0A0A74E74FEA8C24002386EA94 +:10C5A0008C214FF0010EAC4662E71D4686F0C05468 +:10C5B00011464FF0C05313E700244FF0010C024620 +:10C5C00031462346E64653E700A4781F00C00F40DB +:10C5D000000008400046C32323B24C001F85EB51E6 +:10C5E00000366E0100800D4040300080FFB19F2674 +:10C5F000808D5B00FF7EF64D00643F4D7FD1F008DB +:10C600007F17B42C9F10E50083DE1B43CC10002065 +:10C61000C8100020B02B0020819F5E16001BB700C1 +:10C620006C2000807F3001800020008000B97047BE +:10C630002DE9F84F01218146214C224D224E54E82C +:10C64000003F2A68306844E80013002BF7D11F49E7 +:10C650004B684FF47A7BDFF878A01B1A01270BFB9D +:10C6600002F8DAF80020A3FB02325A4594BF904446 +:10C67000D84454E8003F2A68306844E80073002B2F +:10C68000F7D14B68DAF800C01B1A0BFB02F2A3FBD0 +:10C690000C3CBCF57A7F94BF624402F57A72A2EB3F +:10C6A0000802B2F57A7F06D3B9F1010908F57A7864 +:10C6B000DFD1BDE8F88F01F0D5FB0449D9E700BF11 +:10C6C000C82B0020C42B0020C02B0020001000E04D +:10C6D000B02B002030B40F4B4FF0010C0E4D0F4C1F +:10C6E00053E8002F2868216843E800C2002AF7D1E8 +:10C6F0000B4B5B680B4A5B1A4FF47A71126801FBB3 +:10C7000000F0A3FB023230BC8A4294BF801840186C +:10C71000704700BFC82B0020C42B0020C02B002076 +:10C72000001000E0B02B0020272816D80201104B83 +:10C7300003EB00109B5810B4C2685C68144205D02B +:10C7400061B95DF8044BC3F888207047836851B124 +:10C75000084A5DF8044B1A60704770475DF8044B57 +:10C76000C3F884207047044A5DF8044B1A60704790 +:10C77000E40B002038F001003830010027280BD8E6 +:10C78000064B020103EB00109A58C36892681A42E4 +:10C7900014BF01200020704700207047E40B0020E8 +:10C7A000272829D8164B0201012903EB00109A58BB +:10C7B00010B45368C4680ED004290CD023EA0403D3 +:10C7C00053608368A9B1022917D003290CBF0D4A11 +:10C7D0000D4A1A6007E0234301295360836808D09B +:10C7E00040F638021A60436815225DF8044B1A605F +:10C7F000704738221A60F6E77047044A1A60F2E779 +:10C80000E40B0020383001003800010038F001004E +:10C8100008B5F5F749FCF5F799FC01F023FBFAE7B9 +:10C82000844641EA000313F003036DD1403A41D33B +:10C8300051F8043B40F8043B51F8043B40F8043BFA +:10C8400051F8043B40F8043B51F8043B40F8043BEA +:10C8500051F8043B40F8043B51F8043B40F8043BDA +:10C8600051F8043B40F8043B51F8043B40F8043BCA +:10C8700051F8043B40F8043B51F8043B40F8043BBA +:10C8800051F8043B40F8043B51F8043B40F8043BAA +:10C8900051F8043B40F8043B51F8043B40F8043B9A +:10C8A00051F8043B40F8043B51F8043B40F8043B8A +:10C8B000403ABDD2303211D351F8043B40F8043B2A +:10C8C00051F8043B40F8043B51F8043B40F8043B6A +:10C8D00051F8043B40F8043B103AEDD20C3205D33A +:10C8E00051F8043B40F8043B043AF9D2043208D032 +:10C8F000D2071CBF11F8013B00F8013B01D30B88A4 +:10C9000003806046704700BF082A13D38B078DD081 +:10C9100010F003038AD0C3F10403D21ADB071CBF53 +:10C9200011F8013B00F8013B80D331F8023B20F8BD +:10C93000023B7BE7043AD9D3013A11F8013B00F8F6 +:10C94000013BF9D20B7803704B7843708B7883707E +:10C950006046704701F0F8BA01F0FEBA01F1FF3C01 +:10C9600070B56646002400E00134B0FBF2F502FB2E +:10C970001503092B03F1370E03F130035FFA8EFE26 +:10C9800098BF5FFA83FE9042284606F801EFEBD28B +:10C99000631C0022C818CA547CB162461CF8015FAF +:10C9A00010F8016DA1EB0C0302328CF80060013B22 +:10C9B000521A057023449A42EFDB084670BD00BF4F +:10C9C00000230F2248F2B82C194610B54FF47044DA +:10C9D0004FF4806EA0F88C414FF46044A0F88E2193 +:10C9E0000A46A0F89031B0F888319BB243F0F003CA +:10C9F000A0F8883101EB4103013100EB4313042916 +:10CA00009C80A3F806E05A841A865A805A81A3F8BB +:10CA10000EC05A82DA825A83DA83EBD1B0F88831B9 +:10CA20009BB243F00F03A0F88831B0F888319BB275 +:10CA300043F47063A0F8883110BD00BF374B384A0B +:10CA4000996F384841F47F0170B5996741F201064A +:10CA5000D3F8801045F6C05543F226040A43C3F8C4 +:10CA60008020FFF7ADFF00F58040FFF7A9FF00F53C +:10CA70008040FFF7A5FF00F58040FFF7A1FF0022EF +:10CA8000A0F503104FF00F0E114600EB42134FEAD2 +:10CA9000421C01329981042A5981A3F80EE09E823A +:10CAA000DD8020F80C1019829C81EED100221E48F6 +:10CAB0004FF00F0E41F20106114645F6C05543F204 +:10CAC000260400EB42134FEA421C01329981042AEA +:10CAD0005981A3F80EE09E82DD8020F80C101982A7 +:10CAE0009C81EED1002211480F2641F2010511462A +:10CAF00045F6C05443F2260E00EB42134FEA421CA7 +:10CB000001329981042A5981DE819D82DC8020F8DE +:10CB10000C101982A3F80CE0EED170BD00C00F40DC +:10CB2000000003FC00C03D4000001E4000401E40CD +:10CB3000074A506A936A19468446506A936A994232 +:10CB4000F9D18445F7D1DB0B43EA4040704700BF81 +:10CB500000400D4072B6EFF30583524CC4F88430A8 +:10CB60001EF0040F0CBFEFF30882EFF309824FF0C1 +:10CB7000E0234D4E4D4DD3F8280DD3F82C1DC4E9BC +:10CB80002201D3F8341DD3F8383DC4E92413936946 +:10CB9000C4F89830D369C4F89C3000F0D3F884ED21 +:10CBA000280AFFF7C5FF0B214FF0FF32C4F8A4009D +:10CBB0000B46C4F880103E49301D5A40202402F034 +:10CBC0000103013C01FB03F383EA5202F7D1A842BF +:10CBD00002D073680646EFE7324BC3F8A820BFF3D4 +:10CBE0004F8F4FF0E0233049324AC3F8701FC3F82B +:10CBF000702FBFF34F8FBFF36F8F2F4A02252F483F +:10CC0000D36E2F4943F44053D3660560D3692D4852 +:10CC100023F07F0343F04003D3610B6883423DD888 +:10CC2000264D00214FF0E0234FF0FF32296001260E +:10CC3000C5F808112449C5F80011C5F80861C3F802 +:10CC40008021C3F88421C3F88821C3F88C21C3F85C +:10CC5000902101E000F068F9D5F80C31002BF9D0F3 +:10CC60000134C5F80C614F2CF4D9184B0220184937 +:10CC70004FF00042C1F840015A63D5F80C313BB97E +:10CC8000144815490D4A0163D2F80C31002BFAD033 +:10CC90004FF0E023114AC3F80C2DFEE7FFF74EFBDF +:10CCA000BEE700BF00FF272080FF2720A8FF272026 +:10CCB0002083B8EDA0FF272000C00F4000400840AF +:10CCC000CC100020803DCD0B009F240000900D4033 +:10CCD00000002E4000800F40F100AD0B0400FA056B +:10CCE0000A490A6838B108B513180948834204D8BC +:10CCF00010460B6008BD1046704702F055F90C2332 +:10CD00004FF0FF320360104608BD00BFF81400204A +:10CD100000002820002070474FF0FF30704700BF10 +:10CD20004FF4005300204B60704700BF0120704754 +:10CD30004FF0FF30704700BF30BFFDE730BFFDE769 +:10CD4000FFF708BF124AD2F880305B07FBD5D2F854 +:10CD500080301048C3F30B230F4990ED007A07EEA3 +:10CD6000903A91ED006AB8EE477A0C4AF8EEE77A0D +:10CD70000B4BD2ED006A77EEC77A93ED007AB8EEEE +:10CD8000477A67EE867A87EEA60A37EE400A704742 +:10CD900000810D40A02B0020A82B0020AC2B0020F0 +:10CDA000A42B0020836BF0B41BB1536843F4004301 +:10CDB000536072B6446B3CB31A4B2260D3F8B04157 +:10CDC0000C421DD1184E776804E07468E41BB4F57A +:10CDD000166F0BD2D3F8404144F48044C3F840416D +:10CDE000D3F8B851D3F840416404EED50D4007D1D3 +:10CDF0000C4CC0E90225D4F8B0310B43C4F8B03173 +:10CE0000426362B6F0BC7047064DC0E90224D5F813 +:10CE1000B0310B43C5F8B0310263426362B6F0BC77 +:10CE2000704700BF00002E40001000E070B5056B99 +:10CE30009DB106462A46002403E012680134012A07 +:10CE40000CD0536813F08003F7D032632CB128461E +:10CE5000B36B2D689847013CF9D170BDC6E90C331E +:10CE6000F4E700BF30B4D9B91F4C204B0021204A51 +:10CE700001254FF0011099601D60C4E90231802442 +:10CE80005C60C2F8BC01D2F8B0311A482B43C2F83A +:10CE9000B0310160D2F8B031002BFBD130BC70470B +:10CEA0000904154B104C012541F080019860104A8F +:10CEB000596000F580511D60D96000F50051A364F0 +:10CEC000196100F5405100F58040596100219861D9 +:10CED000E164D2F8B03143F48033C2F8B031D2F813 +:10CEE000B031002BFBD1C0E700000020201F002044 +:10CEF00000002E40002B0020401F00200849012286 +:10CF00000B7802FA00F023EA0000087030B9054AF5 +:10CF1000D2F8483123F08003C2F84831704700BF8F +:10CF2000052C002000002E402DE9F04F974C83B0D7 +:10CF3000D4F84471FB07C4F8447153D5D4F8AC213C +:10CF4000002A4AD0924EDFF860A2DFF87492DFF830 +:10CF500074B2DFF87482C4F8AC21D6E90A20D4F8A0 +:10CF6000403143F40053C4F84031D4F840319D04BB +:10CF7000F5D5D4F8403123F40053C4F840314FF0D4 +:10CF80000113C4F8B431D4F8B45115F00115FAD135 +:10CF900093B28446CAF80050B3F5086F00F0CF8111 +:10CFA00000F2DB8040F202318B4200F0E78100F2B8 +:10CFB0009A80822B00F0CB81B3F5817F40F08A808C +:10CFC00010F0780F83B200F003824FF00113C4F821 +:10CFD000C031D4F8AC21002ABDD16C4AD2F8BC31A2 +:10CFE000002B42D17E0616D5684BD3F8AC21C3F88E +:10CFF000AC21D3F8BC21C3F8BC21D3F8B041002C3C +:10D00000FBD14FF0FF32C3F8B421D3F8843100F0E4 +:10D010002DFD604B1C60FC0103D55F4B1B6803B109 +:10D020009847B80103D55D4B1B6803B19847790752 +:10D0300008D5564BD3F8843113F4007347D0584BBE +:10D0400001221A70514BD3F848311A060AD53B0613 +:10D0500008D5544A13782BB1013BDBB21370002B77 +:10D0600000F0728203B0BDE8F08F4F49C2F8BC31C6 +:10D070000868034240F0D181464A14681C40B1D090 +:10D080005FEA144810D0424E4FF0010998FAA8F513 +:10D09000B5FA85F506EBC51009FA05F54030FFF73E +:10D0A000C5FE38EA0508F1D1A4B2002C9AD0384E5A +:10D0B0004FF0010894FAA4F5B5FA85F506EBC51012 +:10D0C00008FA05F5FFF7B2FEAC43F3D18AE7344A1C +:10D0D0001370B7E7802B7FF478AF344802210580C6 +:10D0E000FFF7C0FE75E7B3F5A06F00F00B81A3F565 +:10D0F000D063012B3FF669AF2D4B5D68002D3FF4E7 +:10D1000064AF1FFA8CFC4FEA124E04E01D690C3329 +:10D11000002D3FF45AAF1A887245F7D15A886245FC +:10D12000F4D14FEA1E22032A00F0A5811A89000CCF +:10D13000824228BF0246BEF5007F40F0A181184B15 +:10D140001C4918781C4B0192002818BF19461B482F +:10D15000FFF766FB194D019AE1E142F221218B4272 +:10D160007CD033D942F221318B4200F081804FF6DE +:10D17000C0018B427FF429AF10F47F4F83B27FF45C +:10D1800024AF43F46E4363F30F0CB5E700002E4069 +:10D1900000000020042B0020D82B0020DC2B0020D6 +:10D1A0000B2C00200C2C0020002B0020682B0020D2 +:10D1B000040F00206C1F0060D01F0060400E202074 +:10D1C000F82A00205DCFC6B8C0012E40B3F5106F1D +:10D1D00066D042F221018B427FF4F7AE030C072B9D +:10D1E0007FF4F3AEB24BB349F560D960B249B36096 +:10D1F000C3F80890C1E9002001221A60AF4A5A60C2 +:10D20000AF4A1A61D4F8B01141F00101C4F8B0116D +:10D2100002F5805102F5005259619A61D4F8B0319B +:10D22000002BFBD1A74AF36493600123B26413601F +:10D2300048F2800353604FF00113C4F8BC31D4F8B6 +:10D24000B03143F48033C4F8B0314FF48033CAF8BE +:10D250000030D4F8B031002BFBD1BAE680B238B937 +:10D26000994BC2F307421968984B1960984B1A7092 +:10D27000944B00229A60F2640122B3641A60802207 +:10D280005A604FF00113C4F8BC31D4F8B03143F404 +:10D290008033C4F8B031D4F8B031002BFBD198E61C +:10D2A000C2F307428B4B1A708B4BC4F8C8318B4BBF +:10D2B000C4F8CC318A4BC4F8D03100F0D9FB8022BD +:10D2C0002946884801F03AFD874B8022C6F8A0B075 +:10D2D000C6F8E0307B4BF5645A600122B3649D6070 +:10D2E0001A604FF00113C4F8BC31D4F8B03143F4E4 +:10D2F0008033C4F8B031CAF80050D4F8B031002BF4 +:10D30000FBD166E66F4B0121F564196080219D60B9 +:10D31000B36459604FF00113C4F8BC31D4F8B03194 +:10D3200043F48033C4F8B031D4F8B031002BFBD1D2 +:10D33000130C5B0643F08073C4F8543149E6654B27 +:10D3400001216A481B780370FFF78CFD41E683B228 +:10D3500010F078007FF439AE03F07F0258F8221005 +:10D36000624A1080180600F19E80CB0701D5012388 +:10D37000137002215D48FFF775FD2AE610F0780F63 +:10D3800083B27FF422AE03F07F0213F0800F58F8CF +:10D39000223014BF43F4803343F0010348F82230B5 +:10D3A0000022484BF2649A600122B3641A60802222 +:10D3B0005A604FF00113C4F8BC31D4F8B03143F4D3 +:10D3C0008033C4F8B031D4F8B031002BFBD100E683 +:10D3D00003F07F0213F0800F58F8223014BF23F4BB +:10D3E000803323F0010348F822300022354BF264E9 +:10D3F0009A600122B3641A6080225A604FF00113D0 +:10D40000C4F8BC31D4F8B03143F48033C4F8B0313F +:10D41000D4F8B031002BFBD1DBE5002008602649B1 +:10D420000C88486842F221018C427FF425AE80B21C +:10D4300000287FF421AE2E492E4C03C9A1808628F6 +:10D440004FEA11412060A1717FF416AE72B62A48EE +:10D45000017841F008010170D2F848110D0605D499 +:10D4600080200143C2F84401C2F8481162B6234A41 +:10D470005021117000E6000C2A78824228BF024633 +:10D48000BEF5E06F44D11E4B1E4D18781E491F4B50 +:10D490000192002818BF19462846FFF7C1F9072353 +:10D4A0006B70019A3BE0C9033FF561AF61E700BFD4 +:10D4B000401F0020F83A0020F020002080000700E4 +:10D4C000F84A0020201F0020C42B0020D42B00206D +:10D4D000092C00200A2C00200200CC00C800020009 +:10D4E0000200C800800000201993D574682B00202A +:10D4F000F82A0020CC2B0020052C00200C2C00202A +:10D500000B2C0020400E2020D01F00606C1F0060FC +:10D510002946104D01922846FFF782F9019A25F01D +:10D520001F031544BFF34F8F4FF0E021C1F8703F48 +:10D5300020339D42FAD8BFF34F8FBFF36F8F05485A +:10D540001146FFF78FFC44E50320FFF7D7FC06F0F8 +:10D5500007FF00BF400E20202DE9F0471F46831E25 +:10D56000022B01D9BDE8F087DFF84C9015460C4638 +:10D570003C2209EBC01806464FEAC01A002108F108 +:10D580000400240401F0DAFBB5FA85F20123520904 +:10D5900044EA427449F80A40C8F83870C8F80830BC +:10D5A000002FDFD0034AB34011680B431360BDE87E +:10D5B000F08700BF042B0020000000202DE9F04779 +:10D5C0000D46811E022901D9BDE8F087C701DFF8A9 +:10D5D0004C909246044640373C2200211E4609EBFF +:10D5E00007082D0408F1040001F0A8FBBAFA8AF23A +:10D5F000520945EA427249F807200122C8F838600A +:10D60000C8F80820002EDFD0034B10341968A24060 +:10D610000A431A60BDE8F087042B002000000020B8 +:10D6200012048160C36101F5405342F0800210B4DE +:10D630000124426001F50052046001F5805401F5B7 +:10D640008041C46081615DF8044BC0E904237047E8 +:10D65000831E0A46022B00D97047064B00F11001C9 +:10D660004FF0010C03EBC0100CFA01F14030FFF752 +:10D6700099BB00BF00000020831E0A46022B00D980 +:10D6800070470121024B814003EBC010FFF78ABBBA +:10D690000000002040687047124A134BD2F8200265 +:10D6A00020F07F40984210B584B002D200EB800099 +:10D6B00040000E4C01A90A22FFF750F901A90023EE +:10D6C000204611F8012B01333AB10A2B20F8022F22 +:10D6D000F7D11623237004B010BD5B00DBB22370BA +:10D6E00004B010BD00441F4080969800E01A00204E +:10D6F00000F0DCBA00F0ACBA00F010BB00F0CABA1F +:10D7000000F066BB00F03CBB0846114600F02CBBA5 +:10D71000F8B5144C4FF0E025134E4FF4003204EBF3 +:10D720004024124F06EB40160346C5F88C212146D3 +:10D730003A883046FFF774FF3B882344BFF34F8F8E +:10D74000C5F85C4F2034A342FAD8BFF34F8FBFF324 +:10D750006F8F03203146FFF78FFF4FF40033C5F87A +:10D760000C31F8BDC00E2020601F0020EE2B0020E1 +:10D77000244B2DE9F0411C884368C569C3F30E436F +:10D78000E41A002C24DD204920480A780078D3B21E +:10D790001F4E82421F4807D010F8038036F81870D9 +:10D7A000C7F50072944218D90133002226F81540BB +:10D7B000082B194E88BF134626F8152098BFDAB2F9 +:10D7C000C554164B0A701A6814441C60BDE8F081F9 +:10D7D0002846BDE8F041FFF79BBF07EB4820104902 +:10D7E00022462744084401EB4521FFF719F80B4A6C +:10D7F000284626F8187013682344BDE8F0411360EA +:10D80000FFF786BFEE2B0020032C0020042C002005 +:10D81000742B0020942B0020842B0020702B0020E0 +:10D82000C00E20201D4B1A78002A36D102F0FF03CB +:10D830001B4A12788AB32DE9F0411A4D2A8852B357 +:10D84000194EC2F50068194F3278194C07EB421790 +:10D8500004EBC224424638462146FFF7E1FE04EBC2 +:10D860000802BFF34F8F4FF0E023C3F8704F20340E +:10D87000A242FAD8BFF34F8FBFF36F8F042039460F +:10D88000FFF7E6FE33780133DBB2032B88BF0023BA +:10D89000337000232B80BDE8F0817047082C0020F6 +:10D8A0000A2C0020F02B0020072C002060200020F4 +:10D8B000C01E20202DE9F04F85B0CDE901100029D0 +:10D8C00000F0BF800023604CDFF89881DFF898A15A +:10D8D0005E4F009301235E4A23705E4B1978B8F8BF +:10D8E000003002EB4119002B40F0A7801E461D4678 +:10D8F0009B464846FFF7CEFE10F0800000F08C807B +:10D90000BFF34F8F9AF8003084F800B005B93E6835 +:10D91000002B7DD13B689B1B782B00F287804E4B00 +:10D920001B78002B74D000F09DFA0122B8F800306B +:10D9300015462270002BDCD0464AC3F500601178F2 +:10D940001A4600EBC120454DC9022844019D95426D +:10D9500017D20393DDE901512A46FEF761FF039BCD +:10D960004FF040425B1BA8F800303D4BC3F88420C9 +:10D97000BFF34F8F009800232844237005B0BDE803 +:10D98000F08F364BCD180299FEF74AFF00234FF473 +:10D99000006229464846FFF743FEBFF34F8F05F16B +:10D9A000200205F50063934234BF012340234FF06A +:10D9B000E02205EB4313C2F8705F2035AB42FAD189 +:10D9C000BFF34F8FBFF36F8F04204946FFF740FE30 +:10D9D000204A13780133DBB2032B84BF00231D4A96 +:10D9E0001370B8F80030019AD11A009A1A440191C4 +:10D9F0000092029A1A4400230292194AA8F80030B1 +:10DA0000C2F88430BFF34F8F237000297FF462AFD8 +:10DA1000009805B0BDE8F08F4FF400620D4B8AF816 +:10DA2000000019781346A8F800208AE7012300981F +:10DA30008AF8003005B0BDE8F08F1A46C3F50060E3 +:10DA40007FE70198E5E700BF082C0020C42B0020E9 +:10DA500060200020072C00200A2C0020C01E20205F +:10DA600000002E40F02B0020062C0020704700BF45 +:10DA70002D4B002180222D4870B51B7800242C4DA1 +:10DA80008B422C4E0CBF40234FF400732B8033800D +:10DA900001F054F9284A2146284B14704FF4807243 +:10DAA00027481C8001F04AF9264A1021264B022003 +:10DAB000C2E90044C2E90244244AC3E900441470A4 +:10DAC000234AC3E90244234B1C70234614602246B8 +:10DAD000FFF774FD2246318803201F4BFFF73CFD02 +:10DAE0002346012229880420FFF768FD20460134DF +:10DAF000FFF70EFE082CF9D1184B00214A221848D6 +:10DB0000184C0460C3F88410C3F88020D3F848216F +:10DB1000154942F08072C3F8482121B1134A1378A5 +:10DB200043F00103137070BD0B2C00206020002017 +:10DB3000F22B0020EE2B0020072C0020F02B0020E1 +:10DB4000601F0020742B0020842B0020032C002059 +:10DB5000702B0020042C002031B7000000002E4064 +:10DB6000D82B0020E5B70000000000000D2C00209D +:10DB70002DE9F04F4FF0E0234FF40032DFF8C8A05A +:10DB800083B0C3F88C218B469AF8004000294FD00F +:10DB90008046E4B20027DFF8B490264BABEB0702D7 +:10DBA00025491B78A34204F101043FD0092C234BE3 +:10DBB000404628BF00241E5D39F816C00CEB4623F2 +:10DBC00019441F4B33F81650A5EB0C05AA421CD282 +:10DBD0000CEB462C18491B4C61440192FEF720FEC9 +:10DBE000216839F816505846019AA1EB0B012A44D6 +:10DBF000394429F8162021604FF0E0234FF4003219 +:10DC0000C3F80C2103B0BDE8F08F2A462F44FEF77D +:10DC100007FE0C49E3B230460A68A844521B0A606A +:10DC20008AF80030FFF774FDBB45B6D83846E3E705 +:10DC30000846E1E7032C0020C00E2020942B002092 +:10DC4000742B0020702B0020042C0020842B00203B +:10DC50000B4B0C4A12781978D3B28A420DD001339B +:10DC600009480A4A092B0A4928BF0023C35C31F836 +:10DC7000131002EB4323585C70474FF0FF3070479E +:10DC8000032C0020042C0020942B0020C00E202008 +:10DC9000842B0020044B10B51C680CB1204610BD2D +:10DCA00000F0E0F8204610BD702B00202DE9F84F61 +:10DCB000144E154D33782A78934221D0DCB2DFF828 +:10DCC0005090DFF850B0DFF85080104F0134082C2E +:10DCD0005FFA84FA01D90024A24619F80400DBF89F +:10DCE000003038F8102037F81010521A9B1ACBF871 +:10DCF0000030FFF70DFD86F800A02B78A342E5D198 +:10DD0000BDE8F88F042C0020032C0020842B002079 +:10DD1000942B0020702B0020742B002000B583B0C2 +:10DD200001210DF10700FFF723FF20B19DF8070047 +:10DD300003B05DF804FB4FF0FF30F9E7094B00B585 +:10DD400083B01B788DF807003BB101210DF107006E +:10DD5000FFF7B0FD03B05DF804FB03F0FF0003B074 +:10DD60005DF804FB0A2C0020044B1B7803F0FF0233 +:10DD70000BB1FFF79FBD1046704700BF0A2C002073 +:10DD80002DE9F0410024DFF8448001230D4D2746A2 +:10DD90000D4E88F80030337828462035A34204F130 +:10DDA000010405D0FFF776FC030658BF07F50067AE +:10DDB000042CF0D1BFF34F8F0023384688F8003091 +:10DDC000BDE8F08160200020072C0020082C0020F6 +:10DDD0002DE9F8431D4B1B7813B11D4D2A880AB954 +:10DDE000BDE8F8831B4EC2F500691B4933784A46EB +:10DDF0001A4C01EB43181A4F04EBC324012340468D +:10DE00003B7021460023FFF70BFC04EB0902BFF334 +:10DE10004F8F4FF0E023C3F8704F2034A242FAD85E +:10DE2000BFF34F8FBFF36F8F04204146FFF710FC05 +:10DE300033780133DBB2032B88BF00233370002318 +:10DE40002B80BFF34F8F3B70BDE8F8830A2C002076 +:10DE5000F02B0020072C002060200020C01E202076 +:10DE6000082C00202DE9F8432D4B1E7866B12D4F6C +:10DE70003B784BB90123F1073B7043D4B20726D45A +:10DE800000233B70730701D4BDE8F883264B1A6862 +:10DE9000002AF9D0EFF30582002AF5D1EFF31085BF +:10DEA00072B61868002834D0204C2178002930D16F +:10DEB0000122227042691A60002A2ED0916105B9B0 +:10DEC00062B600258368457798472570DCE7DFF860 +:10DED000648098F80030002BD2D00025DFF85890ED +:10DEE0002B4659F823400135236820461B69984783 +:10DEF00010B163699B68984798F80020EBB29A428A +:10DF0000EFD8BDE7FFF7C6FE0028B7D0AFF300801B +:10DF1000B4E7002DB8D162B6B6E7054B1A60CEE77C +:10DF20000D2C0020FD2B002020270020FB2B0020A3 +:10DF30002C270020FC2B0020A827002003460846A1 +:10DF4000194600F0B9BC00BF024B0146186800F04A +:10DF50000BB800BF881A0020024B0146186801F078 +:10DF6000B1B900BF881A00202DE9F04F01F10B066E +:10DF7000162E83B0044624D8102900F2BA8000F08F +:10DF8000A3FA102618220220B54F3A44A2F1080144 +:10DF900053688B4200F0BA805A68D96822F00302B5 +:10DFA0001A449D68E9608D60516841F00101204686 +:10DFB000516003F1080500F08DFA284603B0BDE872 +:10DFC000F08F36F0070600F19480B14200F29180A4 +:10DFD00000F07AFAB6F5FC7FC0F09A81730A00F07F +:10DFE0008F80042B00F26F81B30903F1390003F134 +:10DFF000380CC3009A4F3B44A3F108055B689D426F +:10E0000006D10CE0002980F22781DB689D4206D012 +:10E010005A6822F00302911B0F29F3DD60463D6927 +:10E02000DFF850C265457CD06A6822F00302931B7A +:10E030000F2B00F37B81002BC7E904CC80F26C81AD +:10E04000B2F5007F80F01A81D308796801334FEA76 +:10E05000521E012202FA0EF20A4357F833E0C5F8C5 +:10E0600008E007EBC3010839E9607A6047F83350EC +:10E07000CEF80C50831001219940914257D811429B +:10E0800006D120F003004900114200F10400FAD04B +:10E0900007EBC0094D468646D5F80C80454508D1AA +:10E0A0001DE1002B80F22481D8F80C80454500F05A +:10E0B0001681D8F8042022F00302931B0F2BF0DD09 +:10E0C0002046D8E9025408EB060146F00106C8F8DC +:10E0D0000460EC60A56043F00104C7E90411C1E9E4 +:10E0E00002CC4C6048F8023000F0F4F908F1080561 +:10E0F00002E00C2323600025284603B0BDE8F08F22 +:10E100004FF4007340204FF03F0C73E7D3689A42FE +:10E1100008BF02307FF440AF3D69DFF858C1654564 +:10E1200082D17A688310012199409142A7D9BD68B4 +:10E130006B6823F003094E4503D8A9EB06030F2BA8 +:10E140007ADCDFF834B1474BDBF800201B68013282 +:10E15000334405EB090A00F0338103F580530F3394 +:10E1600023F47F6828F00F084146204600F0F4FEB3 +:10E17000411C024600F0F380824500F2EE803A4BEB +:10E18000196841441960084600F04E81DBF8001020 +:10E19000019301311BBFA2EB0A010918CBF8002043 +:10E1A000196012F0070B00F01781CBF108010A4447 +:10E1B000CBF5805190440831A1EB0801C1F30B0A63 +:10E1C00051462046009200F0C7FE421CDDE90023C4 +:10E1D00000F04F81801A00EB0A081968BA6048F015 +:10E1E00001005144BD425060196000F02981B9F12D +:10E1F0000F0F40F227816868A9F10C0C2CF0070C76 +:10E2000000F0010040EA0C0068604FF0050E05EBDD +:10E210000C00BCF10F0FC0E901EE00F23281506832 +:10E220001546124B1A688A4238BF1960104B1A689B +:10E230008A4238BF196094E0AA1943F0010346F0FE +:10E2400001066E602046BA60536000F043F908355D +:10E25000284603B0BDE8F08FD9681A44A1E600BF94 +:10E260006C160020B829002088290020B029002041 +:10E27000B429002074160020741A0020B2F5206F13 +:10E280004FEA522363D3142B00F2B78003F15C01F1 +:10E29000C9005B3307EB010E7958AEF1080E8E45CD +:10E2A00000F091804B6823F00303934202D9896800 +:10E2B0008E45F7D1D1F80CE07A68C5E9021ECEF898 +:10E2C0000850CD60D6E6142B59D9542B00F29D800E +:10E2D000330B03F16F0003F16E0CC3008AE60EF1FD +:10E2E000010E1EF0030F05F108057FF4D5AE51E0D5 +:10E2F000424445465368D8F80C1043F0010353607C +:10E3000055F8083F2046D9608B6000F0E3F8F3E64B +:10E31000F00806F1080237E62A442046536843F025 +:10E3200001035360083500F0D5F8E5E6A919204649 +:10E3300046F0010643F001046E60C7E90411C1E92B +:10E3400002CC4C60AB5000F0C5F80835D4E6930918 +:10E3500003F13901C90038339CE7BD425FD0BD6885 +:10E36000686820F003084645A8EB060302D80F2B87 +:10E370003FF762AF204600F0ADF80025BCE603F1A0 +:10E380005C0003F15B0CC30034E659F808394B45D7 +:10E3900040F0968010F0030F00F1FF30F5D17B685C +:10E3A00023EA01037B60490099423FF6C0AE19B9E8 +:10E3B000BDE649000EF1040E1942FAD0704667E638 +:10E3C00003F11008D0E69A104FF001087B6808FAB4 +:10E3D00002F21A437A6070E702EB08014942C1F386 +:10E3E0000B0A51462046009200F0B6FD431CDDE9C1 +:10E3F00000237FF4EFAEDA46EFE6542B25D8130B5B +:10E4000003F16F01C9006E3344E7B3F5AA7F25D845 +:10E41000F30B03F1780003F1770CC300EAE5294B15 +:10E42000186840441860B1E6CAF30B0CBCF1000F49 +:10E430007FF4ACAEBD68C84448F001006860F0E607 +:10E440001546EEE60123536094E7B3F5AA7F23D87F +:10E45000D30B03F17801C90077331BE740F2545224 +:10E46000934223D8B30C03F17D0003F17C0CC3006D +:10E47000C0E5ABF1080BD844A8EB02084FF0000A46 +:10E48000ABE605F108012046009300F01BFFBD68D4 +:10E49000009B68681968C4E640F254518B420BD85F +:10E4A000930C03F17D01C9007C33F3E64FF47E73D6 +:10E4B0007F204FF07E0C9DE54FF47E717E23E9E6D0 +:10E4C0007B6870E788290020014800F09BBD00BFF1 +:10E4D00080290020014800F097BD00BF802900205E +:10E4E0002DE9F84F1746002900F098800C4607F1F7 +:10E4F0000B058046FFF7E8FF162D54F8041C5BD887 +:10E5000010252A46AF425CD821F003069642A4F1BA +:10E51000080962DABC4BD3F808C009EB0600844551 +:10E5200000F09780D0F804C02CF0010303445B682E +:10E53000DB0768D42CF0030C06EB0C03934247DA9C +:10E54000CB0710D454F8083CA9EB030ADAF80430DE +:10E5500023F003018C44B444944580F21181731874 +:10E56000934280F2E88039464046FFF7FDFC0746BB +:10E57000E0B154F8043C23F001034B44A0F108023D +:10E58000934200F0D280321F242A00F2F580132A31 +:10E5900000F2AC8003462246116819605168596048 +:10E5A00092689A602146404600F08CFE4046FFF794 +:10E5B00091FF3846BDE8F88F25F00705002D2A4663 +:10E5C000A0DA0C23C8F8003000273846BDE8F88FE1 +:10E5D0001E46D0E90223D3609A60731B0F2B22D80A +:10E5E000D9F8043003F0010333434E44C9F8043032 +:10E5F000736843F00103736040462746FFF76AFFE4 +:10E600003846BDE8F88FC907ADD454F8083CA9EBEB +:10E61000030ADAF8041021F00301A0E7BDE8F84F7F +:10E620001146FFF7A1BCD9F8042009EB050102F05F +:10E6300001024E4443F001032A43C9F804204B6011 +:10E64000736843F0010308317360404600F03AFEFE +:10E65000D2E7DCF8040020F0030B06EB0B0C05F10D +:10E66000100084454DDAC9073FF57DAF54F8081C0A +:10E67000A9EB010ADAF8041021F003018B44B3443A +:10E6800058453FF76CAF5746DAF80C1057F8080FAB +:10E69000321F242AC160886000F2DB80132A40F216 +:10E6A000D6802168CAF808106168CAF80C101B2AC5 +:10E6B00000F2DF8008340AF11002216811606168FD +:10E6C0005160A16891600AEB0501ABEB050242F0D5 +:10E6D000010299604A60DAF8043003F001032B4329 +:10E6E0004046CAF80430FFF7F5FE6EE72368036082 +:10E6F000636843601B2A68D804F1080200F108032C +:10E700004AE709EB05029A60ACEB050343F001030D +:10E71000536054F8043C03F001032B43404644F893 +:10E72000043CFFF7D7FE27464FE750F8043C23F0A0 +:10E7300003031E4451E75746DAF80C1057F8080F48 +:10E74000321F242AC16088604CD8132A48D9216816 +:10E75000CAF808106168CAF80C101B2A56D8083489 +:10E760000AF110021E462368136063685360A368B1 +:10E770009360D1463C4630E7214600F063FA11E74A +:10E78000D0E902135746CB60996057F8081FDAF8B2 +:10E790000C30CB60321F242A99602DD8132A29D936 +:10E7A0002368CAF808306368CAF80C301B2A42D8BC +:10E7B00008340AF1100322681A6062685A60A2687D +:10E7C0009A606646D1463C4607E7A3688360E368E3 +:10E7D000C360242A26D004F1100200F11003DBE606 +:10E7E0003A46BFE7214638461E46D14600F02AFA8F +:10E7F0003C46F2E63B46DEE7214638466646D146D1 +:10E8000000F020FA3C46E8E66C160020A168CAF841 +:10E810001010E168CAF81410242A20D010340AF12C +:10E8200018029FE7236903616169416104F11802DD +:10E8300000F11803B0E6A368CAF81030E368CAF81C +:10E840001430242A21D010340AF11803B3E73A46D1 +:10E8500033E72146384600F0F5F9164B33E72269D5 +:10E86000CAF818206269CAF81C2018340AF120027C +:10E8700078E7A168CAF81010E168CAF81410242AD1 +:10E880000DD010340AF1180217E72369CAF81830BE +:10E890006369CAF81C3018340AF120038BE7226937 +:10E8A000CAF818206269CAF81C2018340AF120023C +:10E8B00003E700BF6C16002013460A4601460220FB +:10E8C00000F06CBC024A0349034800F0BBB800BF2B +:10E8D0007C1A002095F70000A80F00200C4B41681F +:10E8E000994210B5044601D002F074FFA168094BAB +:10E8F000994202D0204602F06DFFE168064B994232 +:10E9000004D02046BDE8104002F064BF10BD00BF37 +:10E91000BC290020242A00208C2A00202DE9F8435D +:10E920002A4C2B4B2B48DFF8C090DFF8C0802A4FD1 +:10E930001860002504230822294604F15C00274EB4 +:10E940006566C4E90253C4E90055C4E90455A561EC +:10E9500000F0F4F9224B63670822294604F1C40051 +:10E96000C4E90749C4E90987C4E91A55C4E91E5531 +:10E97000C4F8CC502567C4F88050E66200F0DEF998 +:10E98000184BC4F8DC30294604F16803082204F56A +:10E990009670C4F88430C4E92298C4E92476C4E9A6 +:10E9A0003455C4E93855C4F83451C4F8D850C4F8C3 +:10E9B000E85000F0C3F904F1D003C4E93C98C4E97D +:10E9C0003E76C4F8EC30BDE8F88300BFBC290020D7 +:10E9D000F42A002085C80000B1CA0000D1CA000096 +:10E9E00009000100120002004DCA000071CA0000B7 +:10E9F00010B504460A4800F005FB636B23B9094BC8 +:10EA0000094A1B68626323B1BDE81040044800F066 +:10EA1000FBBAFFF783FFBDE81040014800F0F4BAED +:10EA200084290020F42A00209DC80000014800F03D +:10EA3000E9BA00BF84290020014800F0E5BA00BF10 +:10EA4000842900202DE9F84380460F4616464FF0F2 +:10EA50000009D6E90154013D11D4A389012B05F128 +:10EA6000FF3508D9B4F90E300133214603D04046B2 +:10EA7000B84749EA00096B1C04F16804EDD1366817 +:10EA8000002EE6D14846BDE8F88300BF10B50C461D +:10EA9000B1F90E1000F04AFA002803DB236D03449D +:10EAA000236510BDA38923F48053A38110BD00BF4B +:10EAB0002DE9F0410C46B1F90C101F46CB05054677 +:10EAC00016460BD421F48051A1813B46B4F90E10B7 +:10EAD00032462846BDE8F04100F050BAB4F90E10B5 +:10EAE0000223002200F00CFAB4F90C10EAE700BF90 +:10EAF00010B50C46B1F90E1000F002FAA389421CC1 +:10EB00000EBF23F4805343F480532065A38110BDCE +:10EB1000B1F90E1000F0E2B9F0B5ADF5057D04AF26 +:10EB2000009313464FF400720E460392394603AA2F +:10EB3000054600F025F888B104460246039B31469D +:10EB4000284600F01BFABC42039004D02846214618 +:10EB500000F0B8FB03980DF5057DF0BD4FF0FF30D8 +:10EB6000F9E700BF10B4054C8446134620685DF8F1 +:10EB7000044B0A466146FFF7CFBF00BF881A00204A +:10EB800030B5146815469BB01A4609B1002C19D14E +:10EB900000214FF42273ADF80C30009104914FF630 +:10EBA000FF7302910591ADF80E3069461E9B01F08E +:10EBB0006FF8002813DB009B286000221A7004986D +:10EBC0001BB030BD4FF4C16300910491ADF80C301F +:10EBD0002146E4DA8B23036000201BB030BD002007 +:10EBE000EEE700BF032A70B514D940EA01039B0782 +:10EBF00022D104460B46194620460E680568B542E8 +:10EC000004F1040403F1040316D1043A032A204654 +:10EC10001946F0D8541E9AB1421E013901E0C318BA +:10EC20000CD012F801EF11F801CFE645A4EB020376 +:10EC3000F5D0AEEB0C0070BD541EEDE7184670BD6C +:10EC4000104670BD88420DD98B1883420AD900EB5B +:10EC5000020CBAB1624613F801CD02F801CD994217 +:10EC6000F9D170470F2A0ED8034602F1FF3C4AB192 +:10EC70000CF1010C013B8C4411F8012B03F8012F1E +:10EC80006145F9D1704740EA01039B0750D1A2F1D9 +:10EC9000100370B501F1200C23F00F0501F1100EE7 +:10ECA00000F11004AC441B095EF8105C44F8105CE1 +:10ECB0005EF80C5C44F80C5C5EF8085C44F8085C98 +:10ECC0005EF8045C44F8045C0EF1100EE64504F1B5 +:10ECD0001004E9D1013312F00C0F01EB031102F023 +:10ECE0000F0400EB031327D0043C24F003064FEA83 +:10ECF000940C1E441C1F8E465EF8045B44F8045FAF +:10ED0000B442F9D10CF1010402F0030203EB8403D5 +:10ED100001EB840102F1FF3C4AB10CF1010C013B13 +:10ED20008C4411F8012B03F8012F6145F9D170BD16 +:10ED300002F1FF3C03469BE72246EBE7830730B531 +:10ED400048D0541E002A3FD0CAB2034601E0013C1D +:10ED50003AD303F8012B9D07F9D1032C2DD9CDB25D +:10ED600045EA05250F2C45EA054536D9A4F11002E0 +:10ED700022F00F0C03F1200EE6444FEA121C03F1BF +:10ED8000100242E9045542E9025510327245F8D1A9 +:10ED90000CF1010214F00C0F03EB021204F00F0C43 +:10EDA00013D0ACF1040323F003030433134442F8FB +:10EDB000045B9342FBD10CF003042CB1C9B21C4498 +:10EDC00003F8011B9C42FBD130BD64461346002C66 +:10EDD000F4D1F9E703461446BFE71A46A446E0E734 +:10EDE000002A3ED040EA01039B0730B584462FD16C +:10EDF000032A2DD90B4608E0043A8446194625D04B +:10EE00001EF0803F22D1032A22D90468194653F804 +:10EE1000045BA4F1013EAC4284462EEA040E00F1EC +:10EE20000400E9D09CF800000C78A0421BD1E64613 +:10EE300068B11EF8010F11F8014FA2EB0E03A042BA +:10EE400003F1FF330FD11CEB0303F1D1002030BDE0 +:10EE50009CF800000C78844205D1012AF6D0E646E1 +:10EE6000E6E710467047001B30BD00BF40EA0103D3 +:10EE70009B0730B501D1032A0FD8844601F1FF3E2C +:10EE800007E01EF8011F03F8011B541EC1B19C4688 +:10EE900022466346002AF4D130BD0B46844619460B +:10EEA00053F8045BA5F1013424EA050414F0803F13 +:10EEB000E4D1043A032A4CF8045B1946EFD8DDE7A5 +:10EEC0009444002CE8D003F8011B6345FBD130BD0E +:10EED000014B93F8280170470015002038B5074D05 +:10EEE0000022044608462A60FDF716FF431C00D0A6 +:10EEF00038BD2B68002BFBD0236038BD082B0020C9 +:10EF000038B50C46084D8446114620461A46002363 +:10EF10002B606446FDF70CFF431C00D038BD2B6806 +:10EF2000002BFBD0236038BD082B002038B50C46E1 +:10EF3000084D8446114620461A4600232B6064463D +:10EF4000FDF7E8FE431C00D038BD2B68002BFBD03A +:10EF5000236038BD082B002038B5074D0022044639 +:10EF600008462A60FDF7BCFE431C00D038BD2B6864 +:10EF7000002BFBD0236038BD082B002038B50C4691 +:10EF8000084D8446114620461A4600232B606446ED +:10EF9000FDF7B8F9431C00D038BD2B68002BFBD01F +:10EFA000236038BD082B0020014B1868704700BF54 +:10EFB000881A002070B50D4E0D4D761BB61006D088 +:10EFC000002455F8043B01349847A642F9D1094E74 +:10EFD000094D761B05F0C8F9B61006D0002455F887 +:10EFE000043B01349847A642F9D170BDD01D0060A2 +:10EFF000D01D0060481E0060D01D0060704700BF3B +:10F00000704700BF704700BF704700BF000000009E +:10F0100001F0FF01102A2BDB10F0070F08D010F8C9 +:10F02000013B013A8B422DD010F0070F42B3F6D1CD +:10F03000F0B441EA012141EA014122F007047FF0E6 +:10F0400000070023F0E80256083C85EA010586EA3D +:10F05000010685FA47F5A3FA87F586FA47F6A5FA79 +:10F0600087F68EB9EED1F0BC01F0FF0102F0070285 +:10F0700032B110F8013B013A83EA010313B1F8D130 +:10F080000020704701387047002D06BF3546033811 +:10F09000073815F0010F07D1013015F4807F02BF4A +:10F0A000013015F4C03F0130F0BC0138704700BF9B +:10F0B0000000000000000000000000000000000050 +:10F0C00090F800F06DE9024520F007016FF0000CA8 +:10F0D00010F0070491F820F040F049804FF0000450 +:10F0E0006FF00700D1E9002391F840F000F108002B +:10F0F00082FA4CF2A4FA8CF283FA4CF3A2FA8CF363 +:10F100004BBBD1E9022382FA4CF200F10800A4FAC9 +:10F110008CF283FA4CF3A2FA8CF3E3B9D1E904231D +:10F1200082FA4CF200F10800A4FA8CF283FA4CF354 +:10F13000A2FA8CF37BB9D1E9062301F1200182FA0E +:10F140004CF200F10800A4FA8CF283FA4CF3A2FA14 +:10F150008CF3002BC6D0002A04BF04301A4612BA22 +:10F16000B2FA82F2FDE8024500EBD2007047D1E925 +:10F17000002304F00305C4F100004FEAC50514F0B4 +:10F18000040F91F840F00CFA05F562EA05021CBF85 +:10F1900063EA050362464FF00004A9E72DE9F04752 +:10F1A000DFF87CA00646DAF8000098460F46914644 +:10F1B000FFF728FF184B1C6824B365681F2D24DC5B +:10F1C0005EB96B1C0235DAF80000636044F8257004 +:10F1D000FFF71AFF0020BDE8F08704EB850101234B +:10F1E000C1F88890D4F88821AB401A43022EC4F8A5 +:10F1F0008821C1F80881E4D1D4F88C211A43C4F8DD +:10F200008C21DEE7054C1C60D7E7DAF80000FFF739 +:10F21000FBFE4FF0FF30DEE7E8270020EC27002060 +:10F22000F4140020F8B5244F0C460646FFF74CF9BD +:10F23000BB685D68C4F57E610F3125F003054B198D +:10F2400023F47F6323F00F03A3F58054B4F5805FAC +:10F2500007DB00213046FFF77FFEBB682B44984256 +:10F2600004D03046FFF736F90020F8BD6142304641 +:10F27000FFF772FE01300DD0104ABB682D1B45F020 +:10F2800001055D60136830461B1B1360FFF722F910 +:10F290000120F8BD00213046FFF75EFEBA68831AF0 +:10F2A0000F2BDEDD43F001035360054B03491B6860 +:10F2B000C01A0860D5E700BF6C160020882900201E +:10F2C000741A0020002961D0F8B50C460646FFF7F5 +:10F2D000FBF854F8042C7B4FA4F1080522F001013F +:10F2E00005EB010CB868DCF80430604523F003033B +:10F2F00000F08B80D207CCF8043032D454F8082CBC +:10F30000AD1A1144AA6807F1080082426AD00CEBDA +:10F310000304D4F804E0EC68D4601EF0010FA2608E +:10F3200000F0978041F001036B60CCF80010B1F55C +:10F33000007F35D27868CB080122490901338A4021 +:10F34000024357F833107A6007EBC302083AC5E965 +:10F35000021247F83350CD603046BDE8F840FFF761 +:10F36000B9B80CEB03025268D00710D4194407F166 +:10F370000800DCF80830834273D0DCF80C20DA6037 +:10F38000936041F001036B606950D0E7704741F032 +:10F390000103B1F5007F44F8043CCCF80010C9D358 +:10F3A000B1F5206F4FEA512348D28B0903F13900A0 +:10F3B00003F13802C300F818FB580838984259D0B6 +:10F3C0005A6822F003028A4202D99B689842F7D118 +:10F3D000D868C5E902308560DD603046BDE8F84098 +:10F3E000FFF778B80CEB03025268D20763D40B44E2 +:10F3F000DCE90212CA60916043F001026A603046A3 +:10F40000EB50BDE8F840FFF765B80B44D10707D4CF +:10F4100054F8082CAD1A1344D5E90212CA60916061 +:10F4200043F001026A60284ABD6012689A4293D88C +:10F43000264B30461968FFF7F5FE8DE7142B0AD9E5 +:10F44000542B1FD80B0B03F16F0003F16E02C300A6 +:10F45000B1E719448DE703F15C0003F15B02C300DF +:10F46000A9E741F00103C7E90455C5E902006B6053 +:10F47000695071E779689210012404FA02F20A4394 +:10F480007A60A6E7B3F5AA7F06D8CB0B03F1780024 +:10F4900003F17702C3008EE740F25452934206D83C +:10F4A0008B0C03F17D0003F17C02C30083E74FF472 +:10F4B0007E737E227FE741F001036B60CCF8001081 +:10F4C0004AE700BF6C160020781A0020B8290020F7 +:10F4D00082B049B15AB16BB113780B601278101E2B +:10F4E00018BF012002B0704701A9002AF3D11046CD +:10F4F00002B070476FF00100F4E700BF436C70B5D5 +:10F5000005460C464BB153F8240080B1026843F81D +:10F5100024200023C0E9033370BD2122042102F01E +:10F52000DFFA034668640028EDD1002070BD012198 +:10F5300001FA04F6721D9200284602F0D1FA002862 +:10F54000F3D0C0E90146E4E731B1436C4A6853F8AF +:10F550002200086043F82210704700BF2DE9F041F7 +:10F560000E6980460F461D4601F1140E0020DEF89C +:10F5700000108CB202FB0453090C4FEA134C02FB3F +:10F5800001CC01309CB204EB0C4486424EF8044B93 +:10F590004FEA1C45EBDC3DB1BB68B34207DD07EB2E +:10F5A000860301365D613E613846BDE8F0817968C9 +:10F5B00040460131FFF7A2FF0446B0B13A6902327A +:10F5C00007F10C0192000C30FDF72AF9D8F844300D +:10F5D0007A6853F82210396043F82270274607EB07 +:10F5E000860301365D613E61DEE7034B0348224638 +:10F5F000BA2102F055FA00BFA0090020B40900208A +:10F60000030C1B04D3B90004102310F07F4F04BF78 +:10F610000002083310F0704F04BF0001043310F0F3 +:10F62000404F04BF80000233002805DB10F0804FFC +:10F6300003F1010308BF2023184670470023E4E7C5 +:10F64000036813F0070208D0D9071FD49A0722D500 +:10F650005B08036001221046704799B209B91B0C80 +:10F660001022D9B209B908321B0A190704BF1B09B5 +:10F670000432990704BF9B080232D90703D45B0800 +:10F6800002F1010205D003601046704700221046C7 +:10F6900070472022DFE79B08022203601046704774 +:10F6A00038B5436C04460D464BB15868B0B102689A +:10F6B0005A6000220123C0E90435C26038BD21220E +:10F6C000042102F00DFA034660640028EDD1094BD5 +:10F6D0000948002240F2451102F0E2F91C22012102 +:10F6E000204602F0FDF90028F1D001220223C0E9F2 +:10F6F0000123DEE7A0090020B40900202DE9F04F26 +:10F700000E691569AE4285B08846144605DB2A4667 +:10F71000234635460C4616469846A3686168AF19DD +:10F72000BB42B8BF0131FFF7E9FE0190002800F0AD +:10F730008780019B03F1140909EB870AD14505D2A3 +:10F740004B46002243F8042B9A45FBD808F11408D5 +:10F7500008EB860B04F11403D8451A4603EB850524 +:10F760005FD22B1B153B23F0030304331534A54252 +:10F7700038BF0423CDE902A7AC461F46924605E0F8 +:10F78000090C29D1C34509F1040948D958F8041BCB +:10F790008DB2002DF4D056464C46002356F8041B7B +:10F7A00022681FFA81FE90B2090C05FB0E00120CB4 +:10F7B000034405FB012202EB13429BB243EA0243DE +:10F7C000B44544F8043B4FEA1243E7D849F8073000 +:10F7D00058F8041C090CD5D0D9F8003050461A4608 +:10F7E0004C4600260588120C01FB052216449BB2EC +:10F7F00043EA064344F8043B50F8045B22682D0CAE +:10F8000093B201FB053303EB164384454FEA1346DD +:10F81000E8D8C34549F8073009F10409B6D8DDE94D +:10F8200002A7002F02DC05E0013F03D05AF8043D97 +:10F83000002BF9D0019B18461F6105B0BDE8F08F81 +:10F84000034B0448019A4FF4B17102F029F900BF4B +:10F85000A0090020B409002012F003032DE9F041B3 +:10F860001446064632D10D46A41020D0D6F840806A +:10F87000B8F1000F33D0E3074FF0000707D464104E +:10F8800015D0D8F80000A8B18046E307F7D5424666 +:10F8900029463046FFF732FFB5B16968736C6410D2 +:10F8A00053F821202A6043F821500546E9D1284623 +:10F8B000BDE8F081424641463046FFF71FFFC8F8D9 +:10F8C000000007608046E0E70546D8E7013B0F4AA5 +:10F8D00052F823200023FFF741FE0546C4E701212B +:10F8E0003046FFF70BFE804640B1012340F2712203 +:10F8F000C0E90432002330640360BCE7044B0548D0 +:10F90000424640F2451102F0CBF800BFB40E002091 +:10F91000A0090020B40900202DE9F0470D46144647 +:10F920002F69AB68496807EB62177E1C9E428046D0 +:10F930004FEA621904DD5B009E4201F10101FADC2D +:10F940004046FFF7DBFD8446002852D0B9F1000F96 +:10F9500000F114020EDD09F105014FEA810E134694 +:10F9600000EB8101002043F8040B8B42FBD1AEF188 +:10F9700014031A44296905F1140314F01F0E03EB54 +:10F9800081012ED0CEF1200910464FF0000A1C68EC +:10F9900004FA0EF444EA0A0440F8044B53F8044B0A +:10F9A000994224FA09FAF2D84B1B153B23F00303C2 +:10F9B000043305F11500814238BF0423BAF1000F6A +:10F9C00018BF374642F803A0D8F844306A68CCF82C +:10F9D000107053F822102960604643F82250BDE8A9 +:10F9E000F087043A53F8040B42F8040F9942F9D80F +:10F9F000EAE7034B034862464FF4EF7102F050F818 +:10FA0000A0090020B40900200B6984460069C01ACF +:10FA100016D10CF1140C14310CEB830210B401EB71 +:10FA2000830301E0944508D252F8044D53F8041DB5 +:10FA30008C42F7D005D24FF0FF305DF8044B704791 +:10FA4000704701205DF8044B704700BF2DE9F84F67 +:10FA50000F691369FF1A002F0E4690467FD101F1FE +:10FA60001405143202EB830205EB830301E09D428F +:10FA700078D253F8041D52F8044DA142F7D069D34F +:10FA80007168FFF73BFD8146002877D03569D8F8CB +:10FA90001020C76008F1140E06F1140009F1140AD1 +:10FAA00006F110010EEB820200EB850756464FF07F +:10FAB000000C5EF8044B51F804BFA3B21CFA8BFC97 +:10FAC000ACEB03034FEA144CCCEB1B4C0CEB234C7C +:10FAD0009BB243EA0C43724546F8043B4FEA2C4C78 +:10FAE000E7D8A2EB0801153908F11508424521F0C5 +:10FAF000030404F1040438BF0424204421F0030269 +:10FB000038BF002287425244544418D92646014641 +:10FB100051F8043B1CFA83FC4FEA2C4202EB1342DF +:10FB20001FFA8CFC4CEA02438F4246F8043B4FEA32 +:10FB3000224CEDD8013F3F1A27F00307E21923B901 +:10FB400052F8043D013D002BFAD0C9F81050484648 +:10FB5000BDE8F88F334601274646984690E7F9DB23 +:10FB600000278DE70021FFF7C9FC814668B101221B +:10FB70000023C9E904234846BDE8F88F064B07482F +:10FB80004A4640F2452101F08BFF034B03484A46A9 +:10FB900040F2372101F084FFA0090020B4090020C1 +:10FBA0002DE9F043884683B0012157EC106B1546D0 +:10FBB000FFF7A4FC0446002851D0C7F30A59C7F345 +:10FBC0001303B9F1000F01D043F48013002E019309 +:10FBD00018D101A8FFF734FD019A6261012200F1FA +:10FBE00020032261B9F1000F25D0A9F2334909EBB6 +:10FBF00003022046C3F13503C8F800202B6003B090 +:10FC0000BDE8F08368460096FFF71AFD034610B37F +:10FC1000DDE90002C3F1200102FA01F10143DA40FB +:10FC200061610192002AA26114BF022201222261B5 +:10FC3000B9F1000FD9D1A3F23243C8F8003004EB78 +:10FC400082031869FFF7DCFCC0EB421320462B60EF +:10FC500003B0BDE8F083009A6261019AE2E7034BCA +:10FC60000348224640F20F3101F01AFFA00900209C +:10FC7000B409002049B1FF2A02D80A700120704758 +:10FC80008A2303604FF0FF3070470846704700BF7B +:10FC90002DE9F04F2DED088BD1B00C460BEE101A6C +:10FCA00090460893834601F0BBFE03681293184602 +:10FCB000FFF706FA20AF1090082200213846FFF720 +:10FCC0003DF8A3891B0603D52369002B00F0558757 +:10FCD00000239FED838B9FED849BCDE92533CDE9F8 +:10FCE0001333CDE9153327AA0E932492924611932C +:10FCF00004934446A1467E4BD3F8E450FFF7E8F85E +:10FD00004A4603461CA900975846A847002800F019 +:10FD1000B080C0F2A6801C9A252A034601D09944DF +:10FD2000E9E7B9EB0405064640F0A78000234FF051 +:10FD3000FF328DF867309846069309F1010999F86A +:10FD4000003003922B25202609F10109A3F120029E +:10FD50005A2A00F2CF80DFE812F0E802CD00CD0091 +:10FD6000E302CD00CD00CD006A00CD00CD0005023C +:10FD70008402CD001002C902CD00BD025B005B0011 +:10FD80005B005B005B005B005B005B005B00CD0029 +:10FD9000CD00CD00CD00CD00CD00CD005301CD0074 +:10FDA00083011A02530153015301CD00CD00CD0050 +:10FDB000CD001502CD00CD009602CD00CD00CD00C6 +:10FDC000AB01CD00AA02CD00CD00E306CD00CD00F1 +:10FDD000CD00CD00CD00CD00CD00CD005301CD0034 +:10FDE0008301DE015301530153017702DE017F00DD +:10FDF000CD008902CD005F02E0062F027F00CD001A +:10FE0000AB017C00B806CD00CD00BD06CD007C0066 +:10FE1000A3F13002002119F8013B01EB810102EB53 +:10FE20004101A3F13002092AF5D906918EE758461F +:10FE300001F0F6FD436815931846FFF741F9169057 +:10FE4000584601F0EDFD83681393169B002B40F09C +:10FE50002D8699F8003077E799F8003048F02008AF +:10FE600072E7082200213846FEF768FF0123994413 +:10FE700041E7B9EB0405064611D0269B2B44269397 +:10FE8000259B0133072BCAE9004525931CDC0AF1A9 +:10FE9000080A049B2B440493002E7FF447AF269B53 +:10FEA000002B41F00B821BEE103AB3F90C3013F02B +:10FEB000400F049B18BF4FF0FF330493049851B0D8 +:10FEC000BDEC088BBDE8F08F1BEE101A24AA584633 +:10FED00002F092FD0028E6D10DF19C0AD9E700BF9F +:10FEE0000000000000000000FFFFFFFFFFFFEF7FAA +:10FEF000001500200B93002BD1D00021CDE90C116F +:10FF00008DF8DC3001238DF867100293079105937B +:10FF100003910F9137AC18F00203099302D0029BB2 +:10FF20000233029318F084030A9305D1069B029AC8 +:10FF30009D1A002D00F36983269A89B125990DF148 +:10FF4000670001310132CAF8000007294FF00100B3 +:10FF500026922591CAF8040000F3A2830AF1080A48 +:10FF6000099B83B1259B1AA901330232CAF80010FC +:10FF7000072B4FF0020126922593CAF8041000F3D4 +:10FF8000A3830AF1080A0A9B802B00F06C82039B72 +:10FF900005995D1A002D00F3A58218F4807F40F0CA +:10FFA0000D82059BCAF804301A44259BCAF800400C +:10FFB0000133072B2692259300F31B830AF1080ACD +:10FFC00018F0040F05D0069B02995C1A002C00F370 +:10FFD0008883049B069902988142ACBF5B181B186A +:10FFE0000493002A40F0B08200232593079B1BB1A5 +:10FFF00007995846FFF766F90DF19C0A4C4679E6D9 +:02000004600199 +:100000000B93089B073323F00703B3EC028BB0EE8E +:10001000C87BB4EE497BF1EE10FA089340F3E98413 +:10002000B5EEC08BF1EE10FA01F159809DF8671022 +:10003000AB4CAC4B28F080080B9A472AC8BF1C4633 +:100040000023CDE90C330322079302920592039318 +:100050000F9300293FF45FAF029B013302935AE7ED +:10006000432B0B9303D018F0100F00F05D85089D13 +:100070000822002122A837ACFEF760FE22AB55F81B +:10008000042B2146584602F071FC034601330590CB +:1000900001F0EE82059B089523EAE37302930021A9 +:1000A000CDE90C118DF86710079103910F9132E79C +:1000B0000B93089B1A4600238DF86730134653F8BC +:1000C000044B0893002C00F048850B9B532B00F049 +:1000D000EC8618F010030C9340F0E786039B5D1C40 +:1000E00001F0E5800C991A462046FEF791FF079033 +:1000F000002801F02883079B1A1B05920C9B039391 +:1001000022EAE2720F930D93079373239DF8671011 +:1001100002920B939DE718F0200F0B93089B3DD0A4 +:10012000073323F007031A4611465B6851F8082B82 +:1001300008911946002BC0F20C84039B013300F098 +:100140009E8228F0800052EA0103029040F09982DA +:10015000039B002B40F09A82804600230393059373 +:1001600050AC06E1089B53F8042B0692002A80F25B +:100170001984069A08935242069299F8003048F082 +:100180000408E1E599F8003048F00808DCE548F09B +:10019000100818F0200F0B93089BC1D118F0100F16 +:1001A00040F00B8418F0400F00F0038433F9042B67 +:1001B0000893D1170B46BDE7089B48F00202029254 +:1001C00053F8042B089347F63003ADF868307820D5 +:1001D000454B1193002102230B900020039C8DF8C6 +:1001E0006700601C00F0AD80029820F0800852EAA1 +:1001F000010040F0A480002C40F0AE86002BACD172 +:10020000029B13F00103059300F0D18330238DF896 +:100210003F310DF23F14ACE018F0200F40F0D483D2 +:1002200018F0100F40F09F8618F0400F40F09787AD +:1002300018F4007F00F09786089B049953F8042B6C +:10024000089311704C4655E599F80030682B03BFB0 +:1002500099F8013048F4007809F1010948F04008A4 +:1002600072E599F800308DF867506DE599F8003027 +:100270006C2B03BF99F8013048F0200809F10109FF +:1002800048F0100860E50B9348F0100818F02001C2 +:1002900000F05183089B073323F00703596853F894 +:1002A000082B089328F480630293002395E70B93AF +:1002B00048F010030293029B13F0200100F0298301 +:1002C000089B073323F00703596853F8082B08935A +:1002D000012382E799F8003048F0800834E500BF38 +:1002E000800B0020840B0020900B0020494611F861 +:1002F000013B2A2B01F04982A3F13002092A8946E9 +:1003000098BF002101F2448119F8013B01EB810102 +:1003100002EB4101A3F13002092AF5D9039115E559 +:1003200099F8003048F001080EE59DF86730002B81 +:100330007FF48FAD99F800308DF8676004E5CDF853 +:100340000880012B00F09D81022B50AC20D1119828 +:1003500002F00F031209C35C04F8013D42EA017286 +:10036000090952EA0103F3D150AB1B1BDDF80880E9 +:100370000593059A03989DF8671082424FF0000399 +:10038000B8BF0246CDE90C33079302920F9360E6A3 +:1003900002F00703D20842EA4172C908303352EA38 +:1003A0000105204604F8013DF2D1029AD10700F17F +:1003B0004D8250AB1B1B90460593DAE70B9B652BD8 +:1003C00040F3D480B5EE408BF1EE10FA40F0C181DD +:1003D000259BBA49CAF80010013301320121072BCD +:1003E00026922593CAF8041000F351850AF1080AF1 +:1003F0001B9B0E998B4280F2D082109B12991A445B +:10040000CAE90013259B26920133072B259300F39D +:1004100097830AF1080A0E9B5C1E002C7FF7D0AD73 +:10042000102C259B40F36E851BEE106A102505E00D +:100430000AF1080A103C102C40F364850133A049EE +:100440001032072BCAE90015CDE92532F0DD24AAC8 +:100450003146584602F0D0FA00287ED1DDE9253237 +:100460000DF19C0AE6E7069B02995D1A002D7FF7C5 +:100470008EAD102D259B21DD099410261BEE104A10 +:1004800004E0103D102D0AF1080A16DD01338C49F5 +:100490001032072BCAE90016CDE92532F1DD24AA76 +:1004A000214658460DF19C0A02F0A6FA002854D1C4 +:1004B000103D102DDDE92532E8DC099C8049CAF8A1 +:1004C000045001332A44072BCDE92532CAF8001025 +:1004D00000F32685039B05995D1A002D0AF1080A91 +:1004E0007FF75BAD102D259B1FDD514610261BEEBF +:1004F00010AA04E0103D102D01F1080114DD0133B4 +:100500006F481032072BC1E90006CDE92532F1DD35 +:1005100024AA5146584602F06FFAF0B9103D102D4A +:10052000DDE9253227A9EADC8A4601336449CAF8A5 +:1005300004502A44072BCDE92532CAF8001000F3F5 +:10054000DA810AF1080A28E51BEE101A24AA584697 +:1005500002F052FA00283FF447AD079B002B3FF40E +:10056000A2AC07995846FEF7ADFE9CE40E9B012B0A +:1005700040F37A81259BCAF8004001330132012102 +:10058000072B26922593CAF8041000F3F8810AF18C +:10059000080A1099129801330A44072BCAE900018E +:1005A000CDE9253200F3DD810AF1080AB5EE408B72 +:1005B000F1EE10FA00F077810E9901330139013420 +:1005C0000A44072BCAF800402593CAF80410269263 +:1005D00000F35B810AF1080A1499CAF80410013388 +:1005E0000A44072B1EA9CDE92532CAF800107FF76F +:1005F000E5AC1BEE101A24AA584602F0FDF90028BB +:10060000ABD1269A0DF19C0ADAE4102DDDE9251212 +:100610002C4E24DD179410231BEE104A084604E0EC +:10062000103D102D0AF1080A17DD0130103207289D +:10063000CAE90063CDE92502F2DD24AA2146584625 +:100640000DF19C0A02F0D8F9002886D1103D102D3A +:10065000DDE925024FF01003E7DC179C014601316C +:100660002A440729CDE92512CAF80060CAF80450C7 +:1006700000F3BD839DF867100AF1080A5DE4CDF828 +:1006800008800A2A71F1000380F04583303201238B +:10069000DDF808808DF83F2105930DF23F1468E6E0 +:1006A0001BEE101A24AA584602F0A6F900287FF47F +:1006B00054AF269A0DF19C0A52E400BFC00B0020F3 +:1006C000880F0020C40B00201BEE101A24AA5846E5 +:1006D00002F092F900287FF440AF269A0DF19C0AAF +:1006E00051E4102C259BBE4E1FDD1BEE108A1025F9 +:1006F00004E0103C102C0AF1080A16DD0133103218 +:10070000072BCAE90065CDE92532F2DD24AA41466E +:1007100058460DF19C0A02F06FF900287FF41DAFD6 +:10072000103C102CDDE92532E8DC01332244072B94 +:10073000CAE90064CDE925327FF74BAC1BEE101AF5 +:1007400024AA584602F058F900287FF406AF269AEA +:100750003FE41B99002940F35A830C9E0E9B9E4256 +:10076000A8BF1E46002E0BDD259B01333244072B0C +:10077000CAE900462692259300F389860AF1080A01 +:100780000C9D002EA8BFAD1B002D00F303820C9B17 +:1007900018F4806F2344059340F01F821B9B0E9931 +:1007A0008B4203DB18F0010F00F0CF8410991298F0 +:1007B0000A44CAE9000125992692013107292591A9 +:1007C00000F3A5860AF1080A0E996518CC1A059B54 +:1007D000ED1AA542A8BF2546002D0DDDCAF8003050 +:1007E000259BCAF8045001332A44072B26922593EF +:1007F00000F3BB860AF1080A002DA8BF641B002C79 +:100800007FF7DEAB102C259B40F37C831BEE106A38 +:10081000102505E00AF1080A103C102C40F3728301 +:10082000013370491032072BCAE90015CDE9253292 +:10083000F0DD24AA3146584602F0DEF800287FF4A5 +:100840008CAEDDE925320DF19C0AE5E7302B3FF453 +:100850008BAD3023023804F8013C50AB1B1ADDF895 +:1008600008800593044684E518F0010F7FF482AEFA +:10087000259BCAF80040013301320121072B269243 +:100880002593CAF804107FF7A5AE1BEE101A24AA10 +:10089000584602F0B1F800287FF45FAEDDE925325A +:1008A0000DF19C0A98E60E994C1E002C7FF794AE31 +:1008B000102C40F361831BEE106A102505E00AF14D +:1008C000080A103C102C40F357830133454910327D +:1008D000072BCAE90015CDE92532F0DD24AA3146FF +:1008E000584602F089F800287FF437AEDDE925325A +:1008F0000DF19C0AE5E71BEE101A24AA584602F0F7 +:100900007BF800287FF429AE269A0DF19C0AFFF7A8 +:1009100044BB029B13F0100340F0C180029A12F016 +:10092000400200F07A83089850F8042B089019468A +:1009300092B2012351E418F0100355D118F040028F +:1009400000F05D83089850F8042B0890194692B285 +:10095000A8E4524261EB4101CDF808802D2001232B +:100960003CE41BEE101A24AA584602F045F8002871 +:100970007FF4F3ADDDE925320DF19C0A16E61BEE9E +:10098000101A24AA584602F037F800287FF4E5AD83 +:10099000DDE925320DF19C0AFBE518F0010F3FF46B +:1009A0000FAB2AE5089399F80030FFF7CDB950ACAA +:1009B000DFE418F4007F40F0DB8353F8042B089346 +:1009C000D1170B46FFF7B6BB089B049853F8041BDE +:1009D0000893C217C1E900024C46FFF78BB900BF6C +:1009E000C40B0020880F0020089B53F8042B0893A9 +:1009F00058E4B4EE488BF1EE10FA80F194860B9B2C +:100A0000612B00F05285412B00F0C085039B013320 +:100A10000B9B23F0200500F08084472D04D1039B1D +:100A2000002B08BF0123039318EE903A002B48F4E3 +:100A300080724646C0F21886B0EE48AB002390465E +:100A4000099307930B9B413B252B00F29883DFE82A +:100A500013F06F0496039603960368046C049603E0 +:100A600096039603960396039603960396039603BE +:100A700096039603960396039603960396039603AE +:100A8000960396039603960396039603960396039E +:100A90009603960396039603960368046C04089BDA +:100AA00053F8042B08930123FFF797BB139B002BEC +:100AB0003FF4CFA9139B1B78002B3FF4CAA999F8E8 +:100AC000003048F48068FFF73FB90B93CDF80880F9 +:100AD000FFF7F1BB0B939A4B119318F0200100F034 +:100AE0000581089B073323F00703596853F8082B47 +:100AF000089318F0010F0AD052EA010307D00B9BAC +:100B00008DF86930302348F002088DF8683028F4F9 +:100B1000806302930223FFF760BB0B93FFF7B6BB22 +:100B20000B93884B1193D8E7089B012153F8042BB2 +:100B300002918DF8DC200893059137ACFFF7AFBA2E +:100B40001BEE101A24AA584601F056FF00287FF425 +:100B500004AD269A0DF19C0A5DE4039B0794062BD5 +:100B6000224628BF062303942146CDE90C22764C69 +:100B7000029305930F92FFF76CBA40215846FDF798 +:100B8000F3F920602061002800F00F8640236361A4 +:100B9000FFF79EB8102D259B40F35D82514610262D +:100BA0001BEE10AA04E00831103D102D40F35282D4 +:100BB000013366481032072BC1E90006CDE9253222 +:100BC000F1DD24AA5146584601F016FF00287FF4B3 +:100BD000C4ACDDE9253227A9E6E70E9BCDF82490C9 +:100BE000E31803930D9BCDF82880139E059DDDF837 +:100BF0005890DDF83C800B941BEE101A5046002BE9 +:100C000034D0B8F1000F35D10D9B013B013E0D935F +:100C1000159BC0E90039259B01334A44072B2692D6 +:100C200025936CDC0830039B96F800C05B1B634582 +:100C3000A8BF6346002B9A460CDD259C01341A445C +:100C4000072CC0E900532692259400F3778196F88B +:100C500000C00830BAF1000FACBFACEB0A04644628 +:100C6000002C0ADC65440D9B002BCAD1B8F1000FA3 +:100C700000F0AC8308F1FF38CAE7102CDDF894C00F +:100C800024DD05954FF0100A63460D4604E0103C44 +:100C9000102C00F1080016DD01332C491032072B0F +:100CA000C0E9001ACDE92532F1DD24AA29465846CB +:100CB00001F0A2FE00287FF450AC103C102CDDE9BE +:100CC000253227A8E8DC2946059D9C460CF1010346 +:100CD00022444460072B1D4C0460CDE9253200F30B +:100CE000C68396F800C008306544BCE718F01003CE +:100CF00000F0C280089B53F8042B0893F9E624AA5D +:100D00005846059101F078FE00287FF426AC269A1B +:100D1000059927A887E70298CDF81CA050AC00F4ED +:100D2000806000250AEE10BA094BDDF84CA0CDF822 +:100D30001490A3464FF00508AC46044610E000BFEF +:100D4000900B0020A40B0020B80B0020880F00207F +:100D5000CDCCCCCC0A2A71F1000136D34A463146BB +:100D6000501840F10000A3FB005626F0030505EBE8 +:100D70009605401B151A4FF0CC3661F1000E06FBAC +:100D800005F6A5FB039503FB0E6609F0010E2E4444 +:100D9000AEFB085E2D184FEA590930350BF8015C9F +:100DA00049EAC6790CF1010C0BF1FF3B7608002CE7 +:100DB000D0D09AF800008445CCD1BCF1FF0FC9D047 +:100DC0000A2A71F1000180F08F815C4650AB1B1B39 +:100DD000DDF81490CDF84CA01AEE10BADDF81CA086 +:100DE000DDF80880CDF838C00593FFF7C2BA1BEED6 +:100DF000101A24AA584601F0FFFD00287FF4ADAB7D +:100E00009DF86710269A0DF19C0AFFF796B8259B6E +:100E1000BE48CAF80000013301320120072B269298 +:100E20002593CAF8040000F377810AF1080A002923 +:100E300040F0AF800E9908F001030B433FF4C0A8C7 +:100E4000109B12991A44CAE90013259B269201337C +:100E5000072B259300F352820AF1080A0E99CAF86B +:100E6000004001330A44072BCDE92532CAF80410AB +:100E70007FF7A4A8FFF7BDBB18F0400200F0DD80AB +:100E8000089850F8042B0890194692B231E61BEEF0 +:100E9000101A24AA584601F0AFFD00287FF45DAB7C +:100EA000269A0DF19C0AFFF7A3BA22AE0822002170 +:100EB00030461D94FDF742FF039B5A1C00F0DB8077 +:100EC0000025CDF80890CDF81C809946A8460CE086 +:100ED00037A9584601F04AFD431C404400F0C8833E +:100EE000484508DC00F0188480461D9A5259334664 +:100EF0000435002AECD1CDF81480DDF80890DDF837 +:100F00001C80C5E001338249CAF804402244072B03 +:100F1000CAF80010CDE925327FF750A8FFF769BB6A +:100F20001BEE101A24AA584601F066FD00287FF433 +:100F300014AB269A0DF19C0AFFF729B824AA58464B +:100F4000059101F059FD00287FF407AB96F800C029 +:100F5000269A059927A87DE6012BCDF808807FF415 +:100F6000F3A9FFF793BB089B049953F8042B4C4655 +:100F700011600893FEF7BEBE01336549CAF804400C +:100F80002244072BCDE92532CAF800107FF722ABA7 +:100F90007BE4109B12981A44CAE90003259B269211 +:100FA0000133072B259300F3A9810AF1080A0029D0 +:100FB000BFF654AF4D42103180F20F831BEE101A72 +:100FC000102605E00AF1080A103D102D40F30583B4 +:100FD00001334F481032072BCAE90006CDE925320C +:100FE000F0DD24AA5846039101F006FD00287FF4A5 +:100FF000B4AADDE9253203990DF19C0AE4E7089BC8 +:1010000018F400711ABF114653F8042B53F8042B3F +:10101000089318BFD2B2FFF745B9029B13F40071D1 +:10102000089B1ABF114653F8042B53F8042B08935E +:1010300018BFD2B20123FFF7D0B8089B18F4007193 +:101040001ABF114653F8042B53F8042B089318BF0A +:10105000D2B24EE58A4601332D49CAF804502A44DB +:10106000072BCDE92532CAF8001000F339810AF1C7 +:10107000080AFFF78CBB0023194600961DAA5846A4 +:1010800001F09AFC03460133059000F0F1821D94B3 +:10109000059B002B4ED0632B00F318810023079390 +:1010A00037AC082200213046FDF748FE059D00962A +:1010B0002B461DAA2146584601F07EFC854240F091 +:1010C0007C83059A0023A35422EAE272CDE90C3313 +:1010D0009DF86710039302920F93FEF7BABF2D217C +:1010E0008DF86710FEF7A4BF169B1599ABEB030BA9 +:1010F0001A465846FDF7BAFE9AF80120054B0AB188 +:101100000AF1010A4FF0000C28E600BFC00B0020D6 +:10111000880F0020CDCCCCCC1BEE101A24AA584648 +:1011200001F06AFC00287FF418AA1B99269A0DF199 +:101130009C0A7CE6059B9DF867100F93CDE902336E +:10114000CDE90C330793FEF784BF0E990598651817 +:101150002D1ACC1AA542A8BF2546FFF74DBB089B08 +:10116000049953F8042B089311804C46FEF7C2BD36 +:1011700013F9042B0893D1170B46FEF7DBBF039A34 +:10118000022122AB01931DAB009358461BABB0EE7E +:101190004A0B029200F074FD472D029A044600F0BB +:1011A0006181462D104405D12378302B00F06F82E9 +:1011B0001B9A1044B5EE40ABF1EE10FA40F04681B8 +:1011C00003461B1B0E93472D00F01081462D00F0A7 +:1011D000B5811B9B0C930C9B412D03F1FF331B939B +:1011E00000F0E5819DF82C200021002BB8BF0C9B5E +:1011F0008DF87820BABFC3F101032D222B22092BD1 +:101200008DF8792040F3DA810DF18F05DFF81CC4E9 +:101210002A4610468CFB0321DA17C2EBA10202EB2F +:101220008201A3EB4101303100F8011C194663290A +:10123000134600F1FF32ECDC3033D9B2831E9D42FD +:1012400002F8011C40F28B8213460DF17A0201E094 +:1012500013F8011B02F8011B9D42F9D10DF1910316 +:101260000DF17A021B1A13441EAA9B1A14930E9BAB +:10127000149A012B1A44059240F30382059B109A9D +:101280001344059326F48063059A43F48078002381 +:10129000CDE90C3322EAE2720F930292099B002BF4 +:1012A00040F0B1809DF867100393FEF7D2BE204650 +:1012B000FDF706FF02460590FEF720BF1BEE101A51 +:1012C00024AA584601F098FBFEF7EDBD591C58467C +:1012D000FCF74AFE0446002800F0CA810790E0E6C9 +:1012E0001BEE101A24AA584601F086FB00287FF452 +:1012F00034A9269A0DF19C0AFFF749BA1BEE101A81 +:1013000024AA584601F078FB00287FF426A9DDE9DD +:1013100025321B990DF19C0A49E606230393FFF73A +:1013200083BB039B02215A1C2BE7039A032128E766 +:101330001BA8B0EE4A0B00F077FBB4EE007B20EE6A +:10134000070BB5EE400BF1EE10FA01D101231B9310 +:10135000B348039BB3EE005B013B224604E0B5EECD +:10136000400BF1EE10FA13D020EE050BFDEEC07B22 +:10137000B3F1FF3F17EE901A415CB8EEE76B94466D +:1013800030EE460B02F8011B194603F1FF33E6D19C +:10139000B6EE006BB4EEC60BF1EE10FA00F3488126 +:1013A000B4EE460BF1EE10FA04D117EE903ADB07DB +:1013B00000F13E81002906DB4B1C1344302102F86A +:1013C000011B9342FBD1131B0E93FCE60B9C0E9B5F +:1013D000DDF82490DDF828801396E3189D42294615 +:1013E00028BF194682460591FFF7D8B91B9B0C937D +:1013F000DA1C02DB039A93420CDD0B9B023B0B933E +:1014000023F02005E7E62D2100238DF867100393D4 +:10141000FEF722BE0C9B0E9A9342C0F2BD80F007ED +:101420000C9B40F13281109A13440593710503D54A +:101430000C9B002B00F33581059B23EAE373029399 +:1014400067230B9300230F930D9327E7229B83427F +:10145000BFF4B7AE30215A1C22921970229B9842D9 +:10146000F9D8AEE6F30700F1A780229BA9E624AAEB +:101470005846059101F0C0FA00287FF46EA896F84E +:1014800000C0269A059927A86544FFF7ECBB1BEE20 +:10149000101A24AA584601F0AFFA00287FF45DA87C +:1014A000269A0DF19C0AFFF76BB978238DF8693005 +:1014B00030238DF86830039B632B48F0020600F35D +:1014C000A6800023079337AC18EE903A002B48F41F +:1014D00081782BDBB0EE48AB0B9B23F0200500237B +:1014E00009930B9B612B7FF4ADAAB0EE4A0B1BA8AE +:1014F00000F09AFAB4EE007B20EE070BB5EE400B3D +:10150000F1EE10FA01D101231B93464821E71BEEAF +:10151000101A24AA584601F06FFA00287FF41DA87B +:101520001B9B269A0DF19C0AFFF74EB90B9B23F0EB +:1015300020052D230993B1EE48ABD2E71B9A0C92FC +:10154000002A06F0010340F30D8103990B4340F09C +:10155000CF800C9B059366230B93720500F1A3804B +:10156000059B23EAE37302936CE71BEE101A24AA8F +:10157000584601F041FA00287EF4EFAF1B9C0E9B09 +:10158000269A1C1B0DF19C0AFFF736B958238DE7EC +:1015900000220392FEF7DABB0E9B109A9A180C9B5E +:1015A0000592002B40F3AB8067230B93D5E70B9A92 +:1015B0000F32D2B2012118E6A018FBE5002940F055 +:1015C000A88030228DF87A200DF17B02303302F8AA +:1015D000013B1EABD31A149349E601331249CAF8F2 +:1015E00004502A44072BCDE92532CAF800107FF7B2 +:1015F00033AC1BEE101A24AA584601F0FDF900285E +:101600007EF4ABAFDDE925320DF19C0A26E4591CCE +:101610005846FCF7A9FC044650B3079054E700BFB6 +:10162000A40B0020900B0020880F002067666666E0 +:10163000CDF888C012F8011C90F80FC06145134620 +:101640000AD14FF0300E03F801EC229B591E229173 +:1016500013F8011C8C45F6D0392916BF0131817A67 +:10166000C9B203F8011CAEE600239046079360E779 +:101670001BEE102AB2F90C3043F040039381FEF7C1 +:1016800016BCF5077FF5FEADF8E50593CEE6B5EEA1 +:1016900040ABF1EE10FA3FF48BADC2F101021B92A8 +:1016A00087E567230B9313990B78FF2B79D00025DF +:1016B0000C9A284603E001300131FF2B08D09342F9 +:1016C00006DAD21A4B78002BF5D10B780135F4E706 +:1016D0000C9213910D900F950F9A0D9B1699134430 +:1016E000059A01FB0323059323EAE3730293D5E5EF +:1016F000109BD3181944662305910B932DE7C3F172 +:1017000001031A4422EAE2730293672305920B93C2 +:1017100098E60DF17A0259E7039BDDF80890DDF8B1 +:101720001C800593B4E418EE903A002BB4BF2D2131 +:101730009DF86710254C264BB8BF8DF8671028F030 +:101740008008FEF779BC039B0293059373239DF8F1 +:10175000671003900F900D900B93FEF77ABC022355 +:10176000149384E5039A134305D10123662202935F +:101770000B92059366E6109B01331A4422EAE2734A +:101780000293662305920B935CE6089A99F8013060 +:10179000894652F8041B089241EAE1710391FEF771 +:1017A000D3BA00230F930D9396E70C23CBF80030A8 +:1017B0004FF0FF330493FEF781BB1BEE102A938991 +:1017C00043F040039381FEF7C8BE00BF880B0020A2 +:1017D0008C0B002070B500294BD006460C4610B18A +:1017E000436B002B48D0636ED80734D5B4F90C3066 +:1017F000002B3ED02146304600F050F8E36A054603 +:1018000033B1E169304698470028B8BF4FF0FF3543 +:10181000A3891A063CD4216B41B104F140039942DB +:1018200002D03046FDF74EFD00232363616C21B1E9 +:101830003046FDF747FD00236364FDF7F7F8636E5C +:101840000022DB07A2811FD5A06DFDF7D9FBFDF7B4 +:10185000F3F8284670BDA3899905CBD4A06DFDF798 +:10186000D1FBB4F90C30002BC4D1656E15F0010525 +:1018700005D00025284670BDFDF7BAF8B3E7A06D86 +:10188000FDF7C2FB284670BDA06DFDF7BDFBDBE791 +:1018900021693046FDF716FDBDE700BFB1F90C2008 +:1018A0002DE9F0410C461107804647D4636842F4A5 +:1018B0000062002BA2815EDDA56A002D58D00023B6 +:1018C000D8F80060C8F8003093B212F4805256D1B4 +:1018D0000123E1694046A847431C67D0A389A56A54 +:1018E0005F0705D56368C01A236B0BB1E36BC01AA1 +:1018F000E169024600234046A847411C41D1D8F87F +:101900000030002B3DD01D2B01D0162B56D1A389C2 +:101910002269226023F4006300216160A381216BAE +:10192000C8F8006021B304F14003994202D0404658 +:10193000FDF7C8FC00202063BDE8F0812669BEB138 +:1019400093B2256826609A070CBF63690023AD1B1C +:10195000A3600BE02B463246E169676A4046B84710 +:10196000B0F1000CA5EB0C05664417DD002DF1DC91 +:101970000020BDE8F081E36B002B9DDCF8E7206DD3 +:10198000AEE7B4F90C302269226023F40063A3812E +:101990000022DB046260C2D52065C0E7A38943F062 +:1019A00040034FF0FF30A381BDE8F081D8F800304C +:1019B000002B93D01D2B06D0162B04D0A38943F007 +:1019C0004003A381D5E7C8F80060D1E738B50C46DD +:1019D000054608B1436B03B3B4F90C0088B1636EDC +:1019E000DB0701D481050FD528462146FFF756FFB6 +:1019F000636EDA07054602D4A3899B0508D52846FD +:101A000038BD0546284638BDA06DFDF7FBFAEBE76B +:101A1000A06DFDF7F9FA284638BDFCF7E9FFDBE7D2 +:101A200000487047F015002030B482B08DED000BF7 +:101A3000019A194C22F000430021A342016021DCED +:101A4000009C1C431ED0154C144054B99FED107BD4 +:101A500020EE077B8DED007B019A6FF0350122F0BF +:101A6000004322F0FF42DDE9004522F4E00242F0AB +:101A70007F551B1545F40015A3F2FE33CDE9004553 +:101A80000B4403609DED000B02B030BC704700BFFB +:101A90000000000000005043FFFFEF7F0000F07FD8 +:101AA00000B50B4C25681446EE681A4685B003460F +:101AB0000D464CB107490095CDE901143046064961 +:101AC00000F086FFFBF73AF904490C46F3E700BF44 +:101AD000881A002060090020700900209C05002061 +:101AE00038B5A1FB02148CBBFCF73EFA0546E0B109 +:101AF00050F8042C22F00302043A242A17D8132A9F +:101B00001AD91B2AC0E900441DD9242A14BF00F1A8 +:101B1000100200F118024FF00003C0E9024404BFB4 +:101B200004614461C2E900339360284638BD214610 +:101B3000FDF704F9284638BD02460023C2E9003308 +:101B40009360284638BD00F10802F6E7FDF72CFA4D +:101B50000C2300250360E8E72DE9F04F03690C69C9 +:101B6000A34283B0C0F28780013C01F11405A300B9 +:101B700000F11408009355F8243058F8242001335C +:101B800081469A4208EB840005EB84070190B2FB82 +:101B9000F3F63BD34FF0000CAE464046E2466346B8 +:101BA0005EF804BB02681FFA8BFC06FB0C334FEA9D +:101BB000134C4FEA1B4B06FB0BCC9BB2AAEB030367 +:101BC0001FFA8CFA13FA82F3CAEB124202EB234299 +:101BD0009BB243EA0243774540F8043B4FEA224A6E +:101BE0004FEA1C43DCD2009B58F8033073B9019BC9 +:101BF000043B984504D307E0984504F1FF3403D231 +:101C000053F80429002AF7D0C9F810404846FDF7D8 +:101C1000FBFE00282BDB01364146002355F8040B60 +:101C2000D1F800C082B29A1A030C12FA8CF2C3EBFC +:101C30001C4303EB224392B242EA0342AF4241F813 +:101C4000042B4FEA2343E9D258F8242008EB8403FD +:101C50006AB9043B984504D307E0984504F1FF3482 +:101C600003D253F80429002AF7D0C9F810403046AF +:101C700003B0BDE8F08F002003B0BDE8F08F00BFD7 +:101C80002DE9F04F2DED028B8FB08DED020B019100 +:101C9000816B1A9D059357EC106B0446934641B136 +:101CA000C26B4A60012393408B60FDF74DFC00231B +:101CB000A363B7F10008B4BF012300232B60BE4B20 +:101CC000BCBF28F00048CDF80C8033EA080300F0D0 +:101CD0009F809DED028BB5EE408BF1EE10FA11D195 +:101CE000059A012313601B9B002B00F03F82B34B2E +:101CF0001B9A1360013B009300980FB0BDEC028B60 +:101D0000BDE8F08F0CAA0DA92046B0EE480BFDF7F8 +:101D100047FF5FEA1853054640F09280DDE90C1357 +:101D20000B4403F23242202A40F3FA82C2F140020D +:101D300008FA02F803F21242D64048EA060207EE19 +:101D4000102AB8EE477B581E17EE906A53EC172BFB +:101D50004FF0010AA6F1F8739FED913B9FED927B46 +:101D60009FED935B06EE900A43EC122BB8EEE64B28 +:101D7000B7EE086B32EE466BA6EE037BA4EE057B56 +:101D8000FDEEC76BB5EEC07BF1EE10FA16EE907A61 +:101D900008D5B8EEE66BB4EE476BF1EE10FA18BF5B +:101DA00007F1FF37162F00F24581854B03EBC70380 +:101DB00093ED007BB4EEC78BF1EE10FA57D5091AFC +:101DC0000023B1F1010807F1FF370A9300F13981CF +:101DD00000230693002F52DA069B0497DB1B069321 +:101DE0007B420893019B092B4FF000074ED8052B2F +:101DF00040F39D82043B01930026019B9A1E032A17 +:101E000000F22581DFE812F0AA03A7039D037E03F9 +:101E1000059AC8F3130842F20F7358EA06081360D4 +:101E20001ED11B9B002B00F09185664B009308335D +:101E30001B9A009813600FB0BDEC028BBDE8F08FC9 +:101E400018EE906AC6F31306A3F2FF3053EC182B7A +:101E500046F07F530C994FF0000A43F440137BE7A0 +:101E60001B9B002B40F03B83574B009344E7091A20 +:101E70000023B1F101080A9300F1E38006930023E7 +:101E80000893019B0497092BB844B0D9002301267D +:101E9000019307964FF0FF399B460021E163CDF88F +:101EA0002C902046FDF72AFB0090002800F040858A +:101EB000009BA363B9F10E0F00F2DC80002E00F04E +:101EC000D980049B002B40F3DE833D4A03F00F01D1 +:101ED00002EBC10292ED007B1A11DB0540F1828317 +:101EE0003A4991ED086B02F00F02032088EE065B81 +:101EF0005AB13649D60704D591ED006B013027EE73 +:101F0000067B521001F10801F4D185EE076B0A9BA4 +:101F10003BB1B7EE007BB4EEC76BF1EE10FA00F107 +:101F2000AE8407EE900AB8EEE75BB1EE0C7BA5EE4F +:101F3000067B17EE902A51EC170BA2F15071B9F104 +:101F4000000F00F08883049E4A46079B002B00F098 +:101F50004784B6EE003B1A4BFDEEC64B03EBC20CBA +:101F6000B8EEE47B36EE477B1CED026B83EE065B3E +:101F700041EC160B14EE900A35EE465B0099B4EE78 +:101F8000C75B3030F1EE10FA01F8010B00F3AC84BE +:101F9000B7EE002BB2EE044B4FF0000C31E000BF67 +:101FA00061436F63A787D23FB3C8608B288AC63F5F +:101FB000FB799F501344D33F0000F07FC10B0020FA +:101FC000A8020020140B0020200B0020800200201B +:101FD0000CF1010C94454DDA27EE047B25EE045BF1 +:101FE000FDEEC76B16EE903AB8EEE63B303337EEB7 +:101FF000437BB4EEC57BF1EE10FA01F8013B00F132 +:10200000738432EE476BB4EEC56BF1EE10FADFD598 +:10201000009A049602E08A4200F05084894611F842 +:10202000013D392BF7D00133DBB20B70049B013338 +:10203000049355E1091A0123B1F101080A937FF5D0 +:10204000C7AEC1F1010306934FF00008C2E60026B7 +:10205000E66331462046FDF751FA0090002800F073 +:102060006784009BA3634FF0FF330B9399460123D2 +:10207000B34607930D9A002A55DB04990E2952DCCA +:10208000B74BBBF1000F03EBC10393ED006B15DA07 +:10209000B9F1000F12DC40F0F282B1EE047B26EEC3 +:1020A000077BB4EEC78BF1EE10FACA464E4600F23B +:1020B0006D82DDF800806FEA0B0B70E288EE067B24 +:1020C000BDEEC77B009917EE103AB9F1010F03F18D +:1020D0003003B8EEC75B01F8013BA5EE468B00F07C +:1020E0003483B2EE044B012311E088EE067BBDEE93 +:1020F000C77B013317EE102A4B4502F13002B8EED0 +:10210000C75B01F8012BA5EE468B00F01E8328EE7D +:10211000048BB5EE408BF1EE10FAE6D1049B01334F +:1021200004938946DCE0079B43B3019B012B40F3FA +:102130007682089B09F1FF3A534580F23F82089B63 +:10214000CDF820A0AAEB030217444FF0000AB9F122 +:10215000000FC0F22583069B09934B44C8440693A5 +:1021600001212046FDF79CFA06460CE07D4B0093CA +:1021700000980FB0BDEC028BBDE8F08F069BDDF838 +:1021800020A0079E0993099B6BB1B8F1000F0ADDEF +:10219000434506991A46A8BF4246891A9B1A0691DA +:1021A0000993A8EB0208089B63B1079B002B00F082 +:1021B000A782BAF1000F00F30482089BB3EB0A0276 +:1021C00040F0FF8201212046FDF76AFA002F824687 +:1021D00000F3AF80019B012B40F38781002308931C +:1021E0000120002F40F0B180404410F01F0000F0AB +:1021F0007A81C0F12002042A00F3888040F0F68141 +:10220000069B002B05DD29461A462046FDF784FB78 +:102210000546B8F1000F05DD514642462046FDF760 +:102220007BFB82460A9B002B40F03F81B9F1000FF7 +:1022300040F32581079B002B40F0A380049B0133D2 +:102240000493DDF80080012707E0294600230A22D5 +:102250002046FDF783F90137054651462846FFF72A +:102260007BFCB94500F1300008F8010BEDDCB9F159 +:10227000000F009ACCBFCB464FF0010B03469344AE +:1022800000272946012220460193FDF745FB5146D0 +:102290000546FDF7B9FB002840F3AF811BF8013C70 +:1022A000009A0BF1FF3B04E05A4500F0B1811BF8A6 +:1022B000013D392B0BF10109F6D001338BF80030C9 +:1022C00051462046FDF740F956B12FB1B74203D031 +:1022D00039462046FDF738F931462046FDF734F9F6 +:1022E00029462046FDF730F9002389F80030DDE962 +:1022F00004231A601B9B002B3FF4FEAC0098C3F82C +:1023000000900FB0BDEC028BBDE8F08FC0F11C0057 +:10231000069B03440693099B0344099380446FE79B +:10232000C2F1200206FA02F207EE102A09E50126A0 +:1023300063E501463A462046FDF78EFA019B012BE4 +:10234000824640F3C58100230893DAF810200AEB97 +:1023500082021069FDF754F9C0F1200044E700BF84 +:10236000A8020020C00B0020314600230A2220468C +:10237000FDF7F4F80B9B002B064640F3CE82049742 +:102380009946099B002B05DD31461A462046FDF78C +:10239000C3FA0646089B002B40F0EB81B046029B37 +:1023A000009F03F001027B1E4B440893019B0A929D +:1023B0001343099351462846FFF7CEFB3146834627 +:1023C0002846FDF721FB4246514681462046FDF74F +:1023D0003DFBC26801460BF13003002A42D1CDE932 +:1023E00006032846FDF710FB069902902046FDF7EC +:1023F000ABF8029A079B1AB90999002900F07E826E +:10240000B9F1000FC0F28381019949EA01090A99E3 +:1024100051EA090900F07B81002A00F3C681089A7D +:102420003B7007F101099742CB4600F0C481294671 +:1024300000230A222046FDF791F84645054631461D +:102440004FF000034FF00A02204612D0FDF786F845 +:102450004146064600230A222046FDF77FF84F46F4 +:102460008046A7E720460293FDF76EF8029B012203 +:10247000C6E7FDF773F84F46064680469AE7019B8C +:10248000022B71DC079B002B7FF47BAF049B514632 +:10249000013328460493FFF75FFBDDF800B000F13D +:1024A00030030BF8013B0027EBE651462846FDF7C9 +:1024B000ABFA0028BFF6BAAE294600230A2220460E +:1024C000FDF74CF8049B5F1E079B0546002B7FF42D +:1024D0004BAF0B9B002B40F318829946B1E6BC4BE7 +:1024E00000930333A4E41C2012E7DDE90201002875 +:1024F0007FF474AEC1F31302002A00F0F480029B53 +:1025000008936DE601230793049B5B4403F10109E3 +:10251000B9F1010FCC460B93B8BF4FF0010C00216D +:10252000BCF1170FE1637FF7BCAC0120042252001D +:1025300002F114036345014600F10100F7D9E1639C +:10254000AFE401230793BBF1000F52DDCDF82CB0AF +:10255000D946DC46E3E700230793D5E7002307933A +:10256000F1E7DDF82C900497B9F1000F7FF4A1ADED +:1025700051464B4605222046FCF7F0FF01468246B5 +:102580002846FDF741FA00287FF793AD049B03F13D +:10259000010B009B3122984603F8012B0093514612 +:1025A0002046FCF7D1FF0BF10103DDF80090049306 +:1025B000CDF80080002E7FF48FAE91E6A3EB0A0ADF +:1025C000C5E5314652462046FDF746F92A46014602 +:1025D00006462046FDF792F8294605462046FCF7B8 +:1025E000B3FFEAE50220B0EE485B81E4C0F13C00B5 +:1025F0008EE64FF0010BD9464FE403D1019BDB0778 +:102600003FF54CAED9461BF8013D302BFAD057E6CA +:10261000049B009A013304933123137050E6BAF1FE +:10262000000F00F0238102F23342069B099313440A +:10263000DDF820A00693904492E507EE900AB1EEF3 +:102640000C5BB8EEE77BA6EE075B15EE902A51EC2B +:10265000150BA2F1507141EC150BB1EE047B36EE77 +:10266000477BB4EEC57BF1EE10FA00F33781B1EE93 +:10267000455BB4EEC57BF1EE10FA7FF5FBAC4FF095 +:10268000000A564615E500F0F580049B51495A4270 +:1026900002F00F0001EBC00191ED006B121128EE6A +:1026A000066B00F04281B0EE467B4B4900260220CB +:1026B000D30705D591ED005B0130012627EE057BA0 +:1026C000521001F10801F3D1002E06FE076B1EE443 +:1026D000029B002B7FF437AEDDE90201C1F3130248 +:1026E000002A40F037813D4A0A40002A00F0FA8073 +:1026F000069B01330693012308F1010808936FE557 +:102700002946089A2046FDF7A7F805465AE5002A0B +:1027100012DD2946012220460193FDF7FDF85146BE +:102720000546FDF771F90028019B40F3E180392B44 +:1027300000F0CA800BF13103B94609F8013B049B54 +:102740000133374604934646BAE538EE088BB4EEBB +:10275000C68BF1EE10FA0ADCB4EE468BF1EE10FAFD +:102760007FF4DCAC17EE103AD8077FF5D7AC009AAF +:1027700054E471682046FCF7C1FE0746002800F0CB +:10278000DE80336902339A0006F10C010C30FAF74F +:1027900047F8394601222046FDF7BEF88046FEE59F +:1027A000069BA3EB09030993DAE4392B00F08C8034 +:1027B000B9460133C1E7049A0132374604924646CE +:1027C0005FE529462046FDF747F80546FAE400BFD5 +:1027D000200B0020A8020020800200200000F07FD3 +:1027E0005E4BFDEEC65B03EBC20C1CED023BB8EE8C +:1027F000E57B36EE477B41EC160B15EE901A23EE87 +:10280000063B00983031012A00F8011B00F083805C +:10281000B2EE044B009B991827EE047BFDEEC76BCC +:1028200016EE903A303300F8013B8142B8EEE65B99 +:1028300037EE457BF0D1B6EE006B33EE065BB4EEBF +:10284000C75BF1EE10FA3FF5E3AB36EE436BB4EE47 +:10285000C76BF1EE10FA7FF70DAC8946013919F814 +:10286000013C302BF9D0731C049339E50C9AC2F16A +:102870003602DAE60220B0EE486BFFF748BBB9F14A +:10288000000F3FF4DAAE0B9A002A7FF7F3ABB2EEFB +:10289000044B26EE046B013007EE900A049BB8EE61 +:1028A000E75BB1EE0C7BA6EE057B17EE90CA51EC10 +:1028B000170B5E1EACF15071FFF747BB049B013351 +:1028C00004933123FFF7B1BB049BBB460133049350 +:1028D000392337460BF8013B4646E1E44FF0000A46 +:1028E000564653E608927BE4731C04938946F7E44A +:1028F0007FF422AFDA077FF51FAF18E7392BE3D05B +:10290000B9F1000F3FF716AF16E7019B022B3FF717 +:1029100028AE0497BAE501468DE7019B022B3FF7ED +:1029200020AEDDF82C9004972BE50220FFF7EFBADC +:102930000B4B0C48002240F2AF11FFF7B1F8084BE7 +:1029400008483A4640F2EF21FFF7AAF8064B0093F9 +:10295000FFF7D2B9029B0893F7E400BFA80200205A +:10296000A0090020240B0020140B002070B50546A0 +:1029700084B05BB11C4669B10E4B2846D3F8E060C9 +:102980002346B047431C0FD004B070BD00F58274DD +:102990000029F1D1074A2346D2F8E06028460A46CA +:1029A00001A9B047431CEFD100228A2322602B608B +:1029B00004B070BD0015002010B582B0049CCDE9B4 +:1029C00000344FF0FF3301F0C7FB02B010BD00BF71 +:1029D0000EB410B583B005AB064C53F8042B01932D +:1029E0000146206800F0C4F803B0BDE8104003B011 +:1029F000704700BF881A00202DE9F04F93681768D0 +:102A000083B09246002B70D081468A6808680C46D5 +:102A1000083743E0A38913F4906F2ED0D4E904164D +:102A2000A0EB010806EB460606EBD67608F101009E +:102A300076102844B042324684BF064632465B05D3 +:102A400037D511464846FBF78FFA019000283AD057 +:102A500042462169F9F7E4FEA289019B22F49062C3 +:102A600042F08002A281A6EB080203EB0800666137 +:102A7000A260236120602E46A84642465946FCF7D4 +:102A8000E1F8DAF80830A2682068921B40445B1B2A +:102A9000A2602060CAF808303BB3083757E902B596 +:102AA000002DFAD0AA4216469046B3D92E46A84623 +:102AB000E3E74846FBF714FD03460028D3D121691C +:102AC0004846FCF7FFFBA3890C2243F04003C9F8FA +:102AD00000204FF0FF30A38100220023CAF8082015 +:102AE000CAF8043003B0BDE8F08F00200023CAF814 +:102AF000043003B0BDE8F08F2DE9F84F4B6E9C0415 +:102B000090462DD59368126843B38B46064602F172 +:102B1000080959E9025A5FEA9A0715D0043D0024D2 +:102B200001E0A7420ED055F8041F5A46304601F086 +:102B30005BFA431C04F10104F3D10023C8E901331B +:102B4000BDE8F88FD8F808302AF0030AA3EB0A038F +:102B5000C8F8083009F10809002BDAD10020ECE7A9 +:102B600001F00CF80023C8E90133BDE8F88F00BF7D +:102B70002DE9F04F2DED028BC5B00DF1500A8346C3 +:102B800008EE101A16460021082250461C460793EC +:102B9000FCF7D4F8BBF1000F04D0DBF83430002B85 +:102BA00000F0A08618EE102A536EDB0740F1138563 +:102BB000B2F90C108AB295040BD418EE103A41F415 +:102BC000005199815B6E8AB218EE101A23F40053FB +:102BD0004B66100740F1058118EE103A1B69002B77 +:102BE00000F0FF8002F01A030A2B00F00A81002394 +:102BF000CDE91933CDE90D331BAA0C9318929146F8 +:102C00000B930593B0464446A84BD3F8E450FCF729 +:102C10005FF92246034612A9CDF800A05846A847FE +:102C2000002800F04581C0F23981129A252A034616 +:102C300001D01C44E8E7B4EB0806054640F03C81AF +:102C4000002361788DF8433004F1010806934FF0BA +:102C5000FF371E462B2408F10108A1F120035A2B4F +:102C600000F27881DFE813F0B50276017601B00258 +:102C70007601760176016A00760176017D028D0289 +:102C8000760188029702760192025B005B005B008E +:102C90005B005B005B005B005B005B007601760124 +:102CA00076017601760176017601760176015C0285 +:102CB000840076017601760176017601760176014F +:102CC000760176017601E80076017601760133021D +:102CD0007601DA02760176018B05760176017601BE +:102CE00076017601760176017601760176015C0245 +:102CF0008600760176017601CD0286007F0076019E +:102D0000C0027601FD02EA00ED027F007601330287 +:102D10007C006905760176016B0576017C00A1F1E6 +:102D20003003002218F8011B02EB820203EB42027F +:102D3000A1F13003092BF5D906928EE75846FEF72C +:102D40006FFE43680D931846FCF7BAF90E900546DE +:102D50005846FEF765FE83680B93002D40F0D6843D +:102D600098F8001077E798F8001046F0200672E710 +:102D700046F01006B40640F18E81079B073323F01E +:102D800007031A46596852F8083B07920A46002979 +:102D9000C0F27084791C00F0A28526F080010391B6 +:102DA00053EA020100F03F840A2B72F1000180F027 +:102DB000418530338DF80F31039E012304930DF2CA +:102DC0000F14049BBB42B8BF3B46039300230893F8 +:102DD0009DF84330002B00F0CB80039B013303931D +:102DE000C6E018EE101A584618EE105A01F040F8D6 +:102DF000002840F05286AA8902F01A030A2B7FF4B9 +:102E0000F6AE18EE101AB1F90E30002BFFF6EFAE49 +:102E10004B6EDB0702D4970540F1128618EE101AAC +:102E200023463246584600F069FE0590059845B0A5 +:102E3000BDEC028BBDE8F08F46F0100616F02002C4 +:102E400000F03681079B073323F0070319465A68C1 +:102E500051F8083B079126F480610391002100207E +:102E60008DF84300781C00F01082039820F0800653 +:102E700053EA020040F00882002F40F03885002914 +:102E800040F0D583039B13F00103049300F01184F9 +:102E900030238DF80F310DF20F1492E70822002134 +:102EA0005046FBF74BFF01231C44ADE60015002004 +:102EB000B4EB080605461BD0199B1A9A013332441D +:102EC000072BC9E900861A9219931CDD002A00F02D +:102ED000A68318EE101A18AA5846FFF70DFE20BB5D +:102EE0000DF16C09059B33440593002D7FF4A8AECA +:102EF0001A9B002B40F0C18518EE103A0022B3F95E +:102F00000C30199215E009F10809EBE718EE101AD8 +:102F100018AA5846FFF7F0FD002800F0A680089B8D +:102F20001BB108995846FCF7CDF918EE103AB3F9E1 +:102F30000C3018EE102A526E12F0010F9AB200F007 +:102F4000A080500600F1B285059845B0BDEC028B1B +:102F5000BDE8F08F0029CBD000238DF8433001234A +:102F6000CDE903338DF8AC102BAC002308931F463A +:102F700016F00203099302D0039B0233039316F069 +:102F800084030A9305D1069B039A9D1A002D00F332 +:102F90007B82DDE91903411C9DF8432082B10122A7 +:102FA0000133C9F8042007290DF14302CDE91913B3 +:102FB000C9F8002000F34A82084609F108090131E6 +:102FC000099AE2B111AA0233C9F8002007294FF08B +:102FD0000202CDE91913C9F8042040F35082002BF6 +:102FE00000F0438318EE101A18AA5846FFF784FD24 +:102FF000002894D1DDE919030DF16C09411C0A9AEE +:10300000802A00F08481049ABD1A002D00F3D78134 +:10301000049AC9F8004013440729CDE91913C9F8E7 +:10302000042040F36E81002B00F0758218EE101A18 +:1030300018AA5846FFF760FD00287FF470AF1A9B6E +:103040000DF16C09750705D5069A0399541A002CE1 +:1030500000F36B82DDE9052103988142ACBF521871 +:1030600012180592002B7FF451AF08990023199391 +:10307000002900F049815846FCF724F90DF16C094C +:10308000C1E59C053FF55DAF18EE104AA06DFBF75A +:10309000BBFFA28955E7F006079A00F11F8371066E +:1030A00040F1198332F9043B0792DA1711466EE6B4 +:1030B00016F01003079940F0098316F0400000F065 +:1030C00001831A4651F8043B07919BB2C3E6079B64 +:1030D0001A4600238DF84330134653F8044B0393EC +:1030E000002C00F01284532900F0658316F01005BF +:1030F00040F061837B1C00F0B3843A4629462046A9 +:10310000FBF786FF0890002800F09F84031B039ABA +:10311000049323EAE3732F4607920393089557E637 +:10312000432902D0F50640F12D83079D0822002196 +:1031300016A82BACFBF702FE16AB55F8042B214664 +:103140005846FFF713FC03460133049000F0B384A4 +:10315000049B079523EAE373039300238DF8433020 +:1031600003E7079B53F8042B0692002A80F29C8207 +:10317000069A5242CDE9062398F8001046F004065C +:1031800069E598F800108DF8434064E598F8001060 +:1031900046F080065FE5424612F8011B2A2900F03E +:1031A0009684A1F13003092B90464FF000073FF6BB +:1031B00054AD18F8011B07EB870703EB4707A1F194 +:1031C0003003092BF5D948E598F8001046F00106C0 +:1031D00041E59DF84330002B7FF4C2AD202398F8E1 +:1031E00000108DF8433036E598F800106C2903BFC5 +:1031F00098F8011046F0200608F1010846F0100684 +:1032000029E598F80010682903BF98F8011046F4E2 +:10321000007608F1010846F040061CE546F0100370 +:103220000393039B13F0200200F00682079B0733F1 +:1032300023F0070319465A6851F8083B079101210A +:103240000DE6079A46F00203039352F8043B0792F7 +:1032500047F63002ADF84420B84A0C920221002211 +:10326000FDE5B70600F14882F50600F146837406D5 +:1032700000F1D583B00540F14083079B059953F8D1 +:10328000042B07931170BEE4039601293FF48CAD23 +:10329000022944AC11D10C9803F00F011B09415CC9 +:1032A00004F8011D43EA0273120953EA0201F3D143 +:1032B000039E44AB1B1B049383E503F00701DB086B +:1032C00043EA4273D208303153EA0205204604F83B +:1032D000011DF2D1039EF307EBD53029E8D030234E +:1032E000023804F8013C44AB1B1A039E04930446C5 +:1032F00067E5049B1B9401221C931A9319920DF10C +:103300006C0909F108099DE60DF16C097BE4069A48 +:10331000039D551B002D7FF776AE102D40F3BB8328 +:10332000099418EE104A07E000F1020C09F10809AF +:103330001046103D102D1EDD8149C9F80010421CB9 +:1033400010331021072ACDE91923C9F80410EBDD49 +:1033500018AA002B74D0214658460DF16C09FFF7CE +:10336000CBFB00287FF4DBADDDE91903103D102D08 +:1033700000F1010CE0DC099C714AC9F804502B44AF +:10338000BCF1070FCDE919C3C9F8002040F39481BF +:10339000002B00F01F8318EE101A18AA5846FFF7EA +:1033A000ABFB00287FF4BBAD049ADDE91903BD1A1D +:1033B000002D00F101010DF16C097FF729AE102DF0 +:1033C00029DD0994102718EE104A07E000F1020CDD +:1033D00009F108091046103D102D1ADD421C58490C +:1033E0001033072AC9E90017CDE91923EEDD18AA21 +:1033F00003B3214658460DF16C09FFF77DFB002809 +:103400007FF48DADDDE91903103D102D00F1010CA5 +:10341000E4DC099C61464A4AC9F804502B44072958 +:10342000CDE91913C9F8002000F3E78009F1080974 +:103430000131EDE54FF0010C18460DF16C09CAE7BA +:103440004FF0010C18460DF16C0972E7002B00F0EB +:10345000048118EE101A18AA5846FFF74DFB0028F1 +:103460007FF45DADDDE919030DF16C09411CA7E5A1 +:10347000022311AA1C931B9201210DF16C0908462D +:1034800009F10809411CBAE5102D40F3E582DDE998 +:1034900019130F94084618EE104A07E000F1020CC9 +:1034A00009F108091046103D102D1DDD2549C9F808 +:1034B0000010421C10331021072ACDE91923C9F846 +:1034C0000410EBDD18AA03B3214658460DF16C0930 +:1034D000FFF712FB00287FF422ADDDE91903103D50 +:1034E000102D00F1010CE1DC0F9C6046154AC9F873 +:1034F00004502B440728CDE91903C9F8002000F334 +:10350000C18009F10809411C46E518464FF0010C3D +:103510000DF16C09C7E77607199353D5069A0399FD +:10352000541A002C4EDD0DF16C09102C40F3B082C2 +:10353000199918EE106A10250DE000BF900B0020BD +:10354000980F0020D40B0020881C09F108091146AF +:10355000103C102C1ADD4A1CB3481033072AC9E965 +:103560000005CDE91923EFDD18AA33B331465846DB +:10357000FFF7C2FA00287FF4D2ACDDE91913103C42 +:10358000102C01F101000DF16C09E4DCA64AC9F828 +:10359000044023440728CDE91903C9F800207FF728 +:1035A00059AD7BB118EE101A18AA5846FFF7A4FAC5 +:1035B00000287FF4B4AC1A9B4CE5012019460DF1AC +:1035C0006C09C5E7DDE9053203998A42ACBF9B1857 +:1035D0005B18059349E5B2F90C108F0518EE103A07 +:1035E0008AB23FF5E8AA18EE105A986DFBF70AFD6B +:1035F000B5F90C108AB2FFF7DEBA002B3FF479AEB2 +:1036000018EE101A18AA5846FFF776FA00287FF429 +:1036100086AC19991A9B01310DF16C09F8E41992E5 +:103620000DF16C095EE4002F7FF4C3AB039E00270D +:10363000049744ACFFF7C5BB039B13F0100354D1B0 +:10364000039A12F0400000F06B8107991A4651F876 +:10365000043B07919BB2012101E4099A002A64D13D +:10366000184601210DF16C09C9E4012118460DF13C +:103670006C09C4E45B4262EB420203962D200121F7 +:10368000FFF7EEBB002B00F0888018EE101A18AA86 +:103690005846FFF731FA00287FF441ACDDE9190301 +:1036A0000DF16C09411C77E498F800100793FFF7BF +:1036B000D2BA44ACFFF785BB09F108090CF101014E +:1036C0006046A0E416F4007240F0978151F8043B84 +:1036D0000791FFF7C0BBB30500F1888152F8043BA6 +:1036E0000792DA171146FFF752BB079951F8043BCE +:1036F00007910121FFF7B3BB079B059853F8041B03 +:103700000793C217C1E90002FFF77DBA0B9B002B9C +:103710003FF426AB0B9B1B78002B3FF421AB98F8B2 +:10372000001046F48066FFF796BA022311AA1C9394 +:103730001B9201200DF16C09A2E6039671E53B4B4B +:103740000C9316F0200259D0079B073323F0070390 +:1037500018465A6850F8083B0790F40709D553EA11 +:10376000020006D08DF84510302146F002068DF893 +:10377000441026F4806103910221FFF770BB2C4BAB +:103780000C93DEE7079B012153F8042B03918DF87E +:10379000AC20079304912BACDFE49DF84320002A72 +:1037A00040F03281099A002A7FF462AE1846012166 +:1037B0000DF16C0927E40021082216A81394FBF7E9 +:1037C000BDFA791C00F0BC80002507942C460CE063 +:1037D0002BA95846FFF7CAF8421C204400F06B8121 +:1037E000B84208DC00F070810446139A525916ABB7 +:1037F0000435002AECD10494079CAFE016F01003C6 +:1038000007980CD116F0400405D01A4650F8043B36 +:1038100007909BB2A1E716F4007240F0E18050F8E7 +:10382000043B079099E700BFD40B0020900B0020C9 +:10383000A40B00200399049744AC9E4608EE90BA6E +:1038400001F480664FF0000C234606E0BEF10A0F3B +:1038500072F1000239D3A6462A46A6491EEB0200A1 +:1038600040F100000F46A1FB001424F0030101EB1E +:103870009401401ABEEB00014FF0CC3562F1000418 +:1038800005FB01F507FB0455A1FB07410D44052786 +:1038900004F00101A1FB071B09186408303103F88B +:1038A000011C44EAC5740CF1010C013B6D08002EAB +:1038B000CCD00B9909786145C8D1BCF1FF0FC5D0B8 +:1038C000BEF10A0F72F100026CD21C4644AB1B1B06 +:1038D000049F039E049318EE90BAFFF772BA039602 +:1038E000FFF762BA5846FBF783F8FFF75BB9012987 +:1038F00003967FF4CDACFFF75CBA079B059953F8AC +:10390000042B11600793FFF77EB9062F3B46039AFD +:10391000794C079228BF062304930393FFF725BB36 +:10392000039B079913F4007214BF51F8043B51F83C +:10393000043B07911CBF0246DBB20121FFF78FBA9F +:1039400016AB00930023194613AA5846FFF734F824 +:1039500003460133049000F0AE801394049B002BC7 +:1039600030D0632B63DC002308932BAC08220021AA +:1039700016A8FBF7E3F9049D16AB009313AA2B4698 +:1039800021465846FFF718F8854240F0AB80039B6C +:10399000049A07930023A3541F4622EAE273039379 +:1039A000FFF716BA0E9A0D999B1A18460893FBF763 +:1039B0005DFA0B99089B4A780AB101310B914FF0DF +:1039C000000C48E7039B0793049B03931F4608934F +:1039D000FFF7FEB9012118460DF16C09FFF713BB83 +:1039E00050F8043B07902246DBB2B6E612F9043BDE +:1039F0000792DA171146FFF7CAB951F8043B07914D +:103A00000246DBB2FFF727BA01231C9301210DF117 +:103A100043031B930DF16C090B46FFF7CDBA079BCF +:103A2000059953F8042B07931180FFF7ECB8591C44 +:103A30005846FAF799FA044600283CD0089095E7D2 +:103A4000886DFBF7E1FAFFF7E9B9039B0793CDE92E +:103A50000377089FFFF7BCB919981A9B013045E519 +:103A6000039B07932046FBF72BFB20EAE0732F46CE +:103A7000049003930895FFF7ABB918EE101A18AA33 +:103A80005846FFF739F800283FF436AAFFF74DBA39 +:103A9000199801307AE58C466EE46B6ED90705D42F +:103AA000AB899A0502D4A86DFBF7AEFA4FF0FF334D +:103AB0000593FFF749BA18EE102AB2F90C3043F01B +:103AC00040039381FFF735BA079C049746E7079BAD +:103AD00098F8011053F8047B0793904647EAE7777C +:103AE000FFF7B9B818EE102A938943F04003938189 +:103AF000FFF715BACDCCCCCCB80B002070B50C4676 +:103B00008989ADF58E6D21F00201ADF81410616E5A +:103B10001B91E189ADF81610E1690991616A0B9179 +:103B20001CA9029106914FF4806106460491079109 +:103B300018A80021CDE900320891FBF75FFADDE912 +:103B4000003202A93046FFF713F8051E07DB02A971 +:103B50003046FDF73BFF002818BF4FF0FF35BDF89A +:103B600014305B0603D5A38943F04003A381189862 +:103B7000FBF746FA28460DF58E6D70BD9368002B55 +:103B800000F085802DE9F04FB1F90C300C46190793 +:103B9000804683B0174698B225D523691BB310F031 +:103BA00002033D682DD04FF0000ADFF8C0B2564640 +:103BB000B9465E453346524628BF5B464046002E16 +:103BC00052D0E169676AB847002856DDD9F8083055 +:103BD0001B1A8244361AC9F80830002BE9D100209C +:103BE00003B0BDE8F08F2146404600F041F90028BF +:103BF00040F03881B4F90C303D6898B210F00203FF +:103C0000D1D110F0010944D14E46009746B3820548 +:103C1000D4F808B040F18580B3455A4600F2B4802C +:103C200010F4906F40F0C180206801924946FBF784 +:103C300009F8A368019AA3EB0B012368A160134460 +:103C4000B24623600026009A9368A3EB0A03D1448E +:103C50009360002BC3D0B4F90C0080B2002ED6D1F3 +:103C6000D5E900960835D1E7D5E900A60835A0E7E3 +:103C700021464046FDF7AAFE88B3B4F90C3043F064 +:103C800040034FF0FF30A38103B0BDE8F08F002068 +:103C900070471E46BA469946184600951F4666B3B9 +:103CA000002832D04A46D4E904132068A568B242FD +:103CB00028BF3246884204D905EB030B5A4500F36E +:103CC000A780934264DCE169656A3A464046A847AA +:103CD000B0F1000BD1DDB9EB0B09C9D00120DAF846 +:103CE0000830A3EB0B035F44A6EB0B06CAF80830C1 +:103CF000002B3FF474AF002ED2D1009A56681346C1 +:103D000008320092002EF8D01F6832460A21384649 +:103D1000FBF77EF9002800F09C800130A0EB07093A +:103D2000C0E720682369984216D86269B24213D866 +:103D30006FF00043B34228BF3346E16993FBF2F3CF +:103D4000676A02FB03F340464A46B847B0F1000AEF +:103D500093DDA6EB0A0676E7B345DA4628BFB246FE +:103D600052464946FAF76EFFA3682268A3EB0A039E +:103D70005244A3602260002BEBD121464046FDF760 +:103D800025FE0028E5D078E72068B34632464CE7A8 +:103D900039460192FAF756FF019AA3689B1AA3606D +:103DA000236813442360934695E723682169A3EBB6 +:103DB000010B636903EB430A0AEBDA7A0BF10103A7 +:103DC0004FEA6A0A33445345524684BF9A465246E4 +:103DD00043052CD511464046FAF7C6F800283BD0DB +:103DE0005A4621690190F8F71BFDA289019B22F434 +:103DF000906242F08002A28103EB0B002361AAEBE8 +:103E00000B03C4F814A0A3602060B34632460CE74D +:103E100039465A46FAF716FF23685B442360214669 +:103E20004046FDF7D3FD00283FF455AF25E7404657 +:103E3000FAF756FB03460028DED121694046FBF71E +:103E400041FAB4F90C300C2223F08003C8F80020AA +:103E500015E7721C914626E70C22B4F90C30C8F81D +:103E600000200CE74FF0FF30BAE600BF00FCFF7FF8 +:103E700038B5314B1B6805460C4613B15A6B002A06 +:103E80004ED0B4F90C3018079AB21CD5216929B369 +:103E900012F0010007D00020A06060694042A061DC +:103EA00039B1002038BD950758BF6069A06000296E +:103EB000F7D1120658BF0846F4D543F04003A3815A +:103EC0004FF0FF3038BDD1062ED5520714D42169EA +:103ED00043F00803A3819AB20029D9D102F42070DB +:103EE000B0F5007FD4D02146284600F047F9B4F958 +:103EF0000C3021699AB2CBE7216B51B104F1400239 +:103F0000914204D02846FBF7DDF9B4F90C300022C9 +:103F1000226321690022C4E9001223F02403D7E7B9 +:103F20001846FAF765FDACE7092243F040032A6022 +:103F30004FF0FF30A38138BD881A00202DE9F047EB +:103F400082B0824688461446FAF7C2FF012803D1A0 +:103F500008F1FF33FE2B36D90DF10409424604F176 +:103F60005C0349465046FEF701FD421C064632D02E +:103F700020B39DF804C0002509E023685A1C226084 +:103F800083F800C00135B54218D219F801CFA368F3 +:103F9000013B002BA360F0DAA769BB4261462246D1 +:103FA000504602DBBCF10A0FE7D100F053F9431C85 +:103FB000E8D10646304602B0BDE8F08746463046B6 +:103FC00002B0BDE8F0875FFA88FC8DF804C00646B1 +:103FD0000DF10409CFE7A389304643F04003A381E4 +:103FE00002B0BDE8F08700BF30B5536E13F0010F8B +:103FF000B2F90C30144683B005469AB201D1980547 +:104000001CD5900406D4626E43F4005342F400526F +:10401000A381626622462846FFF790FF636EDA07A7 +:10402000054602D4A3899B0502D5284603B030BDBE +:10403000A06DFAF7E9FF284603B030BDA06D0191ED +:10404000FAF7E0FFB4F90C3001999AB2D9E700BF52 +:104050002DE9F04F8BB0DDE9158A149F039181465D +:1040600005921E46B8F1000F5CD0039B002B5ED07A +:10407000059B1D68002F6AD0741E4EB3039B0493EA +:10408000043D002601950BE0039B2BBB019B1A68A6 +:10409000002A3AD0BC455CD2013C631C664617D06E +:1040A000D8F800300293019BDAF8E05053F8042F5F +:1040B000019307A943464846D8F804B0A847421CD4 +:1040C0003AD000EB060CBC45DED9029BC8E9003BA8 +:1040D00030460BB0BDE8F08F00280EDD049B019D3B +:1040E00018445A1E07A900F1FF3E11F8013B02F8DF +:1040F000013F7245F9D101950490059B1A6804327D +:104100001A60019B1A68002AC4D1039B0BB1059B5E +:104110001A600CF1FF3600223046C8F800200BB0C0 +:10412000BDE8F08F039B00F58678002BA0D1059B9E +:104130004FF0FF371D689FE706468A210022304670 +:10414000C9F80010C8F800200BB0BDE8F08F3E465B +:10415000BEE76646BCE700BF10B584B0054C0698C4 +:10416000009007980190044800680294FFF770FFE0 +:1041700004B010BD00150020881A00202DE9F04180 +:104180008B890C46990796B008D504F143030122A8 +:10419000C4E90432236016B0BDE8F081B4F90E1012 +:1041A0000029064625DB6A4600F0ACF800281FDB34 +:1041B000019D05F47045A5F50055B5FA85F54FF458 +:1041C00080686D094FF4006741463046F9F7CCFE30 +:1041D000E0B1B4F90C30C4F8148043F080032060DF +:1041E0002061A38135BB3B43A38116B0BDE8F081BC +:1041F000A38913F0800519D04FF0400800254146EF +:1042000030462F46F9F7B0FE0028E2D1B4F90C3061 +:104210009A05C0D423F0030304F1430243F00203E0 +:104220000121C4E90421A3812260B4E74FF480682E +:104230002F46C9E7B4F90E10304600F079F810B9EE +:10424000B4F90C30CFE7A38923F0030343F0010353 +:104250001BB2C8E7F8B50D461446064610B1436BCD +:10426000002B4CD0B4F90C20A369A360170790B2BF +:104270001BD52369CBB1EDB281042F4622D522682C +:104280006169D31A994229DD0133A1680139A1601E +:10429000511C2160157062699A4227D0A389DB07FF +:1042A00001D50A2D22D03846F8BD21463046FFF709 +:1042B000DFFD08BBB4F90C20236990B2EDB2810494 +:1042C0002F46DCD442F40052A281626E616922F46E +:1042D000005262662268D31A9942D5DC21463046E4 +:1042E000FDF774FB40B922680123CEE72146304632 +:1042F000FDF76CFB0028D6D04FF0FF37D3E7FAF775 +:1043000077FBAFE770B50C46084D03460026204604 +:1043100011461C462E60F8F703FD431C00D070BD0B +:104320002B68002BFBD0236070BD00BF082B002042 +:1043300038B5074D0022044608462A60F8F7F6FC17 +:10434000431C00D038BD2B68002BFBD0236038BD48 +:10435000082B0020000000005FF800F071160060DC +:104360005FF800F0CD1C00605FF800F0751D006084 +:104370005FF800F0D91700605FF800F041180060A6 +:04438000F8B500BFCD +:08438400B89BFF7F010000005F +:10438C000000000000000000000000000000000021 +:10439C000000000000000000000000000000000011 +:1043AC000000000000000000000000000000000001 +:1043BC0000000000000000000000000000000000F1 +:1043CC0000000000000000000000000000000000E1 +:1043DC0000000000000000000000000000000000D1 +:1043EC0000000000000000000000000000000000C1 +:1043FC0000000000000000000000000000000000B1 +:10440C0000000000000000000000000000000000A0 +:10441C000000000000000000000000000000000090 +:10442C000000000000000000000000000000000080 +:10443C000000000000000000000000000000000070 +:10444C000000000000000000000000000000000060 +:10445C000000000000000000000000000000000050 +:10446C000000000000000000000000000000000040 +:10447C000000000000000000000000000000000030 +:10448C000000000000000000000000000000000020 +:10449C000000000000000000000000000000000010 +:1044AC000000000000000000000000000000000000 +:1044BC0000000000000000000000000000000000F0 +:1044CC0000000000000000000000000000000000E0 +:1044DC0000000000000000000000000000000000D0 +:1044EC0000000000000000000000000000000000C0 +:1044FC0000000000000000000000000000000000B0 +:10450C00000000000000000000000000000000009F +:10451C00000000000000000000000000000000008F +:10452C00000000000000000000000000000000007F +:10453C00000000000000000000000000000000006F +:10454C00000000000000000000000000000000005F +:10455C00000000000000000000000000000000004F +:10456C00000000000000000000000000000000003F +:10457C00000000000000000000000000000000002F +:10458C00000000000000000000000000000000001F +:10459C00000000000000000000000000000000000F +:1045AC0000000000000000000000000000000000FF +:1045BC0000000000000000000000000000000000EF +:1045CC0000000000000000000000000000000000DF +:1045DC0000000000000000000000000000000000CF +:1045EC0000000000000000000000000000000000BF +:1045FC0000000000000000000000000000000000AF +:10460C000080E03779C34143176E05B5B5B89346C2 +:10461C00F5F93FE9034F384D321D30F94877825A8E +:10462C003CBF737FDD4F1575000000000000F03FAC +:10463C000000000000002440000000000000594071 +:10464C000000000000408F40000000000088C340C4 +:10465C0000000000006AF8400000000080842E4139 +:10466C0000000000D01263410000000084D7974185 +:10467C000000000065CDCD41000000205FA002428B +:10468C00000000E876483742000000A2941A6D4200 +:10469C00000040E59C30A2420000901EC4BCD642F3 +:1046AC0000003426F56B0C430080E03779C341439E +:1046BC0000A0D8855734764300C84E676DC1AB4314 +:1046CC00003D9160E458E143408CB5781DAF154432 +:1046DC0050EFE2D6E41A4B4492D54D06CFF080440D +:1046EC00F64AE1C7022DB544B49DD9794378EA4422 +:1046FC000000C0410000C8418FC2EF41FF007801AB +:10470C0080014302880187018C018B019201910188 +:10471C009501F601990198019A013D029E01200232 +:10472C00A801A701AD01AC01B001AF01B901B801FD +:10473C00BD01BC01BF01F701C601C401C901C7011C +:10474C00CC01CA01DD018E01F301F101F501F40187 +:10475C003A02652C3C023B023E02662C42024102AC +:10476C0053028101540286015602890157028A01C3 +:10477C0059028F015B029001600293016302940164 +:10478C0068029701690296016B02622C6F029C0110 +:10479C0072029D0175029F017D02642C8002A601AC +:1047AC008302A9018802AE01890244028A02B10186 +:1047BC008B02B2018C0245029202B7017B03FD030E +:1047CC007C03FE037D03FF03AC038603C203A30338 +:1047DC00CC038C03CD038E03CE038F03F203F903BA +:1047EC00F803F703FB03FA03CF04C0047D1D632C0D +:1047FC00511F591F531F5B1F551F5D1F571F5F1FF5 +:10480C00781FF81F791FF91FB31FBC1FCC1FC31FC4 +:10481C00E51FEC1FFC1FF31F4E2132218421832145 +:10482C00612C602C762C752CD007000064000000E5 +:10483C00F40100006100E01AE000E017F800E00766 +:10484C000001013032010106390101104A01012E2B +:10485C007901010682010104A0010106B3010104E2 +:10486C00CD010110DE010112F80101282202011212 +:10487C004602010AAD03DB03B103E011C303E009F7 +:10488C00D80301183004E0205004B0106004012259 +:10489C008A040136C104010ED00401446105D026FE +:1048AC00001E0196A01E015A001F0808101F0806C2 +:1048BC00201F0808301F0808401F0806601F080842 +:1048CC00701F4A02721F5604761F64027A1F700210 +:1048DC007C1F7E02801F0808901F0808A01F080874 +:1048EC00B01F0802D01F0802E01F08027021F01050 +:1048FC00D024E61A302CD02F672C0106802C0164B2 +:10490C00002D002641FFE01A436172642069732078 +:10491C00746F6F20736D616C6C2E0D0A00000000BB +:10492C00466F726D617420446F6E650D0A00000055 +:10493C00466F726D6174204661696C65640D0A0086 +:10494C0042616420636C757374657220636F756E5D +:10495C00740D0A0044657669636520697320746F71 +:10496C006F20736D616C6C0D0A00000057726974D6 +:10497C00696E672046415420000000002E000000A4 +:10498C0057726974696E6720757063617365207402 +:10499C0061626C650D0A000057726974696E67205C +:1049AC00726F6F740D0A0000466F726D6174206433 +:1049BC006F6E650D0A000000466F726D61742066A3 +:1049CC0061696C65640D0A0045584641540000004D +:1049DC0089A000008DA0000091A0000095A000000F +:1049EC006CC00F40C0000000504F00005519000073 +:1049FC000C000000130000000000000024851F4084 +:104A0C000B000000130000000000000028851F4070 +:104A1C000D000000130000000000000020851F4066 +:104A2C000A00000013000000010000001C851F405C +:104A3C000000000000000000F9140000E514000064 +:104A4C007D0F000065140000811500001914000092 +:104A5C00C11300000000000000000000F9AC0000D1 +:104A6C000000000000000000C50A0000000000006B +:104A7C0000000000AD9300000000000000000000EA +:104A8C00096E0000156E00000D6E0000156F000021 +:104A9C0085760000B575000011760000B174000039 +:104AAC0091700000C57A0000256E0000996D000021 +:104ABC0055770000856D0000896D0000916D000038 +:104ACC00956D0000A9700000E57800006D7800007D +:104ADC00C57300007D6D00008D6D0000C579000070 +:104AEC00ED760000896E0000000000000000000060 +:104AFC006DA20000C9B60000C5B60000C1B600002A +:104B0C00BDB60000B9B60000B5B60000B1B60000E5 +:104B1C000000000000000000C5070000590500005F +:104B2C00510800005D050000F507000000000000C2 +:104B3C000000000019160000C91100007D0F0000D4 +:104B4C006D1200000D120000791400009512000087 +:104B5C00851700002D180000000000000000000068 +:104B6C00F9140000E51400007D0F0000651400002E +:104B7C008115000019140000C11300000000000092 +:104B8C00000000006D160000AD16000001140000BE +:104B9C00D1140000CD150000A91300005114000021 +:104BAC0011100000F5160000C1120000DD1200000B +:104BBC00990F0000850F0000C10F0000D9130000F1 +:104BCC00F9120000A110000059110000E9100000BA +:104BDC002D1500004D10000000000000000000002A +:104BEC00F9AC000075A200007D0F0000810F0000E1 +:104BFC00F9AC0000F9AC0000F9AC000000000000BA +:104C0C0000000000B91C0000C91E00008D1E000031 +:104C1C00D51D0000391E0000811D0000011F000081 +:104C2C00F11F00002D2000000921000000000000F1 +:104C3C0000000000DD950000099600007D0F0000CB +:104C4C00D995000095950000A1950000C195000034 +:104C5C000000000000000000A57C0000A97C000002 +:104C6C00157B000099800000E18C0000618600003B +:104C7C00C5630000D57C0000B18C0000F18D0000F4 +:104C8C00E98600001D5C000009840000357C0000F2 +:104C9C00417C0000097B00000D7B0000117B0000B3 +:104CAC004D7C0000717C0000957C0000158100009B +:104CBC00B97C0000ED7E00006181000035820000AF +:104CCC002D9B0000319B0000399B0000419B000094 +:104CDC00D8399D270054EA2A00A4781F007B9A1724 +:104CEC002C2066756E6374696F6E3A2000000000AC +:104CFC00617373657274696F6E202225732220664E +:104D0C0061696C65643A2066696C652022257322A2 +:104D1C002C206C696E65202564257325730A0000B0 +:104D2C0042616C6C6F632073756363656564656465 +:104D3C00000000002F646174612F6A656E6B696EF0 +:104D4C00732F776F726B73706163652F474E552DA0 +:104D5C00746F6F6C636861696E2F61726D2D313188 +:104D6C002F7372632F6E65776C69622D6379677729 +:104D7C00696E2F6E65776C69622F6C6962632F7335 +:104D8C0074646C69622F6D707265632E6300000031 +:104D9C0000202020202020202020282828282820FF +:104DAC0020202020202020202020202020202020F7 +:104DBC00208810101010101010101010101010105F +:104DCC00100404040404040404040410101010104F +:104DDC001010414141414141010101010101010119 +:104DEC00010101010101010101010101101010106B +:104DFC0010104242424242420202020202020202EB +:104E0C00020202020202020202020202101010103E +:104E1C002000000000000000000000000000000066 +:104E2C000000000000000000000000000000000076 +:104E3C000000000000000000000000000000000066 +:104E4C000000000000000000000000000000000056 +:104E5C000000000000000000000000000000000046 +:104E6C000000000000000000000000000000000036 +:104E7C000000000000000000000000000000000026 +:104E8C000000000000000000000000000000000016 +:104E9C0000000000496E66696E69747900000000BC +:104EAC004E614E002F646174612F6A656E6B696E82 +:104EBC00732F776F726B73706163652F474E552D2F +:104ECC00746F6F6C636861696E2F61726D2D313117 +:104EDC002F7372632F6E65776C69622D63796777B8 +:104EEC00696E2F6E65776C69622F6C6962632F73C4 +:104EFC0074646C69622F64746F612E63000000002F +:104F0C00494E4600696E66004E414E006E616E0061 +:104F1C003031323334353637383961626364656623 +:104F2C0000000000303132333435363738394142E5 +:104F3C004344454600000000286E756C6C29000047 +:104F4C0030000000202020202020202020202020A5 +:104F5C002020202020202020202020202020202045 +:104F6C002020202000000042C8801F40B8821F4033 +:104F7C000800000000000042C4801F40B4821F40A3 +:104F8C000400000000C0004224801F4014821F4017 +:104F9C001000000000C0004228801F4018821F40F3 +:104FAC002000000000C000422C801F401C821F40CB +:104FBC004000000000C0004234801F4024821F408B +:104FCC00000100000040004264811F4054831F40D8 +:104FDC00000400000040004280811F4070831F408D +:104FEC0000000200004000427C811F406C831F4087 +:104FFC00000001000040004268811F4058831F40A0 +:10500C0000080000004000423C811F402C831F40E0 +:10501C00010000000040004244811F4034831F40C7 +:10502C00040000000040004240811F4030831F40BC +:10503C00020000000040004248811F4038831F409E +:10504C00080000000000004204811F40F4821F4051 +:10505C00000004000000004208811F40F8821F403D +:10506C00000008000000004218811F4008831F4008 +:10507C00000080000000004214811F4004831F4088 +:10508C00000040000000004200811F40F0821F40E1 +:10509C000000020000000042FC801F40EC821F4018 +:1050AC00000001000000004224811F4014831F40B7 +:1050BC00000000040000004228811F4018831F409C +:1050CC0000000008000000421C811F400C831F40A0 +:1050DC00000000010000004220811F4010831F408F +:1050EC000000000200000042EC801F40DC821F40E8 +:1050FC000010000000000042F0801F40E0821F40C2 +:10510C00002000000000004234811F4024831F4017 +:10511C00000000400000004238811F4028831F40DF +:10512C00000000800080004294801F4084821F4059 +:10513C000000040000C0004290801F4080821F408D +:10514C000000008000800042A8801F4098821F4011 +:10515C000000800000800042A4801F4094821F4009 +:10516C0000004000004000426C811F405C831F40E7 +:10517C000010000000C0004230801F4020821F4001 +:10518C008000000000800042C8811F40B8831F408F +:10519C000080000000800042C4811F40B4831F4087 +:1051AC000040000000800042C0811F40B0831F40BF +:1051BC000020000000800042BC811F40AC831F40D7 +:1051CC000010000000800042D0811F40C0831F40AF +:1051DC000000020000800042CC811F40BC831F40B5 +:1051EC00000001005B4C4F434B5D20253032643A8C +:1051FC00253032643A253032642563253032642000 +:10520C007C20252E32666670730D0A005B46524573 +:10521C00455D20253032643A253032643A253032EF +:10522C00643A25303264207C20252E3266667073F9 +:10523C000D0A000005000000190000007D000000B0 +:10524C004C435F434F4C4C41544500004C435F432F +:10525C0054595045000000004C435F4D4F4E45548F +:10526C00415259004C435F4E554D45524943000045 +:10527C004C435F54494D45004C435F4D455353419E +:10528C004745530000010000901A00201200000056 +:10529C0000060000342000600A000000000200003C +:1052AC00D01F006062000000000700006C1F00604F +:1052BC0062000000EE030000CC1A00201200000077 +:1052CC00000004EEA41A00202800000000030000D7 +:1052DC00681F00600000000001030904501F0060FB +:1052EC000000000002030904381F006000000000E9 +:1052FC0003030904E01A0020000000000000000075 +:10530C000000000000000000303030303030303011 +:10531C003030303030303030303030303030303081 +:10532C00303030303030303000000000BC290020EC +:10533C00242A00208C2A002000000000000000001D +:10534C000000000000000000000000000000000051 +:10535C000000000000000000000000000000000041 +:10536C000000000000000000000000000000000031 +:10537C000000000000000000000000000000000021 +:10538C000000000000000000000000000000000011 +:10539C000000000000000000000000000000000001 +:1053AC0000000000000000000000000000000000F1 +:1053BC0000000000000000000000000000000000E1 +:1053CC0001000000000000000E33CDAB34126DE67E +:1053DC00ECDE05000B0000000000000000000000E7 +:1053EC0000000000000000000000000000000000B1 +:1053FC0000000000000000000000000000000000A1 +:10540C000000000000000000000000000000000090 +:10541C000000000000000000000000000000000080 +:10542C000000000000000000000000000000000070 +:10543C000000000000000000000000000000000060 +:10544C0000000000000000000029DE07007B9A1716 +:10545C0000003A4060060020000000000000000040 +:10546C000000000000000000000000000000000030 +:10547C000000000000000000000000000000000020 +:10548C000000000000000000000000000000000010 +:10549C000000000000000000000000000000000000 +:1054AC007007002000000000E8030000000000006E +:1054BC00B408002000000000E80300000000000019 +:1054CC0000003F40E81E00600000000000000000EB +:1054DC0000000000000000000000000000000000C0 +:1054EC0000000000000000000000000000000000B0 +:1054FC0000000000000000000000000000000000A0 +:10550C00000000000000000000000000000000008F +:10551C00000000000000000000000000000000007F +:10552C00000000000000000000000000000000006F +:10553C00000000000000000000000000000000005F +:10554C00000000000000000000000000000000004F +:10555C00000000000000000000000000000000003F +:10556C00000000000000000000000000000000002F +:10557C00000000000000000000000000000000001F +:10558C00000000000000000000000000000000000F +:10559C0000000000000000000000000000000000FF +:1055AC0000000000000000000000000000000000EF +:1055BC0000000000000000000000000000000000DF +:1055CC0000000000000000000000000000000000CF +:1055DC0000000000000000000000000000000000BF +:1055EC0000000000000000000000000000000000AF +:1055FC00B408002000000000E803000000000000D8 +:10560C0000803F40981E0060000000000000000079 +:10561C00000000000000000000000000000000007E +:10562C00000000000000000000000000000000006E +:10563C00000000000000000000000000000000005E +:10564C00000000000000000000000000000000004E +:10565C00000000000000000000000000000000003E +:10566C00000000000000000000000000000000002E +:10567C00000000000000000000000000000000001E +:10568C00000000000000000000000000000000000E +:10569C0000000000000000000000000000000000FE +:1056AC0000000000000000000000000000000000EE +:1056BC0000000000000000000000000000000000DE +:1056CC0000000000000000000000000000000000CE +:1056DC0000000000000000000000000000000000BE +:1056EC0000000000000000000000000000000000AE +:1056FC00000000000000000000000000000000009E +:10570C00000000000000000000000000000000008D +:10571C00000000000000000000000000000000007D +:10572C00000000000000000000000000000000006D +:10573C00B408002000000000E80300000000000096 +:10574C0000C03F40481E0060000000000000000048 +:10575C00000000000000000000000000000000003D +:10576C00000000000000000000000000000000002D +:10577C00000000000000000000000000000000001D +:10578C00000000000000000000000000000000000D +:10579C0000000000000000000000000000000000FD +:1057AC0000000000000000000000000000000000ED +:1057BC0000000000000000000000000000000000DD +:1057CC0000000000000000000000000000000000CD +:1057DC0000000000000000000000000000000000BD +:1057EC0000000000000000000000000000000000AD +:1057FC00000000000000000000000000000000009D +:10580C00000000000000000000000000000000008C +:10581C00000000000000000000000000000000007C +:10582C00000000000000000000000000000000006C +:10583C00000000000000000000000000000000005C +:10584C00000000000000000000000000000000004C +:10585C00000000000000000000000000000000003C +:10586C00000000000000000000000000000000002C +:10587C00FFFFFFFF7C290020C03E2020000000001D +:10588C0043000000000000000000000000000000C9 +:10589C0000000000000000000000000000000000FC +:1058AC0043000000000000000000000000000000A9 +:1058BC0000000000000000000000000000000000DC +:1058CC004300000000000000000000000000000089 +:1058DC0000000000000000000000000000000000BC +:1058EC004300000000000000000000000000000069 +:1058FC00000000000000000000000000000000009C +:10590C004300000000000000000000000000000048 +:10591C00000000000000000000000000000000007B +:10592C004300000000000000000000000000000028 +:10593C00000000000000000000000000000000005B +:10594C004300000000000000000000000000000008 +:10595C00000000000000000000000000000000003B +:10596C0035DC000091D4000000000000100A00207B +:10597C00FC0500209C0500209C0500209C050020B7 +:10598C009C0500209C0500209C0500209C05002007 +:10599C009C0500209C050020FFFFFFFFFFFFFFFF81 +:1059AC00FFFFFFFFFFFF0000010041534349490087 +:1059BC0000000000000000000000000000000000DB +:1059CC000000000000000000000041534349490062 +:1059DC0000000000000000000000000000000000BB +:1059EC0000000000000000000000000000000000AB +:1059FC00000000006C1600206C16002074160020AD +:105A0C00741600207C1600207C16002084160020C2 +:105A1C00841600208C1600208C1600209416002072 +:105A2C00941600209C1600209C160020A416002022 +:105A3C00A4160020AC160020AC160020B4160020D2 +:105A4C00B4160020BC160020BC160020C416002082 +:105A5C00C4160020CC160020CC160020D416002032 +:105A6C00D4160020DC160020DC160020E4160020E2 +:105A7C00E4160020EC160020EC160020F416002092 +:105A8C00F4160020FC160020FC1600200417002041 +:105A9C00041700200C1700200C17002014170020EE +:105AAC00141700201C1700201C170020241700209E +:105ABC00241700202C1700202C170020341700204E +:105ACC00341700203C1700203C17002044170020FE +:105ADC00441700204C1700204C17002054170020AE +:105AEC00541700205C1700205C170020641700205E +:105AFC00641700206C1700206C170020741700200E +:105B0C00741700207C1700207C17002084170020BD +:105B1C00841700208C1700208C170020941700206D +:105B2C00941700209C1700209C170020A41700201D +:105B3C00A4170020AC170020AC170020B4170020CD +:105B4C00B4170020BC170020BC170020C41700207D +:105B5C00C4170020CC170020CC170020D41700202D +:105B6C00D4170020DC170020DC170020E4170020DD +:105B7C00E4170020EC170020EC170020F41700208D +:105B8C00F4170020FC170020FC170020041800203C +:105B9C00041800200C1800200C18002014180020E9 +:105BAC00141800201C1800201C1800202418002099 +:105BBC00241800202C1800202C1800203418002049 +:105BCC00341800203C1800203C18002044180020F9 +:105BDC00441800204C1800204C18002054180020A9 +:105BEC00541800205C1800205C1800206418002059 +:105BFC00641800206C1800206C1800207418002009 +:105C0C00741800207C1800207C18002084180020B8 +:105C1C00841800208C1800208C1800209418002068 +:105C2C00941800209C1800209C180020A418002018 +:105C3C00A4180020AC180020AC180020B4180020C8 +:105C4C00B4180020BC180020BC180020C418002078 +:105C5C00C4180020CC180020CC180020D418002028 +:105C6C00D4180020DC180020DC180020E4180020D8 +:105C7C00E4180020EC180020EC180020F418002088 +:105C8C00F4180020FC180020FC1800200419002037 +:105C9C00041900200C1900200C19002014190020E4 +:105CAC00141900201C1900201C1900202419002094 +:105CBC00241900202C1900202C1900203419002044 +:105CCC00341900203C1900203C19002044190020F4 +:105CDC00441900204C1900204C19002054190020A4 +:105CEC00541900205C1900205C1900206419002054 +:105CFC00641900206C1900206C1900207419002004 +:105D0C00741900207C1900207C19002084190020B3 +:105D1C00841900208C1900208C1900209419002063 +:105D2C00941900209C1900209C190020A419002013 +:105D3C00A4190020AC190020AC190020B4190020C3 +:105D4C00B4190020BC190020BC190020C419002073 +:105D5C00C4190020CC190020CC190020D419002023 +:105D6C00D4190020DC190020DC190020E4190020D3 +:105D7C00E4190020EC190020EC190020F419002083 +:105D8C00F4190020FC190020FC190020041A002032 +:105D9C00041A00200C1A00200C1A0020141A0020DF +:105DAC00141A00201C1A00201C1A0020241A00208F +:105DBC00241A00202C1A00202C1A0020341A00203F +:105DCC00341A00203C1A00203C1A0020441A0020EF +:105DDC00441A00204C1A00204C1A0020541A00209F +:105DEC00541A00205C1A00205C1A0020641A00204F +:105DFC00641A0020FFFFFFFF0000020000000000FB +:105E0C0003000000BC290020A80F00200000C8419E +:105E1C0012010002EF020140C01683047902010254 +:105E2C000301000028000000000104000100000034 +:105E3C0000000000020157494E555342000000007B +:105E4C0000000000000000000000000012034D00E4 +:105E5C00530046005400310030003000F8000000C0 +:105E6C000C03000000000000000000000000000017 +:105E7C0000000000000029010000000000000000EC +:105E8C000000000000000000000000000000000006 +:105E9C0000000000000000000000000000000000F6 +:105EAC0000000000000000000000000000000000E6 +:105EBC0000000000000000000000000000000000D6 +:105ECC0000000000000000000000000000000000C6 +:105EDC0000000000000000000000000000000000B6 +:105EEC0000000000000000000000000000000000A6 +:105EFC000000000000000000000000000000000096 +:105F0C000000000000000000000000000000000085 +:105F1C000000000000000000000000000000000075 +:105F2C000000000000000000000000000000000065 +:105F3C000000000000000000000000000000000055 +:105F4C000000000000000000000000000000000045 +:105F5C000000000000000000000000000000000035 +:105F6C000000000000000000000000000000000025 +:105F7C000000000000000000000000000000000015 +:105F8C000000000000000000000000000000000005 +:105F9C0000000000000000000000000000000000F5 +:105FAC0000000000000000000000000000000000E5 +:105FBC0000000000000000000000000000000000D5 +:105FCC0000000000000000000000000000000000C5 +:105FDC0000000000000000000000000000000000B5 +:105FEC0000000000000000000000000000000000A5 +:105FFC000000000000000000000000000000000095 +:10600C000000000000000000000000000000000084 +:10601C000000000000000000000000000000000074 +:10602C000000000000000000000000000000000064 +:10603C000000000000000000000000000000000054 +:10604C000000000000000000000000000000000044 +:10605C000000000000000000000000000000000034 +:10606C000000000000000000000000000000000024 +:10607C000000000000000000000000000000000014 +:10608C000000000000000000000000000000000004 +:10609C0000000000000000000000000000000000F4 +:1060AC0000000000000000000000000000000000E4 +:1060BC0000000000000000000000000000000000D4 +:1060CC0000000000000000000000000000000000C4 +:1060DC0000000000000000000000000000000000B4 +:1060EC0000000000000000000000000000000000A4 +:1060FC000000000000000000000000000000000094 +:10610C000000000000000000000000000000000083 +:10611C000000000000000000000000000000000073 +:10612C000000000000000000000000000000000063 +:10613C000000000000000000000000000000000053 +:10614C000000000000000000000000000000000043 +:10615C000000000000000000000000000000000033 +:10616C000000000000000000000000000000000023 +:10617C000000000000000000000000000000000013 +:10618C000000000000000000000000000000000003 +:10619C0000000000000000000000000000000000F3 +:1061AC0000000000000000000000000000000000E3 +:1061BC0000000000000000000000000000000000D3 +:1061CC0000000000000000000000000000000000C3 +:1061DC0000000000000000000000000000000000B3 +:1061EC0000000000000000000000000000000000A3 +:1061FC000000000000000000000000000000000093 +:10620C000000000000000000000000000000000082 +:10621C000000000000000000000000000000000072 +:10622C000000000000000000000000000000000062 +:10623C000000000000000000000000000000000052 +:10624C00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF52 +:10625C00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF42 +:10626C00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF32 +:10627C00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF22 +:10628C00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF12 +:10629C00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF02 +:1062AC00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2 +:1062BC00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE2 +:1062CC00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD2 +:1062DC00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC2 +:1062EC00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB2 +:1062FC00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA2 +:10630C00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF91 +:10631C00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF81 +:10632C00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF71 +:10633C00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF61 +:10634C00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF51 +:10635C00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF41 +:10636C00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF31 +:10637C00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF21 +:10638C00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF11 +:10639C00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF01 +:1063AC00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1 +:1063BC00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE1 +:1063CC00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD1 +:1063DC00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC1 +:1063EC00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB1 +:1063FC00FFFFFFFF00000000000000000000000095 +:10640C000000000000000000000000000000000080 +:10641C000000000000000000000000000000000070 +:10642C000000000000000000000000000000000060 +:10643C000000000000000000000000000000000050 +:10644C000000000000000000000000000000000040 +:10645C000000000000000000000000000000000030 +:10646C000000000000000000000000000000000020 +:10647C000000000000000000000000000000000010 +:10648C000000000000000000000000000000000000 +:10649C0000000000000000000000000000000000F0 +:1064AC0000000000000000000000000000000000E0 +:1064BC0000000000000000000000000000000000D0 +:1064CC0000000000000000000000000000000000C0 +:1064DC0000000000000000000000000000000000B0 +:1064EC0000000000000000000000000000000000A0 +:1064FC000000000000000000000000000000000090 +:10650C00000000000000000000000000000000007F +:10651C00000000000000000000000000000000006F +:10652C00000000000000000000000000000000005F +:10653C00000000000000000000000000000000004F +:10654C00000000000000000000000000000000003F +:10655C00000000000000000000000000000000002F +:10656C00000000000000000000000000000000001F +:10657C00000000000000000000000000000000000F +:10658C0000000000000000000000000000000000FF +:10659C0000000000000000000000000000000000EF +:1065AC0000000000000000000000000000000000DF +:1065BC0000000000000000000000000000000000CF +:1065CC0000000000000000000000000000000000BF +:1065DC0000000000000000000000000000000000AF +:1065EC00000000000000000000000000000000009F +:1065FC00000000000000000000000000000000008F +:10660C00000000000000000000000000000000007E +:10661C00000000000000000000000000000000006E +:10662C00000000000000000000000000000000005E +:10663C00000000000000000000000000000000004E +:10664C00000000000000000000000000000000003E +:10665C00000000000000000000000000000000002E +:10666C00000000000000000000000000000000001E +:10667C00000000000000000000000000000000000E +:10668C0000000000000000000000000000000000FE +:10669C0000000000000000000000000000000000EE +:1066AC0000000000000000000000000000000000DE +:1066BC0000000000000000000000000000000000CE +:1066CC0000000000000000000000000000000000BE +:1066DC0000000000000000000000000000000000AE +:1066EC00000000000000000000000000000000009E +:1066FC00000000000000000000000000000000008E +:10670C00000000000000000000000000000000007D +:10671C00000000000000000000000000000000006D +:10672C00000000000000000000000000000000005D +:10673C00000000000000000000000000000000004D +:10674C00000000000000000000000000000000003D +:10675C00000000000000000000000000000000002D +:10676C00000000000000000000000000000000001D +:10677C00000000000000000000000000000000000D +:10678C0000000000000000000000000000000000FD +:10679C0000000000000000000000000000000000ED +:1067AC0000000000000000000000000000000000DD +:1067BC0000000000000000000000000000000000CD +:1067CC0000000000000000000000000000000000BD +:1067DC0000000000000000000000000000000000AD +:1067EC00000000000000000000000000000000009D +:1067FC00000000000000000000000000000000008D +:10680C00000000000000000000000000000000007C +:10681C00000000000000000000000000000000006C +:10682C00000000000000000000000000000000005C +:10683C00000000000000000000000000000000004C +:10684C00000000000000000000000000000000003C +:10685C00000000000000000000000000000000002C +:10686C00000000000000000000000000000000001C +:10687C00000000000000000000000000000000000C +:10688C0000000000000000000000000000000000FC +:10689C0000000000000000000000000000000000EC +:1068AC0000000000000000000000000000000000DC +:1068BC0000000000000000000000000000000000CC +:1068CC0000000000000000000000000000000000BC +:1068DC0000000000000000000000000000000000AC +:1068EC00000000000000000000000000000000009C +:1068FC00000000000000000000000000000000008C +:10690C00000000000000000000000000000000007B +:10691C00000000000000000000000000000000006B +:10692C00000000000000000000000000000000005B +:10693C00000000000000000000000000000000004B +:10694C00000000000000000000000000000000003B +:10695C00000000000000000000000000000000002B +:10696C00000000000000000000000000000000001B +:10697C00000000000000000000000000000000000B +:10698C0000000000000000000000000000000000FB +:10699C0000000000000000000000000000000000EB +:1069AC0000000000000000000000000000000000DB +:1069BC0000000000000000000000000000000000CB +:1069CC0000000000000000000000000000000000BB +:1069DC0000000000000000000000000000000000AB +:1069EC00000000000000000000000000000000009B +:1069FC00000000000000000000000000000000008B +:106A0C00000000000000000000000000000000007A +:106A1C00000000000000000000000000000000006A +:106A2C00000000000000000000000000000000005A +:106A3C00000000000000000000000000000000004A +:106A4C00000000000000000000000000000000003A +:106A5C00000000000000000000000000000000002A +:106A6C00000000000000000000000000000000001A +:106A7C00000000000000000000000000000000000A +:106A8C0000000000000000000000000000000000FA +:106A9C0000000000000000000000000000000000EA +:106AAC0000000000000000000000000000000000DA +:106ABC0000000000000000000000000000000000CA +:106ACC0000000000000000000000000000000000BA +:106ADC0000000000000000000000000000000000AA +:106AEC00000000000000000000000000000000009A +:106AFC00000000000000000000000000000000008A +:106B0C000000000000000000000000000000000079 +:106B1C000000000000000000000000000000000069 +:106B2C000000000000000000000000000000000059 +:106B3C000000000000000000000000000000000049 +:106B4C000000000000000000000000000000000039 +:106B5C000000000000000000000000000000000029 +:106B6C000000000000000000000000000000000019 +:106B7C000000000000000000000000000000000009 +:106B8C0000000000000000000000000000000000F9 +:106B9C0000000000000000000000000000000000E9 +:106BAC0000000000000000000000000000000000D9 +:106BBC0000000000000000000000000000000000C9 +:106BCC0000000000000000000000000000000000B9 +:106BDC0000000000000000000000000000000000A9 +:106BEC000000000000000000000000000000000099 +:106BFC000000000000000000000000000000000089 +:106C0C000000000000000000000000000000000078 +:106C1C000000000000000000000000000000000068 +:106C2C000000000000000000000000000000000058 +:106C3C000000000000000000000000000000000048 +:106C4C000000000000000000000000000000000038 +:106C5C000000000000000000000000000000000028 +:106C6C000000000000000000000000000000000018 +:106C7C000000000000000000000000000000000008 +:106C8C0000000000000000000000000000000000F8 +:106C9C0000000000000000000000000000000000E8 +:106CAC0000000000000000000000000000000000D8 +:106CBC0000000000000000000000000000000000C8 +:106CCC0000000000000000000000000000000000B8 +:106CDC0000000000000000000000000000000000A8 +:106CEC000000000000000000000000000000000098 +:106CFC000000000000000000000000000000000088 +:106D0C000000000000000000000000000000000077 +:106D1C000000000000000000000000000000000067 +:106D2C000000000000000000000000000000000057 +:106D3C000000000000000000000000000000000047 +:106D4C000000000000000000000000000000000037 +:106D5C000000000000000000000000000000000027 +:106D6C000000000000000000000000000000000017 +:106D7C000000000000000000000000000000000007 +:106D8C0000000000000000000000000000000000F7 +:106D9C0000000000000000000000000000000000E7 +:106DAC0000000000000000000000000000000000D7 +:106DBC0000000000000000000000000000000000C7 +:106DCC0000000000000000000000000000000000B7 +:106DDC0000000000000000000000000000000000A7 +:106DEC000000000000000000000000000000000097 +:106DFC000000000000000000000000000000000087 +:106E0C000000000000000000000000000000000076 +:106E1C000000000000000000000000000000000066 +:106E2C000000000000000000000000000000000056 +:106E3C000000000000000000000000000000000046 +:106E4C000000000000000000000000000000000036 +:106E5C000000000000000000000000000000000026 +:106E6C000000000000000000000000000000000016 +:106E7C000000000000000000000000000000000006 +:106E8C0000000000000000000000000000000000F6 +:106E9C0000000000000000000000000000000000E6 +:106EAC0000000000000000000000000000000000D6 +:106EBC0000000000000000000000000000000000C6 +:106ECC0000000000000000000000000000000000B6 +:106EDC0000000000000000000000000000000000A6 +:106EEC000000000000000000000000000000000096 +:106EFC000000000000000000000000000000000086 +:106F0C000000000000000000000000000000000075 +:106F1C000000000000000000000000000000000065 +:106F2C000000000000000000000000000000000055 +:106F3C000000000000000000000000000000000045 +:106F4C000000000000000000000000000000000035 +:106F5C000000000000000000000000000000000025 +:106F6C000000000000000000000000000000000015 +:106F7C000000000000000000000000000000000005 +:106F8C0000000000000000000000000000000000F5 +:106F9C0000000000000000000000000000000000E5 +:106FAC0000000000000000000000000000000000D5 +:106FBC0000000000000000000000000000000000C5 +:106FCC0000000000000000000000000000000000B5 +:106FDC0000000000000000000000000000000000A5 +:106FEC000000000000000000000000000000000095 +:046FFC000000000091 +:040000056000100087 +:00000001FF diff --git a/firmware/ltc_audiohat_lock_v2.ino b/firmware/ltc_audiohat_lock_v2.ino new file mode 100644 index 0000000..67e31a6 --- /dev/null +++ b/firmware/ltc_audiohat_lock_v2.ino @@ -0,0 +1,174 @@ +/* Linear Timecode for Audio Library for Teensy 3.x / 4.x + Copyright (c) 2019, Frank BΓΆsing, f.boesing (at) gmx.de + + Development of this audio library was funded by PJRC.COM, LLC by sales of + Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop + open source software by purchasing Teensy or other PJRC products. + + 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, development funding 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. +*/ + +/* + + https://forum.pjrc.com/threads/41584-Audio-Library-for-Linear-Timecode-(LTC) + + LTC example audio at: https://www.youtube.com/watch?v=uzje8fDyrgg + + Adapted by Chris Frankland-Wright 2025 for Teensy Audio Shield Input with autodetect FPS for the NTP-TimeTurner Project + +*/ + +#include +#include +#include "analyze_ltc.h" + +// β€”β€” Configuration β€”β€” +const float FORCE_FPS = 0.0f; // 0 β†’ auto‑detect +const int FRAME_OFFSET = 4; // compensation in frames +const unsigned long LOSS_TIMEOUT = 1000UL; // ms before we go into LOST +const unsigned long BLINK_PERIOD[3] = {2000,100,500}; // NO_LTC, ACTIVE, LOST + +AudioInputI2S i2s1; +AudioAnalyzeLTC ltc1; +AudioControlSGTL5000 sgtl5000; +AudioConnection patchCord(i2s1, 0, ltc1, 0); + +enum State { NO_LTC=0, LTC_ACTIVE, LTC_LOST }; +State ltcState = NO_LTC; +bool ledOn = false; +unsigned long lastDecode = 0; +unsigned long lastBlink = 0; + +// FPS detection +float currentFps = 25.0f; +float periodMs = 0; +const float SMOOTH_ALPHA = 0.1f; +unsigned long lastDetectTs = 0; + +// free‑run +long freeAbsFrame = 0; +unsigned long lastFreeRun = 0; + +void setup() { + Serial.begin(115200); + AudioMemory(12); + sgtl5000.enable(); + sgtl5000.inputSelect(AUDIO_INPUT_LINEIN); + pinMode(LED_BUILTIN, OUTPUT); +} + +void loop() { + unsigned long now = millis(); + // compute framePeriod from currentFps + unsigned long framePeriod = (unsigned long)(1000.0f / currentFps + 0.5f); + + // 1) If in ACTIVE and we've gone > LOSS_TIMEOUT w/o decode, enter LOST + if (ltcState == LTC_ACTIVE && (now - lastDecode) >= LOSS_TIMEOUT) { + ltcState = LTC_LOST; + // bump freeAbsFrame by 1β€―second worth of frames: + int nominal = (currentFps>29.5f) ? 30 : int(currentFps+0.5f); + long dayFrames= 24L*3600L*nominal; + freeAbsFrame = (freeAbsFrame + nominal) % dayFrames; + // reset free‑run timer so we start next tick fresh + lastFreeRun = now; + } + + // 2) Handle incoming LTC frame + if (ltc1.available()) { + ltcframe_t frame = ltc1.read(); + int h = ltc1.hour(&frame), + m = ltc1.minute(&frame), + s = ltc1.second(&frame), + f = ltc1.frame(&frame); + + // β€” FPS detect or force β€” + if (FORCE_FPS > 0.0f) { + currentFps = FORCE_FPS; + } else { + if (lastDetectTs) { + float dt = now - lastDetectTs; + periodMs = periodMs==0 ? dt : (SMOOTH_ALPHA*dt + (1-SMOOTH_ALPHA)*periodMs); + float meas = 1000.0f/periodMs; + const float choices[3] = {24.0f,25.0f,29.97f}; + float bestD=1e6, pick=25.0f; + for (auto c: choices) { + float d = fabs(meas-c); + if (d < bestD) { bestD=d; pick=c; } + } + currentFps = pick; + } + lastDetectTs = now; + } + + // β€” pack + offset + wrap β€” + int nominal = (currentFps>29.5f) ? 30 : int(currentFps+0.5f); + long dayFrames = 24L*3600L*nominal; + long absF = ((long)h*3600 + m*60 + s)*nominal + f + FRAME_OFFSET; + absF = (absF % dayFrames + dayFrames) % dayFrames; + + // β€” reset anchors & state β€” + freeAbsFrame = absF; + lastFreeRun = now; + lastDecode = now; + ltcState = LTC_ACTIVE; + + // β€” print LOCK β€” + long totSec = absF/nominal; + int outF = absF % nominal; + int outS = totSec % 60; + long totMin = totSec/60; + int outM = totMin % 60; + int outH = (totMin/60) % 24; + bool isDF = ltc1.bit10(&frame); + char sep = isDF?';':':'; + Serial.printf("[LOCK] %02d:%02d:%02d%c%02d | %.2ffps\r\n", + outH,outM,outS,sep,outF,currentFps); + + // β€” LED β†’ ACTIVE immediately β€” + lastBlink = now; + ledOn = true; + digitalWrite(LED_BUILTIN, HIGH); + } + // 3) If in LOST, do free‑run printing + else if (ltcState == LTC_LOST) { + if ((now - lastFreeRun) >= framePeriod) { + freeAbsFrame = (freeAbsFrame + 1) % (24L*3600L*((int)(currentFps+0.5f))); + lastFreeRun += framePeriod; + + // β€” print FREE β€” + int nominal = (currentFps>29.5f) ? 30 : int(currentFps+0.5f); + long totSec = freeAbsFrame/nominal; + int outF = freeAbsFrame % nominal; + int outS = totSec % 60; + long totMin = totSec/60; + int outM = totMin % 60; + int outH = (totMin/60)%24; + Serial.printf("[FREE] %02d:%02d:%02d:%02d | %.2ffps\r\n", + outH,outM,outS,outF,currentFps); + } + } + + // 4) LED heartbeat + unsigned long bp = BLINK_PERIOD[ltcState]; + if ((now - lastBlink) >= (bp/2)) { + ledOn = !ledOn; + digitalWrite(LED_BUILTIN, ledOn); + lastBlink = now; + } +} \ No newline at end of file diff --git a/setup.sh b/setup.sh index efef9d9..0b68c12 100644 --- a/setup.sh +++ b/setup.sh @@ -1,125 +1,280 @@ #!/bin/bash set -e -echo "" -echo "─────────────────────────────────────────────" -echo " Welcome to the NTP TimeTurner Installer" -echo "─────────────────────────────────────────────" -echo "" -echo "\"It's a very complicated piece of magic...\" – Hermione Granger" -echo "Preparing the Ministry-grade temporal interface..." -echo "" +echo "--- TimeTurner Setup ---" -# --------------------------------------------------------- -# Step 1: Update and upgrade packages -# --------------------------------------------------------- -echo "Step 1: Updating package lists and upgrading..." -sudo apt update && sudo apt upgrade -y - -# --------------------------------------------------------- -# Step 2: Install core tools and Python dependencies -# --------------------------------------------------------- -echo "Step 2: Installing required tools..." -sudo apt install -y git curl python3 python3-pip build-essential cmake \ - python3-serial libusb-dev - -# --------------------------------------------------------- -# Step 2.5: Install teensy-loader-cli from source -# --------------------------------------------------------- -echo "Installing teensy-loader-cli manually from source..." -cd "$HOME" -if [ ! -d teensy_loader_cli ]; then - git clone https://github.com/PaulStoffregen/teensy_loader_cli.git +# Check if TimeTurner is already installed. +INSTALL_DIR="/opt/timeturner" +if [ -f "${INSTALL_DIR}/timeturner" ]; then + echo "βœ… TimeTurner is already installed." + # Ask the user what to do + read -p "Do you want to (U)pdate, (R)einstall, or (A)bort? [U/r/a] " choice + case "$choice" in + r|R ) + echo "Proceeding with full re-installation..." + # Stop the service to allow overwriting the binary, ignore errors if not running + echo "Stopping existing TimeTurner service..." + sudo systemctl stop timeturner.service || true + # The script will continue to the installation steps below. + ;; + a|A ) + echo "Aborting setup." + exit 0 + ;; + * ) # Default to Update + echo "Attempting to run the update script..." + # Ensure we are in a git repository and the update script exists + if [ -d ".git" ] && [ -f "update.sh" ]; then + chmod +x update.sh + ./update.sh + # Exit cleanly after the update + exit 0 + else + echo "⚠️ Could not find 'update.sh' or not in a git repository." + echo "Please re-clone the repository to get the update script, or remove the existing installation to run setup again:" + echo " sudo rm -rf ${INSTALL_DIR}" + exit 1 + fi + ;; + esac fi -cd teensy_loader_cli -make -sudo install -m 755 teensy_loader_cli /usr/local/bin/teensy-loader-cli -echo "Verifying teensy-loader-cli..." -teensy-loader-cli --version || echo "⚠️ teensy-loader-cli failed to install properly" -# --------------------------------------------------------- -# Step 2.6: Install udev rules for Teensy -# --------------------------------------------------------- -echo "Installing udev rules for Teensy access..." -cd "$HOME" -wget -O 49-teensy.rules https://www.pjrc.com/teensy/49-teensy.rules -sudo cp 49-teensy.rules /etc/udev/rules.d/ -sudo udevadm control --reload-rules -sudo udevadm trigger -echo "βœ… Teensy udev rules installed. Reboot required to take full effect." - -# --------------------------------------------------------- -# Step 3: Install Arduino CLI manually (latest version) -# --------------------------------------------------------- -echo "Step 3: Downloading and installing arduino-cli..." -cd "$HOME" -curl -fsSL https://downloads.arduino.cc/arduino-cli/arduino-cli_latest_Linux_ARM64.tar.gz -o arduino-cli.tar.gz -tar -xzf arduino-cli.tar.gz -sudo mv arduino-cli /usr/local/bin/ -rm arduino-cli.tar.gz - -echo "Verifying arduino-cli install..." -arduino-cli version || echo "⚠️ arduino-cli install failed or not found in PATH" - -# --------------------------------------------------------- -# Step 4: Download and apply splash screen -# --------------------------------------------------------- -echo "Step 4: Downloading and applying splash screen..." -cd "$HOME" -wget -O splash.png https://raw.githubusercontent.com/cjfranko/NTP-Timeturner/master/splash.png - -if [ -f splash.png ]; then - sudo cp splash.png /usr/share/plymouth/themes/pix/splash.png - sudo chmod 644 /usr/share/plymouth/themes/pix/splash.png - echo "βœ… Splash screen applied." +# Determine package manager +PKG_MANAGER="" +if command -v apt &> /dev/null; then + PKG_MANAGER="apt" +elif command -v dnf &> /dev/null; then + PKG_MANAGER="dnf" +elif command -v pacman &> /dev/null; then + PKG_MANAGER="pacman" else - echo "⚠️ splash.png not found β€” skipping." + echo "Error: No supported package manager (apt, dnf, pacman) found. Please install dependencies manually." + exit 1 fi -# --------------------------------------------------------- -# Step 4.5: Configure Plymouth to stay on screen longer -# --------------------------------------------------------- -echo "Step 4.5: Configuring splash screen timing..." +echo "Detected package manager: $PKG_MANAGER" -# Ensure 'quiet splash' is in /boot/cmdline.txt -sudo sed -i 's/\(\s*\)console=tty1/\1quiet splash console=tty1/' /boot/cmdline.txt -echo "βœ… Set 'quiet splash' in /boot/cmdline.txt" +# --- Update System Packages --- +echo "Updating system packages..." +if [ "$PKG_MANAGER" == "apt" ]; then + sudo apt update + sudo DEBIAN_FRONTEND=noninteractive apt upgrade -y -o Dpkg::Options::="--force-confold" +elif [ "$PKG_MANAGER" == "dnf" ]; then + sudo dnf upgrade -y +elif [ "$PKG_MANAGER" == "pacman" ]; then + sudo pacman -Syu --noconfirm +fi +echo "System packages updated." -# Update Plymouth config -sudo sed -i 's/^Theme=.*/Theme=pix/' /etc/plymouth/plymouthd.conf -sudo sed -i 's/^ShowDelay=.*/ShowDelay=0/' /etc/plymouth/plymouthd.conf || echo "ShowDelay=0" | sudo tee -a /etc/plymouth/plymouthd.conf -sudo sed -i 's/^DeviceTimeout=.*/DeviceTimeout=10/' /etc/plymouth/plymouthd.conf || echo "DeviceTimeout=10" | sudo tee -a /etc/plymouth/plymouthd.conf -sudo sed -i 's/^DisableFadeIn=.*/DisableFadeIn=true/' /etc/plymouth/plymouthd.conf || echo "DisableFadeIn=true" | sudo tee -a /etc/plymouth/plymouthd.conf -echo "βœ… Updated /etc/plymouth/plymouthd.conf" +# --- Install Rust/Cargo if not installed --- +if ! command -v cargo &> /dev/null; then + echo "Rust/Cargo not found. Installing Rustup..." + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y + # Source cargo's env for the current shell session + # This is for the current script's execution path, typically rustup adds to .bashrc/.profile for future sessions. + # We need it now, but for non-interactive script, sourcing won't affect parent shell. + # However, cargo build below will rely on it being in PATH. rustup makes sure of this if it installs. + # For safety, ensure PATH is updated. + export PATH="$HOME/.cargo/bin:$PATH" + echo "Rust/Cargo installed successfully." +else + echo "Rust/Cargo is already installed." +fi + +# --- Install common build dependencies for Rust --- +echo "Installing common build dependencies..." +if [ "$PKG_MANAGER" == "apt" ]; then + sudo apt update + sudo apt install -y build-essential libudev-dev pkg-config curl wget +elif [ "$PKG_MANAGER" == "dnf" ]; then + sudo dnf install -y gcc make perl-devel libudev-devel pkg-config curl wget +elif [ "$PKG_MANAGER" == "pacman" ]; then + sudo pacman -Sy --noconfirm base-devel libudev pkg-config curl +fi +echo "Common build dependencies installed." + +# --- Install Python dependencies for testing --- +echo "🐍 Installing Python dependencies for test scripts..." +if [ "$PKG_MANAGER" == "apt" ]; then + # We no longer need hotspot dependencies + sudo apt install -y python3 python3-pip python3-serial +elif [ "$PKG_MANAGER" == "dnf" ]; then + # python3-pyserial is the name for pyserial in dnf + sudo dnf install -y python3 python3-pip python3-pyserial +elif [ "$PKG_MANAGER" == "pacman" ]; then + # python-pyserial is the name for pyserial in pacman + sudo pacman -Sy --noconfirm python python-pip python-pyserial +fi +# sudo pip3 install pyserial # This is replaced by the native package manager installs above +echo "βœ… Python dependencies installed." + +# --- Apply custom splash screen --- +if [[ "$(uname)" == "Linux" ]]; then + echo "πŸ–ΌοΈ Applying custom splash screen..." + SPLASH_URL="https://raw.githubusercontent.com/cjfranko/NTP-Timeturner/refs/heads/main/splash.png" + PLYMOUTH_THEME_DIR="/usr/share/plymouth/themes/pix" + PLYMOUTH_IMAGE_PATH="${PLYMOUTH_THEME_DIR}/splash.png" + + sudo mkdir -p "${PLYMOUTH_THEME_DIR}" + echo "Downloading splash image from ${SPLASH_URL}..." + sudo curl -L "${SPLASH_URL}" -o "${PLYMOUTH_IMAGE_PATH}" + + if [ -f "${PLYMOUTH_IMAGE_PATH}" ]; then + echo "Splash image downloaded. Updating Plymouth configuration..." + # Set 'pix' as the default plymouth theme if not already. + # This is a common theme that expects splash.png. + sudo update-alternatives --install /usr/share/plymouth/themes/default.plymouth default.plymouth "${PLYMOUTH_THEME_DIR}/pix.plymouth" 100 || true + # Ensure the pix theme exists and is linked + if [ ! -f "${PLYMOUTH_THEME_DIR}/pix.plymouth" ]; then + echo "Creating dummy pix.plymouth for update-initramfs" + echo "[Plymouth Theme]" | sudo tee "${PLYMOUTH_THEME_DIR}/pix.plymouth" > /dev/null + echo "Name=Pi Splash" | sudo tee -a "${PLYMOUTH_THEME_DIR}/pix.plymouth" > /dev/null + echo "Description=TimeTurner Raspberry Pi Splash Screen" | sudo tee -a "${PLYMOUTH_THEME_DIR}/pix.plymouth" > /dev/null + echo "SpriteAnimation=/splash.png" | sudo tee -a "${PLYMOUTH_THEME_DIR}/pix.plymouth" > /dev/null + fi + + # Update the initial RAM filesystem to include the new splash screen + sudo update-initramfs -u + echo "βœ… Custom splash screen applied. Reboot may be required to see changes." + else + echo "❌ Failed to download splash image from ${SPLASH_URL}." + fi +else + echo "⚠️ Skipping splash screen configuration on non-Linux OS." +fi + +# --- Remove NTPD and install Chrony, NMTUI, Adjtimex --- +echo "Removing NTPD (if installed) and installing Chrony, NMTUI, Adjtimex..." + +# --- Remove NTPD and install Chrony, NMTUI, Adjtimex --- +echo "Removing NTPD (if installed) and installing Chrony, NMTUI, Adjtimex..." + +if [ "$PKG_MANAGER" == "apt" ]; then + sudo apt update + sudo apt remove -y ntp || true # Remove ntp if it exists, ignore if not + sudo apt install -y chrony network-manager adjtimex + sudo systemctl enable chrony --now +elif [ "$PKG_MANAGER" == "dnf" ]; then + sudo dnf remove -y ntp + sudo dnf install -y chrony NetworkManager-tui adjtimex + sudo systemctl enable chronyd --now +elif [ "$PKG_MANAGER" == "pacman" ]; then + sudo pacman -Sy --noconfirm ntp || true + sudo pacman -R --noconfirm ntp || true # Ensure ntp is removed + sudo pacman -Sy --noconfirm chrony networkmanager adjtimex + sudo systemctl enable chronyd --now + sudo systemctl enable NetworkManager --now # nmtui relies on NetworkManager +fi + +echo "NTPD removed (if present). Chrony, NMTUI, and Adjtimex installed and configured." + +# --- Configure Chrony to act as a local NTP server --- +echo "βš™οΈ Configuring Chrony to serve local time..." +# The path to chrony.conf can vary +if [ -f /etc/chrony/chrony.conf ]; then + CHRONY_CONF="/etc/chrony/chrony.conf" +elif [ -f /etc/chrony.conf ]; then + CHRONY_CONF="/etc/chrony.conf" +else + CHRONY_CONF="" +fi + +if [ -n "$CHRONY_CONF" ]; then + # Comment out any existing pool, server, or sourcedir lines to prevent syncing with external sources + echo "Disabling external NTP sources..." + sudo sed -i -E 's/^(pool|server|sourcedir)/#&/' "$CHRONY_CONF" + + # Add settings to the top of the file to serve local clock + # Using a temp file to prepend is safer than multiple sed calls + TEMP_CONF=$(mktemp) + cat < "$TEMP_CONF" +# Serve the system clock as a reference at stratum 1 +server 127.127.1.0 +allow 127.0.0.0/8 +local stratum 1 -# Create autostart delay to keep splash visible until desktop is ready -mkdir -p "$HOME/.config/autostart" -cat << EOF > "$HOME/.config/autostart/delayed-plymouth-exit.desktop" -[Desktop Entry] -Type=Application -Name=Delayed Plymouth Exit -Exec=/bin/sh -c "sleep 3 && /usr/bin/plymouth quit" -X-GNOME-Autostart-enabled=true EOF -echo "βœ… Splash screen will exit 3 seconds after desktop starts" + # Append the rest of the original config file after our new lines + cat "$CHRONY_CONF" >> "$TEMP_CONF" + sudo mv "$TEMP_CONF" "$CHRONY_CONF" -# --------------------------------------------------------- -# Step 5: Download Teensy firmware -# --------------------------------------------------------- -echo "Step 5: Downloading Teensy firmware..." -cd "$HOME" -wget -O ltc_audiohat_lock.ino.hex https://raw.githubusercontent.com/cjfranko/NTP-Timeturner/master/firmware/ltc_audiohat_lock.ino.hex -# --------------------------------------------------------- -# Final Message & Reboot -# --------------------------------------------------------- + # Add settings to the bottom of the file to allow LAN clients + echo "Allowing LAN clients..." + sudo tee -a "$CHRONY_CONF" > /dev/null <, + hardware_offset_ms: i64, +} + +// AppState to hold shared data +pub struct AppState { + pub ltc_state: Arc>, + pub config: Arc>, + pub log_buffer: Arc>>, +} + +#[get("/api/status")] +async fn get_status(data: web::Data) -> impl Responder { + let state = data.ltc_state.lock().unwrap(); + let config = data.config.lock().unwrap(); + let hw_offset_ms = config.hardware_offset_ms; + + let ltc_status = state.latest.as_ref().map_or("(waiting)".to_string(), |f| f.status.clone()); + let ltc_timecode = state.latest.as_ref().map_or("…".to_string(), |f| { + let sep = if f.is_drop_frame { ';' } else { ':' }; + format!( + "{:02}:{:02}:{:02}{}{:02}", + f.hours, f.minutes, f.seconds, sep, f.frames + ) + }); + let frame_rate = state.latest.as_ref().map_or("…".to_string(), |f| { + format!("{:.2}fps", f.frame_rate.to_f64().unwrap_or(0.0)) + }); + + let now_local = Local::now(); + let system_clock = format!( + "{:02}:{:02}:{:02}.{:03}", + now_local.hour(), + now_local.minute(), + now_local.second(), + now_local.timestamp_subsec_millis(), + ); + let system_date = now_local.format("%Y-%m-%d").to_string(); + + let avg_delta = state.get_ewma_clock_delta(); + let mut delta_frames = 0; + if let Some(frame) = &state.latest { + let delta_ms_ratio = Ratio::new(avg_delta, 1); + let frames_ratio = delta_ms_ratio * frame.frame_rate / Ratio::new(1000, 1); + delta_frames = frames_ratio.round().to_integer(); + } + + let sync_status = sync_logic::get_sync_status(avg_delta, &config); + let jitter_status = sync_logic::get_jitter_status(state.average_jitter()); + let lock_ratio = state.lock_ratio(); + + let ntp_active = system::ntp_service_active(); + let interfaces = get_if_addrs() + .unwrap_or_default() + .into_iter() + .filter(|ifa| !ifa.is_loopback()) + .map(|ifa| ifa.ip().to_string()) + .collect(); + + HttpResponse::Ok().json(ApiStatus { + ltc_status, + ltc_timecode, + frame_rate, + system_clock, + system_date, + timecode_delta_ms: avg_delta, + timecode_delta_frames: delta_frames, + sync_status: sync_status.to_string(), + jitter_status: jitter_status.to_string(), + lock_ratio, + ntp_active, + interfaces, + hardware_offset_ms: hw_offset_ms, + }) +} + +#[post("/api/sync")] +async fn manual_sync(data: web::Data) -> impl Responder { + let state = data.ltc_state.lock().unwrap(); + let config = data.config.lock().unwrap(); + if let Some(frame) = &state.latest { + if system::trigger_sync(frame, &config).is_ok() { + HttpResponse::Ok().json(serde_json::json!({ "status": "success", "message": "Sync command issued." })) + } else { + HttpResponse::InternalServerError().json(serde_json::json!({ "status": "error", "message": "Sync command failed." })) + } + } else { + HttpResponse::BadRequest().json(serde_json::json!({ "status": "error", "message": "No LTC timecode available to sync to." })) + } +} + +#[get("/api/config")] +async fn get_config(data: web::Data) -> impl Responder { + let config = data.config.lock().unwrap(); + HttpResponse::Ok().json(&*config) +} + +#[get("/api/logs")] +async fn get_logs(data: web::Data) -> impl Responder { + let logs = data.log_buffer.lock().unwrap(); + HttpResponse::Ok().json(&*logs) +} + +#[derive(Deserialize)] +struct NudgeRequest { + microseconds: i64, +} + +#[post("/api/nudge_clock")] +async fn nudge_clock(req: web::Json) -> impl Responder { + if system::nudge_clock(req.microseconds).is_ok() { + HttpResponse::Ok().json(serde_json::json!({ "status": "success", "message": "Clock nudge command issued." })) + } else { + HttpResponse::InternalServerError().json(serde_json::json!({ "status": "error", "message": "Clock nudge command failed." })) + } +} + +#[derive(Deserialize)] +struct SetDateRequest { + date: String, +} + +#[post("/api/set_date")] +async fn set_date(req: web::Json) -> impl Responder { + if system::set_date(&req.date).is_ok() { + HttpResponse::Ok() + .json(serde_json::json!({ "status": "success", "message": "Date update command issued." })) + } else { + HttpResponse::InternalServerError() + .json(serde_json::json!({ "status": "error", "message": "Date update command failed." })) + } +} + +#[post("/api/config")] +async fn update_config( + data: web::Data, + req: web::Json, +) -> impl Responder { + let mut config = data.config.lock().unwrap(); + *config = req.into_inner(); + + if config::save_config("config.yml", &config).is_ok() { + log::info!("πŸ”„ Saved config via API: {:?}", *config); + + // If timeturner offset is active, trigger a sync immediately. + if config.timeturner_offset.is_active() { + let state = data.ltc_state.lock().unwrap(); + if let Some(frame) = &state.latest { + log::info!("Timeturner offset is active, triggering sync..."); + if system::trigger_sync(frame, &config).is_ok() { + log::info!("Sync triggered successfully after config change."); + } else { + log::error!("Sync failed after config change."); + } + } else { + log::warn!("Timeturner offset is active, but no LTC frame available to sync."); + } + } + + HttpResponse::Ok().json(&*config) + } else { + log::error!("Failed to write config.yml"); + HttpResponse::InternalServerError().json( + serde_json::json!({ "status": "error", "message": "Failed to write config.yml" }), + ) + } +} + +pub async fn start_api_server( + state: Arc>, + config: Arc>, + log_buffer: Arc>>, +) -> std::io::Result<()> { + let app_state = web::Data::new(AppState { + ltc_state: state, + config: config, + log_buffer: log_buffer, + }); + + log::info!("πŸš€ Starting API server at http://0.0.0.0:8080"); + + HttpServer::new(move || { + App::new() + .app_data(app_state.clone()) + .service(get_status) + .service(manual_sync) + .service(get_config) + .service(update_config) + .service(get_logs) + .service(nudge_clock) + .service(set_date) + // Serve frontend static files + .service(fs::Files::new("/", "static/").index_file("index.html")) + }) + .bind("0.0.0.0:8080")? + .run() + .await +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::config::TimeturnerOffset; + use crate::sync_logic::LtcFrame; + use actix_web::{test, App}; + use chrono::Utc; + use std::collections::VecDeque; + use std::fs; + + // Helper to create a default LtcState for tests + fn get_test_ltc_state() -> LtcState { + LtcState { + latest: Some(LtcFrame { + status: "LOCK".to_string(), + hours: 1, + minutes: 2, + seconds: 3, + frames: 4, + is_drop_frame: false, + frame_rate: Ratio::new(25, 1), + timestamp: Utc::now(), + }), + lock_count: 10, + free_count: 1, + offset_history: VecDeque::from(vec![1, 2, 3]), + ewma_clock_delta: Some(5.0), + last_match_status: "IN SYNC".to_string(), + last_match_check: Utc::now().timestamp(), + } + } + + // Helper to create a default AppState for tests + fn get_test_app_state() -> web::Data { + let ltc_state = Arc::new(Mutex::new(get_test_ltc_state())); + let config = Arc::new(Mutex::new(Config { + hardware_offset_ms: 10, + timeturner_offset: TimeturnerOffset::default(), + default_nudge_ms: 2, + auto_sync_enabled: false, + })); + let log_buffer = Arc::new(Mutex::new(VecDeque::new())); + web::Data::new(AppState { + ltc_state, + config, + log_buffer, + }) + } + + #[actix_web::test] + async fn test_get_status() { + let app_state = get_test_app_state(); + let app = test::init_service( + App::new() + .app_data(app_state.clone()) + .service(get_status), + ) + .await; + + let req = test::TestRequest::get().uri("/api/status").to_request(); + let resp: ApiStatus = test::call_and_read_body_json(&app, req).await; + + assert_eq!(resp.ltc_status, "LOCK"); + assert_eq!(resp.ltc_timecode, "01:02:03:04"); + assert_eq!(resp.frame_rate, "25.00fps"); + assert_eq!(resp.hardware_offset_ms, 10); + } + + #[actix_web::test] + async fn test_get_status_drop_frame() { + let app_state = get_test_app_state(); + // Set state to drop frame + app_state + .ltc_state + .lock() + .unwrap() + .latest + .as_mut() + .unwrap() + .is_drop_frame = true; + + let app = test::init_service( + App::new() + .app_data(app_state.clone()) + .service(get_status), + ) + .await; + + let req = test::TestRequest::get().uri("/api/status").to_request(); + let resp: ApiStatus = test::call_and_read_body_json(&app, req).await; + + assert_eq!(resp.ltc_timecode, "01:02:03;04"); + } + + #[actix_web::test] + async fn test_get_config() { + let app_state = get_test_app_state(); + app_state.config.lock().unwrap().hardware_offset_ms = 25; + + let app = test::init_service( + App::new() + .app_data(app_state.clone()) + .service(get_config), + ) + .await; + + let req = test::TestRequest::get().uri("/api/config").to_request(); + let resp: Config = test::call_and_read_body_json(&app, req).await; + + assert_eq!(resp.hardware_offset_ms, 25); + } + + #[actix_web::test] + async fn test_update_config() { + let app_state = get_test_app_state(); + let config_path = "config.yml"; + + // This test has the side effect of writing to `config.yml`. + // We ensure it's cleaned up after. + let _ = fs::remove_file(config_path); + + let app = test::init_service( + App::new() + .app_data(app_state.clone()) + .service(update_config), + ) + .await; + + let new_config_json = serde_json::json!({ + "hardwareOffsetMs": 55, + "defaultNudgeMs": 2, + "autoSyncEnabled": true, + "timeturnerOffset": { "hours": 1, "minutes": 2, "seconds": 3, "frames": 4, "milliseconds": 5 } + }); + + let req = test::TestRequest::post() + .uri("/api/config") + .set_json(&new_config_json) + .to_request(); + + let resp: Config = test::call_and_read_body_json(&app, req).await; + + assert_eq!(resp.hardware_offset_ms, 55); + assert_eq!(resp.auto_sync_enabled, true); + assert_eq!(resp.timeturner_offset.hours, 1); + assert_eq!(resp.timeturner_offset.milliseconds, 5); + let final_config = app_state.config.lock().unwrap(); + assert_eq!(final_config.hardware_offset_ms, 55); + assert_eq!(final_config.auto_sync_enabled, true); + assert_eq!(final_config.timeturner_offset.hours, 1); + assert_eq!(final_config.timeturner_offset.milliseconds, 5); + + // Test that the file was written + assert!(fs::metadata(config_path).is_ok()); + let contents = fs::read_to_string(config_path).unwrap(); + assert!(contents.contains("hardwareOffsetMs: 55")); + assert!(contents.contains("autoSyncEnabled: true")); + assert!(contents.contains("hours: 1")); + assert!(contents.contains("milliseconds: 5")); + + // Cleanup + let _ = fs::remove_file(config_path); + } + + #[actix_web::test] + async fn test_manual_sync_no_ltc() { + let app_state = get_test_app_state(); + // State with no LTC frame + app_state.ltc_state.lock().unwrap().latest = None; + + let app = test::init_service( + App::new() + .app_data(app_state.clone()) + .service(manual_sync), + ) + .await; + + let req = test::TestRequest::post().uri("/api/sync").to_request(); + let resp = test::call_service(&app, req).await; + + assert_eq!(resp.status(), 400); // Bad Request + } +} diff --git a/src/config.rs b/src/config.rs index a9bf931..8669e62 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,69 +1,138 @@ -ο»Ώ// src/config.rs - -use notify::{ - recommended_watcher, Event, EventKind, RecommendedWatcher, RecursiveMode, Result as NotifyResult, - Watcher, -}; -use serde::Deserialize; -use std::{ - fs::File, - io::Read, - path::PathBuf, - sync::{Arc, Mutex}, -}; - -#[derive(Deserialize)] -pub struct Config { - pub hardware_offset_ms: i64, -} - -impl Config { - pub fn load(path: &PathBuf) -> Self { - let mut file = match File::open(path) { - Ok(f) => f, - Err(_) => return Self { hardware_offset_ms: 0 }, - }; - let mut contents = String::new(); - if file.read_to_string(&mut contents).is_err() { - return Self { hardware_offset_ms: 0 }; - } - serde_json::from_str(&contents).unwrap_or(Self { hardware_offset_ms: 0 }) - } -} - -pub fn watch_config(path: &str) -> Arc> { - let initial = Config::load(&PathBuf::from(path)).hardware_offset_ms; - let offset = Arc::new(Mutex::new(initial)); - - // Owned PathBuf for watch() call - let watch_path = PathBuf::from(path); - // Clone for moving into the closure - let watch_path_for_cb = watch_path.clone(); - let offset_for_cb = Arc::clone(&offset); - - std::thread::spawn(move || { - // Move `watch_path_for_cb` into the callback - let mut watcher: RecommendedWatcher = recommended_watcher(move |res: NotifyResult| { - if let Ok(evt) = res { - if matches!(evt.kind, EventKind::Modify(_)) { - let new_cfg = Config::load(&watch_path_for_cb); - let mut hw = offset_for_cb.lock().unwrap(); - *hw = new_cfg.hardware_offset_ms; - eprintln!("πŸ”„ Reloaded hardware_offset_ms = {}", *hw); - } - } - }) - .expect("Failed to create file watcher"); - - // Use the original `watch_path` here - watcher - .watch(&watch_path, RecursiveMode::NonRecursive) - .expect("Failed to watch config.json"); - - loop { - std::thread::sleep(std::time::Duration::from_secs(60)); - } - }); - - offset -} +ο»Ώ// src/config.rs +use notify::{ + recommended_watcher, Event, EventKind, RecommendedWatcher, RecursiveMode, Result as NotifyResult, + Watcher, +}; +use serde::{Deserialize, Serialize}; +use std::{ + fs, + fs::File, + io::Read, + path::PathBuf, + sync::{Arc, Mutex}, +}; + +#[derive(Deserialize, Serialize, Clone, Debug, Default)] +#[serde(rename_all = "camelCase")] +pub struct TimeturnerOffset { + pub hours: i64, + pub minutes: i64, + pub seconds: i64, + pub frames: i64, + #[serde(default)] + pub milliseconds: i64, +} + +impl TimeturnerOffset { + pub fn is_active(&self) -> bool { + self.hours != 0 + || self.minutes != 0 + || self.seconds != 0 + || self.frames != 0 + || self.milliseconds != 0 + } +} + +#[derive(Deserialize, Serialize, Clone, Debug)] +#[serde(rename_all = "camelCase")] +pub struct Config { + pub hardware_offset_ms: i64, + #[serde(default)] + pub timeturner_offset: TimeturnerOffset, + #[serde(default = "default_nudge_ms")] + pub default_nudge_ms: i64, + #[serde(default)] + pub auto_sync_enabled: bool, +} + +fn default_nudge_ms() -> i64 { + 2 // Default nudge is 2ms +} + +impl Config { + pub fn load(path: &PathBuf) -> Self { + let mut file = match File::open(path) { + Ok(f) => f, + Err(_) => return Self::default(), + }; + let mut contents = String::new(); + if file.read_to_string(&mut contents).is_err() { + return Self::default(); + } + serde_yaml::from_str(&contents).unwrap_or_else(|e| { + log::warn!("Failed to parse config, using default: {}", e); + Self::default() + }) + } + +} + +impl Default for Config { + fn default() -> Self { + Self { + hardware_offset_ms: 0, + timeturner_offset: TimeturnerOffset::default(), + default_nudge_ms: default_nudge_ms(), + auto_sync_enabled: false, + } + } +} + +pub fn save_config(path: &str, config: &Config) -> Result<(), Box> { + let mut s = String::new(); + s.push_str("# Hardware offset in milliseconds for correcting capture latency.\n"); + s.push_str(&format!("hardwareOffsetMs: {}\n\n", config.hardware_offset_ms)); + + s.push_str("# Enable automatic clock synchronization.\n"); + s.push_str("# When enabled, the system will perform an initial full sync, then periodically\n"); + s.push_str("# nudge the clock to keep it aligned with the LTC source.\n"); + s.push_str(&format!("autoSyncEnabled: {}\n\n", config.auto_sync_enabled)); + + s.push_str("# Default nudge in milliseconds for adjtimex control.\n"); + s.push_str(&format!("defaultNudgeMs: {}\n\n", config.default_nudge_ms)); + + s.push_str("# Time-turning offsets. All values are added to the incoming LTC time.\n"); + s.push_str("# These can be positive or negative.\n"); + s.push_str("timeturnerOffset:\n"); + s.push_str(&format!(" hours: {}\n", config.timeturner_offset.hours)); + s.push_str(&format!(" minutes: {}\n", config.timeturner_offset.minutes)); + s.push_str(&format!(" seconds: {}\n", config.timeturner_offset.seconds)); + s.push_str(&format!(" frames: {}\n", config.timeturner_offset.frames)); + s.push_str(&format!(" milliseconds: {}\n", config.timeturner_offset.milliseconds)); + + fs::write(path, s)?; + Ok(()) +} + +pub fn watch_config(path: &str) -> Arc> { + let initial_config = Config::load(&PathBuf::from(path)); + let config = Arc::new(Mutex::new(initial_config)); + + let watch_path = PathBuf::from(path); + let watch_path_for_cb = watch_path.clone(); + let config_for_cb = Arc::clone(&config); + + std::thread::spawn(move || { + let mut watcher: RecommendedWatcher = recommended_watcher(move |res: NotifyResult| { + if let Ok(evt) = res { + if matches!(evt.kind, EventKind::Modify(_)) { + let new_cfg = Config::load(&watch_path_for_cb); + let mut cfg = config_for_cb.lock().unwrap(); + *cfg = new_cfg; + log::info!("πŸ”„ Reloaded config.yml: {:?}", *cfg); + } + } + }) + .expect("Failed to create file watcher"); + + watcher + .watch(&watch_path, RecursiveMode::NonRecursive) + .expect("Failed to watch config.yml"); + + loop { + std::thread::sleep(std::time::Duration::from_secs(60)); + } + }); + + config +} diff --git a/src/logger.rs b/src/logger.rs new file mode 100644 index 0000000..33c410e --- /dev/null +++ b/src/logger.rs @@ -0,0 +1,52 @@ +use chrono::Local; +use log::{LevelFilter, Log, Metadata, Record}; +use std::collections::VecDeque; +use std::sync::{Arc, Mutex}; + +const MAX_LOG_ENTRIES: usize = 100; + +struct RingBufferLogger { + buffer: Arc>>, +} + +impl Log for RingBufferLogger { + fn enabled(&self, metadata: &Metadata) -> bool { + metadata.level() <= LevelFilter::Info + } + + fn log(&self, record: &Record) { + if self.enabled(record.metadata()) { + let msg = format!( + "{} [{}] {}", + Local::now().format("%Y-%m-%d %H:%M:%S"), + record.level(), + record.args() + ); + + // Also print to stderr for console/daemon logging + eprintln!("{}", msg); + + let mut buffer = self.buffer.lock().unwrap(); + if buffer.len() == MAX_LOG_ENTRIES { + buffer.pop_front(); + } + buffer.push_back(msg); + } + } + + fn flush(&self) {} +} + +pub fn setup_logger() -> Arc>> { + let buffer = Arc::new(Mutex::new(VecDeque::with_capacity(MAX_LOG_ENTRIES))); + let logger = RingBufferLogger { + buffer: buffer.clone(), + }; + + // We use `set_boxed_logger` to install our custom logger. + // The `log` crate will then route all log messages to it. + log::set_boxed_logger(Box::new(logger)).expect("Failed to set logger"); + log::set_max_level(LevelFilter::Info); + + buffer +} diff --git a/src/main.rs b/src/main.rs index 2464a0e..8006681 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,81 +1,402 @@ -ο»Ώ// src/main.rs - -mod config; -mod sync_logic; -mod serial_input; -mod ui; - -use crate::config::watch_config; -use crate::sync_logic::LtcState; -use crate::serial_input::start_serial_thread; -use crate::ui::start_ui; - -use std::{ - fs, - path::Path, - sync::{Arc, Mutex, mpsc}, - thread, -}; - -/// Embed the default config.json at compile time. -const DEFAULT_CONFIG: &str = include_str!("../config.json"); - -/// If no `config.json` exists alongside the binary, write out the default. -fn ensure_config() { - let p = Path::new("config.json"); - if !p.exists() { - fs::write(p, DEFAULT_CONFIG) - .expect("Failed to write default config.json"); - eprintln!("βš™οΈ Emitted default config.json"); - } -} - -fn main() { - // πŸ”„ Ensure there's always a config.json present - ensure_config(); - - // 1️⃣ Start watching config.json for changes - let hw_offset = watch_config("config.json"); - println!("πŸ”§ Watching config.json (hardware_offset_ms)..."); - - // 2️⃣ Channel for raw LTC frames - let (tx, rx) = mpsc::channel(); - println!("βœ… Channel created"); - - // 3️⃣ Shared state for UI and serial reader - let ltc_state = Arc::new(Mutex::new(LtcState::new())); - println!("βœ… State initialised"); - - // 4️⃣ Spawn the serial reader thread (no offset here) - { - let tx_clone = tx.clone(); - let state_clone = ltc_state.clone(); - thread::spawn(move || { - println!("πŸš€ Serial thread launched"); - start_serial_thread( - "/dev/ttyACM0", - 115200, - tx_clone, - state_clone, - 0, // ignored in serial path - ); - }); - } - - // 5️⃣ Spawn the UI renderer thread, passing the live offset Arc - { - let ui_state = ltc_state.clone(); - let offset_clone = hw_offset.clone(); - let port = "/dev/ttyACM0".to_string(); - thread::spawn(move || { - println!("πŸ–₯️ UI thread launched"); - start_ui(ui_state, port, offset_clone); - }); - } - - // 6️⃣ Keep main thread alive - println!("πŸ“‘ Main thread entering loop..."); - for _frame in rx { - // no-op - } -} +ο»Ώ// src/main.rs + +mod api; +mod config; +mod logger; +mod serial_input; +mod sync_logic; +mod system; +mod ui; + +use crate::api::start_api_server; +use crate::config::watch_config; +use crate::serial_input::start_serial_thread; +use crate::sync_logic::LtcState; +use crate::ui::start_ui; +use clap::Parser; +use daemonize::Daemonize; +use serialport; + +use std::{ + fs, + path::Path, + sync::{mpsc, Arc, Mutex}, + thread, +}; +use tokio::task::{self, LocalSet}; + +#[derive(Parser, Debug)] +#[command(author, version, about, long_about = None)] +struct Args { + #[command(subcommand)] + command: Option, +} + +#[derive(clap::Subcommand, Debug)] +enum Command { + /// Run as a background daemon providing a web UI. + Daemon, + /// Stop the running daemon process. + Kill, +} + +/// Default config content, embedded in the binary. +const DEFAULT_CONFIG: &str = r#" +# Hardware offset in milliseconds for correcting capture latency. +hardwareOffsetMs: 20 + +# Enable automatic clock synchronization. +# When enabled, the system will perform an initial full sync, then periodically +# nudge the clock to keep it aligned with the LTC source. +autoSyncEnabled: false + +# Default nudge in milliseconds for adjtimex control. +defaultNudgeMs: 2 + +# Time-turning offsets. All values are added to the incoming LTC time. +# These can be positive or negative. +timeturnerOffset: + hours: 0 + minutes: 0 + seconds: 0 + frames: 0 + milliseconds: 0 +"#; + +/// If no `config.yml` exists alongside the binary, write out the default. +fn ensure_config() { + let p = Path::new("config.yml"); + if !p.exists() { + fs::write(p, DEFAULT_CONFIG.trim()) + .expect("Failed to write default config.yml"); + log::info!("βš™οΈ Emitted default config.yml"); + } +} + +fn find_serial_port() -> Option { + if let Ok(ports) = serialport::available_ports() { + for p in ports { + if p.port_name.starts_with("/dev/ttyACM") + || p.port_name.starts_with("/dev/ttyAMA") + || p.port_name.starts_with("/dev/ttyUSB") + { + return Some(p.port_name); + } + } + } + None +} + +#[tokio::main(flavor = "current_thread")] +async fn main() { + // This must be called before any logging statements. + let log_buffer = logger::setup_logger(); + let args = Args::parse(); + + if let Some(command) = &args.command { + match command { + Command::Daemon => { + log::info!("πŸš€ Starting daemon..."); + + // Create files for stdout and stderr in the current directory + let stdout = + fs::File::create("daemon.out").expect("Could not create daemon.out"); + let stderr = + fs::File::create("daemon.err").expect("Could not create daemon.err"); + + let daemonize = Daemonize::new() + .pid_file("ntp_timeturner.pid") // Create a PID file + .working_directory(".") // Keep the same working directory + .stdout(stdout) + .stderr(stderr); + + match daemonize.start() { + Ok(_) => { /* Process is now daemonized */ } + Err(e) => { + log::error!("Error daemonizing: {}", e); + return; // Exit if daemonization fails + } + } + } + Command::Kill => { + log::info!("πŸ›‘ Stopping daemon..."); + let pid_file = "ntp_timeturner.pid"; + match fs::read_to_string(pid_file) { + Ok(pid_str) => { + let pid_str = pid_str.trim(); + log::info!("Found daemon with PID: {}", pid_str); + match std::process::Command::new("kill").arg("-9").arg(format!("-{}", pid_str)).status() { + Ok(status) => { + if status.success() { + log::info!("βœ… Daemon stopped successfully."); + if fs::remove_file(pid_file).is_err() { + log::warn!("Could not remove PID file '{}'. It may need to be removed manually.", pid_file); + } + } else { + log::error!("'kill' command failed with status: {}. The daemon may not be running, or you may not have permission to stop it.", status); + log::warn!("Attempting to remove stale PID file '{}'...", pid_file); + if fs::remove_file(pid_file).is_ok() { + log::info!("Removed stale PID file."); + } else { + log::warn!("Could not remove PID file."); + } + } + } + Err(e) => { + log::error!("Failed to execute 'kill' command. Is 'kill' in your PATH? Error: {}", e); + } + } + } + Err(_) => { + log::error!("Could not read PID file '{}'. Is the daemon running in this directory?", pid_file); + } + } + return; + } + } + } + + // πŸ”„ Ensure there's always a config.yml present + ensure_config(); + + // 1️⃣ Start watching config.yml for changes + let config = watch_config("config.yml"); + + // 2️⃣ Channel for raw LTC frames + let (tx, rx) = mpsc::channel(); + + // 3️⃣ Shared state for UI and serial reader + let ltc_state = Arc::new(Mutex::new(LtcState::new())); + + // 4️⃣ Find serial port and spawn the serial reader thread + let serial_port_path = match find_serial_port() { + Some(port) => port, + None => { + log::error!("❌ No serial port found. Please connect the Teensy device."); + return; + } + }; + log::info!("Found serial port: {}", serial_port_path); + + { + let tx_clone = tx.clone(); + let state_clone = ltc_state.clone(); + let port_clone = serial_port_path.clone(); + thread::spawn(move || { + start_serial_thread( + &port_clone, + 115200, + tx_clone, + state_clone, + 0, // ignored in serial path + ); + }); + } + + // 5️⃣ Spawn UI or setup daemon logging. The web service is only started + // when running as a daemon. The TUI is for interactive foreground use. + if args.command.is_none() { + // --- Interactive TUI Mode --- + log::info!("πŸ”§ Watching config.yml..."); + log::info!("πŸš€ Serial thread launched"); + log::info!("πŸ–₯️ UI thread launched"); + let ui_state = ltc_state.clone(); + let config_clone = config.clone(); + let port = serial_port_path; + thread::spawn(move || { + start_ui(ui_state, port, config_clone); + }); + } else { + // --- Daemon Mode --- + // In daemon mode, logging is already set up to go to stderr. + // The systemd service will capture it. The web service (API and static files) + // is launched later in the main async block. + log::info!("πŸš€ Starting TimeTurner daemon..."); + } + + // 6️⃣ Spawn the auto-sync thread + { + let sync_state = ltc_state.clone(); + let sync_config = config.clone(); + thread::spawn(move || { + // Wait for the first LTC frame to arrive + loop { + if sync_state.lock().unwrap().latest.is_some() { + log::info!("Auto-sync: Initial LTC frame detected."); + break; + } + thread::sleep(std::time::Duration::from_secs(1)); + } + + // Initial sync + { + let state = sync_state.lock().unwrap(); + let config = sync_config.lock().unwrap(); + if config.auto_sync_enabled { + if let Some(frame) = &state.latest { + log::info!("Auto-sync: Performing initial full sync."); + if system::trigger_sync(frame, &config).is_ok() { + log::info!("Auto-sync: Initial sync successful."); + } else { + log::error!("Auto-sync: Initial sync failed."); + } + } + } + } + + thread::sleep(std::time::Duration::from_secs(10)); + + // Main auto-sync loop + loop { + { + let state = sync_state.lock().unwrap(); + let config = sync_config.lock().unwrap(); + + if config.auto_sync_enabled && state.latest.is_some() { + let delta = state.get_ewma_clock_delta(); + let frame = state.latest.as_ref().unwrap(); + + if delta.abs() > 40 { + log::info!("Auto-sync: Delta > 40ms ({}ms), performing full sync.", delta); + if system::trigger_sync(frame, &config).is_ok() { + log::info!("Auto-sync: Full sync successful."); + } else { + log::error!("Auto-sync: Full sync failed."); + } + } else if delta.abs() >= 1 { + // nudge_clock takes microseconds. A positive delta means clock is + // ahead, so we need a negative nudge. + let nudge_us = -delta * 1000; + log::info!("Auto-sync: Delta is {}ms, nudging clock by {}us.", delta, nudge_us); + if system::nudge_clock(nudge_us).is_ok() { + log::info!("Auto-sync: Clock nudge successful."); + } else { + log::error!("Auto-sync: Clock nudge failed."); + } + } + } + } // locks released here + + thread::sleep(std::time::Duration::from_secs(10)); + } + }); + } + + // 7️⃣ Set up a LocalSet for the API server and main loop + let local = LocalSet::new(); + local + .run_until(async move { + // 8️⃣ Spawn the API server task. + // This server provides the JSON API and serves the static web UI files + // from the `static/` directory. It runs in both TUI and daemon modes, + // but is primarily for the web UI used in daemon mode. + { + let api_state = ltc_state.clone(); + let config_clone = config.clone(); + let log_buffer_clone = log_buffer.clone(); + task::spawn_local(async move { + if let Err(e) = + start_api_server(api_state, config_clone, log_buffer_clone).await + { + log::error!("API server error: {}", e); + } + }); + } + + // 9️⃣ Main logic loop: process frames from serial and update state + let loop_state = ltc_state.clone(); + let loop_config = config.clone(); + let logic_task = task::spawn_blocking(move || { + for frame in rx { + let mut state = loop_state.lock().unwrap(); + let config = loop_config.lock().unwrap(); + + // Only calculate delta for LOCK frames + if frame.status == "LOCK" { + let target_time = system::calculate_target_time(&frame, &config); + let arrival_time_local: chrono::DateTime = + frame.timestamp.with_timezone(&chrono::Local); + let delta = arrival_time_local.signed_duration_since(target_time); + state.record_and_update_ewma_clock_delta(delta.num_milliseconds()); + } + + state.update(frame); + } + }); + + // 1️⃣0️⃣ Keep main thread alive + if args.command.is_some() { + // In daemon mode, wait forever. The logic_task runs in the background. + std::future::pending::<()>().await; + } else { + // In TUI mode, block until the logic_task finishes (e.g. serial port disconnects) + // This keeps the TUI running. + log::info!("πŸ“‘ Main thread entering loop..."); + let _ = logic_task.await; + } + }) + .await; +} + +#[cfg(test)] +mod tests { + use super::*; + use std::fs; + use std::path::Path; + + /// RAII guard to manage config file during tests. + /// It saves the original content of `config.yml` if it exists, + /// and restores it when the guard goes out of scope. + /// If the file didn't exist, it's removed. + struct ConfigGuard { + original_content: Option, + } + + impl ConfigGuard { + fn new() -> Self { + Self { + original_content: fs::read_to_string("config.yml").ok(), + } + } + } + + impl Drop for ConfigGuard { + fn drop(&mut self) { + if let Some(content) = &self.original_content { + fs::write("config.yml", content).expect("Failed to restore config.yml"); + } else { + let _ = fs::remove_file("config.yml"); + } + } + } + + #[test] + fn test_ensure_config() { + let _guard = ConfigGuard::new(); // Cleanup when _guard goes out of scope. + + // --- Test 1: File creation --- + // Pre-condition: config.yml does not exist. + let _ = fs::remove_file("config.yml"); + + ensure_config(); + + // Post-condition: config.yml exists and has default content. + let p = Path::new("config.yml"); + assert!(p.exists(), "config.yml should have been created"); + let contents = fs::read_to_string(p).expect("Failed to read created config.yml"); + assert_eq!(contents, DEFAULT_CONFIG.trim(), "config.yml content should match default"); + + // --- Test 2: File is not overwritten --- + // Pre-condition: config.yml exists with different content. + let custom_content = "hardwareOffsetMs: 999"; + fs::write("config.yml", custom_content) + .expect("Failed to write custom config.yml for test"); + + ensure_config(); + + // Post-condition: config.yml still has the custom content. + let contents_after = fs::read_to_string("config.yml") + .expect("Failed to read config.yml after second ensure_config call"); + assert_eq!(contents_after, custom_content, "config.yml should not be overwritten"); + } +} diff --git a/src/serial_input.rs b/src/serial_input.rs index 39e2be7..d1dea36 100644 --- a/src/serial_input.rs +++ b/src/serial_input.rs @@ -1,56 +1,178 @@ -ο»Ώ// src/serial_input.rs - -use std::io::BufRead; -use std::sync::{Arc, Mutex}; -use std::sync::mpsc::Sender; -use chrono::Utc; -use regex::Regex; -use crate::sync_logic::{LtcFrame, LtcState}; - -pub fn start_serial_thread( - port_path: &str, - baud_rate: u32, - sender: Sender, - state: Arc>, - _hardware_offset_ms: i64, // no longer used here -) { - println!("πŸ“‘ Opening serial port {} @ {} baud", port_path, baud_rate); - - let port = match serialport::new(port_path, baud_rate) - .timeout(std::time::Duration::from_millis(1000)) - .open() - { - Ok(p) => { - println!("βœ… Serial port opened"); - p - } - Err(e) => { - eprintln!("❌ Serial open failed: {}", e); - return; - } - }; - - let reader = std::io::BufReader::new(port); - let re = Regex::new( - r"\[(LOCK|FREE)\]\s+(\d{2}):(\d{2}):(\d{2})[:;](\d{2})\s+\|\s+([\d.]+)fps", - ) - .unwrap(); - - println!("πŸ”„ Entering LTC read loop…"); - for line in reader.lines() { - if let Ok(text) = line { - if let Some(caps) = re.captures(&text) { - let arrival = Utc::now(); - if let Some(frame) = LtcFrame::from_regex(&caps, arrival) { - // update LOCK/FREE counts & timestamp - { - let mut st = state.lock().unwrap(); - st.update(frame.clone()); - } - // forward raw frame - let _ = sender.send(frame); - } - } - } - } -} +ο»Ώ// src/serial_input.rs + +use std::io::BufRead; +use std::sync::{Arc, Mutex}; +use std::sync::mpsc::Sender; +use chrono::Utc; +use regex::Regex; +use crate::sync_logic::{LtcFrame, LtcState}; + +pub fn start_serial_thread( + port_path: &str, + baud_rate: u32, + sender: Sender, + state: Arc>, + _hardware_offset_ms: i64, // no longer used here +) { + println!("πŸ“‘ Opening serial port {} @ {} baud", port_path, baud_rate); + + let port = match serialport::new(port_path, baud_rate) + .timeout(std::time::Duration::from_millis(1000)) + .open() + { + Ok(p) => { + println!("βœ… Serial port opened"); + p + } + Err(e) => { + eprintln!("❌ Serial open failed: {}", e); + return; + } + }; + + let reader = std::io::BufReader::new(port); + let re = Regex::new( + r"\[(LOCK|FREE)\]\s+(\d{2}):(\d{2}):(\d{2})([:;])(\d{2})\s+\|\s+([\d.]+)fps", + ) + .unwrap(); + + println!("πŸ”„ Entering LTC read loop…"); + for line in reader.lines() { + if let Ok(text) = line { + if let Some(caps) = re.captures(&text) { + let arrival = Utc::now(); + if let Some(frame) = LtcFrame::from_regex(&caps, arrival) { + // update LOCK/FREE counts & timestamp + { + let mut st = state.lock().unwrap(); + st.update(frame.clone()); + } + // forward raw frame + let _ = sender.send(frame); + } + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::sync::mpsc; + use crate::sync_logic::LtcState; + use num_rational::Ratio; + use regex::Regex; + + fn get_ltc_regex() -> Regex { + Regex::new( + r"\[(LOCK|FREE)\]\s+(\d{2}):(\d{2}):(\d{2})([:;])(\d{2})\s+\|\s+([\d.]+)fps", + ).unwrap() + } + + #[test] + fn test_process_lock_line() { + let (tx, rx) = mpsc::channel(); + let state = Arc::new(Mutex::new(LtcState::new())); + let re = get_ltc_regex(); + let line = "[LOCK] 10:20:30:00 | 25.00fps"; + + // Simulate the processing logic from start_serial_thread + if let Some(caps) = re.captures(line) { + let arrival = Utc::now(); + if let Some(frame) = LtcFrame::from_regex(&caps, arrival) { + { + let mut st = state.lock().unwrap(); + st.update(frame.clone()); + } + let _ = tx.send(frame); + } + } + + let st = state.lock().unwrap(); + assert_eq!(st.lock_count, 1); + assert_eq!(st.free_count, 0); + let received_frame = rx.try_recv().unwrap(); + assert_eq!(received_frame.status, "LOCK"); + assert_eq!(received_frame.hours, 10); + } + + #[test] + fn test_process_free_line() { + let (tx, rx) = mpsc::channel(); + let state = Arc::new(Mutex::new(LtcState::new())); + let re = get_ltc_regex(); + let line = "[FREE] 01:02:03:04 | 29.97fps"; + + // Simulate the processing logic + if let Some(caps) = re.captures(line) { + let arrival = Utc::now(); + if let Some(frame) = LtcFrame::from_regex(&caps, arrival) { + { + let mut st = state.lock().unwrap(); + st.update(frame.clone()); + } + let _ = tx.send(frame); + } + } + + let st = state.lock().unwrap(); + assert_eq!(st.lock_count, 0); + assert_eq!(st.free_count, 1); + let received_frame = rx.try_recv().unwrap(); + assert_eq!(received_frame.status, "FREE"); + assert_eq!(received_frame.frame_rate, Ratio::new(30000, 1001)); + } + + #[test] + fn test_ignore_non_matching_line() { + let (tx, rx) = mpsc::channel(); + let state = Arc::new(Mutex::new(LtcState::new())); + let re = get_ltc_regex(); + let line = "this is not a valid ltc line"; + + // Simulate the processing logic + if let Some(caps) = re.captures(line) { + let arrival = Utc::now(); + if let Some(frame) = LtcFrame::from_regex(&caps, arrival) { + { + let mut st = state.lock().unwrap(); + st.update(frame.clone()); + } + let _ = tx.send(frame); + } + } + + let st = state.lock().unwrap(); + assert_eq!(st.lock_count, 0); + assert_eq!(st.free_count, 0); + assert!(rx.try_recv().is_err()); + } + + #[test] + fn test_ignore_line_with_bad_parseable_data() { + let (tx, rx) = mpsc::channel(); + let state = Arc::new(Mutex::new(LtcState::new())); + let re = get_ltc_regex(); + // The regex will match, but `from_regex` should fail to parse "1.2.3.4" as f64 + let line = "[LOCK] 10:20:30:00 | 1.2.3.4fps"; + + // Simulate the processing logic + if let Some(caps) = re.captures(line) { + let arrival = Utc::now(); + if let Some(frame) = LtcFrame::from_regex(&caps, arrival) { + { + let mut st = state.lock().unwrap(); + st.update(frame.clone()); + } + let _ = tx.send(frame); + } + } else { + panic!("Regex should have matched"); + } + + let st = state.lock().unwrap(); + assert_eq!(st.lock_count, 0); + assert_eq!(st.free_count, 0); + assert!(rx.try_recv().is_err()); + } +} diff --git a/src/sync_logic.rs b/src/sync_logic.rs index 0afa002..c6a3e80 100644 --- a/src/sync_logic.rs +++ b/src/sync_logic.rs @@ -1,7 +1,22 @@ -ο»Ώuse chrono::{DateTime, Local, Timelike, Utc}; +ο»Ώuse crate::config::Config; +use chrono::{DateTime, Local, Timelike, Utc}; +use num_rational::Ratio; use regex::Captures; use std::collections::VecDeque; +const EWMA_ALPHA: f64 = 0.1; + +fn get_frame_rate_ratio(rate_str: &str) -> Option> { + match rate_str { + "23.98" => Some(Ratio::new(24000, 1001)), + "24.00" => Some(Ratio::new(24, 1)), + "25.00" => Some(Ratio::new(25, 1)), + "29.97" => Some(Ratio::new(30000, 1001)), + "30.00" => Some(Ratio::new(30, 1)), + _ => None, + } +} + #[derive(Clone, Debug)] pub struct LtcFrame { pub status: String, @@ -9,7 +24,8 @@ pub struct LtcFrame { pub minutes: u32, pub seconds: u32, pub frames: u32, - pub frame_rate: f64, + pub is_drop_frame: bool, + pub frame_rate: Ratio, pub timestamp: DateTime, // arrival stamp } @@ -20,8 +36,9 @@ impl LtcFrame { hours: caps[2].parse().ok()?, minutes: caps[3].parse().ok()?, seconds: caps[4].parse().ok()?, - frames: caps[5].parse().ok()?, - frame_rate: caps[6].parse().ok()?, + is_drop_frame: &caps[5] == ";", + frames: caps[6].parse().ok()?, + frame_rate: get_frame_rate_ratio(&caps[7])?, timestamp, }) } @@ -41,8 +58,8 @@ pub struct LtcState { pub free_count: u32, /// Stores the last up-to-20 raw offset measurements in ms. pub offset_history: VecDeque, - /// Stores the last up-to-20 timecode Ξ” measurements in ms. - pub clock_delta_history: VecDeque, + /// EWMA of clock delta. + pub ewma_clock_delta: Option, pub last_match_status: String, pub last_match_check: i64, } @@ -54,7 +71,7 @@ impl LtcState { lock_count: 0, free_count: 0, offset_history: VecDeque::with_capacity(20), - clock_delta_history: VecDeque::with_capacity(20), + ewma_clock_delta: None, last_match_status: "UNKNOWN".into(), last_match_check: 0, } @@ -68,12 +85,14 @@ impl LtcState { self.offset_history.push_back(offset_ms); } - /// Record one timecode Ξ” in ms. - pub fn record_clock_delta(&mut self, delta_ms: i64) { - if self.clock_delta_history.len() == 20 { - self.clock_delta_history.pop_front(); + /// Update EWMA of clock delta. + pub fn record_and_update_ewma_clock_delta(&mut self, delta_ms: i64) { + let new_delta = delta_ms as f64; + if let Some(current_ewma) = self.ewma_clock_delta { + self.ewma_clock_delta = Some(EWMA_ALPHA * new_delta + (1.0 - EWMA_ALPHA) * current_ewma); + } else { + self.ewma_clock_delta = Some(new_delta); } - self.clock_delta_history.push_back(delta_ms); } /// Clear all stored jitter measurements. @@ -81,11 +100,6 @@ impl LtcState { self.offset_history.clear(); } - /// Clear all stored timecode Ξ” measurements. - pub fn clear_clock_deltas(&mut self) { - self.clock_delta_history.clear(); - } - /// Update LOCK/FREE counts and timecode-match status every 5 s. pub fn update(&mut self, frame: LtcFrame) { match frame.status.as_str() { @@ -107,7 +121,7 @@ impl LtcState { "FREE" => { self.free_count += 1; self.clear_offsets(); - self.clear_clock_deltas(); + self.ewma_clock_delta = None; self.last_match_status = "UNKNOWN".into(); } _ => {} @@ -129,21 +143,17 @@ impl LtcState { /// Convert average jitter into frames (rounded). pub fn average_frames(&self) -> i64 { if let Some(frame) = &self.latest { - let ms_per_frame = 1000.0 / frame.frame_rate; - (self.average_jitter() as f64 / ms_per_frame).round() as i64 + let jitter_ms_ratio = Ratio::new(self.average_jitter(), 1); + let frames_ratio = jitter_ms_ratio * frame.frame_rate / Ratio::new(1000, 1); + frames_ratio.round().to_integer() } else { 0 } } - /// Average timecode Ξ” over stored history, in ms. - pub fn average_clock_delta(&self) -> i64 { - if self.clock_delta_history.is_empty() { - 0 - } else { - let sum: i64 = self.clock_delta_history.iter().sum(); - sum / self.clock_delta_history.len() as i64 - } + /// Get EWMA of clock delta, in ms. + pub fn get_ewma_clock_delta(&self) -> i64 { + self.ewma_clock_delta.map_or(0, |v| v.round() as i64) } /// Percentage of samples seen in LOCK state versus total. @@ -161,10 +171,33 @@ impl LtcState { &self.last_match_status } } + +pub fn get_sync_status(delta_ms: i64, config: &Config) -> &'static str { + if config.timeturner_offset.is_active() { + "TIMETURNING" + } else if delta_ms.abs() <= 8 { + "IN SYNC" + } else if delta_ms > 10 { + "CLOCK AHEAD" + } else { + "CLOCK BEHIND" + } +} + +pub fn get_jitter_status(jitter_ms: i64) -> &'static str { + if jitter_ms.abs() < 10 { + "GOOD" + } else if jitter_ms.abs() < 40 { + "AVERAGE" + } else { + "BAD" + } +} // This module provides the logic for handling LTC (Linear Timecode) frames and maintaining state. #[cfg(test)] mod tests { use super::*; + use crate::config::{Config, TimeturnerOffset}; use chrono::{Local, Utc}; fn get_test_frame(status: &str, h: u32, m: u32, s: u32) -> LtcFrame { @@ -174,7 +207,8 @@ mod tests { minutes: m, seconds: s, frames: 0, - frame_rate: 25.0, + is_drop_frame: false, + frame_rate: Ratio::new(25, 1), timestamp: Utc::now(), } } @@ -291,4 +325,63 @@ mod tests { "Status should update after throttle period" ); } + + #[test] + fn test_ewma_clock_delta() { + let mut state = LtcState::new(); + assert_eq!(state.get_ewma_clock_delta(), 0); + + // First value initializes the EWMA + state.record_and_update_ewma_clock_delta(100); + assert_eq!(state.get_ewma_clock_delta(), 100); + + // Second value moves it + state.record_and_update_ewma_clock_delta(200); + // 0.1 * 200 + 0.9 * 100 = 20 + 90 = 110 + assert_eq!(state.get_ewma_clock_delta(), 110); + + // Third value + state.record_and_update_ewma_clock_delta(100); + // 0.1 * 100 + 0.9 * 110 = 10 + 99 = 109 + assert_eq!(state.get_ewma_clock_delta(), 109); + + // Reset on FREE frame + state.update(get_test_frame("FREE", 0, 0, 0)); + assert_eq!(state.get_ewma_clock_delta(), 0); + assert!(state.ewma_clock_delta.is_none()); + } + + #[test] + fn test_get_sync_status() { + let mut config = Config::default(); + assert_eq!(get_sync_status(0, &config), "IN SYNC"); + assert_eq!(get_sync_status(8, &config), "IN SYNC"); + assert_eq!(get_sync_status(-8, &config), "IN SYNC"); + assert_eq!(get_sync_status(9, &config), "CLOCK BEHIND"); + assert_eq!(get_sync_status(10, &config), "CLOCK BEHIND"); + assert_eq!(get_sync_status(11, &config), "CLOCK AHEAD"); + assert_eq!(get_sync_status(-9, &config), "CLOCK BEHIND"); + assert_eq!(get_sync_status(-100, &config), "CLOCK BEHIND"); + + // Test auto-sync status + config.auto_sync_enabled = true; + assert_eq!(get_sync_status(0, &config), "IN SYNC"); + + // Test TIMETURNING status takes precedence + config.timeturner_offset = TimeturnerOffset { hours: 1, minutes: 0, seconds: 0, frames: 0, milliseconds: 0 }; + assert_eq!(get_sync_status(0, &config), "TIMETURNING"); + assert_eq!(get_sync_status(100, &config), "TIMETURNING"); + } + + #[test] + fn test_get_jitter_status() { + assert_eq!(get_jitter_status(5), "GOOD"); + assert_eq!(get_jitter_status(-5), "GOOD"); + assert_eq!(get_jitter_status(9), "GOOD"); + assert_eq!(get_jitter_status(10), "AVERAGE"); + assert_eq!(get_jitter_status(39), "AVERAGE"); + assert_eq!(get_jitter_status(-39), "AVERAGE"); + assert_eq!(get_jitter_status(40), "BAD"); + assert_eq!(get_jitter_status(-40), "BAD"); + } } diff --git a/src/system.rs b/src/system.rs new file mode 100644 index 0000000..8db481d --- /dev/null +++ b/src/system.rs @@ -0,0 +1,262 @@ +use crate::config::Config; +use crate::sync_logic::LtcFrame; +use chrono::{DateTime, Duration as ChronoDuration, Local, TimeZone}; +use num_rational::Ratio; +use std::process::Command; + +/// Check if Chrony is active +pub fn ntp_service_active() -> bool { + #[cfg(target_os = "linux")] + { + if let Ok(output) = Command::new("systemctl").args(&["is-active", "chrony"]).output() { + output.status.success() + && String::from_utf8_lossy(&output.stdout).trim() == "active" + } else { + false + } + } + #[cfg(not(target_os = "linux"))] + { + // systemctl is not available on non-Linux platforms. + false + } +} + +/// Toggle Chrony (not used yet) +#[allow(dead_code)] +pub fn ntp_service_toggle(start: bool) { + #[cfg(target_os = "linux")] + { + let action = if start { "start" } else { "stop" }; + let _ = Command::new("systemctl").args(&[action, "chrony"]).status(); + } + #[cfg(not(target_os = "linux"))] + { + // No-op on non-Linux. + // The parameter is unused, but the function is dead code anyway. + let _ = start; + } +} + +pub fn calculate_target_time(frame: &LtcFrame, config: &Config) -> DateTime { + let today_local = Local::now().date_naive(); + + // Total seconds from timecode components + let timecode_secs = + frame.hours as i64 * 3600 + frame.minutes as i64 * 60 + frame.seconds as i64; + + // Timecode is always treated as wall-clock time. NDF scaling is not applied + // as the LTC source appears to be pre-compensated. + let total_duration_secs = + Ratio::new(timecode_secs, 1) + Ratio::new(frame.frames as i64, 1) / frame.frame_rate; + + // Convert to milliseconds + let total_ms = (total_duration_secs * Ratio::new(1000, 1)) + .round() + .to_integer(); + + let naive_midnight = today_local.and_hms_opt(0, 0, 0).unwrap(); + let naive_dt = naive_midnight + ChronoDuration::milliseconds(total_ms); + + let mut dt_local = Local + .from_local_datetime(&naive_dt) + .single() + .expect("Ambiguous or invalid local time"); + + // Apply timeturner offset + let offset = &config.timeturner_offset; + dt_local = dt_local + + ChronoDuration::hours(offset.hours) + + ChronoDuration::minutes(offset.minutes) + + ChronoDuration::seconds(offset.seconds); + // Frame offset needs to be converted to milliseconds + let frame_offset_ms_ratio = Ratio::new(offset.frames * 1000, 1) / frame.frame_rate; + let frame_offset_ms = frame_offset_ms_ratio.round().to_integer(); + dt_local + ChronoDuration::milliseconds(frame_offset_ms + offset.milliseconds) +} + +pub fn trigger_sync(frame: &LtcFrame, config: &Config) -> Result { + let dt_local = calculate_target_time(frame, config); + + #[cfg(target_os = "linux")] + let (ts, success) = { + let ts = dt_local.format("%H:%M:%S.%3f").to_string(); + let success = Command::new("sudo") + .arg("date") + .arg("-s") + .arg(&ts) + .status() + .map(|s| s.success()) + .unwrap_or(false); + (ts, success) + }; + + #[cfg(target_os = "macos")] + let (ts, success) = { + // macOS `date` command format is `mmddHHMMccyy.SS` + let ts = dt_local.format("%m%d%H%M%y.%S").to_string(); + let success = Command::new("sudo") + .arg("date") + .arg(&ts) + .status() + .map(|s| s.success()) + .unwrap_or(false); + (ts, success) + }; + + #[cfg(not(any(target_os = "linux", target_os = "macos")))] + let (ts, success) = { + // Unsupported OS, always fail + let ts = dt_local.format("%H:%M:%S.%3f").to_string(); + eprintln!("Unsupported OS for time synchronization"); + (ts, false) + }; + + if success { + Ok(ts) + } else { + Err(()) + } +} + +pub fn nudge_clock(microseconds: i64) -> Result<(), ()> { + #[cfg(target_os = "linux")] + { + let success = Command::new("sudo") + .arg("adjtimex") + .arg("--singleshot") + .arg(microseconds.to_string()) + .status() + .map(|s| s.success()) + .unwrap_or(false); + + if success { + log::info!("Nudged clock by {} us", microseconds); + Ok(()) + } else { + log::error!("Failed to nudge clock with adjtimex"); + Err(()) + } + } + #[cfg(not(target_os = "linux"))] + { + let _ = microseconds; + log::warn!("Clock nudging is only supported on Linux."); + Err(()) + } +} + +pub fn set_date(date: &str) -> Result<(), ()> { + #[cfg(target_os = "linux")] + { + let datetime_str = format!("{} 10:00:00", date); + let success = Command::new("sudo") + .arg("date") + .arg("--set") + .arg(&datetime_str) + .status() + .map(|s| s.success()) + .unwrap_or(false); + + if success { + log::info!("Set system date and time to {}", datetime_str); + Ok(()) + } else { + log::error!("Failed to set system date and time"); + Err(()) + } + } + #[cfg(not(target_os = "linux"))] + { + let _ = date; + log::warn!("Date setting is only supported on Linux."); + Err(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::config::TimeturnerOffset; + use chrono::{Timelike, Utc}; + use num_rational::Ratio; + + // Helper to create a test frame + fn get_test_frame(h: u32, m: u32, s: u32, f: u32) -> LtcFrame { + LtcFrame { + status: "LOCK".to_string(), + hours: h, + minutes: m, + seconds: s, + frames: f, + is_drop_frame: false, + frame_rate: Ratio::new(25, 1), + timestamp: Utc::now(), + } + } + + #[test] + fn test_ntp_service_active_on_non_linux() { + // On non-Linux platforms, this should always be false. + #[cfg(not(target_os = "linux"))] + assert!(!ntp_service_active()); + } + + #[test] + fn test_calculate_target_time_no_offset() { + let frame = get_test_frame(10, 20, 30, 0); + let config = Config::default(); + let target_time = calculate_target_time(&frame, &config); + + assert_eq!(target_time.hour(), 10); + assert_eq!(target_time.minute(), 20); + assert_eq!(target_time.second(), 30); + } + + #[test] + fn test_calculate_target_time_with_positive_offset() { + let frame = get_test_frame(10, 20, 30, 0); + let mut config = Config::default(); + config.timeturner_offset = TimeturnerOffset { + hours: 1, + minutes: 5, + seconds: 10, + frames: 12, // 12 frames at 25fps is 480ms + milliseconds: 20, + }; + + let target_time = calculate_target_time(&frame, &config); + + assert_eq!(target_time.hour(), 11); + assert_eq!(target_time.minute(), 25); + assert_eq!(target_time.second(), 40); + // 480ms + 20ms = 500ms + assert_eq!(target_time.nanosecond(), 500_000_000); + } + + #[test] + fn test_calculate_target_time_with_negative_offset() { + let frame = get_test_frame(10, 20, 30, 12); // 12 frames = 480ms + let mut config = Config::default(); + config.timeturner_offset = TimeturnerOffset { + hours: -1, + minutes: -5, + seconds: -10, + frames: -12, // -480ms + milliseconds: -80, + }; + + let target_time = calculate_target_time(&frame, &config); + + assert_eq!(target_time.hour(), 9); + assert_eq!(target_time.minute(), 15); + assert_eq!(target_time.second(), 19); + assert_eq!(target_time.nanosecond(), 920_000_000); + } + + #[test] + fn test_nudge_clock_on_non_linux() { + #[cfg(not(target_os = "linux"))] + assert!(nudge_clock(1000).is_err()); + } +} diff --git a/src/ui.rs b/src/ui.rs index a8b0286..5854f4a 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -1,338 +1,234 @@ -ο»Ώuse std::{ - io::{stdout, Write}, - process::{self, Command}, - sync::{Arc, Mutex}, - thread, - time::{Duration, Instant}, -}; -use std::collections::VecDeque; - -use chrono::{ - DateTime, Local, Timelike, Utc, - NaiveTime, TimeZone, -}; -use crossterm::{ - cursor::{Hide, MoveTo, Show}, - event::{poll, read, Event, KeyCode}, - execute, queue, - style::{Color, Print, ResetColor, SetForegroundColor}, - terminal::{self, Clear, ClearType, EnterAlternateScreen, LeaveAlternateScreen}, -}; - -use get_if_addrs::get_if_addrs; -use crate::sync_logic::LtcState; - -/// Check if Chrony is active -fn ntp_service_active() -> bool { - if let Ok(output) = Command::new("systemctl").args(&["is-active", "chrony"]).output() { - output.status.success() - && String::from_utf8_lossy(&output.stdout).trim() == "active" - } else { - false - } -} - -/// Toggle Chrony (not used yet) -#[allow(dead_code)] -fn ntp_service_toggle(start: bool) { - let action = if start { "start" } else { "stop" }; - let _ = Command::new("systemctl").args(&[action, "chrony"]).status(); -} - -pub fn start_ui( - state: Arc>, - serial_port: String, - offset: Arc>, -) { - let mut stdout = stdout(); - execute!(stdout, EnterAlternateScreen, Hide).unwrap(); - terminal::enable_raw_mode().unwrap(); - - let mut logs: VecDeque = VecDeque::with_capacity(10); - let mut out_of_sync_since: Option = None; - let mut last_delta_update = Instant::now() - Duration::from_secs(1); - let mut cached_delta_ms: i64 = 0; - let mut cached_delta_frames: i64 = 0; - - loop { - // 1️⃣ hardware offset - let hw_offset_ms = *offset.lock().unwrap(); - - // 2️⃣ Chrony + interfaces - let ntp_active = ntp_service_active(); - let interfaces: Vec = get_if_addrs() - .unwrap_or_default() - .into_iter() - .filter(|ifa| !ifa.is_loopback()) - .map(|ifa| ifa.ip().to_string()) - .collect(); - - // 3️⃣ jitter + Ξ” - { - let mut st = state.lock().unwrap(); - if let Some(frame) = st.latest.clone() { - if frame.status == "LOCK" { - // jitter - let now_utc = Utc::now(); - let raw = (now_utc - frame.timestamp).num_milliseconds(); - let measured = raw - hw_offset_ms; - st.record_offset(measured); - - // Ξ” = system clock - LTC timecode (use LOCAL time) - let today_local = Local::now().date_naive(); - let ms = ((frame.frames as f64 / frame.frame_rate) * 1000.0) - .round() as u32; - let tc_naive = NaiveTime::from_hms_milli_opt( - frame.hours, frame.minutes, frame.seconds, ms, - ).expect("Invalid LTC timecode"); - let naive_dt_local = today_local.and_time(tc_naive); - let dt_local = Local - .from_local_datetime(&naive_dt_local) - .single() - .expect("Invalid local time"); - let delta_ms = (Local::now() - dt_local).num_milliseconds(); - st.record_clock_delta(delta_ms); - } else { - st.clear_offsets(); - st.clear_clock_deltas(); - } - } - } - - // 4️⃣ averages & status override - let (avg_jitter_ms, _avg_frames, _, lock_ratio, avg_delta) = { - let st = state.lock().unwrap(); - ( - st.average_jitter(), - st.average_frames(), - st.timecode_match().to_string(), - st.lock_ratio(), - st.average_clock_delta(), - ) - }; - - // 5️⃣ cache Ξ” once/sec & Ξ” in frames - if last_delta_update.elapsed() >= Duration::from_secs(1) { - cached_delta_ms = avg_delta; - if let Some(frame) = &state.lock().unwrap().latest { - let frame_ms = 1000.0 / frame.frame_rate; - cached_delta_frames = ((avg_delta as f64 / frame_ms).round()) as i64; - } else { - cached_delta_frames = 0; - } - last_delta_update = Instant::now(); - } - - // 6️⃣ sync status wording - let sync_status = if cached_delta_ms.abs() <= 8 { - "IN SYNC" - } else if cached_delta_ms > 10 { - "CLOCK AHEAD" - } else { - "CLOCK BEHIND" - }; - - // 7️⃣ auto‑sync (same as manual but delayed) - if sync_status != "IN SYNC" { - if let Some(start) = out_of_sync_since { - if start.elapsed() >= Duration::from_secs(5) { - if let Some(frame) = &state.lock().unwrap().latest { - let today_local = Local::now().date_naive(); - let ms = ((frame.frames as f64 / frame.frame_rate) * 1000.0) - .round() as u32; - let timecode = NaiveTime::from_hms_milli_opt( - frame.hours, frame.minutes, frame.seconds, ms, - ).expect("Invalid LTC timecode"); - let naive_dt = today_local.and_time(timecode); - let dt_local = Local - .from_local_datetime(&naive_dt) - .single() - .expect("Ambiguous or invalid local time"); - let ts = dt_local.format("%H:%M:%S.%3f").to_string(); - - let success = Command::new("sudo") - .arg("date") - .arg("-s") - .arg(&ts) - .status() - .map(|s| s.success()) - .unwrap_or(false); - - let entry = if success { - format!("πŸ”„ Auto‑synced to LTC: {}", ts) - } else { - "❌ Auto‑sync failed".into() - }; - if logs.len() == 10 { logs.pop_front(); } - logs.push_back(entry); - } - out_of_sync_since = None; - } - } else { - out_of_sync_since = Some(Instant::now()); - } - } else { - out_of_sync_since = None; - } - - // 8️⃣ header & LTC metrics display - { - let st = state.lock().unwrap(); - let opt = st.latest.as_ref(); - let status_str = opt.map(|f| f.status.as_str()).unwrap_or("(waiting)"); - let tc_str = match opt { - Some(f) => format!("LTC Timecode : {:02}:{:02}:{:02}:{:02}", - f.hours, f.minutes, f.seconds, f.frames), - None => "LTC Timecode : …".to_string(), - }; - let fr_str = match opt { - Some(f) => format!("Frame Rate : {:.2}fps", f.frame_rate), - None => "Frame Rate : …".to_string(), - }; - - queue!( - stdout, - MoveTo(0, 0), Clear(ClearType::All), - MoveTo(2, 1), Print("Have Blue - NTP Timeturner"), - MoveTo(2, 2), Print(format!("Serial Port : {}", serial_port)), - MoveTo(2, 3), Print(format!("Chrony Service : {}", - if ntp_active { "RUNNING" } else { "MISSING" })), - MoveTo(2, 4), Print(format!("Interfaces : {}", - interfaces.join(", "))), - MoveTo(2, 6), Print(format!("LTC Status : {}", status_str)), - MoveTo(2, 7), Print(tc_str), - MoveTo(2, 8), Print(fr_str), - ).unwrap(); - } - - // system clock - let now_local: DateTime = DateTime::from(Utc::now()); - let sys_ts = format!( - "{:02}:{:02}:{:02}.{:03}", - now_local.hour(), - now_local.minute(), - now_local.second(), - now_local.timestamp_subsec_millis(), - ); - queue!(stdout, - MoveTo(2, 9), Print(format!( - "System Clock : {}", - sys_ts - ))).unwrap(); - - // Ξ” display - let dcol = if cached_delta_ms.abs() < 20 { - Color::Green - } else if cached_delta_ms.abs() < 100 { - Color::Yellow - } else { - Color::Red - }; - queue!( - stdout, - MoveTo(2, 11), SetForegroundColor(dcol), - Print(format!("Timecode Ξ” : {:+} ms ({:+} frames)", cached_delta_ms, cached_delta_frames)), - ResetColor, - ).unwrap(); - - // sync status - let scol = if sync_status == "IN SYNC" { - Color::Green - } else { - Color::Red - }; - queue!( - stdout, - MoveTo(2, 12), SetForegroundColor(scol), - Print(format!("Sync Status : {}", sync_status)), - ResetColor, - ).unwrap(); - - // jitter & lock ratio - let jstatus = if avg_jitter_ms.abs() < 10 { - "GOOD" - } else if avg_jitter_ms.abs() < 40 { - "AVERAGE" - } else { - "BAD" - }; - let jcol = if jstatus == "GOOD" { - Color::Green - } else if jstatus == "AVERAGE" { - Color::Yellow - } else { - Color::Red - }; - queue!( - stdout, - MoveTo(2, 13), SetForegroundColor(jcol), - Print(format!("Sync Jitter : {}", jstatus)), - ResetColor, - ).unwrap(); - queue!( - stdout, - MoveTo(2, 14), Print(format!("Lock Ratio : {:.1}% LOCK", - lock_ratio - )), - ).unwrap(); - - // footer + logs - queue!( - stdout, - MoveTo(2, 16), Print("[S] Sync System Clock to LTC [Q] Quit"), - ).unwrap(); - for (i, msg) in logs.iter().enumerate() { - queue!(stdout, MoveTo(2, 18 + i as u16), Print(msg)).unwrap(); - } - - stdout.flush().unwrap(); - - // manual sync & quit - if poll(Duration::from_millis(50)).unwrap() { - if let Event::Key(evt) = read().unwrap() { - match evt.code { - KeyCode::Char(c) if c.eq_ignore_ascii_case(&'q') => { - execute!(stdout, Show, LeaveAlternateScreen).unwrap(); - terminal::disable_raw_mode().unwrap(); - process::exit(0); - } - KeyCode::Char(c) if c.eq_ignore_ascii_case(&'s') => { - if let Some(frame) = &state.lock().unwrap().latest { - let today_local = Local::now().date_naive(); - let ms = ((frame.frames as f64 / frame.frame_rate) * 1000.0) - .round() as u32; - let timecode = NaiveTime::from_hms_milli_opt( - frame.hours, frame.minutes, frame.seconds, ms, - ).expect("Invalid LTC timecode"); - let naive_dt = today_local.and_time(timecode); - let dt_local = Local - .from_local_datetime(&naive_dt) - .single() - .expect("Ambiguous or invalid local time"); - let ts = dt_local.format("%H:%M:%S.%3f").to_string(); - - let success = Command::new("sudo") - .arg("date") - .arg("-s") - .arg(&ts) - .status() - .map(|s| s.success()) - .unwrap_or(false); - - let entry = if success { - format!("βœ” Synced exactly to LTC: {}", ts) - } else { - "❌ date cmd failed".into() - }; - if logs.len() == 10 { logs.pop_front(); } - logs.push_back(entry); - } - } - _ => {} - } - } - } - - thread::sleep(Duration::from_millis(25)); - } -} +ο»Ώuse std::{ + io::{stdout, Write}, + process::{self}, + sync::{Arc, Mutex}, + thread, + time::{Duration, Instant}, +}; +use std::collections::VecDeque; + +use chrono::{ + DateTime, Local, Timelike, Utc, +}; +use crossterm::{ + cursor::{Hide, MoveTo, Show}, + event::{poll, read, Event, KeyCode}, + execute, queue, + style::{Color, Print, ResetColor, SetForegroundColor}, + terminal::{self, Clear, ClearType, EnterAlternateScreen, LeaveAlternateScreen}, +}; + +use crate::config::Config; +use crate::sync_logic::{get_jitter_status, get_sync_status, LtcState}; +use crate::system; +use get_if_addrs::get_if_addrs; +use num_rational::Ratio; +use num_traits::ToPrimitive; + + +pub fn start_ui( + state: Arc>, + serial_port: String, + config: Arc>, +) { + let mut stdout = stdout(); + execute!(stdout, EnterAlternateScreen, Hide).unwrap(); + terminal::enable_raw_mode().unwrap(); + + let mut logs: VecDeque = VecDeque::with_capacity(10); + let mut last_delta_update = Instant::now() - Duration::from_secs(1); + let mut cached_delta_ms: i64 = 0; + let mut cached_delta_frames: i64 = 0; + + loop { + // 1️⃣ config + let cfg = config.lock().unwrap().clone(); + let hw_offset_ms = cfg.hardware_offset_ms; + + // 2️⃣ Chrony + interfaces + let ntp_active = system::ntp_service_active(); + let interfaces: Vec = get_if_addrs() + .unwrap_or_default() + .into_iter() + .filter(|ifa| !ifa.is_loopback()) + .map(|ifa| ifa.ip().to_string()) + .collect(); + + // 3️⃣ jitter + { + let mut st = state.lock().unwrap(); + if let Some(frame) = st.latest.clone() { + if frame.status == "LOCK" { + // jitter + let now_utc = Utc::now(); + let raw = (now_utc - frame.timestamp).num_milliseconds(); + let measured = raw - hw_offset_ms; + st.record_offset(measured); + } + } + } + + // 4️⃣ averages & status override + let (avg_jitter_ms, _avg_frames, _, lock_ratio, avg_delta) = { + let st = state.lock().unwrap(); + ( + st.average_jitter(), + st.average_frames(), + st.timecode_match().to_string(), + st.lock_ratio(), + st.get_ewma_clock_delta(), + ) + }; + + // 5️⃣ cache Ξ” once/sec & Ξ” in frames + if last_delta_update.elapsed() >= Duration::from_secs(1) { + cached_delta_ms = avg_delta; + if let Some(frame) = &state.lock().unwrap().latest { + let delta_ms_ratio = Ratio::new(avg_delta, 1); + let frames_ratio = delta_ms_ratio * frame.frame_rate / Ratio::new(1000, 1); + cached_delta_frames = frames_ratio.round().to_integer(); + } else { + cached_delta_frames = 0; + } + last_delta_update = Instant::now(); + } + + // 6️⃣ sync status wording + let sync_status = get_sync_status(cached_delta_ms, &cfg); + + // 7️⃣ header & LTC metrics display + { + let st = state.lock().unwrap(); + let opt = st.latest.as_ref(); + let status_str = opt.map(|f| f.status.as_str()).unwrap_or("(waiting)"); + let tc_str = match opt { + Some(f) => format!("LTC Timecode : {:02}:{:02}:{:02}:{:02}", + f.hours, f.minutes, f.seconds, f.frames), + None => "LTC Timecode : …".to_string(), + }; + let fr_str = match opt { + Some(f) => format!("Frame Rate : {:.2}fps", f.frame_rate.to_f64().unwrap_or(0.0)), + None => "Frame Rate : …".to_string(), + }; + + queue!( + stdout, + MoveTo(0, 0), Clear(ClearType::All), + MoveTo(2, 1), Print("Have Blue - NTP Timeturner"), + MoveTo(2, 2), Print(format!("Serial Port : {}", serial_port)), + MoveTo(2, 3), Print(format!("Chrony Service : {}", + if ntp_active { "RUNNING" } else { "MISSING" })), + MoveTo(2, 4), Print(format!("Interfaces : {}", + interfaces.join(", "))), + MoveTo(2, 6), Print(format!("LTC Status : {}", status_str)), + MoveTo(2, 7), Print(tc_str), + MoveTo(2, 8), Print(fr_str), + ).unwrap(); + } + + // system clock + let now_local: DateTime = DateTime::from(Utc::now()); + let sys_ts = format!( + "{:02}:{:02}:{:02}.{:03}", + now_local.hour(), + now_local.minute(), + now_local.second(), + now_local.timestamp_subsec_millis(), + ); + queue!(stdout, + MoveTo(2, 9), Print(format!( + "System Clock : {}", + sys_ts + ))).unwrap(); + + // Ξ” display + let dcol = if cached_delta_ms.abs() < 20 { + Color::Green + } else if cached_delta_ms.abs() < 100 { + Color::Yellow + } else { + Color::Red + }; + queue!( + stdout, + MoveTo(2, 11), SetForegroundColor(dcol), + Print(format!("Timecode Ξ” : {:+} ms ({:+} frames)", cached_delta_ms, cached_delta_frames)), + ResetColor, + ).unwrap(); + + // sync status + let scol = if sync_status == "IN SYNC" { + Color::Green + } else if sync_status == "TIMETURNING" { + Color::Cyan + } else { + Color::Red + }; + queue!( + stdout, + MoveTo(2, 12), SetForegroundColor(scol), + Print(format!("Sync Status : {}", sync_status)), + ResetColor, + ).unwrap(); + + // jitter & lock ratio + let jstatus = get_jitter_status(avg_jitter_ms); + let jcol = if jstatus == "GOOD" { + Color::Green + } else if jstatus == "AVERAGE" { + Color::Yellow + } else { + Color::Red + }; + queue!( + stdout, + MoveTo(2, 13), SetForegroundColor(jcol), + Print(format!("Sync Jitter : {}", jstatus)), + ResetColor, + ).unwrap(); + queue!( + stdout, + MoveTo(2, 14), Print(format!("Lock Ratio : {:.1}% LOCK", + lock_ratio + )), + ).unwrap(); + + // footer + logs + queue!( + stdout, + MoveTo(2, 16), Print("[S] Sync System Clock to LTC [Q] Quit"), + ).unwrap(); + for (i, msg) in logs.iter().enumerate() { + queue!(stdout, MoveTo(2, 18 + i as u16), Print(msg)).unwrap(); + } + + stdout.flush().unwrap(); + + // manual sync & quit + if poll(Duration::from_millis(50)).unwrap() { + if let Event::Key(evt) = read().unwrap() { + match evt.code { + KeyCode::Char(c) if c.eq_ignore_ascii_case(&'q') => { + execute!(stdout, Show, LeaveAlternateScreen).unwrap(); + terminal::disable_raw_mode().unwrap(); + process::exit(0); + } + KeyCode::Char(c) if c.eq_ignore_ascii_case(&'s') => { + if let Some(frame) = &state.lock().unwrap().latest { + let entry = match system::trigger_sync(frame, &cfg) { + Ok(ts) => format!("βœ” Synced exactly to LTC: {}", ts), + Err(_) => "❌ date cmd failed".into(), + }; + if logs.len() == 10 { logs.pop_front(); } + logs.push_back(entry); + } + } + _ => {} + } + } + } + + thread::sleep(Duration::from_millis(25)); + } +} + diff --git a/static/assets/FuturaStdHeavy.otf b/static/assets/FuturaStdHeavy.otf new file mode 100644 index 0000000..7b8c22d Binary files /dev/null and b/static/assets/FuturaStdHeavy.otf differ diff --git a/static/assets/HaveBlueTransWh.png b/static/assets/HaveBlueTransWh.png new file mode 100644 index 0000000..d9a123d Binary files /dev/null and b/static/assets/HaveBlueTransWh.png differ diff --git a/static/assets/favicon.png b/static/assets/favicon.png new file mode 100644 index 0000000..3683c35 Binary files /dev/null and b/static/assets/favicon.png differ diff --git a/static/assets/header.png b/static/assets/header.png new file mode 100644 index 0000000..f1677ed Binary files /dev/null and b/static/assets/header.png differ diff --git a/static/assets/quartz-ms-regular.ttf b/static/assets/quartz-ms-regular.ttf new file mode 100644 index 0000000..15c7ce4 Binary files /dev/null and b/static/assets/quartz-ms-regular.ttf differ diff --git a/static/assets/timeturner_2398.png b/static/assets/timeturner_2398.png new file mode 100644 index 0000000..763bcba Binary files /dev/null and b/static/assets/timeturner_2398.png differ diff --git a/static/assets/timeturner_24.png b/static/assets/timeturner_24.png new file mode 100644 index 0000000..ffc75d0 Binary files /dev/null and b/static/assets/timeturner_24.png differ diff --git a/static/assets/timeturner_25.png b/static/assets/timeturner_25.png new file mode 100644 index 0000000..3b44c93 Binary files /dev/null and b/static/assets/timeturner_25.png differ diff --git a/static/assets/timeturner_2997.png b/static/assets/timeturner_2997.png new file mode 100644 index 0000000..0bd27fd Binary files /dev/null and b/static/assets/timeturner_2997.png differ diff --git a/static/assets/timeturner_2997DF.png b/static/assets/timeturner_2997DF.png new file mode 100644 index 0000000..bf03215 Binary files /dev/null and b/static/assets/timeturner_2997DF.png differ diff --git a/static/assets/timeturner_30.png b/static/assets/timeturner_30.png new file mode 100644 index 0000000..4ce0211 Binary files /dev/null and b/static/assets/timeturner_30.png differ diff --git a/static/assets/timeturner_controls.png b/static/assets/timeturner_controls.png new file mode 100644 index 0000000..a91f39b Binary files /dev/null and b/static/assets/timeturner_controls.png differ diff --git a/static/assets/timeturner_default.png b/static/assets/timeturner_default.png new file mode 100644 index 0000000..734aa8d Binary files /dev/null and b/static/assets/timeturner_default.png differ diff --git a/static/assets/timeturner_delta_green.png b/static/assets/timeturner_delta_green.png new file mode 100644 index 0000000..ddc84b9 Binary files /dev/null and b/static/assets/timeturner_delta_green.png differ diff --git a/static/assets/timeturner_delta_orange.png b/static/assets/timeturner_delta_orange.png new file mode 100644 index 0000000..64e9776 Binary files /dev/null and b/static/assets/timeturner_delta_orange.png differ diff --git a/static/assets/timeturner_delta_red.png b/static/assets/timeturner_delta_red.png new file mode 100644 index 0000000..c7272ac Binary files /dev/null and b/static/assets/timeturner_delta_red.png differ diff --git a/static/assets/timeturner_jitter_green.png b/static/assets/timeturner_jitter_green.png new file mode 100644 index 0000000..8cc64e3 Binary files /dev/null and b/static/assets/timeturner_jitter_green.png differ diff --git a/static/assets/timeturner_jitter_orange.png b/static/assets/timeturner_jitter_orange.png new file mode 100644 index 0000000..96c5f84 Binary files /dev/null and b/static/assets/timeturner_jitter_orange.png differ diff --git a/static/assets/timeturner_jitter_red.png b/static/assets/timeturner_jitter_red.png new file mode 100644 index 0000000..8813159 Binary files /dev/null and b/static/assets/timeturner_jitter_red.png differ diff --git a/static/assets/timeturner_lock_green.png b/static/assets/timeturner_lock_green.png new file mode 100644 index 0000000..0659c60 Binary files /dev/null and b/static/assets/timeturner_lock_green.png differ diff --git a/static/assets/timeturner_lock_orange.png b/static/assets/timeturner_lock_orange.png new file mode 100644 index 0000000..836a376 Binary files /dev/null and b/static/assets/timeturner_lock_orange.png differ diff --git a/static/assets/timeturner_lock_red.png b/static/assets/timeturner_lock_red.png new file mode 100644 index 0000000..aa8740d Binary files /dev/null and b/static/assets/timeturner_lock_red.png differ diff --git a/static/assets/timeturner_logs.png b/static/assets/timeturner_logs.png new file mode 100644 index 0000000..6bdd935 Binary files /dev/null and b/static/assets/timeturner_logs.png differ diff --git a/static/assets/timeturner_ltc_green.png b/static/assets/timeturner_ltc_green.png new file mode 100644 index 0000000..4329913 Binary files /dev/null and b/static/assets/timeturner_ltc_green.png differ diff --git a/static/assets/timeturner_ltc_orange.png b/static/assets/timeturner_ltc_orange.png new file mode 100644 index 0000000..b060ac2 Binary files /dev/null and b/static/assets/timeturner_ltc_orange.png differ diff --git a/static/assets/timeturner_ltc_red.png b/static/assets/timeturner_ltc_red.png new file mode 100644 index 0000000..a8e7f96 Binary files /dev/null and b/static/assets/timeturner_ltc_red.png differ diff --git a/static/assets/timeturner_network.png b/static/assets/timeturner_network.png new file mode 100644 index 0000000..06ec4b9 Binary files /dev/null and b/static/assets/timeturner_network.png differ diff --git a/static/assets/timeturner_ntp_green.png b/static/assets/timeturner_ntp_green.png new file mode 100644 index 0000000..caf824d Binary files /dev/null and b/static/assets/timeturner_ntp_green.png differ diff --git a/static/assets/timeturner_ntp_orange.png b/static/assets/timeturner_ntp_orange.png new file mode 100644 index 0000000..88319b5 Binary files /dev/null and b/static/assets/timeturner_ntp_orange.png differ diff --git a/static/assets/timeturner_ntp_red.png b/static/assets/timeturner_ntp_red.png new file mode 100644 index 0000000..16e66ee Binary files /dev/null and b/static/assets/timeturner_ntp_red.png differ diff --git a/static/assets/timeturner_sync_green.png b/static/assets/timeturner_sync_green.png new file mode 100644 index 0000000..9b4988e Binary files /dev/null and b/static/assets/timeturner_sync_green.png differ diff --git a/static/assets/timeturner_sync_orange.png b/static/assets/timeturner_sync_orange.png new file mode 100644 index 0000000..0b41130 Binary files /dev/null and b/static/assets/timeturner_sync_orange.png differ diff --git a/static/assets/timeturner_sync_red.png b/static/assets/timeturner_sync_red.png new file mode 100644 index 0000000..1c4c4c9 Binary files /dev/null and b/static/assets/timeturner_sync_red.png differ diff --git a/static/assets/timeturner_timeturning.png b/static/assets/timeturner_timeturning.png new file mode 100644 index 0000000..fd3eaeb Binary files /dev/null and b/static/assets/timeturner_timeturning.png differ diff --git a/static/favicon.ico b/static/favicon.ico new file mode 100644 index 0000000..83d6317 Binary files /dev/null and b/static/favicon.ico differ diff --git a/static/icon-map.js b/static/icon-map.js new file mode 100644 index 0000000..64336b3 --- /dev/null +++ b/static/icon-map.js @@ -0,0 +1,43 @@ +// In this file, you can define the paths to your local icon image files. +const iconMap = { + ltcStatus: { + 'LOCK': { src: 'assets/timeturner_ltc_green.png', tooltip: 'LTC signal is locked and stable.' }, + 'FREE': { src: 'assets/timeturner_ltc_orange.png', tooltip: 'LTC signal is in freewheel mode.' }, + 'default': { src: 'assets/timeturner_ltc_red.png', tooltip: 'LTC signal is not detected.' } + }, + ntpActive: { + true: { src: 'assets/timeturner_ntp_green.png', tooltip: 'NTP service is active.' }, + false: { src: 'assets/timeturner_ntp_red.png', tooltip: 'NTP service is inactive.' } + }, + syncStatus: { + 'IN SYNC': { src: 'assets/timeturner_sync_green.png', tooltip: 'System clock is in sync with LTC source.' }, + 'CLOCK AHEAD': { src: 'assets/timeturner_sync_orange.png', tooltip: 'System clock is ahead of the LTC source.' }, + 'CLOCK BEHIND': { src: 'assets/timeturner_sync_orange.png', tooltip: 'System clock is behind the LTC source.' }, + 'TIMETURNING': { src: 'assets/timeturner_timeturning.png', tooltip: 'Timeturner offset is active.' }, + 'default': { src: 'assets/timeturner_sync_red.png', tooltip: 'Sync status is unknown.' } + }, + jitterStatus: { + 'GOOD': { src: 'assets/timeturner_jitter_green.png', tooltip: 'Clock jitter is within acceptable limits.' }, + 'AVERAGE': { src: 'assets/timeturner_jitter_orange.png', tooltip: 'Clock jitter is moderate.' }, + 'BAD': { src: 'assets/timeturner_jitter_red.png', tooltip: 'Clock jitter is high and may affect accuracy.' }, + 'default': { src: 'assets/timeturner_jitter_red.png', tooltip: 'Jitter status is unknown.' } + }, + deltaStatus: { + 'good': { src: 'assets/timeturner_delta_green.png', tooltip: 'Clock delta is 0ms.' }, + 'average': { src: 'assets/timeturner_delta_orange.png', tooltip: 'Clock delta is less than 10ms.' }, + 'bad': { src: 'assets/timeturner_delta_red.png', tooltip: 'Clock delta is 10ms or greater.' } + }, + frameRate: { + '23.98fps': { src: 'assets/timeturner_2398.png', tooltip: '23.98 frames per second' }, + '24.00fps': { src: 'assets/timeturner_24.png', tooltip: '24.00 frames per second' }, + '25.00fps': { src: 'assets/timeturner_25.png', tooltip: '25.00 frames per second' }, + '29.97fps': { src: 'assets/timeturner_2997.png', tooltip: '29.97 frames per second' }, + '30.00fps': { src: 'assets/timeturner_30.png', tooltip: '30.00 frames per second' }, + 'default': { src: 'assets/timeturner_default.png', tooltip: 'Unknown frame rate' } + }, + lockRatio: { + 'good': { src: 'assets/timeturner_lock_green.png', tooltip: 'Lock ratio is 100%.' }, + 'average': { src: 'assets/timeturner_lock_orange.png', tooltip: 'Lock ratio is 90% or higher.' }, + 'bad': { src: 'assets/timeturner_lock_red.png', tooltip: 'Lock ratio is below 90%.' } + } +}; diff --git a/static/index.html b/static/index.html new file mode 100644 index 0000000..02bb279 --- /dev/null +++ b/static/index.html @@ -0,0 +1,141 @@ + + + + + + Fetch | Hachi + + + + +
+ + + + + +
+ +
+

LTC Input

+

--:--:--:--

+
+ + + +
+
+ + +
+

NTP Clock

+

--:--:--.---

+

---- -- --

+
+ + + + +
+

Ξ” -- ms (-- frames)

+
+ + +
+
+ Network Icon +

Network

+
+

--

+
+ + +
+
+ Controls Icon +

Controls

+
+
+ + +
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + + +
+ +
+ + + + +
+
+
+ + +
+
+ Logs Icon +

Logs

+
+
+

+                        
+
+
+ +
+ + + + + diff --git a/static/index_dev.html b/static/index_dev.html new file mode 100644 index 0000000..edc555d --- /dev/null +++ b/static/index_dev.html @@ -0,0 +1,141 @@ + + + + + + NTP TimeTurner + + + + +
+ + + + + +
+ +
+

LTC Input

+

--:--:--:--

+
+ + + +
+
+ + +
+

NTP Clock

+

--:--:--.---

+

---- -- --

+
+ + + + +
+

Ξ” -- ms (-- frames)

+
+ + +
+
+ Network Icon +

Network

+
+

--

+
+ + +
+
+ Controls Icon +

Controls

+
+
+
+ + +
+
+ + +
+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + + +
+
+ + + + + +
+
+ + + + +
+
+
+ + +
+
+ Logs Icon +

Logs

+
+
+

+                        
+
+
+ +
+ + + + + diff --git a/static/mock-data.js b/static/mock-data.js new file mode 100644 index 0000000..a953e59 --- /dev/null +++ b/static/mock-data.js @@ -0,0 +1,168 @@ +// This file contains mock data sets for UI development and testing without a live backend. +const mockApiDataSets = { + allGood: { + status: { + ltc_status: 'LOCK', + ltc_timecode: '10:20:30:00', + frame_rate: '25.00fps', + lock_ratio: 99.5, + system_clock: '10:20:30.500', + system_date: '2025-08-07', + ntp_active: true, + sync_status: 'IN SYNC', + timecode_delta_ms: 5, + timecode_delta_frames: 0.125, + jitter_status: 'GOOD', + interfaces: ['192.168.1.100/24 (eth0)', '10.0.0.5/8 (wlan0)'], + }, + config: { + hardwareOffsetMs: 10, + autoSyncEnabled: true, + defaultNudgeMs: 2, + timeturnerOffset: { hours: 1, minutes: 2, seconds: 3, frames: 4, milliseconds: 50 }, + }, + logs: [ + '2025-08-07 10:20:30 [INFO] Starting up...', + '2025-08-07 10:20:32 [INFO] LTC LOCK detected. Frame rate: 25.00fps.', + '2025-08-07 10:20:35 [INFO] Initial sync complete. Clock adjusted by -15ms.', + ] + }, + ltcFree: { + status: { + ltc_status: 'FREE', + ltc_timecode: '11:22:33:11', + frame_rate: '25.00fps', + lock_ratio: 40.2, + system_clock: '11:22:33.800', + system_date: '2025-08-07', + ntp_active: true, + sync_status: 'IN SYNC', + timecode_delta_ms: 3, + timecode_delta_frames: 0.075, + jitter_status: 'GOOD', + interfaces: ['192.168.1.100/24 (eth0)'], + }, + config: { + hardwareOffsetMs: 10, + autoSyncEnabled: true, + defaultNudgeMs: 2, + timeturnerOffset: { hours: 0, minutes: 0, seconds: 0, frames: 0, milliseconds: 0 }, + }, + logs: [ '2025-08-07 11:22:30 [WARN] LTC signal lost, entering freewheel.' ] + }, + clockAhead: { + status: { + ltc_status: 'LOCK', + ltc_timecode: '12:00:05:00', + frame_rate: '25.00fps', + lock_ratio: 98.1, + system_clock: '12:00:04.500', + system_date: '2025-08-07', + ntp_active: true, + sync_status: 'CLOCK AHEAD', + timecode_delta_ms: -500, + timecode_delta_frames: -12.5, + jitter_status: 'AVERAGE', + interfaces: ['192.168.1.100/24 (eth0)'], + }, + config: { + hardwareOffsetMs: 10, + autoSyncEnabled: true, + defaultNudgeMs: 2, + timeturnerOffset: { hours: 0, minutes: 0, seconds: 0, frames: 0, milliseconds: 0 }, + }, + logs: [ '2025-08-07 12:00:00 [WARN] System clock is ahead of LTC source by 500ms.' ] + }, + clockBehind: { + status: { + ltc_status: 'LOCK', + ltc_timecode: '13:30:10:00', + frame_rate: '25.00fps', + lock_ratio: 99.9, + system_clock: '13:30:10.800', + system_date: '2025-08-07', + ntp_active: true, + sync_status: 'CLOCK BEHIND', + timecode_delta_ms: 800, + timecode_delta_frames: 20, + jitter_status: 'AVERAGE', + interfaces: ['192.168.1.100/24 (eth0)'], + }, + config: { + hardwareOffsetMs: 10, + autoSyncEnabled: true, + defaultNudgeMs: 2, + timeturnerOffset: { hours: 0, minutes: 0, seconds: 0, frames: 0, milliseconds: 0 }, + }, + logs: [ '2025-08-07 13:30:00 [WARN] System clock is behind LTC source by 800ms.' ] + }, + timeturning: { + status: { + ltc_status: 'LOCK', + ltc_timecode: '14:00:00:00', + frame_rate: '25.00fps', + lock_ratio: 100, + system_clock: '15:02:03.050', + system_date: '2025-08-07', + ntp_active: true, + sync_status: 'TIMETURNING', + timecode_delta_ms: 3723050, // a big number + timecode_delta_frames: 93076, + jitter_status: 'GOOD', + interfaces: ['192.168.1.100/24 (eth0)'], + }, + config: { + hardwareOffsetMs: 10, + autoSyncEnabled: false, + defaultNudgeMs: 2, + timeturnerOffset: { hours: 1, minutes: 2, seconds: 3, frames: 4, milliseconds: 50 }, + }, + logs: [ '2025-08-07 14:00:00 [INFO] Timeturner offset is active.' ] + }, + badJitter: { + status: { + ltc_status: 'LOCK', + ltc_timecode: '15:15:15:15', + frame_rate: '25.00fps', + lock_ratio: 95.0, + system_clock: '15:15:15.515', + system_date: '2025-08-07', + ntp_active: true, + sync_status: 'IN SYNC', + timecode_delta_ms: 10, + timecode_delta_frames: 0.25, + jitter_status: 'BAD', + interfaces: ['192.168.1.100/24 (eth0)'], + }, + config: { + hardwareOffsetMs: 10, + autoSyncEnabled: true, + defaultNudgeMs: 2, + timeturnerOffset: { hours: 0, minutes: 0, seconds: 0, frames: 0, milliseconds: 0 }, + }, + logs: [ '2025-08-07 15:15:00 [ERROR] High jitter detected on LTC source.' ] + }, + ntpInactive: { + status: { + ltc_status: 'UNKNOWN', + ltc_timecode: '--:--:--:--', + frame_rate: '--', + lock_ratio: 0, + system_clock: '16:00:00.000', + system_date: '2025-08-07', + ntp_active: false, + sync_status: 'UNKNOWN', + timecode_delta_ms: 0, + timecode_delta_frames: 0, + jitter_status: 'UNKNOWN', + interfaces: [], + }, + config: { + hardwareOffsetMs: 0, + autoSyncEnabled: false, + defaultNudgeMs: 2, + timeturnerOffset: { hours: 0, minutes: 0, seconds: 0, frames: 0, milliseconds: 0 }, + }, + logs: [ '2025-08-07 16:00:00 [INFO] NTP service is inactive.' ] + } +}; diff --git a/static/script.js b/static/script.js new file mode 100644 index 0000000..634ed33 --- /dev/null +++ b/static/script.js @@ -0,0 +1,443 @@ +ο»Ώdocument.addEventListener('DOMContentLoaded', () => { + // --- Mock Data Configuration --- + // Set to true to use mock data, false for live API. + const useMockData = false; + let currentMockSetKey = 'allGood'; // Default mock data set + + let lastApiData = null; + let lastApiFetchTime = null; + + const statusElements = { + ltcStatus: document.getElementById('ltc-status'), + ltcTimecode: document.getElementById('ltc-timecode'), + frameRate: document.getElementById('frame-rate'), + lockRatio: document.getElementById('lock-ratio'), + systemClock: document.getElementById('system-clock'), + systemDate: document.getElementById('system-date'), + ntpActive: document.getElementById('ntp-active'), + syncStatus: document.getElementById('sync-status'), + deltaStatus: document.getElementById('delta-status'), + jitterStatus: document.getElementById('jitter-status'), + deltaText: document.getElementById('delta-text'), + interfaces: document.getElementById('interfaces'), + logs: document.getElementById('logs'), + }; + + const hwOffsetInput = document.getElementById('hw-offset'); + const autoSyncCheckbox = document.getElementById('auto-sync-enabled'); + const offsetInputs = { + h: document.getElementById('offset-h'), + m: document.getElementById('offset-m'), + s: document.getElementById('offset-s'), + f: document.getElementById('offset-f'), + ms: document.getElementById('offset-ms'), + }; + const saveConfigButton = document.getElementById('save-config'); + const manualSyncButton = document.getElementById('manual-sync'); + const syncMessage = document.getElementById('sync-message'); + + const nudgeDownButton = document.getElementById('nudge-down'); + const nudgeUpButton = document.getElementById('nudge-up'); + const nudgeValueInput = document.getElementById('nudge-value'); + const nudgeMessage = document.getElementById('nudge-message'); + + const dateInput = document.getElementById('date-input'); + const setDateButton = document.getElementById('set-date'); + const dateMessage = document.getElementById('date-message'); + + // --- Collapsible Sections --- + const controlsToggle = document.getElementById('controls-toggle'); + const controlsContent = document.getElementById('controls-content'); + const logsToggle = document.getElementById('logs-toggle'); + const logsContent = document.getElementById('logs-content'); + + // --- Mock Controls Setup --- + const mockControls = document.getElementById('mock-controls'); + const mockDataSelector = document.getElementById('mock-data-selector'); + + function setupMockControls() { + if (useMockData) { + mockControls.style.display = 'block'; + + // Populate dropdown + Object.keys(mockApiDataSets).forEach(key => { + const option = document.createElement('option'); + option.value = key; + option.textContent = key.replace(/([A-Z])/g, ' $1').replace(/^./, str => str.toUpperCase()); + mockDataSelector.appendChild(option); + }); + + mockDataSelector.value = currentMockSetKey; + + // Handle selection change + mockDataSelector.addEventListener('change', (event) => { + currentMockSetKey = event.target.value; + // Re-fetch all data from the new mock set + fetchStatus(); + fetchConfig(); + fetchLogs(); + }); + } + } + + function updateStatus(data) { + const ltcStatus = data.ltc_status || 'UNKNOWN'; + const ltcIconInfo = iconMap.ltcStatus[ltcStatus] || iconMap.ltcStatus.default; + statusElements.ltcStatus.innerHTML = ``; + statusElements.ltcStatus.className = ltcStatus.toLowerCase(); + statusElements.ltcTimecode.textContent = data.ltc_timecode; + + const frameRate = data.frame_rate || 'unknown'; + const frameRateIconInfo = iconMap.frameRate[frameRate] || iconMap.frameRate.default; + statusElements.frameRate.innerHTML = ``; + + const lockRatio = data.lock_ratio; + let lockRatioCategory; + if (lockRatio === 100) { + lockRatioCategory = 'good'; + } else if (lockRatio >= 90) { + lockRatioCategory = 'average'; + } else { + lockRatioCategory = 'bad'; + } + const lockRatioIconInfo = iconMap.lockRatio[lockRatioCategory]; + statusElements.lockRatio.innerHTML = ``; + statusElements.systemClock.textContent = data.system_clock; + statusElements.systemDate.textContent = data.system_date; + + // Autofill the date input, but don't overwrite user edits. + if (!lastApiData || dateInput.value === lastApiData.system_date) { + dateInput.value = data.system_date; + } + + const ntpIconInfo = iconMap.ntpActive[!!data.ntp_active]; + if (data.ntp_active) { + statusElements.ntpActive.innerHTML = ``; + statusElements.ntpActive.className = 'active'; + } else { + statusElements.ntpActive.innerHTML = ``; + statusElements.ntpActive.className = 'inactive'; + } + + const syncStatus = data.sync_status || 'UNKNOWN'; + const syncIconInfo = iconMap.syncStatus[syncStatus] || iconMap.syncStatus.default; + statusElements.syncStatus.innerHTML = ``; + statusElements.syncStatus.className = syncStatus.replace(/\s+/g, '-').toLowerCase(); + + // Delta Status + const deltaMs = data.timecode_delta_ms; + let deltaCategory; + if (deltaMs === 0) { + deltaCategory = 'good'; + } else if (Math.abs(deltaMs) < 10) { + deltaCategory = 'average'; + } else { + deltaCategory = 'bad'; + } + const deltaIconInfo = iconMap.deltaStatus[deltaCategory]; + statusElements.deltaStatus.innerHTML = ``; + + const deltaTextValue = `${data.timecode_delta_ms} ms (${data.timecode_delta_frames} frames)`; + statusElements.deltaText.textContent = `Ξ” ${deltaTextValue}`; + + const jitterStatus = data.jitter_status || 'UNKNOWN'; + const jitterIconInfo = iconMap.jitterStatus[jitterStatus] || iconMap.jitterStatus.default; + statusElements.jitterStatus.innerHTML = ``; + statusElements.jitterStatus.className = jitterStatus.toLowerCase(); + + if (data.interfaces.length > 0) { + statusElements.interfaces.textContent = data.interfaces.join(' | '); + } else { + statusElements.interfaces.textContent = 'No active interfaces found.'; + } + } + + function animateClocks() { + if (!lastApiData || !lastApiFetchTime) return; + + const elapsedMs = new Date() - lastApiFetchTime; + + // Animate System Clock + if (lastApiData.system_clock && lastApiData.system_clock.includes(':')) { + const parts = lastApiData.system_clock.split(/[:.]/); + if (parts.length === 4) { + const baseDate = new Date(); + baseDate.setHours(parseInt(parts[0], 10), parseInt(parts[1], 10), parseInt(parts[2], 10)); + baseDate.setMilliseconds(parseInt(parts[3], 10)); + + const newDate = new Date(baseDate.getTime() + elapsedMs); + + const h = String(newDate.getHours()).padStart(2, '0'); + const m = String(newDate.getMinutes()).padStart(2, '0'); + const s = String(newDate.getSeconds()).padStart(2, '0'); + const ms = String(newDate.getMilliseconds()).padStart(3, '0'); + statusElements.systemClock.textContent = `${h}:${m}:${s}.${ms}`; + } + } + + // Animate LTC Timecode - only if status is LOCK + if (lastApiData.ltc_status === 'LOCK' && lastApiData.ltc_timecode && lastApiData.ltc_timecode.match(/[:;]/) && lastApiData.frame_rate) { + const separator = lastApiData.ltc_timecode.includes(';') ? ';' : ':'; + const tcParts = lastApiData.ltc_timecode.split(/[:;]/); + const frameRate = parseFloat(lastApiData.frame_rate); + + if (tcParts.length === 4 && !isNaN(frameRate) && frameRate > 0) { + let h = parseInt(tcParts[0], 10); + let m = parseInt(tcParts[1], 10); + let s = parseInt(tcParts[2], 10); + let f = parseInt(tcParts[3], 10); + + const msPerFrame = 1000.0 / frameRate; + const elapsedFrames = Math.floor(elapsedMs / msPerFrame); + + f += elapsedFrames; + + const frameRateInt = Math.round(frameRate); + + s += Math.floor(f / frameRateInt); + f %= frameRateInt; + + m += Math.floor(s / 60); + s %= 60; + + h += Math.floor(m / 60); + m %= 60; + + h %= 24; + + statusElements.ltcTimecode.textContent = + `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}${separator}${String(f).padStart(2, '0')}`; + } + } + } + + async function fetchStatus() { + if (useMockData) { + const data = mockApiDataSets[currentMockSetKey].status; + updateStatus(data); + lastApiData = data; + lastApiFetchTime = new Date(); + return; + } + try { + const response = await fetch('/api/status'); + if (!response.ok) throw new Error('Failed to fetch status'); + const data = await response.json(); + updateStatus(data); + lastApiData = data; + lastApiFetchTime = new Date(); + } catch (error) { + console.error('Error fetching status:', error); + lastApiData = null; + lastApiFetchTime = null; + } + } + + async function fetchConfig() { + if (useMockData) { + const data = mockApiDataSets[currentMockSetKey].config; + hwOffsetInput.value = data.hardwareOffsetMs; + autoSyncCheckbox.checked = data.autoSyncEnabled; + offsetInputs.h.value = data.timeturnerOffset.hours; + offsetInputs.m.value = data.timeturnerOffset.minutes; + offsetInputs.s.value = data.timeturnerOffset.seconds; + offsetInputs.f.value = data.timeturnerOffset.frames; + offsetInputs.ms.value = data.timeturnerOffset.milliseconds || 0; + nudgeValueInput.value = data.defaultNudgeMs; + return; + } + try { + const response = await fetch('/api/config'); + if (!response.ok) throw new Error('Failed to fetch config'); + const data = await response.json(); + hwOffsetInput.value = data.hardwareOffsetMs; + autoSyncCheckbox.checked = data.autoSyncEnabled; + offsetInputs.h.value = data.timeturnerOffset.hours; + offsetInputs.m.value = data.timeturnerOffset.minutes; + offsetInputs.s.value = data.timeturnerOffset.seconds; + offsetInputs.f.value = data.timeturnerOffset.frames; + offsetInputs.ms.value = data.timeturnerOffset.milliseconds || 0; + nudgeValueInput.value = data.defaultNudgeMs; + } catch (error) { + console.error('Error fetching config:', error); + } + } + + async function saveConfig() { + const config = { + hardwareOffsetMs: parseInt(hwOffsetInput.value, 10) || 0, + autoSyncEnabled: autoSyncCheckbox.checked, + defaultNudgeMs: parseInt(nudgeValueInput.value, 10) || 0, + timeturnerOffset: { + hours: parseInt(offsetInputs.h.value, 10) || 0, + minutes: parseInt(offsetInputs.m.value, 10) || 0, + seconds: parseInt(offsetInputs.s.value, 10) || 0, + frames: parseInt(offsetInputs.f.value, 10) || 0, + milliseconds: parseInt(offsetInputs.ms.value, 10) || 0, + } + }; + + if (useMockData) { + console.log('Mock save:', config); + alert('Configuration saved (mock).'); + // We can also update the mock data in memory to see changes reflected + mockApiDataSets[currentMockSetKey].config = config; + return; + } + + try { + const response = await fetch('/api/config', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(config), + }); + if (!response.ok) throw new Error('Failed to save config'); + alert('Configuration saved.'); + } catch (error) { + console.error('Error saving config:', error); + alert('Error saving configuration.'); + } + } + + async function fetchLogs() { + if (useMockData) { + // Use a copy to avoid mutating the original mock data array + const logs = mockApiDataSets[currentMockSetKey].logs.slice(); + // Show latest 20 logs, with the newest at the top. + logs.reverse(); + statusElements.logs.textContent = logs.slice(0, 20).join('\n'); + return; + } + try { + const response = await fetch('/api/logs'); + if (!response.ok) throw new Error('Failed to fetch logs'); + const logs = await response.json(); + // Show latest 20 logs, with the newest at the top. + logs.reverse(); + statusElements.logs.textContent = logs.slice(0, 20).join('\n'); + } catch (error) { + console.error('Error fetching logs:', error); + statusElements.logs.textContent = 'Error fetching logs.'; + } + } + + async function triggerManualSync() { + syncMessage.textContent = 'Issuing sync command...'; + if (useMockData) { + syncMessage.textContent = 'Success: Manual sync triggered (mock).'; + setTimeout(() => { syncMessage.textContent = ''; }, 5000); + return; + } + try { + const response = await fetch('/api/sync', { method: 'POST' }); + const data = await response.json(); + if (response.ok) { + syncMessage.textContent = `Success: ${data.message}`; + } else { + syncMessage.textContent = `Error: ${data.message}`; + } + } catch (error) { + console.error('Error triggering sync:', error); + syncMessage.textContent = 'Failed to send sync command.'; + } + setTimeout(() => { syncMessage.textContent = ''; }, 5000); + } + + async function nudgeClock(ms) { + nudgeMessage.textContent = 'Nudging clock...'; + if (useMockData) { + nudgeMessage.textContent = `Success: Clock nudged by ${ms}ms (mock).`; + setTimeout(() => { nudgeMessage.textContent = ''; }, 3000); + return; + } + try { + const response = await fetch('/api/nudge_clock', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ microseconds: ms * 1000 }), + }); + const data = await response.json(); + if (response.ok) { + nudgeMessage.textContent = `Success: ${data.message}`; + } else { + nudgeMessage.textContent = `Error: ${data.message}`; + } + } catch (error) { + console.error('Error nudging clock:', error); + nudgeMessage.textContent = 'Failed to send nudge command.'; + } + setTimeout(() => { nudgeMessage.textContent = ''; }, 3000); + } + + async function setDate() { + const date = dateInput.value; + if (!date) { + alert('Please select a date.'); + return; + } + + dateMessage.textContent = 'Setting date...'; + if (useMockData) { + mockApiDataSets[currentMockSetKey].status.system_date = date; + dateMessage.textContent = `Success: Date set to ${date} (mock).`; + fetchStatus(); // re-render + setTimeout(() => { dateMessage.textContent = ''; }, 5000); + return; + } + try { + const response = await fetch('/api/set_date', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ date: date }), + }); + const data = await response.json(); + if (response.ok) { + dateMessage.textContent = `Success: ${data.message}`; + // Fetch status again to update the displayed date immediately + fetchStatus(); + } else { + dateMessage.textContent = `Error: ${data.message}`; + } + } catch (error) { + console.error('Error setting date:', error); + dateMessage.textContent = 'Failed to send date command.'; + } + setTimeout(() => { dateMessage.textContent = ''; }, 5000); + } + + saveConfigButton.addEventListener('click', saveConfig); + manualSyncButton.addEventListener('click', triggerManualSync); + nudgeDownButton.addEventListener('click', () => { + const ms = parseInt(nudgeValueInput.value, 10) || 0; + nudgeClock(-ms); + }); + nudgeUpButton.addEventListener('click', () => { + const ms = parseInt(nudgeValueInput.value, 10) || 0; + nudgeClock(ms); + }); + setDateButton.addEventListener('click', setDate); + + // --- Collapsible Section Listeners --- + controlsToggle.addEventListener('click', () => { + const isActive = controlsContent.classList.toggle('active'); + controlsToggle.classList.toggle('active', isActive); + }); + + logsToggle.addEventListener('click', () => { + const isActive = logsContent.classList.toggle('active'); + logsToggle.classList.toggle('active', isActive); + }); + + // Initial data load + setupMockControls(); + fetchStatus(); + fetchConfig(); + fetchLogs(); + + // Refresh data every 2 seconds if not using mock data + if (!useMockData) { + setInterval(fetchStatus, 2000); + setInterval(fetchLogs, 2000); + } + setInterval(animateClocks, 50); // High-frequency clock animation +}); diff --git a/static/style.css b/static/style.css new file mode 100644 index 0000000..bc53cce --- /dev/null +++ b/static/style.css @@ -0,0 +1,273 @@ +@font-face { + font-family: 'FuturaStdHeavy'; + src: url('assets/FuturaStdHeavy.otf') format('opentype'); +} + +@font-face { + font-family: 'Quartz'; + src: url('assets/quartz-ms-regular.ttf') format('truetype'); +} + +body { + font-family: 'FuturaStdHeavy', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; + background-color: #221f1f; + background-image: url('assets/HaveBlueTransWh.png'); + background-repeat: no-repeat; + background-position: bottom 20px right 20px; + background-attachment: fixed; + background-size: 100px; + color: #333; + margin: 0; + padding: 20px; + display: flex; + justify-content: center; +} + +.container { + width: 100%; + max-width: 960px; +} + +.header-logo { + display: block; + margin: 0 auto 20px auto; + max-width: 60%; +} + +.grid { + display: grid; + grid-template-columns: 1fr; + gap: 20px; +} + +.card { + background: #c5ced6; + border-radius: 8px; + padding: 20px; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); +} + +.card h2 { + margin-top: 0; + color: #1a7db6; +} + +#ltc-timecode, #system-clock { + font-family: 'Quartz', monospace; + font-size: 2em; + text-align: center; + letter-spacing: 2px; +} + +.card p, .card ul { + margin: 10px 0; +} + +.system-date-display { + text-align: center; + font-size: 1.5em; + font-family: 'Quartz', monospace; + letter-spacing: 2px; +} + +#interfaces { + text-align: center; + white-space: nowrap; + overflow-x: auto; + padding-bottom: 5px; /* Add some space for the scrollbar if it appears */ +} + +.full-width { + grid-column: 1 / -1; +} + +.control-group { + margin-bottom: 15px; + display: flex; + align-items: center; + gap: 10px; +} + +input[type="number"], +input[type="text"] { + padding: 8px; + border: 1px solid #9fb3c8; + border-radius: 4px; + background-color: #f0f4f8; + font-family: inherit; + font-size: 14px; + color: #333; + transition: border-color 0.2s, box-shadow 0.2s; +} + +input[type="number"]:focus, +input[type="text"]:focus { + outline: none; + border-color: #1a7db6; + box-shadow: 0 0 0 2px rgba(26, 125, 182, 0.2); +} + +input[type="number"] { + width: 80px; +} + +input[type="text"] { + width: auto; +} + +button { + padding: 8px 15px; + border: none; + border-radius: 4px; + background-color: #1a7db6; + color: white; + cursor: pointer; + font-size: 14px; + font-family: Arial, sans-serif; + font-weight: bold; + transition: background-color 0.2s; +} + +button:hover { + background-color: #166999; +} + +.offset-controls-container { + display: flex; + flex-wrap: wrap; + gap: 1.5rem; + align-items: center; +} + +.offset-control { + display: flex; + align-items: center; + gap: 5px; +} + +.offset-control input[type="number"] { + width: 40px; + text-align: center; +} + +.offset-control label { + font-size: 14px; + color: #333; +} + +#offset-ms { + width: 60px; +} + +#sync-message { + font-style: italic; + color: #555; +} + +.icon-group { + display: flex; + justify-content: center; + align-items: center; + gap: 20px; + margin: 10px 0; +} + +#delta-text { + text-align: center; +} + +#ltc-status, #ntp-active, #sync-status, #jitter-status, #frame-rate, #lock-ratio, #delta-status { + display: flex; + justify-content: center; + align-items: center; +} + +.status-icon { + width: 60px; + height: 60px; +} + +.collapsible-card { + padding: 0; +} + +.collapsible-card .toggle-header { + display: flex; + align-items: center; + gap: 15px; + padding: 20px; + cursor: pointer; + border-radius: 8px; +} + +.collapsible-card .toggle-header.active { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + border-bottom: 1px solid #eee; +} + +.collapsible-card .toggle-header:hover { + background-color: #e9e9f3; +} + +.toggle-icon { + width: 40px; + height: 40px; +} + +.header-icon { + width: 40px; + height: 40px; +} + +.card-header { + display: flex; + align-items: center; + gap: 15px; +} + +.log-box { + white-space: pre-wrap; + overflow-wrap: break-word; +} + +.collapsible-content { + display: none; + padding: 20px; +} + +.collapsible-content.active { + display: block; +} + +footer { + text-align: center; + margin-top: 40px; + padding-top: 20px; + border-top: 1px solid #444; + color: #c5ced6; +} + +footer p { + margin: 0; +} + +footer a { + color: #1a7db6; + text-decoration: none; +} + +footer a:hover { + text-decoration: underline; +} + +/* Status-specific colors */ +#sync-status.in-sync, #jitter-status.good { font-weight: bold; color: #28a745; } +#sync-status.clock-ahead, #sync-status.clock-behind, #jitter-status.average { font-weight: bold; color: #ffc107; } +#sync-status.timeturning { font-weight: bold; color: #17a2b8; } +#jitter-status.bad { font-weight: bold; color: #dc3545; } +#ntp-active.active { font-weight: bold; color: #28a745; } +#ntp-active.inactive { font-weight: bold; color: #dc3545; } + +#ltc-status.lock { font-weight: bold; color: #28a745; } +#ltc-status.free { font-weight: bold; color: #ffc107; } diff --git a/timeturner.py b/timeturner.py index 92f8cb2..49fe40b 100644 --- a/timeturner.py +++ b/timeturner.py @@ -9,10 +9,11 @@ import threading import queue import json from collections import deque +from fractions import Fraction SERIAL_PORT = None BAUD_RATE = 115200 -FRAME_RATE = 25.0 +FRAME_RATE = Fraction(25, 1) CONFIG_PATH = "config.json" sync_pending = False @@ -30,6 +31,14 @@ sync_enabled = False last_match_check = 0 timecode_match_status = "UNKNOWN" +def framerate_str_to_fraction(s): + if s == "23.98": return Fraction(24000, 1001) + if s == "24.00": return Fraction(24, 1) + if s == "25.00": return Fraction(25, 1) + if s == "29.97": return Fraction(30000, 1001) + if s == "30.00": return Fraction(30, 1) + return None + def load_config(): global hardware_offset_ms try: @@ -50,13 +59,16 @@ def parse_ltc_line(line): if not match: return None status, hh, mm, ss, ff, fps = match.groups() + rate = framerate_str_to_fraction(fps) + if not rate: + return None return { "status": status, "hours": int(hh), "minutes": int(mm), "seconds": int(ss), "frames": int(ff), - "frame_rate": float(fps) + "frame_rate": rate } def serial_thread(port, baud, q): @@ -154,7 +166,7 @@ def run_curses(stdscr): parsed, arrival_time = latest_ltc stdscr.addstr(3, 2, f"LTC Status : {parsed['status']}") stdscr.addstr(4, 2, f"LTC Timecode : {parsed['hours']:02}:{parsed['minutes']:02}:{parsed['seconds']:02}:{parsed['frames']:02}") - stdscr.addstr(5, 2, f"Frame Rate : {FRAME_RATE:.2f}fps") + stdscr.addstr(5, 2, f"Frame Rate : {float(FRAME_RATE):.2f}fps") stdscr.addstr(6, 2, f"System Clock : {format_time(get_system_time())}") if ltc_locked and sync_enabled and offset_history: diff --git a/timeturner.service b/timeturner.service new file mode 100644 index 0000000..f3daec8 --- /dev/null +++ b/timeturner.service @@ -0,0 +1,18 @@ +[Unit] +Description=NTP TimeTurner Daemon +After=network.target + +[Service] +Type=forking +# The 'timeturner daemon' command starts the background process. +# It requires 'config.yml' and the 'static/' web assets directory +# to be present in the WorkingDirectory. +ExecStart=/opt/timeturner/timeturner daemon +WorkingDirectory=/opt/timeturner +PIDFile=/opt/timeturner/ntp_timeturner.pid +Restart=always +User=root +Group=root + +[Install] +WantedBy=multi-user.target diff --git a/update.sh b/update.sh new file mode 100644 index 0000000..ad9fcb9 --- /dev/null +++ b/update.sh @@ -0,0 +1,28 @@ +#!/bin/bash +set -e + +echo "--- TimeTurner Update Script ---" + +# 1. Fetch the latest changes from the git repository +echo "πŸ”„ Pulling latest changes from GitHub..." +git pull origin main + +# 2. Rebuild the release binary +echo "πŸ“¦ Building release binary with Cargo..." +cargo build --release + +# 3. Stop the currently running service to release the file lock +echo "πŸ›‘ Stopping TimeTurner service..." +sudo systemctl stop timeturner.service || true + +# 4. Copy the new binary to the installation directory +echo "πŸš€ Deploying new binary..." +sudo cp target/release/ntp_timeturner /opt/timeturner/timeturner + +# 5. Restart the service with the new binary +echo "βœ… Restarting TimeTurner service..." +sudo systemctl restart timeturner.service + +echo "" +echo "Update complete. To check the status of the service, run:" +echo " systemctl status timeturner.service" \ No newline at end of file