From d264cd93cd4edcc86c91feb8cef2e7dd44bec22e Mon Sep 17 00:00:00 2001 From: Nico Meister Date: Sun, 18 Oct 2026 17:05:44 +0200 Subject: [PATCH] MBMNET-App v2.8.2: Quellcode (GPLv3) Co-Authored-By: Claude Opus 5.5 --- .gitignore | 14 + LICENSE | 674 ++++++++++++ Makefile | 107 ++ README.md | 41 + assets/banner.png | Bin 0 -> 21396 bytes assets/banner.wav | Bin 0 -> 37970 bytes assets/splash.png | Bin 0 -> 16009 bytes cia.rsf | 272 +++++ ftpmodul/Makefile | 27 + ftpmodul/ftpmodul.rsf | 162 +++ ftpmodul/source/ftp.c | 335 ++++++ ftpmodul/source/ftp.h | 10 + ftpmodul/source/ftpstatus.h | 28 + ftpmodul/source/main.c | 181 ++++ icon.png | Bin 0 -> 3029 bytes release.sh | 66 ++ source/admin.c | 57 + source/admin.h | 9 + source/blz.c | 58 + source/blz.h | 6 + source/frdswitch.c | 245 +++++ source/frdswitch.h | 27 + source/ftpcore.c | 2 + source/ftpctl.c | 109 ++ source/ftpctl.h | 16 + source/lumaconfig.c | 135 +++ source/lumaconfig.h | 21 + source/main.c | 547 ++++++++++ source/nnid.c | 217 ++++ source/nnid.h | 23 + source/olvpatch.c | 109 ++ source/olvpatch.h | 11 + source/patcher.c | 885 ++++++++++++++++ source/patcher.h | 30 + source/relaunch.c | 48 + source/relaunch.h | 6 + source/splash_data.c | 1985 +++++++++++++++++++++++++++++++++++ source/spotpass.c | 249 +++++ source/spotpass.h | 17 + source/update.c | 277 +++++ source/update.h | 28 + tools/Dockerfile | 20 + 42 files changed, 7054 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README.md create mode 100644 assets/banner.png create mode 100644 assets/banner.wav create mode 100644 assets/splash.png create mode 100644 cia.rsf create mode 100644 ftpmodul/Makefile create mode 100644 ftpmodul/ftpmodul.rsf create mode 100644 ftpmodul/source/ftp.c create mode 100644 ftpmodul/source/ftp.h create mode 100644 ftpmodul/source/ftpstatus.h create mode 100644 ftpmodul/source/main.c create mode 100644 icon.png create mode 100755 release.sh create mode 100644 source/admin.c create mode 100644 source/admin.h create mode 100644 source/blz.c create mode 100644 source/blz.h create mode 100644 source/frdswitch.c create mode 100644 source/frdswitch.h create mode 100644 source/ftpcore.c create mode 100644 source/ftpctl.c create mode 100644 source/ftpctl.h create mode 100644 source/lumaconfig.c create mode 100644 source/lumaconfig.h create mode 100644 source/main.c create mode 100644 source/nnid.c create mode 100644 source/nnid.h create mode 100644 source/olvpatch.c create mode 100644 source/olvpatch.h create mode 100644 source/patcher.c create mode 100644 source/patcher.h create mode 100644 source/relaunch.c create mode 100644 source/relaunch.h create mode 100644 source/splash_data.c create mode 100644 source/spotpass.c create mode 100644 source/spotpass.h create mode 100644 source/update.c create mode 100644 source/update.h create mode 100644 tools/Dockerfile diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ccb0a48 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +# Build-Ergebnisse +build/ +*.3dsx +*.cia +*.elf +*.smdh +*.o +*.bin +ftpmodul/build/ + +# Alter Versuch (nicht mehr in Benutzung) +unbenutzt-kontowechsel/ + +.DS_Store diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..94a9ed0 --- /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/Makefile b/Makefile new file mode 100644 index 0000000..a910d90 --- /dev/null +++ b/Makefile @@ -0,0 +1,107 @@ +#--------------------------------------------------------------------------------- +# MBMNET Switcher - 3DS Homebrew (.3dsx) +# Benötigt devkitPro mit dem Paket "3ds-dev" (libctru, citro3d, citro2d). +#--------------------------------------------------------------------------------- +.SUFFIXES: + +ifeq ($(strip $(DEVKITARM)),) +$(error "DEVKITARM ist nicht gesetzt. Bitte devkitPro installieren.") +endif + +TOPDIR ?= $(CURDIR) +include $(DEVKITARM)/3ds_rules + +TARGET := mbmnet +BUILD := build +SOURCES := source +INCLUDES := source + +# Bei jedem Release erhöhen - das Auto-Update vergleicht diese Nummer +VERSION := 2.8.2 + +APP_TITLE := MBMNET +APP_DESCRIPTION := Dein eigenes 3DS-Netzwerk (v$(VERSION)) +APP_AUTHOR := MBMNET +ICON := icon.png + +# CIA: feste Titel-ID 000400000FB4E000 +APP_PRODUCT_CODE := CTR-H-MBMN +APP_UNIQUE_ID := 0xFB4E0 +VERSION_PARTS := $(subst ., ,$(VERSION)) +# Titelversion für die CIA. Muss bei jedem Release steigen, sonst verweigert der 3DS die +# Installation (Downgrade). makerom übernimmt die mittlere Stelle nicht, deshalb kodieren wir +# Haupt- und Unterversion zusammen in der ersten Stelle: 2.2.3 -> 22.0.3 (Unterversion max. 9). +TITLE_MAJOR := $(shell echo $$(( $(word 1,$(VERSION_PARTS)) * 10 + $(word 2,$(VERSION_PARTS)) ))) +VERSION_NUM := $(shell echo $$(( ($(TITLE_MAJOR) << 10) | $(word 3,$(VERSION_PARTS)) ))) + +ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft +CFLAGS := -g -Wall -O2 -mword-relocations -ffunction-sections $(ARCH) $(INCLUDE) -D__3DS__ -DAPP_VERSION=\"$(VERSION)\" +ASFLAGS := -g $(ARCH) +LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) +LIBS := -lcitro2d -lcitro3d -lctru -lm +LIBDIRS := $(CTRULIB) $(PORTLIBS) + +ifneq ($(BUILD),$(notdir $(CURDIR))) + +export OUTPUT := $(CURDIR)/$(TARGET) +export TOPDIR := $(CURDIR) +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) +export DEPSDIR := $(CURDIR)/$(BUILD) + +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +export LD := $(CC) +export OFILES := $(CFILES:.c=.o) +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) +export APP_ICON := $(TOPDIR)/$(ICON) +export _3DSXDEPS := $(OUTPUT).smdh +export _3DSXFLAGS += --smdh=$(OUTPUT).smdh + +.PHONY: all clean cia $(BUILD) + +all: $(BUILD) + +# CIA zum Installieren mit FBI o. Ä. (braucht makerom und bannertool, siehe tools/Dockerfile) +cia: $(BUILD) + @bannertool makebanner -i assets/banner.png -a assets/banner.wav -o $(BUILD)/banner.bnr + @bannertool makesmdh -s "$(APP_TITLE)" -l "$(APP_DESCRIPTION)" -p "$(APP_AUTHOR)" -i $(ICON) -o $(BUILD)/icon.icn + @makerom -f cia -o $(TARGET).cia -elf $(TARGET).elf -rsf cia.rsf -target t -exefslogo \ + -icon $(BUILD)/icon.icn -banner $(BUILD)/banner.bnr \ + -DAPP_TITLE="$(APP_TITLE)" -DAPP_PRODUCT_CODE="$(APP_PRODUCT_CODE)" -DAPP_UNIQUE_ID="$(APP_UNIQUE_ID)" \ + -ver $(VERSION_NUM) + @echo built ... $(TARGET).cia + +$(BUILD): + @mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +# FTP-Hintergrund-Modul bauen und als Byte-Feld in die App einbetten +ftpmodul/ftpmodul.cxi: $(wildcard ftpmodul/source/*) ftpmodul/ftpmodul.rsf ftpmodul/Makefile + @$(MAKE) --no-print-directory -C ftpmodul + +source/ftpmodul_data.c: ftpmodul/ftpmodul.cxi + @echo "// Automatisch erzeugt aus ftpmodul/ftpmodul.cxi - nicht bearbeiten" > $@ + @echo "#include <3ds/types.h>" >> $@ + @echo "const u8 ftpmodul_cxi[] __attribute__((aligned(4))) = {" >> $@ + @od -An -v -tx1 $< | sed -e 's/ \([0-9a-f][0-9a-f]\)/0x\1,/g' >> $@ + @echo "};" >> $@ + @echo "const u32 ftpmodul_cxi_size = sizeof(ftpmodul_cxi);" >> $@ + @echo "const u32 ftpmodul_status_addr = $$(cat ftpmodul/ftpmodul.sym);" >> $@ + +clean: + @echo clean ... + @rm -fr $(BUILD) $(TARGET).3dsx $(TARGET).smdh $(TARGET).elf $(TARGET).cia source/ftpmodul_data.c + @$(MAKE) --no-print-directory -C ftpmodul clean + +else + +DEPENDS := $(OFILES:.o=.d) + +$(OUTPUT).3dsx : $(OUTPUT).elf $(_3DSXDEPS) +$(OUTPUT).elf : $(OFILES) + +-include $(DEPENDS) + +endif diff --git a/README.md b/README.md new file mode 100644 index 0000000..38c0313 --- /dev/null +++ b/README.md @@ -0,0 +1,41 @@ +# MBMNET-App (Quellcode) + +Die 3DS-App von MBMNET: schaltet den 3DS zwischen MBMNET und Nintendo um, legt ein eigenes +MBMNET-Freundekonto an, aktiviert Miiverse und SpotPass über MBMNET und aktualisiert sich selbst. + +Fertige Versionen (`.cia` / `.3dsx`) und Anleitung: [MrMaho/MBMNET](https://git.mbm.wtf/MrMaho/MBMNET) + +## Bauen + +Am einfachsten mit Docker (enthält devkitARM, libctru, makerom und bannertool): + +```bash +docker build -t mbmnet-3ds-build tools +docker run --rm -v "$PWD":/app -w /app mbmnet-3ds-build bash -c 'make && make cia' +``` + +Ergebnis: `mbmnet.3dsx` und `mbmnet.cia`. Version steht in `Makefile` (`VERSION`). + +`release.sh` baut, legt die Dateien ins Repo `MBMNET` und erstellt dort ein Gitea-Release. + +## Aufbau + +| Datei | Was | +|---|---| +| `source/main.c` | Oberfläche, Umschalten MBMNET / Nintendo, Werkzeuge | +| `source/patcher.c` | Luma3DS-Patches (`/luma/sysmodules`, `/luma/titles`) schreiben und entfernen | +| `source/olvpatch.c` | Miiverse-Patch (Discovery-Adresse und MBMNET-Zertifikat) | +| `source/frdswitch.c` | Eigenes MBMNET-Freundekonto | +| `source/nnid.c` | Verknüpfte Nintendo Network ID lösen | +| `source/spotpass.c` | SpotPass-Aufgabe für MBMNET-Mitteilungen | +| `source/lumaconfig.c` | Spiel-Patches in der Luma-Konfiguration einschalten | +| `source/update.c` | Selbst-Update aus dem Repo `MBMNET` | +| `source/admin.c` | Entwickler-Werkzeuge nur für Admins | +| `ftpmodul/` | Kleiner FTP-Server für die Entwickler-Werkzeuge | + +## Lizenz + +GPLv3, siehe `LICENSE`. Die Miiverse-Patches stammen aus Pretendos +[Nimbus](https://github.com/PretendoNetwork/Nimbus) (GPLv3); das eigene Freundekonto ist nach Nimbus' Vorbild gebaut. + +Große Teile des Codes wurden mit Hilfe eines KI-Assistenten (Claude) geschrieben. diff --git a/assets/banner.png b/assets/banner.png new file mode 100644 index 0000000000000000000000000000000000000000..2fbb6dda36cfff7faf811b493d0e7e2c491da7b9 GIT binary patch literal 21396 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 nCpE;AsX4x&_PoMm4v@R@c)Kr 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%0AuKSGp}f$q*zJtsmTia-Ve6RSWQR9Le7E1}g zo7Cds8CUmwbEcSjDgA0*knaF}#JV7AUVPp7^HC3jw;NNqR`diEOFpYR#LjM8!Ntse zX;;(R=C$@7p^jNDMxywL_%Bf*Ax>iwKapO6>X0x^FL~V03VLNdO?!}@pS#*~2Awpg zMa+#WiW8#-hqN?};{T=hq3)!kHceXZnOjI@S5NT?r4qW zTi#TA=bX3gM&*pF zIp3X(_C&ubw0TTWT*v4Ip$E;Yh0Y8`-5_yTl0W%sIS%KBW%kXOm($Q$QvIO25OOy9 zRc!C*`=NgG7hy3IOT8s6aR;ThKh@DLZ)@iIjJ7#v9PO1f;Y)CE^rF}S(Q0TbOL5&5 zrY4mI4E=!e)4#;&%Zto%IW zCYoAITIQ)}f0k1*>p^yU;a&d>`kc8$_<-op=;-h$TY(;NPMBn`L27Bsq%iMWdym{D zSr4<96bAYCQlCtd!n{%bsCwZ8Z8Z&bxnQunj%2)+C++u+E6UFOll45iQsHRdGb9`D zg)WWy7}Y2Iux+tnI#+{Uf<}@O+H~PDf1*&$hia zT;}@FJJ5XcNjoT?_8oEP^7m#JWbZ7f;w?j389ImTid+!2I=p01w9&&YqR+s5H-kmF zyuX2SXFij|=JYJs>luhA>vsjmM|OzX9X=#zsIdxvf_{Wfl8U&sa@_yPS*~DAPKlgi z1;L(wwY|F3pnVZhQ76Oq1f4ZbEv{;9qaN(9A4 z{E56A{wc_Byuho_EBgRlflOsfKytM&Y?eDY=YGD~ouDfGNZa=C{gF4q^}!8HZoV|c z?o42_H$DXS&CU*yg3y1`3Le+gZgc*+lT-FS7P80;Bu zFP--#XHI^i>xK-yE6bv=@W`v-qk~_VrU;9`LIuc2&Z$4de?7#$C(oKYH2wkqF~LwV{;YU0W2A-!`{%ekbP$=>s#_JUDcA#G&vz!5z(_ zkjjjq%7Bd|Yx|{x-WbQ~{I$8w@;#0xqJ_C)dJ|GAVpDi}@J4eT$OM;Dbx<|ZN7JN4 z-!TVU@G-Yx{w_yZu{|vsYlXZGpBK)Cyfe?yHDwP|ZBSdXUh5(6^;LDwFNn=+nBU5= zC9sjIYuq0^C45+TVu;0ZS2vA)2zEDw+|y3W5&m0FrC?Ov-}zb*6ZnSa8@S-G@K)jV zLt0sg?gX1kjYBhtT_f@ue^b}=!W((*^RE}p@F${2`q4ob!%ByD3t41otWRMPJs+(l z5xBiV{Lfw9LQ{VK{Fy~=-$bI9RL6xnmU`r4E9yT+?VR@);#Wkf5p^IcVPE)=I-nxtIxAWKLn~OwmB;F~kwN4E^ z9kw(i(MlN>aKq`VK#^DCWVMOd-ZQ2svfxyHs(rC{qL#rITKLe}Ve3LVTN@d!ajWR( zklCNY!_{NrD^Fh0w1T(!H|(L_w`wK6wPkZi^RO);3#{`DMcg_1H*^$V;KQm;YT+I3 z_*&r4-(f%HsiMx|j+x^_%wbzYPFrsoO7Wj*H`FRQ_>Ve5y64Ss)Gkacm}76@*`d5* zS@Y50ccGg@K3M~X0bt7lMI(kpXb+_tz5&iXg`EqA+4J0t63-4Yl?&bwx-LYqRyFS6 zOE7U%5X73cT9kak_ruB9mlbriZ*)(RCo^}9XM@^?E(wXZ{bPK`w_~bN31B1hwQ+K^ zzpHDs{Z2tEdjog2^n#8yRu1Aqr-wAO9X9HP=}a4{5^6)vYWL)o{@1P#cB!C=-RT-2 zm7u2^&e?8;3=ipR`(bP%9E3@M`e-2eshJh8znQyUQO&|e_7kpO;sWZEzPxQrNav90 zu)Hu^c+JeE+QN<%hkHU@bK8BiXhz}R_TjGnVk)YtKW2>ysS~o^*3@)KkeMA&e=R2! z@IK{Hpo%BRai_4Yy^Jd>&;)JJ6}LVKjt@C(n`$Z)O0k!y(P$^>0(ZWoc*HZu!PdyrJax-goBNci8`NR`C~Up}c158MHR|o2{(*nJ$ejL!W@^?<4-MZkGo8D!A$t zU9q=xzVi*zW^xlve%rv{6kBIA)&+4b>6^ex9oVWBz|PVR*P5cQ_Oi|?zHjOuHp{rt zRyjD;HpBdvzA-n7egzysN1AB$c=%?+Dd6)hWcZPPs^ifUNrTZ?Uz<2jL zN5`T<$2@OWC6;Mu=x$vT^vU+i{8Imsdq=ZW6!?+XTB0&I(8QDDm|v9UsP6qKuc9yM z^DG^Lp4%j|s%Ig`h=N&!0VJS}QXT|Oc^Ww{6#a0xJ;P*~Dyg4su?F3;g;>fPs`HUd zMXD+S&V)}Z#l#Trzs~HUZ;neIk2HqbsWVt!+fLcaS$Z3W^9`7$R0Fga`gujL=Qh*p zcg8z@IA(a3NomNe+hJaA+iq)QS#H?Q4`q6TzuN-dp}hJ*{NwHH>gh;zH1)(uz0e{d z+1${!z}Cfb(eR941v3Rb(IK)7k5o%bO?~HFTOIk1V9z!26AADaOg`%{+YrkygUDZG zR>IW6Md-~RQ0GWTd?xp2N5GNg?k;vB?y<3_wX|)vrJS*cK(n`~1+csK8ymG)dAR?HyO%TGxyyYZ&<*$F z+8cQ*XIpIPU|c4Y`yX}qK?1nGHd6l2pXAx=tm&NXZX5WiePzEGE?WLrS6C()uLxaP z7tq^mVkKj=3vxnWfhWt^**Vay`iE+r*?xw;maEoPmMz9~VJ>T?PXixJCOb7ro*nq@ zso+1%G+TXw@A9TfPmPrVjZ}tFL?v)b>tyZE@CgkMu84+cN*? zPni2!ms{Q$>+0UKExhy>&N%6!r3wYbxq@$M|&38fwEwK+`z%S;Pr+NewBme57O7AKLKSW`ZTt$lsm zMpuOUq_3&+o+83V(*w&mORVXpt|NB{CKF1dMWh#GcuCS>-wAguSEzfkFHP=2EfXr6 zR#*mFs+iJsv$#ieF!dMONM_=R>Lf|^iSCiEFn1&0LOBJQg}26bmX4OcO?v%dE|X3M zyW0=m;TUX+cJ;UL>~cl9ZN8H7NVJt7W3*c8S-P4k>ECc1Q=4jq&cJ-@PgO6U^l$gP zaTRxGdEZEW636R|Z_TAFgH2uZ0j?C&p6ZHj0v|VPo#EEycvyFN_g(KyX$d*X9W<;p zTP)*D)AYspR?HA;AnbhQ!nW)Vxoe=Nx1PI>`(JNqDU4L+>Kj^_J?0sv9s1V%7}#hX z1KAKFqqSf1(ZF)=RCinVZ0}F;1ir<7(KF`H<^`tfFu}2&Sr6Un-_R-9s>Lf};H&q% zd!T!ucazua9oFVljrSZ9jho(uUe++Yl)oeq^LlaHyw9fEA_{dJDC74@137Y~T;F)&>B-l1%y?gvRWfJ<2E7X@YwKDBC zqzfXunKnS2y$X|OjkMQtMxcT3rpMr&?!P5lP(N;)-fOI3I$@x7vD|q&2Bsk&5HJ2m zGbt6s#lBomh_|bMqI{b8*@pUC#zfO)LxQd$_Xc)4JEB*_0Ge;5OcS5^BD}@C)&1q< zwqzrlqg!Y+n(i3t>xOUzbR(G6`2xExx3wk89ntJ><*fi^N3P_+<=FMQW=6O1KSM9w zGENWG*D&Z2Rwe1$U4@l8`)7L_cq#ueX)}Jx)X)jWug2$wDZ1mZb3K9@54%9k2#-!AVR-xIN()|h_FQ-*HFXNGsWiu_^bHuz8j#F{1ef!a|% z5m@EB=DqCODi*5g)KvbCzLN2gAye0mf5d#GPJ$QP2$h9XT_+a?9{Ij_&-zA+`_!dW z3_ne;Gu|@zbz}H+CLg*-(Xf$w6US*UWkgfGSmaElKzk3qJf7wDVn9} z$I#n20l7m-Cc%`!bGi+a!H)z zukSnUa|fO&(~+6mt6Of^30r#q@r__(J`FlocfmXCfSq}dc*Z}(ci#6duvAGvm)Wkm zo`zM13i?!j0BnOhVZQqr^hNG!=aj#sTtB?M?_!{t@{06j^}5oAnTDErnV-iFr4ewH z_b^$Pu4TgfSW@7U?}2YyK&Q+kEPGe*>xUT{>O+M+Fo|V@Oz;Op5Ee(M=cNIG-@aGA zxdGtY~4YH9gPpt`@n*EKLuUX2m+o$sMfFtpS65(4Zin0grjk#00h zt{hi~$id}&mi+*c5jc|PTc4Z_SXn# zl3(jVH{f%0dHQzxMM7nc23wvD8P-zRl%cfG@(S^RzqG$x;GJ|%V`(RMM)y+RM!!X9 z%f&LYV46&TX)@@d!u@B8=pq%S>$mFSZ9J(7R|& zV45p2(8nJem?xFe22&|sUdX)zE&;qxJE@G9mIk)?BLg+0W9nmclf5N0(O1^L6RvVA zm=`dakOVWbCh|!8r5u;82QI>AhD-mbGtgLeju4|y*8dXTa)+2d)IG4f$KV~ZG_#s2 z6$C!QIVG`*S^*`n^#qSDQlBm4z`n2#CdR73)Mgd9^YzpSIUe?769Xxtq-2p#jLN^z z8T1a=zWmM@=YU0p0M5$gv23Y-%+D&0vvW)?q1m#b5SGQ63sN&BF4o&}o$1Mx%k8q8!33^WYv z76&Rp#6{QQo9jO5kgh&oifusJp%xf7ZbD6fn79w(!gB4ra!o2NZVB`k*UKNZJ;Gsf0O-652Y4EkMbf+*}VjP#>jKT zhk{Zz8 zwF@`+9F}L6!}LKcRNiG^N_3bySNMnbpA1>taYq)nzRjAW?K!^JP%m!Z5!qowCkaR+v zD$P&^;XTw6b{XFhzI_*$#WV+79soV&lMolaY7Jo~x4Lvw94GZq%Hsi48@4x0*Jbg? zIGO1Uet86RYcIhjun&H};Hun9dM%EWYAdpqLqNek4uDKW@tc7hv@kTCg3XJtDvPrl3yGm(aJ9EENK2C z{1VO={yA5j-A1>AN+|-pfN7i7_?KEkc_x{qAyS?^Mw^0$GDo=g{2TrQ*MdDs_k~(M z7NSyT_{9jM4g7!YocW*5RsYA&IiJsGtTndC)>x(#?n-Imj+pEzvSjS(wl~I}yEG9p zMHrGIDx+kZZrze(DO1M2P9ma|Y}tiepU+vo&++~K3Ev;D9uL3tIFDwRAD<(%_+ zy`l@TZfcnER%AOaxm^J6#ZNj?KhfsF(KKQQ67A%s0Ijto0xA_QIiP2AV#GO?1+X z(l^83V+&#f!^Zjt`>Cwq?+W^}GT(3E9p{z*Nlt&coGGQ9tM7_LxGdH?Owx<(aCzBV z8gxwfE78C>z-f=ipo9C|w#c^WN4O}M+6;knq;;o9h?$r1N?w+ALT8HD}<*t1n& z`IbeO)5A@$&CH=_L1;VypUwIQnxDeXZ#4aMQq(Ez z9`=k<&1zR424rTiKByR+_NJ*m@?AReIkb3Z?Gf0rO{4U%PuMQ1Zr*Uds_6F#Rt8mr z>)rx26jj3muvk8D5$v3$`uS*LI0%NMGCkY@dC6-QEDDkW<$ng3b{X7`Yw#&cx>9z# zo)FCsM}!TcllnooSZ?<24(0^a$@q=1XIG)dj=}V(N)11&7s2z)3?GQL>mqK9eBVn5 zvRGNs->u$<3-vf?TEm(030us3AMFX>2x~pLS8&R@# zN6&O3Iup(gt4HtZuWTjR+}rB+52^+C`{&hKx&QyT!fkjjYGr)wML8(e#_3u1f~e?y z>UZY1Kk93>mAc%XS!@R_I@qzFKOVNl|=zD*5$+fny80I$65J+4s25~R3-U-P(0}3*C#)U$-&_6IMv}N zd%)!AY0*`_XA-R03Zl8v-bLRFdibecX;qGiwK6l#408UW`BpEB{HRJ)N^donTqX4r zY}d%|Z25iHb9qoiAdK>HMfdR6X+aGPBKHmaDx@{#C!9-`%?(SCa8ef*0r@ zC0#We>EEI{(LK@M(R7pJw#b>@QvZxU&>!G6QVmgK)#9YK%vB+i@5F1UY4nfid^FO$ z;y#c=VE6vw5B5iRZB+}I4Og$wo1+e=^!la}ajGAkh`O0BZnSLez33PC>3$}e)De#Q zgP>_GT&e!{8Iz*ZqsGzCQB(7fdrH>ydieSN5WF1*;^DFoglgE0t=ubii0KGMTSf<> z`%I!smKGNDT0S$|8?Dm8azoIR4^wO=lhaWBUeqDl8@W9U@aMuHe+eu< zPEXuPU-$&4wW<0)QO{^cc3vQuDB2pG z*SU73$X4gQxBLPAQgUtzc2jYrRqbx zaoTYodjvkzQJA_%^|fdcE4S-mwx4LJR(XT{-u{=~YPAB@PiLmKUr|+Dus$k>k}$#Z zqjkC?XsWK>@zVTm{(3mvYhlQC19vBwFO98Y%YgfwXiJofl4)K&|7m|SyyE?^SqE^QJqL%b3TN+@IBMiY zyQ0}z*+XtMJ{nd17XCKxHyDC~d#S2;B;>lfc|AIH%0M6FSCQJW;2f}z=VCJ|XGE`T+`Z#i2#{r@|vu!fmxOLnnWZ7A8 zZ*N3LqkroS=0(>={;ZC9wf#Mwg|}G^{`$S3X%iE{`%J=XbWuKam|gCT%cBZ52Q98u#Js;579<>Z6AmV>gMOYCPQO-QHcy zY)?^_8#37+bmLITB-je33*WSt?qz1M}`_>J-z;4{c4@p$Vr3JPYkLbLAMy6%Nm0-1 zs4|$BTQRkrV0K7ky6$CW>$PsR zJ#{i{)FknZl-_^6^*DVDP?O|#v>1iV`lVF+4EvVZs9VCVu4wvMDL#~^)k65#k9))6 z4i`{u?_kDRNzP9o>k4#d-3Oc9UhY=e-b(n_FROVdiF(2}yg~i>qRD?Fs1P?8mh1B(l*=Gl$ollH`i;0PsP`uK7+GL3>NP|xQaK;J!Y03 ztuJY7c;}MOs}^3i*V=nueGlqK)4Mf(10$*7CGBHW@v-_(eZh2dr^)1cUKT5J)E=A` z#^M*`Tmfgw)3zEFZxy~9C-qU&)NL2FRaGyOl}mADCnJ7WFozZeBOkiz?B^o$xBgTg)gOb< zG_g@`S5JFQani8p$v=R9T%5^eF}(Wmc+eHao8_o}&+N2~#3K2HYT`A5g?e3L z+(uW*<@`4jpN&dp11qPQHMY9QBI_RV8lWdhME|ftv;cP(s17Y%jy-1T!kqs_Pc(~c z5j-%mR86lwE*y7qhw}yVKp85|*W~;vdj-#oAM|nkGQ94K?iu_`?(pvScB^XikM&gB za-8PBW#_-6iarB3{)8T3GVPBp1%7*icdxfk)l!4xcQAP?(7*E8`Tb}i;Ir$~da!xH zZg7<)jBQl|{lf!l1RgtGsf>TaOCCWc-$#ao`W(8BZn#`XSzDb_mAxNSiW&>*doeSH zu;s_{{`VMtsff8u#<#K4!AKePqblniP>sl>Bk*ODK+_Mf&JC>kd9e6z=&t6Ub`0v2 zNN!doSlNv8$M0eg2z9WOr{Nv-oLzyZjYb_($M$hwh!ezKv9gVN2W?#j2o+%D9nSN^ znJ^zRp6P(Q$&>DVu}kKtnEFAr&RDvwvz34SOL{d$0)6SH(kGKh9waiwR zRDtS*s;N+ARF^7tf|Er(Hwz_3ds7A%n7~$dgYnUM75|xis;l};ddwJwPDH2BLNsPS zufp1|Y}&$xzs+?JljRHQ2nvCo_|ueNUVa$don>}t4d>UhLs77_HJ40i8;XouDukVQ zer%LwQTnEUyYn!uJHhKNXJ18M(bk+aXKW48MK)L8Sn{@NJ>1zkMsi16LzPg2@vs~SLOn3Dk{jVo_Ff|TlF2ns+ve^$F-YF0CJ-eb4bU+Z7WY!c z&Z3a%!hSx=d_5j#muB{1*H(0v6;WfPtD-1vPograL-#z-?C=~jR!cbKZ?N*8Xem-e zQ(2V1JqX>@IA)=LqY^3fRoXS1vGa@f$<)Co#|BDQdFD*cD@oi z%cA%{tup29VSCX1EWRY7T~q~}g>L7@qY0HUhAQN3GI@b5Pu71)9`CZ7-8S*DtgAXu zL389CpuQQEF>*)P`3K!{^buRkT63G-WWR8$#oMx)YKvNE37PZ}lS6sVbjR@bd5r#9 z4~_2zQw$A2j>|#uQBJjBx3T zR)FP7py>~EJ?*KtPuWu@-*_k|UURSDN)z&%Dyr4=r2kTvtFrPGeW4rq*^PR?(?~pA zMo@8{k{8J3JDGt~cz@{%LKPVK8rQKu?EtIIK2$W*?DMXRcnoDqZKAY+oZHBZQG+UW zo|8p7`#Fm9(jjBbB-_a~M^98BYoK`g7A@cR%oxew?jq`y(acz{*)nt{!z|R?J5M1BlIX;-M5+Q-h<#2LCiEncyAMaG4Eehh%r^s>uO>0u zmIh6~aGTJU+l;=pEGX?{FWEfz5&L;aMslxACzIX;%Vj{*Z%hQ8dEXeygj)ig%^!A^ z%NFhBZocVWIShsObS8&#py>~kO1(G(jirhwf|Q@>v*XC*@8lI$j>6mKZLnM(jGU$~ z44~dlw)gY*pR@&bjvFfKq4GJ$%706rX}uK)6<}l|{!AVn>{04dYrEaP>3WMAsEJO> zJ!pK2GvTxap%RSbajLtWTuNm}TiQG-V>?k+E(A}zQ5_|6yWNg1?}3pm%=U#^vnOp0 zJjK4YLtPW$$#>*WxPXx-%=H~Xs1HVVFyYl;mpY@NYGGG_&@AI}dx~CR4ml|44oMe}F$Zcq>?&37towIxqFjBzIr=SHIWFKbbr*!$! z;-DB#oVMVrRFnMZjaOGuFmjNbZ^HZINc&HI(L&qAd19;RE7yVNsj?P#IDM(M#i=-l z+4%Ru8n=q)^=yya@0%9 z(V$J24|3a+PPHuwnvS#c-BG$_E2|DtNtp!uRP`lxks2EB79sDF^ksL{TyB9o1s zXS*;HW!nl&+tb<4xn$D}rqF$${$UVm&_aF1`(F{%uf5P+O|!RC)5nQq)N-r%*9bqs zm%wtNTiO{Wf{|#ZK0~9`358ccT^UX$XQAoJ#&hWiTDOMuZilbhCc1YeDqaSdf5RHP z1h2s2GE**PV$ZX zUq785e*x`OOAuP90o;!xUlVp|I(t9S@@DAjvh$tMxV=TaxgusWFINF~*O(pVv!7>B zd}Xlms2%2##P(Ynv#GMZye{UVpSz2x?K;&V2WQbM=(R?&@{sNC%7_h2PFY~71KGKN zyWncz?r*BY5>#lBU4kNT5;@n?1?adQk>gq0i94|zrjZ)p?k3eCms=O#t>o9gZui)Z zE_91TZIo)0WM?|!Vk&qt_b4%{!zx_dZgXq-#L0GtZR0MwIU-4pK$-R|o^Q+X)v5(T zBdWt!+{~3{dYHldW()&k4imUSW)QA)s>7d)QR2?LajT8PVII2 z=MlRA4c<4PJ`az%zeGpsQdiD%>p^`zdbdN5xQ!a#09EkEDB#xP*R{r_-SR#g#>zW* zaUBYlOM|9M{Iyxs+jIDOy<_D)1Pn${5PY!7xCtkzim0O<>?(t3W@5&<_j@AQSLk|ACFl zg!`{+n6uYH(}aCe7#P79841zvPO!)Bh|N^W6*mozHzzA2-3YjIJuq~JoiW`;_n26U zabagvL9n7FsRZR<<^-0isfEs{QtS%g1j9t zfp1PM@o#gCWRK|3mY{_q8c5|{)d)n0SpSHx-N60Z?*DZ2e`nBQkzuhCjgf{O1VMG< zg`k9$LQs{AJLqIfi2HBd?A1VVUH+AEUvKJRv~{L&uP=TLtKw0#{8x@m(M6NLb3}Lv z#gbCXna%0MTH7Z;we3fL=k>btG8Ht0Dzz^cXFSl0fATUzzo)$XZ7mw zB6pVsZ_TP)yzVb#0W1Hc{=76J4Zqn5PEoo(G4(8uNkXxRn5ZaJv%}aco-BlM0&f=&_yF5-;X;pjF(m z*pYsj`oXbKryBT6Rd@HW>Vp z^t*V;@du;BZbj5qX10zSmJaND?dE+Zv9;fNu}cZGWyd=ThYGeimqzGFf3VU=c4kXF zs-8p{S*0L_p+fa(6TqIP zk99k?$KiN6T+{Up@A}?-z5n3X;=RatGPUZ+p&|ebw9euBRc7$;Zc5Z_TAT9e7q7~B z#!!a+>JiBi83j5u;P_R`NI}HYuz=mh`4bCv!(jifSbQUA4R49QJm3N6%T0BC!n%eH zOT`S1jds&nGnBzhh02=i-Rsjs_)Xc%6XyC$Gyu&{UI`EfJS{>ng_Q?b9i)PbA>+am z=`BoUp3ONxl%!f!p~_k`puQ#fi8U1w%ZW?8V%EdT@0 zx$s!zw^Twe+0$S?uI?>ckwBOT{`1)U{^Kf_Z3O@72$qq#gw7)-bU=kmGH%jG?W>lq zCynUPt$m~-KEZ`M;}s3dGOg>DJbRlOq9ZT8k;a~VLrCpNl7FAI=LcA~a8e7mIPF;! z(eKdGU34uB&N6ljFCklT8f66zo8hjdjCel0XD9h+ND0`4+NORd@+X0t3sK%(?-qSe zgV>+Kxl%Aa@8@alv~hJ;$f}F8Mf6tgH(A%R^u9aG^hid>jfc4q1)+}g?H=bM(3mN3 z+6(c~-Mn$1gf#bPK0P|7u`a@zaZ!9EMLHwycglPexbZIj>%rq*n*Nam0Rfx&dWwmj z2zb3x#q|{s6=HF^>@@agrpO~YT=hqdU|QYC`-m_W-WM$1iq_Tk*k-;D&r$u32(YBy zb_hQR!?A8BwrU=ye^5wNTHMD-6!K+~n-KbIUS=hw)$4ROUm2N{;9L}How1M#AZqVj zjX13yZqu-*B`)+&c@Vm0m2}-H#H4)m<|V?~!WXeLX_qcDP4HO8LGP*;}f7i@xW4~;eCX|&A_f)G;r07Fnt@luK-D{`RtM_w{EhNgV0m88}X{Bc} z?1~1=h#c5pOP(S@rROBHolj0cxmR+^%_Qz2rO?gQT66-gGe6O9-v(~&E_A7^uRmI!g;5wY?}(Kf_c`1 zWB(1zjVs7n%THf4j+$KS>4jp*FKZ%;k1tnwU+iz+&IO6oK@qx-Us-*4og}cFy>>xa z`KQ%RX{9sopkVl;IE_?Q7^oS=cS*kjvu4(t7lm-9H9-XVQ zzABJo{-Vmg&18N+_j~@9Cohp@-qIFfc~Jo_{DMO zQY3JlOpX&mkUXBqvdltbC-BADmOk8kwhpnZd|kV@_$xPn;3%c6TPsmk-AY1uSglJf z{9^T+5S$ynxkM%rbaAzVQ(myMjLnT*v3g%h^RuHH8+0v%LZ$Xwly-ys;zsV)V}AmF z$S#%2INRZ*vmo3=+Mt>1E7gO!cc}iJ%8Pez1^frzO1|AlFiZvl6iaUakD`U3%+D#H z-4&sXAUOPZiHbtkZLDyEK{LS3E=hTsSxmEgE=14;Gh0SznghrXO?40oc%$xZY`z*I zT?Fhc^dHusNvEo%3!3JANpsDw4_*FBV+_Lf9)()gePVHSIuRW$g^ZJt>Bs{~sq>6D4$GwAO*n%6S>$ujz(Jkcnls(LT$l4}r+DHBQh|lIfW~6o;$3 zADSk5O+KbmY00+VL3rwX;4NU=O@^g#6l=M}AFS(P$Vl{BGfz+znkC){R*{#O7qz1G z1t1{9$#9;b%piosE2(5T?5FhT;{NYe3tlmcQ3~-aFvl zsY!aNS8atHn+xC*6jM%>n;BC0I*c-RID#-D>+dbHgbLX4FikK3xDkgoaI6hd#_}?y+IjatV0G* zi_x&g!?ch&QUT*(M1+*kjI`Brx8p}z%Zs9k3(<~lH!smzgQu)j{q!5kjXPK5)nJht zsIq+zrTvQl&lsEl+il0R9^RL`D=xR%NPpkdS?!^S0FF#oRddCao1 zgt=C#Pg40U;YFUA9+OAEoFQKjaz%|$2D`mbdyZCBgHNxUp!;C3i1KUe{#3{Mm}iB< zw91?AK0~b!2zi%k-&K>7sE2<1rP8pCU{yUAtMWT}x@)luhnFJU>*4jWN+-+WL#L#C z(sxFR)-6ODnf#8!W?s1MmkiHp&j!?}MTssZuq5(mF#_i{Uuj6pD13%55`$VI1}c+$ z1o)$$-qiXzd~E@d`hhsZBcsk7HUSmx{N^7R;>EJigsPq1e|9=Xo~jO8h$18;NJ}hJ z{LFptFqgM^2ZN)tr5%J09lzN_0!}W9F$8#3kwzE>IRLE8aLmsqUIefPAk5&?E^*%A zv`kv<^YZE+M7*B6nX9~hR+zwnZT1C*H9C3ePQzn4r0-Ve;^5AevfdzcM6l*x4;v$_AB z`?xB(&an~gXFaAnz~ed{f9VHHUU)cX_srDu&8V}T3Z*arFm*R7WA6ovvXu?PrD6=0;b74h5?NpT;t6a&p8sA6wu*d0K^!YVim~fGzOXv zsR~u}JPn)(#_0P0)q<5)GCN|~fZCa$!T=1>0CIH&zd8Vt^~j@-i$S+8D@qrZWe;<@ zr$MVp5RwFxen`W=nK#7}0bC5c9Z>$p!1e)~X$iil*_`mxY{Am66%!>Q>7w)VR>A4S zZVfTLl?}XIJ{tI6%@N3atQee=!OoL~rb32g@56Uf&wepeNo0P8K37;tl0#C(_;|PQ5oJU-Mpyvx+aC{rX(!*-Z6gwt_jX^v#+U_Y%>zTX z<@>!GfmQ?c4ul_BUk>0Thk-6@v(M$h!YrjpX8f(Z0Z3EgP&kva#X0)HV5>gChiPpI zP&GWFVn`A<-d#sLf_c^iLA}2a+e2x-WlI;0pnRTT-SIZO@MdC}RBQLW+*p3e!XVxY z>%y>ON1v1Jt9#(00`~xDWKbchqEms=A#cAsU!mn<5+FfWM*x&*X~O)b5d=U;%c((a zyOHLIB+Ym&y-ORh^0wKb2~Oe`tze;jy>AleG2{K2XL`t-xsdauhG2u%_5o=oyUdUN z7xd|-zuQH=hmKV%-0laG?ipq{g#|DEY1e_sXh&5D8Gf}~RXQ^B z=7~qbrECX$3q#GtBhx`9$}^2kRB)vD6#4vKPN`w`z1nS*>y8&jqql5n0nzxGp2E~| zRRnKis(q%#%-DjlTf#s&ULU-cJopeur)4a8)t}v6IW6s*$U19;&NK1r#26pdc-Snz zc|O)f6w3N#g8z%$xOh1EYdkd#&ucdreMO%X+bwQM!63p z;ec-9b3Haj1Jk}94e9>!ilgS4kf7O{XGQF>srY7%7;rDnEJ5l=7EJ+64U)H0)|YvS zbF~rC#+|C+3b$0P?HW&$zeEX|@rkQG{dd|7bN6B1TgpfL8C7QF`q~1_;|d>je3LXe zVQ`R5T6fvBI$LTOO!8FT`1W4C!v|xXvlg@bGb^I)J15-8n$PJM?c?$Sp6tqBDvscX zhqFP!@KZR)C@ETrt-ELJeT68z6km~{+Wos-nod6lPFk1 z=KKo+)~-|@@+>bd)=^KH{X|8yR{9l!NPOE?v&6FDG#ImiK4qz!ko(XB1xWJHTRZz#mR=`b)NlNp+ngIx4fi z+DQcJ*c{w#O8G>?Ap-yOyx^6PFecBtIi(as@Xlta)MlsOUbRzyCEiBtV|t3PT?pY0 zAvj-}mbPkxhGgDJqxLtuJS-NSB-AjzBl!G5giQXP(@okzMt5>6gaIejv=@&QcVx?> z_?CoEboI#Re!GNCih>SFaGm(G1q?p_9wYBB5JEl=CX4$?we8Y`mCzgPsw}s-qZWq_ zSB{LIJtIZ40V%k^t}I*+wG?Pbfg1Wk^sv~<3li-pFac6-G^^X^dZogI8Z6jbTREeu z=V(6E>#5RJ-I3IV0~g#5rFFA%%P00wqG~(6+>fKsNG_nOm43#5;dL{EN*-+nK~iy| z?leZnO0gqg%?k{jZx0Mz5MWu95q6p{;C{)8!sX2hL$Z5i`G{-Q#&A$d7K(D+dfbW{ z_HpGzp?u4Tf2Vc{u4shKV2+W3>y7)oAL@H~UCM|W1wQl?dksbJJ@;|9S=ur-CVEo2 zoz>xZUF;F<3M8I)mbZx@pNu`xX%u;O?IT*iF$FZ{!fZo4iwT=C%y_YxQ=Z2mEE!we z><@3^JVAGzXhG7J6R7T?*ul6q zOf_ZP!qI%ctDxtODRDKxe{i>va5{$$nkF1s-DpNCjifTv3}H6)(jYA;1m)hnbUN6CS)( z5IKvSt+)Chd(lp2ApRweR?^JsFqiRgUwrvg^;Rda?~k9hJy`5!SgWsI%E&UG~!9i&_TZQ z{)z^94&BJ#qJ%{GHaE4maLnx%GwblCt0Mg85t#l~>+oPd4HuqXG|S1f;~8|+kQ;2( zlRMj(bqKOPTy={+Ty*oGK!hVAEPE%nfoH^pxTk8KY0P&TfY6DUI)_?oAyeF+J}~9& z1Rh--x|4@5`s5`=HoYNZ2J6kSuR#vsU?!Dzxfg3h06u@j7bt)Tkyq#X%UOl=H_0!?V+1QF7iVHGLUtqJ5JNQWDQ=Ulh80kGA>3N+z$2D*RlG40 zj;21f0DKez+HC-gM-6gpTAO_|wl@kC9fg=*l0z`1W7MeFXYRwqNFmZEm9c45kBQtk ztTl}~)lxC}JEwFVroG{A-Osuj77)W(y0C7y8RKlB@ftCssU3{u>Yy9j9-dVVffs$M z_Y_~>1AcZEz5PrWf>pkSm_*I>_2nFylrPT+_dcFZ6g8GM4uy!#xc?9G-&4<92(9gp zyjFw2)M5Bf?)9?Ex@FuME*IQQYU-BHS4Xp>4bP8N9`$nYe4n7|p#;y{$_y~!n?=AM zN5vkA>I_85LRNK>jZ#AqloXpns>=wRJMaZ6B944&_mPO?ApG?D_y z3pF;_)l*^IJEshQVZI|GoXAoG4e3p)C$Y74I2U=@75%-HLuFiwV%ER$N^1{1Z&EbD zCHwaPZ94?~H%x6C353Od#osq2o8@*RVbRnLp96e*K-K+X0!EvmmvoeXG>UdxvNVc* zh(A&{?`lk%;@hA*F}P?<~!=+e_vLQ%hvco&U zPrUaa)frQ2ZIAupaq!8Rm$kltFEO>{l*12;zZ z$R51^`=Ku}U;Z|=4o9~;6_PIn^qv`>E}4I{;FofDo4WFp!Boll$E_is$*u1{&in!e^}UN%9i^-d`&bb)f?76x`Ml<3o@_ z`f#L(H$T>X>H0a|S@P8ETjJC_g2%DrTl@Mg?l}G!`t@$g)_iF)% zH57XVrKw)ru46EkOeyW0>BEl?T+yo}g_CxrNp~qMxk-SZl(9S^JKBACJrbFe@Gd(b z4wk1KNBt1rV3Cma@Fz2qZwl0Zt?1Zp)vxPY?@}7C6kftoYTb{WLrOSPBin7JiejV? zYBrTTCmohXN8I{KZ4&NhK$S~WK> z&;91kuC2|*ophGVK{wd{&WTZg=4`V}74DPS7TE2Sr+QBH+pD%g35%$VI4htngO7HB zHqy0nzpfTTBc3@Q^q^ih?l@{6yE8oc0Z+QT`f_evstK=dSuJ+lY|`Bn=;6j5sfB&o zk=<6y{We(I_Cc$mE$xn&{9=44d<50}JqE)_5docg-XGCW1c~T%jUFT`hJ0i-6D4pnfaD{6oj91?bnDOil#z4PF(*rt3dsKb-%6;y%T;9R-Rmh!KB0L% zBbGEr2pa)b65fP)*XB1yhpObzDEU7wLTjJs2+@X$0$mA%Bc*fIn{yDqYZ1C;ddNpr zV0jGL^|wf>Vv`ajGV;9pa zQBnh@p}RQWNaCw;$-PK)Qn#jYTDmh2GkE12z*Ik9^V%AMR{^`-(!&d3Qa{8)*?-P)u2QR# z1P5kb?qiVdc=2Xv2_!oib{a-q6$I2kTZN-@=#;~D~W9s;{U5PZuhJI-s zLeK+`E9X4W{zIoSAycOIbr{i{uuMv-GVK_AKXMRgVmuK5s)ATEsx2DS z{p$KS(yKQ|<75btXOLC1oT3D5zcR=`oSFquvLo2Vhzdo0EpVWZ4?L}zSUlOHwK4}y zg;8x+W9*KGDPU!~EZ9 zW#Jh_y>>+yyrU&6k&MN|rJQ454A%DZ=Mnk! z{uwS@kJa6-5bfi_cMTrP4$Dv15}9nPn)7a7397m10<2CER#djyjD>`(T5-HTzv2d0 zo{$}$W85FUl| z*JPNA*)ZH7i9Pz;+=LfEPIm2gQvR4c)x^)o8mtvtMT*jOku*SsAHWXRq%Qy*Sk@5d zEcUNwLil^tt6nlb`H6}^`;qydqJ2w2a+#$<{6QkFuUqtiL{glhI@9IUtcum}ZwN08 z#c|5by#~!h(z!XUCjZVXvh~bub1!}O{MnnqkX&LFH_}6^AC7}S-(6gT?6&sEwm5va^K@*TGNs~28Y*f49vKw*ut6NrQaV;n5`OW&#(~%w zMTDmhPb<~J!KJSAF~LCob$#b-dD^!|*`Ms9<{#ZyQElvoUGak*EM(B;M-+} zvR0sNca8hg%mk@?awb9>_wI!TYXvgz13UeM$HZJc^c|jk&%ZDGyPjy93aOq~-raV> zM7BzY6*+b@$^ID3pEApRM-h`B7~n4Q8V;vy?`u$bOE=;SAK~dT+~S_CR;uC<9<6`8 z!+qQ{fsJih84)>U{4lomi2c=NGs~8JOYLjb_1uVD0)OR0XLvyImd&bY!-6SfTV?;$ zPWAkYMF)-g-zW1nXZh-s?v&{pp@TMp5zj^epxHI4CB{X^X~ZSZu+dul;ueKZ@$&iV zY7S4k>E_<}spSM?@=L+n=N>)TWwpckql3NyQi?GKs1f-~A^G$TiTM1ez;(C81hl;W z>86NFwj(JnX+CZ^*-%+xvZQU^YstxaEVKPLAT#Tm13+#2i%8Ol;bibb#`|{;2}~q* zyJaIi0gQu7C&aKG#jm6T1=GpRCeqbL4Kg9qd;}--;KMtqIN4ukoXJ|&8TREq`XLJu zy6HAfKKVKO%Nlts{$iN(YKrSk?YD=WKDsxF@}TnTyLXirwHCrF8*zW3n|R!t6T-hS6=jKMQ*ZZtsVm4&rT%?#&m znUfsWXj7OfUk^>FOQ13Dm&@Zj0JC6bNm;x>5lR=At4t{E3}7`*swh_`F3TwEiOeFG zC`Yz@GSsu0F3@P!RTV~6-Xg*(cn3vN2y8BIWP2yQAV?K^Lp(H)qa#;l@n)8$eZeoh zyGW*4%Lfl9naW>%fg9zp*LTC9G1F;%gznum#?(cJCi2^Lj(v2JL&+ggG-Y9X2nU zZDz7p?uRVaG8y8=*467h&MHcyfVXAbv&b1s#sp4>1S82Pna|38IT^jW5NF{a<+$O< z@yt^_uZT9X_C2Q&Psmu14m2SE_Ww1U41hX?o20|%PnEQcj^cs$nKJL2@eyR|)k1QP zaOx6+ohCyKSS_FE6bF4Nu;-9Cc9bz}OcqY(mzsJ3X+EmThPJTbcbS&9BxQFPLswll z!t6O05XxQt$57%iMGD1n)D1Ep?AQPh3igFJlnUS z>njE?Dr<{OCsDAmz>nWs9wDrr2`I+HfgoXgB17=SZa9(D;Yq)wiy}Ug1b~2vCfawtvnJXxDraJkjDM@VP#-EndQr zRgtlY6PAk++NLb?LA_IsZ{+B4VQ9WaD5C8CDb`|Ak2>puqTq@-ANe)W-;o8z-#I;hayCIb310m z20-J$rOCEt)S}<}bZ;taF;xYWROjL2>PL}2s#?C=+(V!H18b%;3I%64Oq;>7Wa9Pm zADK~2Hd+LL>%fg56Yb3Qly9zm_88mBL=}zlZz4pJ$@SW7+8)` zr!K?r_h=aF+uxMG z*@5n`FCyUz8vR)mGI?YK1m){$$&F>M`j;Yv3bc1r>c6ATP?|Go-jjbc(`-M}AI?E8AT_@OP@R=zzs z94QPDI)Y`w&dx}yn)Flhj(XQWRT^Httbt%d#W3sd8H+e23O4#ef6K{Df++G z?WKgaKAowGqVV5z-s}mIW_}tu{rg}`zh}usdJ~!`w?|}o9ePBb-3M6<>bm@ut=NTQ zZ#{$fT_g66MVohrG{Hb*Ne`!vD4!oOY(D6JXH!K|oL%q=g37rCvAxfDW&FTsZyV=r zs47>6Wk93VGU$C&>JoNwR6V3rDjCFo<=^3rM3uM$xa8XW71t%)-et^vOF3x&@_;tf zAsIdQJMwsuA_l12>Qh6g+e4++>%;UG>H3K#B*-$cZtx441|4%KqU7?V%^zYZ()j>N z4E#t&hNTlOfE%G@9ai3x7`zrI&(3uWkobtDzq#exdqeqS`>HL{02B8XP*F3@(0rrJ zxw#V)VZ0k^ZxQ=QYo{7u^uTc;BTaEet5&!vEf`UX!6e$+24p-H9(G-iS1d`KZd7Au zJj_JYDade#yy?d~>TEU7fXY_a2M1Ljh)9wU3YMyrL(Xc8(^QLHKbw0Np}#$5dv0U> zLI~~fA&i9eER;m-^L5*ez4iY4BdmdYXyA%qN^5!1eD0za=$N=kBf7E+X?{Zak{Dd& z^(8UV$J?A)mQw>Gtl{rgkiLya&5kn~X1aM;pwhy5GV%Rrx_BU8OI&%F7qADYqF-!pVxG`aUrZ;@z)GZRdFcWRudPZ z3y^sgq3M9-USFye{2>1%ZO&jqo0^Hj2>FHmnzTtn2t_B(G0rc6*ThY4PI%}@ac=qQ zCjKJ^2SD?#BpxK*Vf@n%ny43o{{NqDzxuYv(JL)2I=ZGTI_Hy^ZY`-kA)V1$sJs}p zBSD|Bz_(pvRQPDs;Byi_W^_ezUri@%%`@ z{qbYeW#8~YvN&-U@a2~F#(%Q)U8w1;FZvSr_-<6tRDbSvL(QmZ5!6H(O(YbYiLi6T z;yJx+cfrI5$UqcIkS9D7+Io_*)BUquVfk3cU60|p2iIVopJ5%}v^grgwWW+2@iZqD zy8*j+u?w~hBy|bmzl&q}ejIYW@S28&HrB|i|8zBLYdL4ID@MS7T;K9=&)v2iwM4}E z7`SS9IEz=bTa1qBLFdf2nyXD* z*6vL$?Q#pI5w@BljxX*vpmz}1httXOw!zWoXAj320tI_^qd^S2y0Km}^uyAo2>#up z`yo{(zc14vn0x!t89y0~ueP-L9zL8zOOeV+KB~pbw>duF#9FWw6TmY6vJdhE^C>OG ziEACvoYuFd*9DD)GZWf;U};=M)4q{lJPGm~59P8&#Wz0$wcgF7k{m6!-L#yJ4lH6Z zs#SJt-Yg!Hn1h}gXB)%07RtwlkLIgL;%7YWip@|SLj5*55pO*XHCDD(9LJtd9)#-) z=;BHTx2hE%BXLytsCSgHjOqn-ba{4M2AK-OEh7YjZT{P~9bQ!*97T ztbbN$8@w7Emr^{`G%7lL>5m6Z@7OMl)t%6PGm&*@_jtg?$D|r+z+;*xhIC{vS>}4F zx*nTp9Wy`7N0KlX4s$UY)hzVtq2o^)DcoT=KD{ihkvgr3;@E#txLYbTt%}ZiIB8

X(YN_k3DhjkWmb>+8$8Xuz%GDMf#-0cvP) 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 Dk7xlb literal 0 HcmV?d00001 diff --git a/cia.rsf b/cia.rsf new file mode 100644 index 0000000..7c4f7a5 --- /dev/null +++ b/cia.rsf @@ -0,0 +1,272 @@ +# Einstellungen für die CIA-Version der MBMNET-App (makerom). +# Werte mit $(...) setzt das Makefile. + +BasicInfo: + Title : $(APP_TITLE) + ProductCode : $(APP_PRODUCT_CODE) + Logo : Homebrew + +TitleInfo: + Category : Application + UniqueId : $(APP_UNIQUE_ID) + +Option: + UseOnSD : true + FreeProductCode : true + MediaFootPadding : false + EnableCrypt : false + EnableCompress : true + +AccessControlInfo: + CoreVersion : 2 + DescVersion : 2 + ReleaseKernelMajor : "02" + ReleaseKernelMinor : "33" + + # Eigene Extdata (ID = Unique ID): Speicher, den SpotPass (BOSS) für die Mitteilungs-Aufgabe braucht + UseExtSaveData : true + ExtSaveDataId : 0xFB4E0 + + # Dateisystem: SD-Karte (Patches, Updates) und Systemtitel lesen (Module patchen) + FileSystemAccess: + - CategorySystemApplication + - CategoryHardwareCheck + - CategoryFileSystemTool + - Debug + - TwlCardBackup + - TwlNandData + - Boss + - DirectSdmc + - Core + - CtrNandRo + - CtrNandRw + - CtrNandRoWrite + - CategorySystemSettings + - CardBoard + - ExportImportIvs + - DirectSdmcWrite + - SwitchCleanup + - SaveDataMove + - Shop + - Shell + - CategoryHomeMenu + - SeedDB + IoAccessControl: + - FsMountNand + - FsMountNandRoWrite + - FsMountTwln + - FsMountWnand + - FsMountCardSpi + - UseSdif3 + - CreateSeed + - UseCardSpi + + MemoryType : Application + SystemMode : 64MB + IdealProcessor : 0 + AffinityMask : 1 + Priority : 16 + MaxCpu : 0x9E + HandleTableSize : 0x200 + DisableDebug : false + EnableForceDebug : false + CanWriteSharedPage : true + CanUsePrivilegedPriority : false + CanUseNonAlphabetAndNumber : true + PermitMainFunctionArgument : true + CanShareDeviceMemory : true + RunnableOnSleep : false + SpecialMemoryArrange : true + + SystemModeExt : Legacy + CpuSpeed : 804MHz + EnableL2Cache : true + CanAccessCore2 : true + + IORegisterMapping: + - 1ff00000-1ff7ffff + MemoryMapping: + - 1f000000-1f5fffff:r + + SystemCallAccess: + ControlMemory: 1 + QueryMemory: 2 + ExitProcess: 3 + GetProcessAffinityMask: 4 + SetProcessAffinityMask: 5 + GetProcessIdealProcessor: 6 + SetProcessIdealProcessor: 7 + CreateThread: 8 + ExitThread: 9 + SleepThread: 10 + GetThreadPriority: 11 + SetThreadPriority: 12 + GetThreadAffinityMask: 13 + SetThreadAffinityMask: 14 + GetThreadIdealProcessor: 15 + SetThreadIdealProcessor: 16 + GetCurrentProcessorNumber: 17 + Run: 18 + CreateMutex: 19 + ReleaseMutex: 20 + CreateSemaphore: 21 + ReleaseSemaphore: 22 + CreateEvent: 23 + SignalEvent: 24 + ClearEvent: 25 + CreateTimer: 26 + SetTimer: 27 + CancelTimer: 28 + ClearTimer: 29 + CreateMemoryBlock: 30 + MapMemoryBlock: 31 + UnmapMemoryBlock: 32 + CreateAddressArbiter: 33 + ArbitrateAddress: 34 + CloseHandle: 35 + WaitSynchronization1: 36 + WaitSynchronizationN: 37 + SignalAndWait: 38 + DuplicateHandle: 39 + GetSystemTick: 40 + GetHandleInfo: 41 + GetSystemInfo: 42 + GetProcessInfo: 43 + GetThreadInfo: 44 + ConnectToPort: 45 + SendSyncRequest1: 46 + SendSyncRequest2: 47 + SendSyncRequest3: 48 + SendSyncRequest4: 49 + SendSyncRequest: 50 + OpenProcess: 51 + OpenThread: 52 + GetProcessId: 53 + GetProcessIdOfThread: 54 + GetThreadId: 55 + GetResourceLimit: 56 + GetResourceLimitLimitValues: 57 + GetResourceLimitCurrentValues: 58 + GetThreadContext: 59 + Break: 60 + OutputDebugString: 61 + ControlPerformanceCounter: 62 + CreatePort: 71 + CreateSessionToPort: 72 + CreateSession: 73 + AcceptSession: 74 + ReplyAndReceive1: 75 + ReplyAndReceive2: 76 + ReplyAndReceive3: 77 + ReplyAndReceive4: 78 + ReplyAndReceive: 79 + BindInterrupt: 80 + UnbindInterrupt: 81 + InvalidateProcessDataCache: 82 + StoreProcessDataCache: 83 + FlushProcessDataCache: 84 + StartInterProcessDma: 85 + StopDma: 86 + GetDmaState: 87 + RestartDma: 88 + DebugActiveProcess: 96 + BreakDebugProcess: 97 + TerminateDebugProcess: 98 + GetProcessDebugEvent: 99 + ContinueDebugEvent: 100 + GetProcessList: 101 + GetThreadList: 102 + GetDebugThreadContext: 103 + SetDebugThreadContext: 104 + QueryDebugProcessMemory: 105 + ReadProcessMemory: 106 + WriteProcessMemory: 107 + SetHardwareBreakPoint: 108 + GetDebugThreadParam: 109 + ControlProcessMemory: 112 + MapProcessMemory: 113 + UnmapProcessMemory: 114 + CreateCodeSet: 115 + CreateProcess: 117 + TerminateProcess: 118 + SetProcessResourceLimits: 119 + CreateResourceLimit: 120 + SetResourceLimitValues: 121 + AddCodeSegment: 122 + Backdoor: 123 + KernelSetState: 124 + QueryProcessMemory: 125 + + # Dienste: u. a. am:net (Updates installieren), http:C (Updates laden), fs:USER, ptm:sysm (Neustart), + # frd:a (Freundekonto umschalten), pm:app (FTP-Modul starten/beenden) + ServiceAccessControl: + - APT:U + - ac:u + - act:a + - act:u + - am:net + - boss:U + - boss:P + - cecd:u + - cfg:nor + - cfg:u + - csnd:SND + - dsp::DSP + - frd:a + - frd:u + - fs:USER + - gsp::Gpu + - gsp::Lcd + - hid:USER + - http:C + - ir:rst + - ir:u + - ir:USER + - mic:u + - ndm:u + - news:s + - nwm::EXT + - nwm::UDS + - pm:app + - ptm:sysm + - ptm:u + - pxi:dev + - soc:U + - ssl:C + - y2r:u + +SystemControlInfo: + SaveDataSize: 0KB + RemasterVersion: 0 + StackSize: 0x40000 + Dependency: + ac: 0x0004013000002402 + am: 0x0004013000001502 + boss: 0x0004013000003402 + camera: 0x0004013000001602 + cecd: 0x0004013000002602 + cfg: 0x0004013000001702 + codec: 0x0004013000001802 + csnd: 0x0004013000002702 + dlp: 0x0004013000002802 + dsp: 0x0004013000001a02 + friends: 0x0004013000003202 + gpio: 0x0004013000001b02 + gsp: 0x0004013000001c02 + hid: 0x0004013000001d02 + http: 0x0004013000002902 + i2c: 0x0004013000001e02 + ir: 0x0004013000003302 + mcu: 0x0004013000001f02 + mic: 0x0004013000002002 + ndm: 0x0004013000002b02 + news: 0x0004013000003502 + nim: 0x0004013000002c02 + nwm: 0x0004013000002d02 + pdn: 0x0004013000002102 + ps: 0x0004013000003102 + ptm: 0x0004013000002202 + ro: 0x0004013000003702 + socket: 0x0004013000002e02 + spi: 0x0004013000002302 + ssl: 0x0004013000002f02 diff --git a/ftpmodul/Makefile b/ftpmodul/Makefile new file mode 100644 index 0000000..0722606 --- /dev/null +++ b/ftpmodul/Makefile @@ -0,0 +1,27 @@ +# MBMNET-FTP-Modul (Hintergrund-Prozess). Wird vom Makefile der App mitgebaut und in die App eingebettet. +ifeq ($(strip $(DEVKITARM)),) +$(error "DEVKITARM ist nicht gesetzt.") +endif + +CC := $(DEVKITARM)/bin/arm-none-eabi-gcc +ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft +CFLAGS := -O2 -Wall -mword-relocations -ffunction-sections $(ARCH) -D__3DS__ -I$(DEVKITPRO)/libctru/include +LDFLAGS := -specs=3dsx.specs $(ARCH) -Wl,--gc-sections -L$(DEVKITPRO)/libctru/lib +SOURCES := $(wildcard source/*.c) + +ftpmodul.cxi: ftpmodul.elf ftpmodul.rsf + @makerom -f ncch -rsf ftpmodul.rsf -elf ftpmodul.elf -o ftpmodul.cxi + @# Lumas pm stürzt ab, wenn die Kennung eines Systemmoduls nicht auf 02 endet (panic 4) + @test "$$(od -An -tx1 -j 0x118 -N 1 ftpmodul.cxi | tr -d ' ')" = "02" || { echo "FEHLER: Kennung endet nicht auf 02"; rm -f ftpmodul.cxi; exit 1; } + @echo built ... ftpmodul.cxi + +ftpmodul.elf: $(SOURCES) $(wildcard source/*.h) + @$(CC) $(CFLAGS) $(SOURCES) $(LDFLAGS) -lctru -lm -o $@ + @# Adresse des Statusblocks für die App (liest ihn per Debug-Zugriff) + @$(DEVKITARM)/bin/arm-none-eabi-nm $@ | awk '$$3 == "ftpStatus" { print "0x" $$1 }' > ftpmodul.sym + @test -s ftpmodul.sym || { echo "FEHLER: ftpStatus nicht gefunden"; exit 1; } + +clean: + @rm -f ftpmodul.elf ftpmodul.cxi ftpmodul.sym + +.PHONY: clean diff --git a/ftpmodul/ftpmodul.rsf b/ftpmodul/ftpmodul.rsf new file mode 100644 index 0000000..3d30d0e --- /dev/null +++ b/ftpmodul/ftpmodul.rsf @@ -0,0 +1,162 @@ +# MBMNET-FTP-Modul: Hintergrund-Prozess (Systemmodul-Kennung 0004013000F1E002). +# Luma lädt es als /luma/sysmodules/0004013000F1E002.cxi, die MBMNET-App startet es. +BasicInfo: + Title : mbmnetftp + CompanyCode : "00" + ProductCode : CTR-S-MFTP + ContentType : Application + Logo : None + +TitleInfo: + UniqueId : 0xF1E0 + Category : Base + Version : 2 # = letzte Stelle der Kennung (02 = normales System). Muss 2 sein, sonst stürzt Lumas pm ab! + +Option: + UseOnSD : false + FreeProductCode : true + MediaFootPadding : false + EnableCrypt : false + EnableCompress : false + +AccessControlInfo: + IdealProcessor : 1 + AffinityMask : 3 + Priority : 40 + DisableDebug : false + EnableForceDebug : false + CanWriteSharedPage : false + CanUsePrivilegedPriority : false + CanUseNonAlphabetAndNumber : false + PermitMainFunctionArgument : false + CanShareDeviceMemory : true + RunnableOnSleep : false + SpecialMemoryArrange : true + ResourceLimitCategory : Other + CoreVersion : 2 + DescVersion : 2 + MemoryType : Base + HandleTableSize : 0x80 + + SystemCallAccess: + ControlMemory: 1 + QueryMemory: 2 + ExitProcess: 3 + GetProcessAffinityMask: 4 + SetProcessAffinityMask: 5 + GetProcessIdealProcessor: 6 + SetProcessIdealProcessor: 7 + CreateThread: 8 + ExitThread: 9 + SleepThread: 10 + GetThreadPriority: 11 + SetThreadPriority: 12 + GetThreadAffinityMask: 13 + SetThreadAffinityMask: 14 + GetThreadIdealProcessor: 15 + SetThreadIdealProcessor: 16 + GetCurrentProcessorNumber: 17 + Run: 18 + CreateMutex: 19 + ReleaseMutex: 20 + CreateSemaphore: 21 + ReleaseSemaphore: 22 + CreateEvent: 23 + SignalEvent: 24 + ClearEvent: 25 + CreateTimer: 26 + SetTimer: 27 + CancelTimer: 28 + ClearTimer: 29 + CreateMemoryBlock: 30 + MapMemoryBlock: 31 + UnmapMemoryBlock: 32 + CreateAddressArbiter: 33 + ArbitrateAddress: 34 + CloseHandle: 35 + WaitSynchronization1: 36 + WaitSynchronizationN: 37 + SignalAndWait: 38 + DuplicateHandle: 39 + GetSystemTick: 40 + GetHandleInfo: 41 + GetSystemInfo: 42 + GetProcessInfo: 43 + GetThreadInfo: 44 + ConnectToPort: 45 + SendSyncRequest1: 46 + SendSyncRequest2: 47 + SendSyncRequest3: 48 + SendSyncRequest4: 49 + SendSyncRequest: 50 + OpenProcess: 51 + OpenThread: 52 + GetProcessId: 53 + GetProcessIdOfThread: 54 + GetThreadId: 55 + GetResourceLimit: 56 + GetResourceLimitLimitValues: 57 + GetResourceLimitCurrentValues: 58 + GetThreadContext: 59 + Break: 60 + OutputDebugString: 61 + ControlPerformanceCounter: 62 + CreatePort: 71 + CreateSessionToPort: 72 + CreateSession: 73 + AcceptSession: 74 + ReplyAndReceive1: 75 + ReplyAndReceive2: 76 + ReplyAndReceive3: 77 + ReplyAndReceive4: 78 + ReplyAndReceive: 79 + BindInterrupt: 80 + UnbindInterrupt: 81 + InvalidateProcessDataCache: 82 + StoreProcessDataCache: 83 + FlushProcessDataCache: 84 + StartInterProcessDma: 85 + StopDma: 86 + GetDmaState: 87 + RestartDma: 88 + DebugActiveProcess: 96 + BreakDebugProcess: 97 + TerminateDebugProcess: 98 + GetProcessDebugEvent: 99 + ContinueDebugEvent: 100 + GetProcessList: 101 + GetThreadList: 102 + GetDebugThreadContext: 103 + SetDebugThreadContext: 104 + QueryDebugProcessMemory: 105 + ReadProcessMemory: 106 + WriteProcessMemory: 107 + SetHardwareBreakPoint: 108 + GetDebugThreadParam: 109 + ControlProcessMemory: 112 + MapProcessMemory: 113 + UnmapProcessMemory: 114 + CreateCodeSet: 115 + CreateProcess: 117 + TerminateProcess: 118 + SetProcessResourceLimits: 119 + CreateResourceLimit: 120 + SetResourceLimitValues: 121 + AddCodeSegment: 122 + Backdoor: 123 + KernelSetState: 124 + QueryProcessMemory: 125 + + ServiceAccessControl: + - fs:USER + - soc:U + - ac:u + + FileSystemAccess: + - DirectSdmc + - DirectSdmcWrite + +SystemControlInfo: + SaveDataSize: 0KB + RemasterVersion: 0 + StackSize: 0x8000 diff --git a/ftpmodul/source/ftp.c b/ftpmodul/source/ftp.c new file mode 100644 index 0000000..947b324 --- /dev/null +++ b/ftpmodul/source/ftp.c @@ -0,0 +1,335 @@ +// FTP-Kern des MBMNET-FTP-Moduls (Hintergrund-Prozess, siehe main.c). +// +// - Ohne Benutzername/Passwort (jede Anmeldung wird angenommen), nur Passiv-Modus (PASV/EPSV). +// - Lesen: ganze SD-Karte. Schreiben/Löschen/Ordner anlegen: nur unter /3ds/mbmnet, damit niemand im +// WLAN Luma oder boot.firm überschreiben kann. +// - Eine Verbindung nach der anderen. +#include <3ds.h> +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ftp.h" + +#define WRITE_ROOT "/3ds/mbmnet" +#define XFER_SIZE (32 * 1024) + + +// --- Hilfen --------------------------------------------------------------------------- + +static void reply(int fd, const char *fmt, ...) +{ + char line[512]; + va_list ap; + va_start(ap, fmt); + int n = vsnprintf(line, sizeof(line) - 2, fmt, ap); + va_end(ap); + if (n < 0) return; + if (n > (int)sizeof(line) - 3) n = sizeof(line) - 3; + line[n++] = '\r'; + line[n++] = '\n'; + send(fd, line, n, 0); +} + +static bool send_all(int fd, const char *buf, size_t len) +{ + while (len) { + ssize_t n = send(fd, buf, len, 0); + if (n <= 0) return false; + buf += n; + len -= n; + } + return true; +} + +// Pfad auflösen: absolut oder relativ zu cwd, ".." und "." entfernen. Ergebnis beginnt mit "/". +static void resolve(const char *cwd, const char *arg, char *out, size_t len) +{ + char tmp[512]; + if (!arg || !arg[0]) snprintf(tmp, sizeof(tmp), "%s", cwd); + else if (arg[0] == '/') snprintf(tmp, sizeof(tmp), "%s", arg); + else snprintf(tmp, sizeof(tmp), "%s/%s", strcmp(cwd, "/") ? cwd : "", arg); + + char *parts[64]; + int count = 0; + for (char *p = strtok(tmp, "/"); p && count < 64; p = strtok(NULL, "/")) { + if (!strcmp(p, ".")) continue; + if (!strcmp(p, "..")) { if (count) count--; continue; } + parts[count++] = p; + } + size_t o = 0; + out[0] = 0; + for (int i = 0; i < count && o + 2 < len; i++) o += snprintf(out + o, len - o, "/%s", parts[i]); + if (!count) snprintf(out, len, "/"); +} + +static void sd_path(const char *path, char *out, size_t len) { snprintf(out, len, "sdmc:%s", path); } + +static bool writable(const char *path) +{ + size_t n = strlen(WRITE_ROOT); + return !strncmp(path, WRITE_ROOT, n) && (path[n] == 0 || path[n] == '/'); +} + +// --- Daten-Verbindung (passiv) ---------------------------------------------------------- + +static int open_passive(int ctrl, bool extended) +{ + static int nextPort = CONTROL_PORT + 1; + int fd = socket(AF_INET, SOCK_STREAM, 0); + if (fd < 0) return -1; + struct sockaddr_in addr = { .sin_family = AF_INET, .sin_addr.s_addr = INADDR_ANY }; + for (int tries = 0; tries < 50; tries++) { + int port = nextPort++; + if (nextPort > CONTROL_PORT + 200) nextPort = CONTROL_PORT + 1; + addr.sin_port = htons(port); + if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == 0 && listen(fd, 1) == 0) { + u32 ip = (u32)gethostid(); + if (extended) reply(ctrl, "229 Entering Extended Passive Mode (|||%d|)", port); + else reply(ctrl, "227 Entering Passive Mode (%lu,%lu,%lu,%lu,%d,%d)", (unsigned long)(ip & 0xFF), + (unsigned long)((ip >> 8) & 0xFF), (unsigned long)((ip >> 16) & 0xFF), (unsigned long)(ip >> 24), + port >> 8, port & 0xFF); + return fd; + } + } + close(fd); + return -1; +} + +// Wartet auf den Client (höchstens 10 s) und gibt die Daten-Verbindung zurück +static int accept_data(int pasvFd) +{ + struct pollfd p = { .fd = pasvFd, .events = POLLIN }; + if (poll(&p, 1, 10000) <= 0) return -1; + return accept(pasvFd, NULL, NULL); +} + +// --- Befehle ----------------------------------------------------------------------------- + +// Ein Eintrag im MLSD/MLST-Format (maschinenlesbar, wie FileZilla es abfragt) +static int mlsx_fact(char *out, size_t len, const struct stat *st, bool dir, const char *name) +{ + char modify[20] = "20000101000000"; + if (st->st_mtime > 0) strftime(modify, sizeof(modify), "%Y%m%d%H%M%S", gmtime(&st->st_mtime)); + return snprintf(out, len, "type=%s;size=%llu;modify=%s;perm=%s; %s\r\n", dir ? "dir" : "file", + (unsigned long long)(dir ? 0 : st->st_size), modify, dir ? "el" : "r", name); +} + +enum { LIST_UNIX, LIST_NAMES, LIST_MLSD }; + +static void list_dir(int ctrl, int data, const char *path, int mode) +{ + char sd[600]; + sd_path(path, sd, sizeof(sd)); + DIR *d = opendir(sd); + if (!d) { reply(ctrl, "550 Ordner nicht gefunden"); return; } + reply(ctrl, "150 Liste folgt"); + struct dirent *e; + char line[700], child[900]; + while ((e = readdir(d))) { + if (!strcmp(e->d_name, ".") || !strcmp(e->d_name, "..")) continue; + if (mode == LIST_NAMES) { int n = snprintf(line, sizeof(line), "%s\r\n", e->d_name); send_all(data, line, n); continue; } + snprintf(child, sizeof(child), "%s/%s", sd, e->d_name); + struct stat st = { 0 }; + stat(child, &st); + bool dir = S_ISDIR(st.st_mode) || e->d_type == DT_DIR; + if (mode == LIST_MLSD) { + int n = mlsx_fact(line, sizeof(line), &st, dir, e->d_name); + if (!send_all(data, line, n)) break; + continue; + } + char date[16] = "Jan 1 2000"; + if (st.st_mtime > 0) strftime(date, sizeof(date), "%b %d %H:%M", localtime(&st.st_mtime)); + int n = snprintf(line, sizeof(line), "%s 1 3ds 3ds %10llu %s %s\r\n", dir ? "drwxr-xr-x" : "-rw-r--r--", + (unsigned long long)(dir ? 0 : st.st_size), date, e->d_name); + if (!send_all(data, line, n)) break; + } + closedir(d); + reply(ctrl, "226 Fertig"); +} + +static void retrieve(int ctrl, int data, const char *path) +{ + char sd[600]; + sd_path(path, sd, sizeof(sd)); + FILE *f = fopen(sd, "rb"); + if (!f) { reply(ctrl, "550 Datei nicht gefunden"); return; } + reply(ctrl, "150 Sende Datei"); + char *buf = malloc(XFER_SIZE); + bool ok = buf != NULL; + size_t n; + while (ok && (n = fread(buf, 1, XFER_SIZE, f)) > 0) ok = send_all(data, buf, n); + free(buf); + fclose(f); + reply(ctrl, ok ? "226 Fertig" : "426 Übertragung abgebrochen"); +} + +static void store(int ctrl, int data, const char *path) +{ + char sd[600]; + sd_path(path, sd, sizeof(sd)); + FILE *f = fopen(sd, "wb"); + if (!f) { reply(ctrl, "550 Datei nicht schreibbar"); return; } + reply(ctrl, "150 Empfange Datei"); + char *buf = malloc(XFER_SIZE); + bool ok = buf != NULL; + ssize_t n; + while (ok && (n = recv(data, buf, XFER_SIZE, 0)) > 0) ok = fwrite(buf, 1, n, f) == (size_t)n; + free(buf); + fclose(f); + reply(ctrl, ok ? "226 Fertig" : "451 Schreiben fehlgeschlagen"); +} + +static void session(int ctrl) +{ + char cwd[512] = "/", line[600], path[512], sd[600], renameFrom[512] = ""; + int pasvFd = -1; + size_t used = 0; + reply(ctrl, "220 MBMNET-FTP (ohne Passwort, Schreiben nur in " WRITE_ROOT ")"); + + while (!ftp_should_exit()) { + // Eine Zeile lesen + char *eol; + while (!(eol = memchr(line, '\n', used))) { + struct pollfd p = { .fd = ctrl, .events = POLLIN }; + if (ftp_should_exit()) goto done; + int r = poll(&p, 1, 500); + if (r < 0) goto done; + if (r == 0) continue; + if (used >= sizeof(line) - 1) used = 0; // zu lange Zeile verwerfen + ssize_t n = recv(ctrl, line + used, sizeof(line) - 1 - used, 0); + if (n <= 0) goto done; + used += n; + } + *eol = 0; + if (eol > line && eol[-1] == '\r') eol[-1] = 0; + char cmd[600]; + snprintf(cmd, sizeof(cmd), "%s", line); + size_t rest = used - (eol - line + 1); + memmove(line, eol + 1, rest); + used = rest; + + char *arg = strchr(cmd, ' '); + if (arg) *arg++ = 0; + for (char *c = cmd; *c; c++) if (*c >= 'a' && *c <= 'z') *c -= 32; + + if (!strcmp(cmd, "USER")) reply(ctrl, "331 Passwort egal"); + else if (!strcmp(cmd, "PASS")) reply(ctrl, "230 Angemeldet"); + else if (!strcmp(cmd, "SYST")) reply(ctrl, "215 UNIX Type: L8"); + else if (!strcmp(cmd, "FEAT")) { reply(ctrl, "211-Features:\r\n PASV\r\n EPSV\r\n SIZE\r\n MDTM\r\n MLST type*;size*;modify*;perm*;\r\n UTF8\r\n211 Ende"); } + else if (!strcmp(cmd, "OPTS")) reply(ctrl, "200 OK"); + else if (!strcmp(cmd, "NOOP")) reply(ctrl, "200 OK"); + else if (!strcmp(cmd, "TYPE") || !strcmp(cmd, "MODE") || !strcmp(cmd, "STRU")) reply(ctrl, "200 OK"); + else if (!strcmp(cmd, "PWD") || !strcmp(cmd, "XPWD")) reply(ctrl, "257 \"%s\"", cwd); + else if (!strcmp(cmd, "CWD") || !strcmp(cmd, "CDUP")) { + resolve(cwd, !strcmp(cmd, "CDUP") ? ".." : arg, path, sizeof(path)); + sd_path(path, sd, sizeof(sd)); + struct stat st; + if (stat(sd, &st) == 0 && S_ISDIR(st.st_mode)) { snprintf(cwd, sizeof(cwd), "%s", path); reply(ctrl, "250 OK"); } + else if (!strcmp(path, "/")) { snprintf(cwd, sizeof(cwd), "/"); reply(ctrl, "250 OK"); } + else reply(ctrl, "550 Ordner nicht gefunden"); + } + else if (!strcmp(cmd, "PASV") || !strcmp(cmd, "EPSV")) { + if (pasvFd >= 0) close(pasvFd); + pasvFd = open_passive(ctrl, !strcmp(cmd, "EPSV")); + if (pasvFd < 0) reply(ctrl, "425 Kein Daten-Port frei"); + } + else if (!strcmp(cmd, "SIZE")) { + resolve(cwd, arg, path, sizeof(path)); + sd_path(path, sd, sizeof(sd)); + struct stat st; + if (stat(sd, &st) == 0 && !S_ISDIR(st.st_mode)) reply(ctrl, "213 %llu", (unsigned long long)st.st_size); + else reply(ctrl, "550 Nicht gefunden"); + } + else if (!strcmp(cmd, "MLST")) { + // Ein einzelner Eintrag, direkt auf der Steuer-Verbindung + resolve(cwd, arg, path, sizeof(path)); + sd_path(path, sd, sizeof(sd)); + struct stat st = { 0 }; + bool root = !strcmp(path, "/"); + if (!root && stat(sd, &st) != 0) { reply(ctrl, "550 Nicht gefunden"); continue; } + char fact[700]; + mlsx_fact(fact, sizeof(fact), &st, root || S_ISDIR(st.st_mode), path); + fact[strcspn(fact, "\r\n")] = 0; + reply(ctrl, "250-Eintrag\r\n %s\r\n250 Ende", fact); + } + else if (!strcmp(cmd, "MDTM")) { + resolve(cwd, arg, path, sizeof(path)); + sd_path(path, sd, sizeof(sd)); + struct stat st; + char modify[20] = "20000101000000"; + if (stat(sd, &st) != 0) { reply(ctrl, "550 Nicht gefunden"); continue; } + if (st.st_mtime > 0) strftime(modify, sizeof(modify), "%Y%m%d%H%M%S", gmtime(&st.st_mtime)); + reply(ctrl, "213 %s", modify); + } + else if (!strcmp(cmd, "LIST") || !strcmp(cmd, "NLST") || !strcmp(cmd, "MLSD") || !strcmp(cmd, "RETR") || !strcmp(cmd, "STOR")) { + bool isList = cmd[0] == 'L' || cmd[0] == 'N' || cmd[0] == 'M'; + // "LIST -la" u. ä.: Optionen ignorieren + const char *target = arg && arg[0] == '-' ? NULL : arg; + resolve(cwd, target, path, sizeof(path)); + if (!strcmp(cmd, "STOR") && !writable(path)) { reply(ctrl, "550 Schreiben nur in " WRITE_ROOT); continue; } + if (pasvFd < 0) { reply(ctrl, "425 Erst PASV senden"); continue; } + int data = accept_data(pasvFd); + close(pasvFd); + pasvFd = -1; + if (data < 0) { reply(ctrl, "425 Keine Daten-Verbindung"); continue; } + if (isList) list_dir(ctrl, data, path, cmd[0] == 'N' ? LIST_NAMES : cmd[0] == 'M' ? LIST_MLSD : LIST_UNIX); + else if (cmd[0] == 'R') retrieve(ctrl, data, path); + else store(ctrl, data, path); + close(data); + } + else if (!strcmp(cmd, "DELE") || !strcmp(cmd, "RMD") || !strcmp(cmd, "MKD") || !strcmp(cmd, "XMKD")) { + resolve(cwd, arg, path, sizeof(path)); + if (!writable(path) || !strcmp(path, WRITE_ROOT)) { reply(ctrl, "550 Ändern nur in " WRITE_ROOT); continue; } + sd_path(path, sd, sizeof(sd)); + int r = !strcmp(cmd, "DELE") ? remove(sd) : !strcmp(cmd, "RMD") ? rmdir(sd) : mkdir(sd, 0777); + if (r == 0) reply(ctrl, cmd[0] == 'M' || cmd[0] == 'X' ? "257 \"%s\" angelegt" : "250 OK", path); + else reply(ctrl, "550 Fehlgeschlagen"); + } + else if (!strcmp(cmd, "RNFR")) { + resolve(cwd, arg, renameFrom, sizeof(renameFrom)); + if (!writable(renameFrom)) { renameFrom[0] = 0; reply(ctrl, "550 Ändern nur in " WRITE_ROOT); } + else reply(ctrl, "350 Weiter mit RNTO"); + } + else if (!strcmp(cmd, "RNTO")) { + resolve(cwd, arg, path, sizeof(path)); + char from[600]; + sd_path(renameFrom, from, sizeof(from)); + sd_path(path, sd, sizeof(sd)); + if (renameFrom[0] && writable(path) && rename(from, sd) == 0) reply(ctrl, "250 OK"); + else reply(ctrl, "550 Umbenennen fehlgeschlagen"); + renameFrom[0] = 0; + } + else if (!strcmp(cmd, "QUIT")) { reply(ctrl, "221 Tschüss"); break; } + else reply(ctrl, "502 Nicht unterstützt"); + } +done: + if (pasvFd >= 0) close(pasvFd); +} + +// Nimmt Verbindungen an, bis das Netz weg ist, sich die IP ändert oder das Modul aufhören soll. +void ftp_serve(int listenFd, u32 ip) +{ + while (!ftp_should_exit()) { + if ((u32)gethostid() != ip) return; // WLAN gewechselt oder weg + struct pollfd p = { .fd = listenFd, .events = POLLIN }; + int r = poll(&p, 1, 2000); + if (r < 0 || (p.revents & (POLLERR | POLLHUP | POLLNVAL))) return; + if (r == 0) continue; + int ctrl = accept(listenFd, NULL, NULL); + if (ctrl < 0) return; + session(ctrl); + close(ctrl); + } +} diff --git a/ftpmodul/source/ftp.h b/ftpmodul/source/ftp.h new file mode 100644 index 0000000..ee38fe6 --- /dev/null +++ b/ftpmodul/source/ftp.h @@ -0,0 +1,10 @@ +#pragma once +#include <3ds/types.h> + +#define CONTROL_PORT 5000 + +// Nimmt FTP-Verbindungen an, bis das Netz weg ist oder sich die IP ändert +void ftp_serve(int listenFd, u32 ip); + +// Soll das Modul aufhören? (Stopp-Datei der App oder Beenden-Aufforderung des Systems; in main.c) +bool ftp_should_exit(void); diff --git a/ftpmodul/source/ftpstatus.h b/ftpmodul/source/ftpstatus.h new file mode 100644 index 0000000..25d1dce --- /dev/null +++ b/ftpmodul/source/ftpstatus.h @@ -0,0 +1,28 @@ +#pragma once +// Statusblock des FTP-Moduls. Die App liest ihn per Debug-Zugriff direkt aus dem Speicher des Moduls +// (die Adresse steht beim Bauen fest) - so klappt die Anzeige auch, wenn das Modul nicht an die SD kommt. +// Über "stop" kann die App das Modul ebenfalls ohne SD zum Beenden auffordern. +// Wird von ftpmodul/source/main.c und source/ftpctl.c (App) benutzt. +#include <3ds/types.h> + +#define FTP_STATUS_MAGIC 0x5446424D // "MBFT" + +enum { + FTP_STAGE_START = 0, // vor __appInit / srvInit + FTP_STAGE_INIT, // srv, fs, SD erledigt (Ergebnisse in srv/fs/sdmc) + FTP_STAGE_SOC, // wartet auf den Netzwerk-Dienst (socInit, Ergebnis in soc) + FTP_STAGE_WIFI, // wartet auf WLAN (keine IP) + FTP_STAGE_PORT, // Port 5000 lässt sich nicht öffnen (errno in bindErrno) + FTP_STAGE_READY, // bereit, IP in ip + FTP_STAGE_EXIT, // beendet sich +}; + +typedef struct { + u32 magic; + u32 stage; + s32 srv, fs, sdmc, soc; + u32 ip; + u32 heartbeat; // zählt hoch, solange das Modul lebt + u32 stop; // die App setzt 1: Modul beendet sich sauber + s32 bindErrno; +} FtpStatus; diff --git a/ftpmodul/source/main.c b/ftpmodul/source/main.c new file mode 100644 index 0000000..be1fd3c --- /dev/null +++ b/ftpmodul/source/main.c @@ -0,0 +1,181 @@ +// MBMNET-FTP-Modul: läuft als eigener Hintergrund-Prozess, auch wenn die MBMNET-App geschlossen ist. +// +// Die App legt dieses Modul als /luma/sysmodules/0004013000F1E002.cxi ab und startet es über den +// Prozess-Manager (Luma lädt Systemmodule mit dieser Kennung von der SD). "FTP aus" in der App +// beendet den Prozess. Nach einem Neustart des 3DS ist es aus, bis die App es wieder startet. +// +// Die aktuelle Adresse steht für die App in /3ds/mbmnet/ftp-adresse.txt. +// +// Beenden immer sauber durch das Modul selbst (nie von außen abschießen - das brachte den 3DS zum +// Absturz): "FTP aus" legt /3ds/mbmnet/ftp-stopp an, beim Neustart/Ausschalten schickt das System +// die Benachrichtigung 0x100. Dann Verbindungen und Netzwerk-Dienst schließen und zurückkehren. +#include <3ds.h> +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ftp.h" +#include "ftpstatus.h" + +// Statusblock für die App (Adresse fest, siehe Makefile -> ftpmodul.sym) +volatile FtpStatus ftpStatus __attribute__((used, aligned(4))) = { .magic = FTP_STATUS_MAGIC }; + +#define SOC_BUFFER_SIZE 0x20000 +#define ADDRESS_FILE "sdmc:/3ds/mbmnet/ftp-adresse.txt" +#define LOG_FILE "sdmc:/3ds/mbmnet/ftp.log" +#define STOP_FILE "sdmc:/3ds/mbmnet/ftp-stopp" + +static Handle notificationSemaphore; +static bool quit; + + +// Protokoll für die Fehlersuche (die App zeigt die letzte Zeile, wenn der Server nicht antwortet) +static void logf_(const char *fmt, ...) +{ + FILE *f = fopen(LOG_FILE, "a"); + if (!f) return; + va_list ap; + va_start(ap, fmt); + vfprintf(f, fmt, ap); + va_end(ap); + fputc('\n', f); + fclose(f); +} + +// Ein Hintergrund-Modul bekommt nur wenig Speicher: Heap fest vorgeben statt "alles, was frei ist" +u32 __ctru_heap_size = 0x80000; +u32 __ctru_linear_heap_size = 0x1000; + +// Nur die Dienste, die das Modul braucht (kein Grafik-/HOME-Menü-Dienst wie bei einer App) +void __appInit(void) +{ + // srv ist beim Start evtl. noch belegt: kurz wiederholen + for (int i = 0; i < 100 && R_FAILED(ftpStatus.srv = srvInit()); i++) svcSleepThread(50 * 1000 * 1000); + ftpStatus.fs = fsInit(); + ftpStatus.sdmc = archiveMountSdmc(); + ftpStatus.stage = FTP_STAGE_INIT; +} + +void __appExit(void) +{ + archiveUnmountAll(); + fsExit(); + srvExit(); +} + +bool ftp_should_exit(void) +{ + ftpStatus.heartbeat++; + if (ftpStatus.stop) quit = true; // Stopp-Bit der App (geht auch ohne SD) + if (quit) return true; + // Beenden-Aufforderung des Systems (Neustart, Ausschalten) + if (notificationSemaphore && R_SUCCEEDED(svcWaitSynchronization(notificationSemaphore, 0))) { + u32 id = 0; + if (R_SUCCEEDED(srvReceiveNotification(&id)) && id == 0x100) quit = true; + } + // Stopp-Datei der App, höchstens alle 2 Sekunden nachsehen + static u64 lastCheck; + u64 now = osGetTime(); + if (!quit && now - lastCheck >= 2000) { + lastCheck = now; + struct stat st; + if (stat(STOP_FILE, &st) == 0) quit = true; + } + return quit; +} + +// Wartet ms Millisekunden, bricht aber ab, sobald das Modul aufhören soll +static void sleep_ms(int ms) +{ + for (int waited = 0; waited < ms && !ftp_should_exit(); waited += 100) svcSleepThread(100LL * 1000 * 1000); +} + +static void write_address(u32 ip) +{ + mkdir("sdmc:/3ds", 0777); + mkdir("sdmc:/3ds/mbmnet", 0777); + FILE *f = fopen(ADDRESS_FILE, "w"); + if (!f) return; + if (ip) fprintf(f, "%lu.%lu.%lu.%lu:%d\n", (unsigned long)(ip & 0xFF), (unsigned long)((ip >> 8) & 0xFF), + (unsigned long)((ip >> 16) & 0xFF), (unsigned long)(ip >> 24), CONTROL_PORT); + fclose(f); +} + +int main(void) +{ + remove(LOG_FILE); + remove(STOP_FILE); + srvEnableNotification(¬ificationSemaphore); // für die Beenden-Aufforderung 0x100 + logf_("MBMNET-FTP-Modul gestartet: srv %08lX, fs %08lX, sdmc %08lX, frei (Base) %lld KB", + (unsigned long)ftpStatus.srv, (unsigned long)ftpStatus.fs, (unsigned long)ftpStatus.sdmc, + osGetMemRegionFree(MEMREGION_BASE) / 1024); + u32 *socBuffer = memalign(0x1000, SOC_BUFFER_SIZE); + if (!socBuffer) { logf_("Fehler: kein Speicher für den Netzwerk-Puffer"); return 1; } + + while (!ftp_should_exit()) { + // Netzwerk-Dienst (nach dem Schlafmodus ggf. neu) + Result rc; + int tries = 0; + ftpStatus.stage = FTP_STAGE_SOC; + while (R_FAILED(rc = ftpStatus.soc = socInit(socBuffer, SOC_BUFFER_SIZE))) { + if (ftp_should_exit()) goto done; + if (tries++ % 15 == 0) logf_("Netzwerk-Dienst (socInit) fehlgeschlagen: %08lX", (unsigned long)rc); + sleep_ms(2000); + } + logf_("Netzwerk-Dienst bereit"); + + int failures = 0, waits = 0; + while (failures < 5 && !ftp_should_exit()) { + u32 ip = (u32)gethostid(); + ftpStatus.ip = ip; + if (!ip) { // noch kein WLAN + ftpStatus.stage = FTP_STAGE_WIFI; + if (waits++ % 15 == 0) logf_("Warte auf WLAN (keine IP)"); + write_address(0); + sleep_ms(2000); + continue; + } + waits = 0; + + int fd = socket(AF_INET, SOCK_STREAM, 0); + struct sockaddr_in addr = { .sin_family = AF_INET, .sin_port = htons(CONTROL_PORT), .sin_addr.s_addr = INADDR_ANY }; + if (fd < 0 || bind(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0 || listen(fd, 2) != 0) { + logf_("Port %d öffnen fehlgeschlagen (Socket %d, errno %d)", CONTROL_PORT, fd, errno); + ftpStatus.stage = FTP_STAGE_PORT; + ftpStatus.bindErrno = errno; + if (fd >= 0) close(fd); + failures++; + sleep_ms(2000); + continue; + } + failures = 0; + ftpStatus.stage = FTP_STAGE_READY; + write_address(ip); + logf_("Bereit: ftp://%lu.%lu.%lu.%lu:%d", (unsigned long)(ip & 0xFF), (unsigned long)((ip >> 8) & 0xFF), + (unsigned long)((ip >> 16) & 0xFF), (unsigned long)(ip >> 24), CONTROL_PORT); + ftp_serve(fd, ip); // kehrt zurück, wenn das Netz weg ist oder sich die IP ändert + close(fd); + sleep_ms(500); + } + socExit(); + if (ftp_should_exit()) break; + // Mehrfach kein Socket möglich (z. B. nach dem Schlafmodus): Netzwerk-Dienst neu aufsetzen + logf_("Netzwerk-Dienst wird neu aufgesetzt"); + sleep_ms(2000); + } +done: + ftpStatus.stage = FTP_STAGE_EXIT; + // Sauber beenden: Adresse weg, Stopp-Datei weg; libctru schließt danach fs und srv + remove(ADDRESS_FILE); + remove(STOP_FILE); + logf_("Beendet"); + free(socBuffer); + return 0; +} diff --git a/icon.png b/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..627e784a576ffce800911d3f12c097e6bb7a7b5c GIT binary patch literal 3029 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 literal 0 HcmV?d00001 diff --git a/release.sh b/release.sh new file mode 100755 index 0000000..d889b37 --- /dev/null +++ b/release.sh @@ -0,0 +1,66 @@ +#!/bin/bash +# Baut die App und lädt sie ins Repo "MBMNET" hoch. Danach aktualisiert sich jede +# MBMNET-App beim nächsten Start von selbst. +# Zusätzlich legt es auf Gitea ein Release "vX.Y.Z" mit .cia und .3dsx an (für Universal-Updater). +# +# Vorher in Makefile die VERSION erhöhen! +# ./release.sh ["Release-Notizen"] bauen, hochladen, Release anlegen +# ./release.sh --nur-release ["Notizen"] nur das Release zur aktuellen Version anlegen +set -euo pipefail +cd "$(dirname "$0")" + +VERSION=$(sed -n 's/^VERSION *:= *//p' Makefile) +RELEASE=../release +GITEA=https://git.mbm.wtf +REPO=MrMaho/MBMNET + +NUR_RELEASE=0 +if [ "${1:-}" = "--nur-release" ]; then NUR_RELEASE=1; shift; fi +NOTIZEN=${1:-"MBMNET-App v$VERSION"} + +if [ "$NUR_RELEASE" = 0 ]; then + # Build-Umgebung mit makerom und bannertool (für die CIA), wird nur beim ersten Mal gebaut + docker image inspect mbmnet-3ds-build >/dev/null 2>&1 || docker build -t mbmnet-3ds-build tools + + echo "Baue MBMNET-App v$VERSION ..." + docker run --rm -v "$PWD":/app -w /app mbmnet-3ds-build bash -c 'make clean >/dev/null && make && make cia' + + cp mbmnet.3dsx mbmnet.cia "$RELEASE/" + echo "$VERSION" > "$RELEASE/version.txt" + + (cd "$RELEASE" && git add mbmnet.3dsx mbmnet.cia version.txt && git commit -m "MBMNET-App v$VERSION" && git push) +fi + +# --- Gitea-Release ------------------------------------------------------------------- +# Zugangsdaten wie bei git push aus dem Schlüsselbund; sie landen nur in einer curl-Konfiguration +# über stdin (nicht in der Prozessliste, nicht in der Ausgabe). +CRED=$(printf 'protocol=https\nhost=git.mbm.wtf\n\n' | git credential fill) +GUSER=$(sed -n 's/^username=//p' <<<"$CRED") +GPASS=$(sed -n 's/^password=//p' <<<"$CRED") +api() { # api METHODE PFAD [weitere curl-Argumente] + local method=$1 path=$2; shift 2 + printf 'user = "%s:%s"\n' "$GUSER" "$GPASS" | curl -sS --fail-with-body -K - -X "$method" "$GITEA/api/v1/repos/$REPO$path" "$@" +} +json() { python3 -c "import json,sys; d=json.load(sys.stdin); print($1)"; } + +TAG="v$VERSION" +COMMIT=$(git -C "$RELEASE" rev-parse HEAD) +if ID=$( (api GET "/releases/tags/$TAG" | json "d['id']") 2>/dev/null ); then + echo "Release $TAG gibt es schon (ID $ID), ersetze die Dateien ..." +else + BODY=$(TAG="$TAG" COMMIT="$COMMIT" NOTIZEN="$NOTIZEN" python3 -c \ + 'import json,os; print(json.dumps({"tag_name": os.environ["TAG"], "target_commitish": os.environ["COMMIT"], "name": "MBMNET " + os.environ["TAG"], "body": os.environ["NOTIZEN"]}))') + ID=$(api POST /releases -H 'Content-Type: application/json' -d "$BODY" | json "d['id']") + echo "Release $TAG angelegt (ID $ID)" +fi + +# Vorhandene Dateien gleichen Namens löschen (bei erneutem Lauf), dann hochladen +for f in mbmnet.cia mbmnet.3dsx; do + for old in $(api GET "/releases/$ID/assets" | json "' '.join(str(a['id']) for a in d if a['name']=='$f')"); do + api DELETE "/releases/$ID/assets/$old" >/dev/null + done + api POST "/releases/$ID/assets?name=$f" -F "attachment=@$RELEASE/$f" >/dev/null + echo " $f hochgeladen" +done + +echo "Fertig: v$VERSION ist veröffentlicht ($GITEA/$REPO/releases/tag/$TAG)." diff --git a/source/admin.c b/source/admin.c new file mode 100644 index 0000000..5e0ec4c --- /dev/null +++ b/source/admin.c @@ -0,0 +1,57 @@ +// Entwickler-Werkzeuge nur für Admins: Die App fragt bei MBMNET, ob die verknüpfte NNID einem Admin +// gehört (GET /mbmnet/app-info?pid=...). Die Antwort wird auf der SD gemerkt, damit die Werkzeuge +// auch im Nintendo-Modus und ohne Verbindung da sind. +#include <3ds.h> +#include +#include + +#include "admin.h" + +#define CACHE_FILE "sdmc:/3ds/mbmnet/admin" + +static volatile bool isAdmin; +static Thread thread; +static char url[128]; + +static void remember(bool on) +{ + FILE *f = fopen(CACHE_FILE, "w"); + if (f) { fputs(on ? "1" : "0", f); fclose(f); } +} + +static void worker(void *arg) +{ + (void)arg; + httpcContext ctx; + if (R_FAILED(httpcOpenContext(&ctx, HTTPC_METHOD_GET, url, 1))) return; + httpcAddRequestHeaderField(&ctx, "User-Agent", "MBMNET-Switcher/" APP_VERSION); + u32 status = 0, got = 0; + char body[32] = { 0 }; + Result rc = httpcBeginRequest(&ctx); + if (R_SUCCEEDED(rc)) rc = httpcGetResponseStatusCodeTimeout(&ctx, &status, 8ULL * 1000 * 1000 * 1000); + if (R_SUCCEEDED(rc) && status == 200) httpcDownloadData(&ctx, (u8 *)body, sizeof(body) - 1, &got); + httpcCloseContext(&ctx); + if (status != 200 || strncmp(body, "admin=", 6) != 0) return; // keine Antwort: gemerkte gilt weiter + isAdmin = body[6] == '1'; + remember(isAdmin); +} + +void admin_start(const char *server, u32 pid) +{ + FILE *f = fopen(CACHE_FILE, "r"); + if (f) { isAdmin = fgetc(f) == '1'; fclose(f); } + if (!pid) return; + snprintf(url, sizeof(url), "http://%s/mbmnet/app-info?pid=%lu", server, (unsigned long)pid); + s32 prio = 0x30; + svcGetThreadPriority(&prio, CUR_THREAD_HANDLE); + thread = threadCreate(worker, NULL, 16 * 1024, prio + 1, -2, false); +} + +bool admin_is(void) { return isAdmin; } + +void admin_finish(void) +{ + if (!thread) return; + if (R_SUCCEEDED(threadJoin(thread, 3ULL * 1000 * 1000 * 1000))) threadFree(thread); + thread = NULL; +} diff --git a/source/admin.h b/source/admin.h new file mode 100644 index 0000000..f6fcff7 --- /dev/null +++ b/source/admin.h @@ -0,0 +1,9 @@ +#pragma once +#include <3ds/types.h> + +// Fragt im Hintergrund bei MBMNET, ob die verknüpfte NNID (pid) einem Admin gehört. +// pid = 0: nicht fragen, nur die gemerkte Antwort vom letzten Mal benutzen. +void admin_start(const char *server, u32 pid); +// Admin? (gemerkte Antwort, bis der Server geantwortet hat) +bool admin_is(void); +void admin_finish(void); diff --git a/source/blz.c b/source/blz.c new file mode 100644 index 0000000..1d3d99f --- /dev/null +++ b/source/blz.c @@ -0,0 +1,58 @@ +// Entpacker für das "Backwards LZ"-Format, mit dem Nintendo die .code von +// Systemmodulen komprimiert. Luma3DS wendet code.ips-Patches auf die +// ENTPACKTE .code an, deshalb müssen wir genauso rechnen. +#include +#include "blz.h" + +static u32 read32(const u8 *p) { return p[0] | (p[1] << 8) | (p[2] << 16) | ((u32)p[3] << 24); } + +bool blz_looks_compressed(const u8 *buf, u32 size) +{ + if (size < 8) return false; + u32 enc = read32(buf + size - 8); + u32 add = read32(buf + size - 4); + u32 hdr = enc >> 24; + u32 enclen = enc & 0xFFFFFF; + return hdr >= 8 && hdr <= 0x10 && enclen >= hdr && enclen <= size && add > 0 && add < 0x1000000; +} + +u32 blz_decompressed_size(const u8 *buf, u32 size) +{ + return size + read32(buf + size - 4); +} + +// buf muss mindestens blz_decompressed_size() Bytes groß sein. +// Daten liegen am Anfang von buf, es wird rückwärts in-place entpackt. +bool blz_decompress(u8 *buf, u32 size) +{ + u32 enc = read32(buf + size - 8); + u32 hdr = enc >> 24; + u32 enclen = enc & 0xFFFFFF; + u32 outsize = blz_decompressed_size(buf, size); + + u8 *src = buf + size - hdr; + u8 *srcEnd = buf + size - enclen; + u8 *dst = buf + outsize; + + while (src > srcEnd) { + u8 flags = *--src; + for (int i = 0; i < 8 && src > srcEnd; i++, flags <<= 1) { + if (flags & 0x80) { + if (src - 2 < buf) return false; + u8 hi = *--src; + u8 lo = *--src; + u32 len = (hi >> 4) + 3; + u32 disp = (((hi & 0x0F) << 8) | lo) + 3; + for (u32 j = 0; j < len; j++) { + if (dst - 1 < buf || dst - 1 + disp >= buf + outsize) return false; + dst--; + *dst = dst[disp]; + } + } else { + if (dst - 1 < buf) return false; + *--dst = *--src; + } + } + } + return true; +} diff --git a/source/blz.h b/source/blz.h new file mode 100644 index 0000000..23e9990 --- /dev/null +++ b/source/blz.h @@ -0,0 +1,6 @@ +#pragma once +#include <3ds/types.h> + +bool blz_looks_compressed(const u8 *buf, u32 size); +u32 blz_decompressed_size(const u8 *buf, u32 size); +bool blz_decompress(u8 *buf, u32 size); diff --git a/source/frdswitch.c b/source/frdswitch.c new file mode 100644 index 0000000..de2cc6c --- /dev/null +++ b/source/frdswitch.c @@ -0,0 +1,245 @@ +// Eigenes MBMNET-Freundekonto, wie bei Pretendos Nimbus: +// +// Freundekonto 1: Nintendo - mit Konto-Platz 1 (Nintendo Network ID) und der Nintendo-Freundesliste +// Freundekonto 3: MBMNET - mit eigenem Konto-Platz (MBMNET-Konto) und eigener Freundesliste +// +// (Freundekonto 2 benutzt Pretendos Nimbus, das bleibt unangetastet.) +// +// Umschalten: beide Konten abmelden, das andere laden, seinen Konto-Platz zum Standard machen, Neustart. +// Beim ersten Mal legt die App das MBMNET-Freundekonto an. Es hat noch keine Kennung; beim ersten +// Login holt es sich bei MBMNET ein neues Konto (NASC "passwd"), der Server gibt ihm den Freundescode +// des MBMNET-Kontos von der Webseite. +#include <3ds.h> +#include +#include +#include + +#include "frdswitch.h" + +#define RESULT_LOCAL_ACCOUNT_NOT_EXISTS 0xC880C4ED +#define LOG_FILE "sdmc:/3ds/mbmnet/konto.log" + +static bool ready; +static FILE *logf; +static const char *failedStep; + +static Result step(const char *name, Result rc) +{ + if (logf) fprintf(logf, "%-36s %08lX%s\n", name, (unsigned long)rc, R_FAILED(rc) ? " <- FEHLER" : ""); + if (R_FAILED(rc) && !failedStep) failedStep = name; + return rc; +} + +static void note(const char *name, Result rc) +{ + if (logf) fprintf(logf, "%-36s %08lX%s\n", name, (unsigned long)rc, R_FAILED(rc) ? " (ignoriert)" : ""); +} + +Result frdswitch_init(void) +{ + Result rc = ndmuInit(); + if (R_SUCCEEDED(rc)) rc = frdInit(false); // frd:a (Verwaltung) + if (R_SUCCEEDED(rc)) rc = actInit(false); // act:a + // Ohne diese SDK-Version lehnt der Freunde-Dienst Anlegen und Umschalten ab (so macht es Nimbus; + // daran scheiterte unser erster Versuch mit C960C4F6) + if (R_SUCCEEDED(rc)) rc = FRD_SetClientSdkVersion(0x70000c8); + ready = R_SUCCEEDED(rc); + return rc; +} + +void frdswitch_exit(void) +{ + actExit(); + frdExit(); + ndmuExit(); +} + +u8 frdswitch_current(void) +{ + u8 id = 0; + if (ready) FRD_GetMyLocalAccountId(&id); + return id; +} + +// Konto-Platz (act) zu einem Freundekonto. 0 = keiner. +static u32 act_slot_of(u8 friendAccount) +{ + u8 count = 0; + if (R_FAILED(ACT_GetCommonInfo(&count, sizeof(count), INFO_TYPE_COMMON_NUM_ACCOUNTS))) return 0; + for (u8 slot = 1; slot <= count; slot++) { + u8 fp = 0; + if (R_SUCCEEDED(ACT_GetAccountInfo(&fp, sizeof(fp), slot, INFO_TYPE_FP_LOCAL_ACCOUNT_ID)) && fp == friendAccount) return slot; + } + return 0; +} + +bool frdswitch_slot_linked(u8 friendAccount, char *id, size_t len) +{ + id[0] = 0; + u32 slot = ready ? act_slot_of(friendAccount) : 0; + if (!slot) return false; + AccountId acc = { 0 }; + if (R_FAILED(ACT_GetAccountInfo(acc, sizeof(acc), slot, INFO_TYPE_ACCOUNT_ID))) return false; + snprintf(id, len, "%s", acc); + return id[0] != 0; +} + +// Beide Konten abmelden. Das Freundekonto lässt sich nur offline entladen. +static Result unload(void) +{ + note("Konto (act) abmelden", ACTA_UnloadConsoleAccount()); // ohne geladenes Konto: "ungültiger Zustand" + + Result rc = step("Offline gehen (exklusiv)", NDMU_EnterExclusiveState(NDM_EXCLUSIVE_STATE_LOCAL_COMMUNICATIONS)); + if (R_FAILED(rc)) return rc; + for (int i = 0; i < 150; i++) { // höchstens 15 Sekunden + bool online = true; + if (R_FAILED(FRD_IsOnline(&online)) || !online) break; + svcSleepThread(100 * 1000 * 1000); + } + // Hängt der Freunde-Dienst noch an einer Anfrage, kurz wiederholen + for (int attempt = 1; attempt <= 20; attempt++) { + rc = FRDA_UnloadLocalAccount(); + if (R_SUCCEEDED(rc)) { + if (logf) fprintf(logf, "%-36s %08lX (Versuch %d)\n", "Freundekonto abmelden", (unsigned long)rc, attempt); + return rc; + } + svcSleepThread(500 * 1000 * 1000); + } + return step("Freundekonto abmelden (10 s)", rc); +} + +// Freundekonto laden. "Schon geladen" (z. B. direkt nach dem Anlegen) zählt als Erfolg. +static Result load_friend_account(u8 friendAccount) +{ + Result rc = FRDA_LoadLocalAccount(friendAccount); + if (R_FAILED(rc) && frdswitch_current() == friendAccount) { + note("Freundekonto laden (war schon geladen)", rc); + return 0; + } + return step("Freundekonto laden", rc); +} + +// Konto-Platz (act) des Freundekontos zum Standard machen; fehlt er, anlegen. *created: neu angelegt. +static Result use_act_slot(u8 friendAccount, u32 *slotOut, bool *created) +{ + Result rc = 0; + u32 slot = act_slot_of(friendAccount); + *created = false; + if (!slot) { + u8 count = 0; + rc = step("Konto-Plätze zählen", ACT_GetCommonInfo(&count, sizeof(count), INFO_TYPE_COMMON_NUM_ACCOUNTS)); + if (R_SUCCEEDED(rc)) rc = step("Konto-Platz anlegen", ACTA_CreateConsoleAccount()); + if (R_FAILED(rc)) return rc; + slot = count + 1; + rc = step("Konto-Platz speichern", ACTA_CommitConsoleAccount(slot)); + if (R_FAILED(rc)) return rc; + *created = true; + } + if (logf) fprintf(logf, " -> Konto-Platz %lu\n", (unsigned long)slot); + *slotOut = slot; + return step("Standard-Konto setzen", ACTA_SetDefaultAccount(slot)); +} + +bool frdswitch_to(u8 target, bool *created, char *msg, size_t msglen) +{ + *created = false; + if (!ready) { + snprintf(msg, msglen, "Kontodienste nicht verfügbar.\nIst Luma3DS aktuell?"); + return false; + } + mkdir("sdmc:/3ds/mbmnet", 0777); + logf = fopen(LOG_FILE, "w"); + failedStep = NULL; + u8 from = frdswitch_current(); + if (logf) fprintf(logf, "MBMNET: Freundekonto %u -> %u (App v%s)\n\n", from, target, APP_VERSION); + + u32 slot = 0; + bool newSlot = false; + Result rc = unload(); + if (R_SUCCEEDED(rc)) { + rc = FRDA_LoadLocalAccount(target); + if (rc == (Result)RESULT_LOCAL_ACCOUNT_NOT_EXISTS && target == FRIEND_ACCOUNT_MBMNET) { + // Erstes Mal: eigenes MBMNET-Freundekonto anlegen (normale Umgebung, die Patches lenken sie um) + note("Freundekonto laden (gibt es noch nicht)", rc); + rc = step("MBMNET-Freundekonto anlegen", FRDA_CreateLocalAccount(FRIEND_ACCOUNT_MBMNET, 0, 0, 1)); + if (R_SUCCEEDED(rc)) { *created = true; rc = load_friend_account(target); } + } else if (R_FAILED(rc) && frdswitch_current() == target) { + note("Freundekonto laden (war schon geladen)", rc); + rc = 0; + } else { + step("Freundekonto laden", rc); + } + if (R_SUCCEEDED(rc)) rc = use_act_slot(target, &slot, &newSlot); + // Neuer Platz: frisch zurücksetzen, damit "Vorhandene ID verknüpfen" angeboten wird (darf scheitern) + if (R_SUCCEEDED(rc) && newSlot) note("Konto-Platz zurücksetzen", ACTA_UnbindServerAccount(slot, true)); + } + + if (R_FAILED(rc)) { + // Zurück auf das vorherige Freundekonto, damit der 3DS nicht ohne/mit falschem Konto dasteht. + // Erst entladen - ein geladenes Konto lässt sich nicht einfach ersetzen. + u8 back = from ? from : FRIEND_ACCOUNT_NINTENDO; + if (frdswitch_current() != back) { + note("Rückweg: Freundekonto abmelden", FRDA_UnloadLocalAccount()); + note("Rückweg: altes Freundekonto laden", FRDA_LoadLocalAccount(back)); + } + NDMU_LeaveExclusiveState(); + } + if (logf) { fprintf(logf, "\nErgebnis: %s\n", R_SUCCEEDED(rc) ? "OK" : "FEHLER"); fclose(logf); logf = NULL; } + if (R_FAILED(rc)) { + snprintf(msg, msglen, "Umschalten fehlgeschlagen bei:\n%s (Fehler %08lX)\nProtokoll: /3ds/mbmnet/konto.log", + failedStep ? failedStep : "?", (unsigned long)rc); + return false; + } + return true; +} + +u32 frdswitch_my_pid(void) +{ + FriendKey key = { 0 }; + if (!ready || R_FAILED(FRD_GetMyFriendKey(&key))) return 0; + return key.principalId; +} + +bool frdswitch_pid_is_mbmnet(u32 pid) +{ + return pid >= MBMNET_PID_FIRST && pid <= MBMNET_PID_LAST; +} + +// Das MBMNET-Freundekonto neu anlegen (es hat eine Kennung von einem anderen Server, z. B. Pretendo). +// Der Konto-Platz mit der verknüpften MBMNET-ID bleibt, nur das Freundekonto wird ersetzt. Danach +// Neustart: Beim ersten Login holt es sich bei MBMNET eine neue Kennung. +bool frdswitch_recreate_mbmnet(char *msg, size_t msglen) +{ + if (!ready || frdswitch_current() != FRIEND_ACCOUNT_MBMNET) { + snprintf(msg, msglen, "MBMNET-Freundekonto ist nicht geladen."); + return false; + } + mkdir("sdmc:/3ds/mbmnet", 0777); + logf = fopen(LOG_FILE, "w"); + failedStep = NULL; + if (logf) fprintf(logf, "MBMNET: Freundekonto 3 neu anlegen, alte Kennung %lu (App v%s)\n\n", + (unsigned long)frdswitch_my_pid(), APP_VERSION); + + u32 slot = 0; + bool newSlot = false; + Result rc = unload(); + if (R_SUCCEEDED(rc)) rc = step("MBMNET-Freundekonto neu anlegen", FRDA_CreateLocalAccount(FRIEND_ACCOUNT_MBMNET, 0, 0, 1)); + if (R_SUCCEEDED(rc)) rc = load_friend_account(FRIEND_ACCOUNT_MBMNET); + if (R_SUCCEEDED(rc)) rc = use_act_slot(FRIEND_ACCOUNT_MBMNET, &slot, &newSlot); + if (R_FAILED(rc)) { + if (frdswitch_current() != FRIEND_ACCOUNT_MBMNET) note("Rückweg: Freundekonto laden", FRDA_LoadLocalAccount(FRIEND_ACCOUNT_MBMNET)); + NDMU_LeaveExclusiveState(); + } + if (logf) { fprintf(logf, "\nErgebnis: %s\n", R_SUCCEEDED(rc) ? "OK" : "FEHLER"); fclose(logf); logf = NULL; } + if (R_FAILED(rc)) { + snprintf(msg, msglen, "Neu anlegen fehlgeschlagen bei:\n%s (Fehler %08lX)\nProtokoll: /3ds/mbmnet/konto.log", + failedStep ? failedStep : "?", (unsigned long)rc); + return false; + } + return true; +} + +u8 frdswitch_slot_of(u8 friendAccount) +{ + return ready ? (u8)act_slot_of(friendAccount) : 0; +} diff --git a/source/frdswitch.h b/source/frdswitch.h new file mode 100644 index 0000000..e769ec1 --- /dev/null +++ b/source/frdswitch.h @@ -0,0 +1,27 @@ +#pragma once +#include <3ds/types.h> +#include + +#define FRIEND_ACCOUNT_NINTENDO 1 +#define FRIEND_ACCOUNT_MBMNET 3 // 2 benutzt Pretendos Nimbus + +// Kennungen (PIDs), die MBMNET für Freundekonten vergibt (FRIEND_PID_BASE in db.js) +#define MBMNET_PID_FIRST 1900000001u +#define MBMNET_PID_LAST 1999999999u + +Result frdswitch_init(void); +void frdswitch_exit(void); +// Geladenes Freundekonto (1 = Nintendo, 3 = MBMNET, 0 = unbekannt) +u8 frdswitch_current(void); +// Ist im Konto-Platz dieses Freundekontos eine ID verknüpft? (Name in id) +bool frdswitch_slot_linked(u8 friendAccount, char *id, size_t len); +// Auf ein Freundekonto umschalten (MBMNET: beim ersten Mal anlegen, *created = true). +// Danach muss der 3DS neu starten. false + msg bei Fehler. +bool frdswitch_to(u8 target, bool *created, char *msg, size_t msglen); +// Kennung des geladenen Freundekontos (0 = noch keine) +u32 frdswitch_my_pid(void); +bool frdswitch_pid_is_mbmnet(u32 pid); +// MBMNET-Freundekonto neu anlegen (hat eine fremde Kennung). Danach Neustart. +bool frdswitch_recreate_mbmnet(char *msg, size_t msglen); +// Konto-Platz (act) eines Freundekontos, 0 = keiner +u8 frdswitch_slot_of(u8 friendAccount); diff --git a/source/ftpcore.c b/source/ftpcore.c new file mode 100644 index 0000000..d3dd1d7 --- /dev/null +++ b/source/ftpcore.c @@ -0,0 +1,2 @@ +// FTP-Kern (Befehle, Pfade, Schreibschutz) aus dem FTP-Modul wiederverwenden - eine Quelle für beides +#include "../ftpmodul/source/ftp.c" diff --git a/source/ftpctl.c b/source/ftpctl.c new file mode 100644 index 0000000..661fa36 --- /dev/null +++ b/source/ftpctl.c @@ -0,0 +1,109 @@ +// FTP-Server in der App (Entwickler-Werkzeuge). Läuft in einem eigenen Thread, solange die App offen ist. +// +// Das Hintergrund-Modul (ftpmodul/, eigener Prozess auf Kern 1) ist abgeschaltet: Es brachte den +// Kernel-Scheduler auf Kern 1 zum Absturz (PC FFF21584, kaputter Thread in der Warteschlange). Die App +// räumt seine Dateien weg, damit es nie wieder startet. +// +// Ohne Passwort, Port 5000, Lesen von der ganzen SD, Schreiben/Löschen nur in /3ds/mbmnet (ftp.c). +#include <3ds.h> +#include +#include +#include +#include +#include +#include +#include + +#include "ftpctl.h" +#include "../ftpmodul/source/ftp.h" + +#define SOC_BUFFER_SIZE 0x100000 + +static u32 *socBuffer; +static Thread thread; +static volatile bool running; +static char address[32]; +static char status[64]; + +bool ftp_should_exit(void) { return !running; } + +static void server(void *arg) +{ + (void)arg; + while (running) { + u32 ip = (u32)gethostid(); + if (!ip) { snprintf(status, sizeof(status), "kein WLAN"); address[0] = 0; svcSleepThread(1000000000LL); continue; } + int fd = socket(AF_INET, SOCK_STREAM, 0); + struct sockaddr_in addr = { .sin_family = AF_INET, .sin_port = htons(CONTROL_PORT), .sin_addr.s_addr = INADDR_ANY }; + if (fd < 0 || bind(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0 || listen(fd, 2) != 0) { + if (fd >= 0) close(fd); + snprintf(status, sizeof(status), "Port %d belegt", CONTROL_PORT); + svcSleepThread(2000000000LL); + continue; + } + snprintf(address, sizeof(address), "%lu.%lu.%lu.%lu:%d", (unsigned long)(ip & 0xFF), (unsigned long)((ip >> 8) & 0xFF), + (unsigned long)((ip >> 16) & 0xFF), (unsigned long)(ip >> 24), CONTROL_PORT); + ftp_serve(fd, ip); // bis WLAN weg, IP neu oder "FTP aus" + close(fd); + address[0] = 0; + } +} + +// Reste des abgeschalteten Hintergrund-Moduls entfernen (sonst startete eine alte App-Version es wieder) +void ftpctl_cleanup_module(void) +{ + remove("sdmc:/luma/sysmodules/0004013000F1E002.cxi"); + remove("sdmc:/luma/sysmodules/0004013000F1E001.cxi"); + remove("sdmc:/3ds/mbmnet/ftp-an"); + remove("sdmc:/3ds/mbmnet/ftp-stopp"); + remove("sdmc:/3ds/mbmnet/ftp-adresse.txt"); +} + +bool ftpctl_running(void) { return running; } + +bool ftpctl_start(char *msg, size_t msglen) +{ + if (running) return true; + socBuffer = memalign(0x1000, SOC_BUFFER_SIZE); + if (!socBuffer || R_FAILED(socInit(socBuffer, SOC_BUFFER_SIZE))) { + free(socBuffer); + socBuffer = NULL; + snprintf(msg, msglen, "FTP: Netzwerk nicht verfügbar."); + return false; + } + running = true; + status[0] = address[0] = 0; + s32 prio = 0x30; + svcGetThreadPriority(&prio, CUR_THREAD_HANDLE); + thread = threadCreate(server, NULL, 32 * 1024, prio + 1, -2, false); + if (!thread) { + running = false; + socExit(); + free(socBuffer); + socBuffer = NULL; + snprintf(msg, msglen, "FTP: konnte nicht starten."); + return false; + } + snprintf(msg, msglen, "FTP-Server an (läuft, solange die App offen ist).\nOhne Passwort, Port 5000. Herunterladen von der ganzen SD,\n" + "Hochladen/Löschen nur in /3ds/mbmnet."); + return true; +} + +void ftpctl_stop(char *msg, size_t msglen) +{ + if (running) { + running = false; + threadJoin(thread, 5000000000LL); + threadFree(thread); + thread = NULL; + socExit(); + free(socBuffer); + socBuffer = NULL; + } + address[0] = 0; + if (msg) snprintf(msg, msglen, "FTP-Server aus."); +} + +bool ftpctl_resume(char *msg, size_t msglen) { (void)msg; (void)msglen; return false; } +const char *ftpctl_address(void) { return address; } +const char *ftpctl_status(void) { return status[0] ? status : "startet ..."; } diff --git a/source/ftpctl.h b/source/ftpctl.h new file mode 100644 index 0000000..b0571c3 --- /dev/null +++ b/source/ftpctl.h @@ -0,0 +1,16 @@ +#pragma once +#include <3ds/types.h> +#include + +// FTP-Server in der App (läuft, solange die App offen ist) +bool ftpctl_running(void); +bool ftpctl_start(char *msg, size_t msglen); +void ftpctl_stop(char *msg, size_t msglen); +// Nach einem Neustart des 3DS: wieder starten, wenn FTP zuletzt an war. true = gestartet (msg gesetzt) +bool ftpctl_resume(char *msg, size_t msglen); +// "192.168.1.42:5000", leer solange das Modul noch keine Adresse hat +const char *ftpctl_address(void); +// Letzte Zeile aus dem Protokoll des Moduls (/3ds/mbmnet/ftp.log), leer wenn keins +const char *ftpctl_status(void); +// Reste des abgeschalteten Hintergrund-Moduls entfernen +void ftpctl_cleanup_module(void); diff --git a/source/lumaconfig.c b/source/lumaconfig.c new file mode 100644 index 0000000..fe007b9 --- /dev/null +++ b/source/lumaconfig.c @@ -0,0 +1,135 @@ +// Ändert Optionen in Lumas Konfiguration (/luma/config.ini): +// splash_position -> Boot-Splash "MBMNET aktiv" anzeigen +// enable_external_firm_and_modules -> nötig, damit Luma die Patches in /luma/sysmodules lädt +// enable_game_patching -> nötig, damit Luma Patches in /luma/titles lädt (Miiverse) +// Beim Zurücksetzen wird eine Option nur wieder ausgeschaltet, wenn MBMNET sie eingeschaltet hat +// (Merker in /3ds/mbmnet/...). +#include +#include +#include +#include +#include + +#include "lumaconfig.h" + +#define CONFIG_FILE "sdmc:/luma/config.ini" +#define SPLASH_MARKER "sdmc:/3ds/mbmnet/splash-war-aus" +#define MODULES_MARKER "sdmc:/3ds/mbmnet/module-waren-aus" +#define PATCHING_MARKER "sdmc:/3ds/mbmnet/game-patching-war-aus" + +// Setzt "key = value". Gibt den alten Wert in oldValue zurück. false, wenn Datei/Option fehlt. +static bool set_option(const char *key, const char *value, char *oldValue, size_t oldLen) +{ + FILE *f = fopen(CONFIG_FILE, "rb"); + if (!f) return false; + fseek(f, 0, SEEK_END); + long size = ftell(f); + fseek(f, 0, SEEK_SET); + if (size <= 0 || size > 64 * 1024) { fclose(f); return false; } + char *in = malloc(size + 1); + char *out = malloc(size + 128); + bool ok = in && out && fread(in, 1, size, f) == (size_t)size; + fclose(f); + if (!ok) { free(in); free(out); return false; } + in[size] = 0; + + size_t keyLen = strlen(key); + bool found = false; + size_t o = 0; + for (char *line = in; *line;) { + char *end = strchr(line, '\n'); + size_t len = end ? (size_t)(end - line + 1) : strlen(line); + char *p = line; + while (*p == ' ' || *p == '\t') p++; + char *eq = strchr(p, '='); + bool isKey = !found && strncmp(p, key, keyLen) == 0 && (p[keyLen] == ' ' || p[keyLen] == '=') + && eq && eq < line + len; + if (isKey) { + char *v = eq + 1; + while (*v == ' ') v++; + size_t vl = strcspn(v, "\r\n"); + snprintf(oldValue, oldLen, "%.*s", (int)vl, v); + o += sprintf(out + o, "%s = %s%s", key, value, (end && end > line && end[-1] == '\r') ? "\r\n" : "\n"); + found = true; + } else { + memcpy(out + o, line, len); + o += len; + } + line += len; + } + + if (found && strcasecmp(oldValue, value) != 0) { + f = fopen(CONFIG_FILE, "wb"); + ok = f && fwrite(out, 1, o, f) == o; + if (f) fclose(f); + } + free(in); + free(out); + return found && ok; +} + +static void touch(const char *path) +{ + FILE *m = fopen(path, "w"); + if (m) fclose(m); +} + +static bool exists(const char *path) +{ + struct stat st; + return stat(path, &st) == 0; +} + +bool lumaconfig_enable_splash(void) +{ + char old[32] = ""; + if (!set_option("splash_position", "after payloads", old, sizeof(old))) return false; + if (strcasecmp(old, "off") == 0) touch(SPLASH_MARKER); + return true; +} + +void lumaconfig_restore_splash(void) +{ + if (!exists(SPLASH_MARKER)) return; // war schon vorher an: nichts ändern + char old[32] = ""; + set_option("splash_position", "off", old, sizeof(old)); + remove(SPLASH_MARKER); +} + +bool lumaconfig_enable_modules(void) +{ + char old[8] = ""; + if (!set_option("enable_external_firm_and_modules", "1", old, sizeof(old))) return false; + if (strcmp(old, "0") == 0) touch(MODULES_MARKER); + return true; +} + +void lumaconfig_keep_modules(void) +{ + remove(MODULES_MARKER); +} + +void lumaconfig_restore_modules(void) +{ + if (!exists(MODULES_MARKER)) return; + char old[8] = ""; + set_option("enable_external_firm_and_modules", "0", old, sizeof(old)); + remove(MODULES_MARKER); +} + +bool lumaconfig_enable_game_patching(void) +{ + char old[8] = ""; + if (!set_option("enable_game_patching", "1", old, sizeof(old))) return false; + if (strcmp(old, "0") != 0) return false; // war schon an + touch(PATCHING_MARKER); + return true; +} + +void lumaconfig_restore_game_patching(void) +{ + if (!exists(PATCHING_MARKER)) return; + char old[8] = ""; + set_option("enable_game_patching", "0", old, sizeof(old)); + remove(PATCHING_MARKER); +} diff --git a/source/lumaconfig.h b/source/lumaconfig.h new file mode 100644 index 0000000..9c492c9 --- /dev/null +++ b/source/lumaconfig.h @@ -0,0 +1,21 @@ +#pragma once +#include + +// Splash in Lumas Konfiguration einschalten ("after payloads"). false, wenn config.ini fehlt. +bool lumaconfig_enable_splash(void); +// Splash wieder ausschalten, falls MBMNET ihn eingeschaltet hat. +void lumaconfig_restore_splash(void); + +// "Enable loading external FIRMs and system modules" einschalten - ohne diese Option lädt +// Luma die Patches in /luma/sysmodules nicht. +bool lumaconfig_enable_modules(void); +// Wieder ausschalten, falls MBMNET sie eingeschaltet hat. +void lumaconfig_restore_modules(void); +// Option dauerhaft anlassen (das FTP-Modul braucht sie auch im Nintendo-Modus) +void lumaconfig_keep_modules(void); + +// "Enable game patching" einschalten - ohne sie lädt Luma die Patches in /luma/titles (Miiverse) nicht. +// true, wenn sie dadurch erst eingeschaltet wurde (dann ist ein Neustart nötig). +bool lumaconfig_enable_game_patching(void); +// Wieder ausschalten, falls MBMNET sie eingeschaltet hat. +void lumaconfig_restore_game_patching(void); diff --git a/source/main.c b/source/main.c new file mode 100644 index 0000000..3003c0a --- /dev/null +++ b/source/main.c @@ -0,0 +1,547 @@ +// MBMNET Switcher - schaltet den 3DS zwischen MBMNET und Nintendo (Original) um. +// +// Unten zwei Kacheln: MBMNET und Nintendo. Antippen schaltet um, unter der aktiven steht "Aktiv". +// SELECT blendet die Entwickler-Werkzeuge ein und aus (beim Öffnen immer aus). +#include <3ds.h> +#include +#include +#include + +#include "patcher.h" +#include "update.h" +#include "relaunch.h" +#include "nnid.h" +#include "frdswitch.h" +#include "admin.h" +#include "ftpctl.h" +#include "spotpass.h" + +#define TOP_W 400 +#define BOT_W 320 +#define SCR_H 240 + +// Farben (gleiche Palette wie Logo und Webseite) +#define COL_RED C2D_Color32(0xE4, 0x00, 0x2B, 0xFF) +#define COL_RED_DARK C2D_Color32(0x9E, 0x00, 0x1E, 0xFF) +#define COL_BG C2D_Color32(0x16, 0x19, 0x1F, 0xFF) +#define COL_BG2 C2D_Color32(0x22, 0x26, 0x2E, 0xFF) +#define COL_CARD C2D_Color32(0x2A, 0x2F, 0x39, 0xFF) +#define COL_CARD_HI C2D_Color32(0x3A, 0x41, 0x4E, 0xFF) +#define COL_WHITE C2D_Color32(0xFF, 0xFF, 0xFF, 0xFF) +#define COL_MUTED C2D_Color32(0x9A, 0xA3, 0xAF, 0xFF) +#define COL_GREEN C2D_Color32(0x22, 0xC5, 0x5E, 0xFF) +#define COL_AMBER C2D_Color32(0xF5, 0x9E, 0x0B, 0xFF) +#define COL_NINTENDO C2D_Color32(0xE6, 0x00, 0x12, 0xFF) + +// Bedienelemente auf dem unteren Bildschirm. Die Werkzeuge gibt es nur für Admins. +enum { BTN_ENABLE, BTN_DISABLE, BTN_DIAG, BTN_FTP, BTN_UNLINK, BTN_SPOTPASS, BTN_REBOOT, BTN_COUNT }; + +typedef struct { float x, y, w, h; } Box; + +#define TILE_Y 14 +#define TILE_W 142 +#define TILE_H_FULL 210 +#define TILE_H_ADMIN 160 +#define TOOL_COUNT 5 +static const Box toolBoxes[TOOL_COUNT] = { { 12, 184, 56, 42 }, { 72, 184, 56, 42 }, { 132, 184, 56, 42 }, { 192, 184, 56, 42 }, { 252, 184, 56, 42 } }; + +static Box box_of(int btn, bool admin) +{ + float h = admin ? TILE_H_ADMIN : TILE_H_FULL; + switch (btn) { + case BTN_ENABLE: return (Box){ 12, TILE_Y, TILE_W, h }; + case BTN_DISABLE: return (Box){ 166, TILE_Y, TILE_W, h }; + case BTN_DIAG: return toolBoxes[0]; + case BTN_FTP: return toolBoxes[1]; + case BTN_UNLINK: return toolBoxes[2]; + case BTN_SPOTPASS: return toolBoxes[3]; + default: return toolBoxes[4]; + } +} + +static C2D_TextBuf textBuf; +static int spotpassTestFrames = -1; // läuft der SpotPass-Test? (Bilder seit dem Start) +static bool ftpOn; // läuft das FTP-Modul? (alle 2 s geprüft, nicht in jedem Bild) + +// --- Zeichenhilfen ------------------------------------------------------------ + +static void text(const char *s, float x, float y, float size, u32 color, u32 flags) +{ + C2D_Text t; + C2D_TextParse(&t, textBuf, s); + C2D_TextOptimize(&t); + C2D_DrawText(&t, C2D_WithColor | flags, x, y, 0.5f, size, size, color); +} + +static void round_rect(float x, float y, float w, float h, float r, u32 color) +{ + C2D_DrawRectSolid(x + r, y, 0.5f, w - 2 * r, h, color); + C2D_DrawRectSolid(x, y + r, 0.5f, w, h - 2 * r, color); + C2D_DrawCircleSolid(x + r, y + r, 0.5f, r, color); + C2D_DrawCircleSolid(x + w - r, y + r, 0.5f, r, color); + C2D_DrawCircleSolid(x + r, y + h - r, 0.5f, r, color); + C2D_DrawCircleSolid(x + w - r, y + h - r, 0.5f, r, color); +} + +// Das MBMNET-Logo: rotes abgerundetes Quadrat mit einem "M" aus verbundenen Netzwerk-Knoten. +// Geometrie identisch zu assets/logo.svg (100x100-Raster). +static void draw_logo(float x, float y, float size) +{ + float s = size / 100.0f; + round_rect(x, y, size, size, 22 * s, COL_RED_DARK); + round_rect(x, y, size, size - 4 * s, 22 * s, COL_RED); + + static const float pts[5][2] = { {24, 72}, {24, 30}, {50, 56}, {76, 30}, {76, 72} }; + for (int i = 0; i < 4; i++) { + C2D_DrawLine(x + pts[i][0] * s, y + pts[i][1] * s, COL_WHITE, + x + pts[i + 1][0] * s, y + pts[i + 1][1] * s, COL_WHITE, 7 * s, 0.5f); + } + for (int i = 0; i < 5; i++) { + C2D_DrawCircleSolid(x + pts[i][0] * s, y + pts[i][1] * s, 0.5f, 9 * s, COL_WHITE); + if (i == 2) C2D_DrawCircleSolid(x + pts[i][0] * s, y + pts[i][1] * s, 0.5f, 4 * s, COL_RED); + } +} + +// Nintendo-Schriftzug im roten Rahmen (nachgezeichnet, kein Bild) +static void draw_nintendo(float cx, float cy, float w) +{ + float h = w * 0.36f, r = h / 2; + round_rect(cx - w / 2, cy - h / 2, w, h, r, COL_NINTENDO); + round_rect(cx - w / 2 + 3, cy - h / 2 + 3, w - 6, h - 6, r - 3, COL_WHITE); + text("Nintendo", cx, cy - h * 0.36f, w / 150.0f, COL_NINTENDO, C2D_AlignCenter); +} + +// --- Bildschirme --------------------------------------------------------------- + +static void draw_update_line(bool admin) +{ + char line[64]; + const char *v = update_new_version(); + switch (update_state()) { + case UPD_CHECKING: snprintf(line, sizeof(line), "v" APP_VERSION); break; + case UPD_AVAILABLE: snprintf(line, sizeof(line), "Update auf v%s bereit", v); break; + case UPD_DOWNLOADING: + if (update_attempt() > 1) snprintf(line, sizeof(line), "lade v%s (Versuch %d) ...", v, update_attempt()); + else snprintf(line, sizeof(line), "lade v%s ...", v); + break; + case UPD_INSTALLED: snprintf(line, sizeof(line), "v%s installiert", v); break; + case UPD_ERROR: snprintf(line, sizeof(line), admin ? "Update-Server offline" : "v" APP_VERSION); break; + default: snprintf(line, sizeof(line), "v" APP_VERSION); break; + } + u32 color = update_state() == UPD_INSTALLED ? COL_GREEN : update_pending() ? COL_AMBER : COL_MUTED; + text(line, TOP_W - 10, 4, 0.4f, color, C2D_AlignRight); +} + +static void draw_top(PatchState st, const char *msg, bool admin, bool isAdmin) +{ + C2D_DrawRectangle(0, 0, 0, TOP_W, SCR_H, COL_BG2, COL_BG2, COL_BG, COL_BG); + draw_update_line(admin); + const char *hint = admin ? "START: Beenden SELECT: Werkzeuge aus" : "START: Beenden SELECT: Werkzeuge"; + text(hint, 10, 4, 0.4f, COL_MUTED, 0); + if (ftpOn) { + // FTP-Adresse direkt daneben + C2D_Text t; + float w = 0; + C2D_TextParse(&t, textBuf, hint); + C2D_TextGetDimensions(&t, 0.4f, 0.4f, &w, NULL); + char ftp[112]; + const char *a = ftpctl_address(); + const char *st = ftpctl_status(); + if (a[0]) snprintf(ftp, sizeof(ftp), "FTP %s", a); + else snprintf(ftp, sizeof(ftp), "FTP: %s", st[0] ? st : "startet ..."); + text(ftp, 10 + w + 12, 4, 0.4f, COL_GREEN, 0); + } + + float y = msg[0] || admin ? 26 : 62; + draw_logo(TOP_W / 2 - 32, y, 64); + text("MBMNET", TOP_W / 2, y + 70, 0.9f, COL_WHITE, C2D_AlignCenter); + y += 108; + + // Admins: was gerade wirklich los ist + if (admin) { + char line[96], id[20]; + const char *label = st == STATE_MBMNET ? "Patch: MBMNET" : st == STATE_FOREIGN ? "Patch: fremd (z. B. Pretendo)" : "Patch: keiner"; + snprintf(line, sizeof(line), "%s · NNID: %s%s", label, nnid_linked(id, sizeof(id)) ? id : "keine", isAdmin ? " · Admin" : ""); + text(line, TOP_W / 2, y, 0.42f, COL_MUTED, C2D_AlignCenter); + y += 18; + } + if (msg[0]) { + round_rect(16, y, TOP_W - 32, SCR_H - y - 8, 10, COL_CARD); + text(msg, 28, y + 6, 0.46f, COL_WHITE, 0); + } else if (!admin) { + text("Tippe unten auf MBMNET oder Nintendo.", TOP_W / 2, 200, 0.45f, COL_MUTED, C2D_AlignCenter); + } +} + +static void draw_tile(int btn, bool sel, bool active, bool admin) +{ + Box b = box_of(btn, admin); + if (sel) round_rect(b.x - 3, b.y - 3, b.w + 6, b.h + 6, 15, COL_RED); + round_rect(b.x, b.y, b.w, b.h, 12, active ? COL_CARD_HI : COL_CARD); + + float cx = b.x + b.w / 2, logoCy = b.y + b.h / 2 - 12; + if (btn == BTN_ENABLE) draw_logo(cx - 36, logoCy - 36, 72); + else draw_nintendo(cx, logoCy, 116); + + if (active) { + C2D_DrawCircleSolid(cx - 26, b.y + b.h - 26, 0.5f, 5, COL_GREEN); + text("Aktiv", cx + 6, b.y + b.h - 36, 0.6f, COL_GREEN, C2D_AlignCenter); + } +} + +static void draw_bottom(int selected, PatchState st, bool admin) +{ + C2D_DrawRectSolid(0, 0, 0, BOT_W, SCR_H, COL_BG); + draw_tile(BTN_ENABLE, selected == BTN_ENABLE, st == STATE_MBMNET, admin); + draw_tile(BTN_DISABLE, selected == BTN_DISABLE, st == STATE_ORIGINAL, admin); + if (!admin) return; + + const char *labels[TOOL_COUNT] = { "Diagnose", ftpOn ? "FTP aus" : "FTP an", "ID lösen", "SpotPass", "Neustart" }; + for (int i = 0; i < TOOL_COUNT; i++) { + Box b = toolBoxes[i]; + bool sel = selected == BTN_DIAG + i; + bool on = i == 1 && ftpOn; + round_rect(b.x, b.y, b.w, b.h, 10, sel ? COL_CARD_HI : COL_CARD); + if (sel) C2D_DrawRectSolid(b.x, b.y + 10, 0.5f, 4, b.h - 20, COL_RED); + if (on) C2D_DrawCircleSolid(b.x + 12, b.y + b.h / 2, 0.5f, 4, COL_GREEN); + text(labels[i], b.x + b.w / 2, b.y + 13, 0.45f, on ? COL_GREEN : COL_WHITE, C2D_AlignCenter); + } +} + +// --- Aktionen -------------------------------------------------------------------- +// +// Wie bei Pretendo hat MBMNET ein eigenes Freundekonto (Nr. 3) mit eigenem Konto-Platz. Umschalten = +// Patches an/aus + auf das andere Freundekonto wechseln + Neustart. Beide Anmeldungen bleiben dabei +// erhalten, die Nintendo-Freundesliste auch. + +// Merker älterer Versionen (bis v2.4): Die MBMNET-ID wurde damals im Nintendo-Platz verknüpft +#define UNLINKED_MARKER "sdmc:/3ds/mbmnet/nnid-geloest" +static bool old_mbmnet_link(void) { FILE *f = fopen(UNLINKED_MARKER, "r"); if (f) fclose(f); return f != NULL; } + +static int armed = -1; // Sicherheitsabfrage (zweimal antippen) + +// Name der MBMNET-ID, gemerkt beim Wechsel zu Nintendo. Der 3DS erlaubt dieselbe ID nicht in zwei Konto-Plätzen +// (022-2571): Heißt die Pretendo-ID genauso, muss sie beim Wechsel zurück zu MBMNET dort gelöst werden. +#define MBMNET_ID_FILE "sdmc:/3ds/mbmnet/mbmnet-id.txt" +static void remember_mbmnet_id(const char *id) +{ + FILE *f = fopen(MBMNET_ID_FILE, "w"); + if (f) { fputs(id, f); fclose(f); } +} +static void remembered_mbmnet_id(char *out, size_t len) +{ + out[0] = 0; + FILE *f = fopen(MBMNET_ID_FILE, "r"); + if (!f) return; + if (fgets(out, len, f)) out[strcspn(out, "\r\n")] = 0; + fclose(f); +} + +// Umschalten auf MBMNET. true = der 3DS muss jetzt neu starten. +static bool enable(bool confirmed, char *msg, size_t msglen) +{ + char detail[160] = "", id[20]; + if (patch_state() == STATE_MBMNET && frdswitch_current() == FRIEND_ACCOUNT_MBMNET) { + // Freundekonto mit fremder Kennung (z. B. von Pretendo geholt): neu anlegen, dann holt es sich + // beim nächsten Start eine Kennung bei MBMNET + u32 pid = frdswitch_my_pid(); + if (pid && !frdswitch_pid_is_mbmnet(pid)) { + if (!confirmed) { + armed = BTN_ENABLE; + snprintf(msg, msglen, "Dein MBMNET-Freundekonto hat eine fremde Kennung\n(%lu, nicht von MBMNET). Neu anlegen?\n" + "Die Verknüpfung mit deinem MBMNET-Konto bleibt.\nZum Bestätigen nochmal antippen.", (unsigned long)pid); + return false; + } + if (!frdswitch_recreate_mbmnet(msg, msglen)) return false; + snprintf(msg, msglen, "MBMNET-Freundekonto neu angelegt. Der 3DS startet neu.\n" + "Danach holt es sich bei MBMNET deinen Freundescode."); + return true; + } + bool linked = frdswitch_slot_linked(FRIEND_ACCOUNT_MBMNET, id, sizeof(id)); + snprintf(msg, msglen, linked ? "MBMNET ist schon aktiv (Konto %s)." : "MBMNET ist schon aktiv.\n" + "Jetzt dein MBMNET-Konto verknüpfen:\nEinstellungen > Nintendo Network ID", id); + return false; + } + + // Umstieg von älteren Versionen: Dort steckte die MBMNET-ID im Nintendo-Platz. Sie muss dort raus, + // sonst lässt sie sich im eigenen MBMNET-Platz nicht verknüpfen (Fehler 022-2571). + bool migrate = old_mbmnet_link() && frdswitch_slot_linked(FRIEND_ACCOUNT_NINTENDO, id, sizeof(id)); + // Die gemerkte MBMNET-ID steckt noch in einem anderen Platz (z. B. Pretendo mit gleichem Namen)? + char mbmnetId[20]; + remembered_mbmnet_id(mbmnetId, sizeof(mbmnetId)); + u8 mbmnetSlot = frdswitch_slot_of(FRIEND_ACCOUNT_MBMNET); + bool sameNameElsewhere = !migrate && mbmnetId[0] && nnid_name_elsewhere(mbmnetId, mbmnetSlot); + if (sameNameElsewhere && !confirmed) { + armed = BTN_ENABLE; + snprintf(msg, msglen, "\"%s\" ist noch in einem anderen Platz verknüpft (z. B. Pretendo).\n" + "Der 3DS erlaubt sie nur einmal: Sie wird dort gelöst, damit du sie\nbei MBMNET verknüpfen kannst. Zum Bestätigen nochmal antippen.", mbmnetId); + return false; + } + if (migrate && !confirmed) { + armed = BTN_ENABLE; + snprintf(msg, msglen, "Umstellung auf ein eigenes MBMNET-Freundekonto:\n\"%s\" wird aus dem Nintendo-Platz gelöst\n" + "und danach im MBMNET-Platz neu verknüpft.\nZum Bestätigen nochmal antippen.", id); + return false; + } + + bool changed = false; + if (!patch_enable(MBMNET_SERVER, &changed, detail, sizeof(detail))) { + snprintf(msg, msglen, "%s", detail); + return false; + } + if (migrate && !nnid_unlink(msg, msglen)) return false; + remove(UNLINKED_MARKER); + if (sameNameElsewhere && !nnid_unlink_named(mbmnetId, mbmnetSlot, msg, msglen)) { + char ignore[160]; + patch_disable(ignore, sizeof(ignore)); + return false; + } + + bool created = false; + if (!frdswitch_to(FRIEND_ACCOUNT_MBMNET, &created, msg, msglen)) { + char ignore[160]; + patch_disable(ignore, sizeof(ignore)); // nichts halb umgestellt lassen + return false; + } + bool linked = frdswitch_slot_linked(FRIEND_ACCOUNT_MBMNET, id, sizeof(id)); + char ignore[96]; + spotpass_register(MBMNET_SERVER, ignore, sizeof(ignore)); // Mitteilungen per SpotPass + snprintf(msg, msglen, "MBMNET aktiv! Der 3DS startet neu.\n%s", + created ? "Eigenes MBMNET-Freundekonto angelegt. Danach einmal:\nEinstellungen > Nintendo Network ID > Vorhandene ID" + : linked ? "Deine MBMNET-Anmeldung und -Freundesliste sind wieder da." + : "Danach einmal: Einstellungen > Nintendo Network ID"); + return true; +} + +// Zurück zu Nintendo. true = der 3DS muss jetzt neu starten. +static bool disable(bool confirmed, char *msg, size_t msglen) +{ + (void)confirmed; + char detail[160] = ""; + PatchState st = patch_state(); + if (st == STATE_ORIGINAL && frdswitch_current() == FRIEND_ACCOUNT_NINTENDO) { + snprintf(msg, msglen, "Nintendo ist schon aktiv."); + return false; + } + if (st == STATE_FOREIGN) { + snprintf(msg, msglen, "MBMNET ist nicht aktiv (anderer Patch)."); + return false; + } + // MBMNET-ID aus dem MBMNET-Platz lösen und merken: Heißt die Pretendo-ID genauso, ließe sie sich sonst + // im Pretendo-Platz nicht verknüpfen (022-2571). Beim Wechsel zurück zu MBMNET neu anmelden. + char id[20] = ""; + bool unlinked = false; + if (frdswitch_current() == FRIEND_ACCOUNT_MBMNET && nnid_linked(id, sizeof(id))) { + remember_mbmnet_id(id); + if (!nnid_unlink(msg, msglen)) return false; + unlinked = true; + } + bool created = false; + if (frdswitch_current() != FRIEND_ACCOUNT_NINTENDO && !frdswitch_to(FRIEND_ACCOUNT_NINTENDO, &created, msg, msglen)) return false; + patch_disable(detail, sizeof(detail)); + spotpass_unregister(); + if (unlinked) + snprintf(msg, msglen, "Nintendo aktiv! Der 3DS startet neu.\n\"%s\" wurde vom MBMNET-Platz gelöst (für Pretendo).\n" + "Zurück zu MBMNET: danach einmal neu anmelden.", id); + else + snprintf(msg, msglen, "Nintendo aktiv! Der 3DS startet neu.\nDeine Nintendo-Freundesliste ist wieder da."); + return true; +} + +// Führt eine Aktion aus. true = der 3DS muss jetzt neu starten. +static bool run(int action, char *msg, size_t msglen) +{ + bool confirmed = armed == action; + armed = -1; + // Während ein Update lädt oder installiert wird, nicht umschalten (der 3DS würde mittendrin neu starten) + if (action != BTN_DIAG && action != BTN_FTP && action != BTN_SPOTPASS && update_pending()) { + snprintf(msg, msglen, "Moment: Das Update auf v%s wird gerade installiert.\nDanach startet die App neu.", update_new_version()); + return false; + } + switch (action) { + case BTN_ENABLE: return enable(confirmed, msg, msglen); + case BTN_DISABLE: return disable(confirmed, msg, msglen); + case BTN_DIAG: patch_diagnose(msg, msglen); return false; + case BTN_UNLINK: { + // Verknüpfte NNID nur auf dem 3DS lösen (ohne Server) - z. B. wenn das Konto gelöscht wurde + char id[20]; + if (!nnid_linked(id, sizeof(id))) { snprintf(msg, msglen, "Hier ist keine ID verknüpft."); return false; } + if (!confirmed) { + armed = BTN_UNLINK; + snprintf(msg, msglen, "\"%s\" vom 3DS lösen?\nNur auf dem 3DS, das Konto selbst bleibt unberührt.\n" + "Zum Bestätigen nochmal antippen.", id); + return false; + } + if (!nnid_unlink(msg, msglen)) return false; + snprintf(msg, msglen, "\"%s\" gelöst. Der 3DS startet neu.\nDanach kannst du eine andere ID verknüpfen.", id); + return true; + } + case BTN_FTP: + if (ftpctl_running()) ftpctl_stop(msg, msglen); + else ftpctl_start(msg, msglen); + ftpOn = ftpctl_running(); + return false; + case BTN_SPOTPASS: + if (spotpassTestFrames >= 0) { snprintf(msg, msglen, "SpotPass-Test läuft schon ..."); return false; } + if (spotpass_test_start(MBMNET_SERVER, msg, msglen)) spotpassTestFrames = 0; + return false; + case BTN_REBOOT: return true; + } + return false; +} + +static bool inside(Box b, touchPosition tp) { return tp.px >= b.x && tp.px < b.x + b.w && tp.py >= b.y && tp.py < b.y + b.h; } + +int main(int argc, char **argv) +{ + gfxInitDefault(); + httpcInit(0); + // Als installierte CIA: am:net zum Installieren von Updates + bool am = !envIsHomebrew() && R_SUCCEEDED(amInit()); + C3D_Init(C3D_DEFAULT_CMDBUF_SIZE); + C2D_Init(C2D_DEFAULT_MAX_OBJECTS); + C2D_Prepare(); + C3D_RenderTarget *top = C2D_CreateScreenTarget(GFX_TOP, GFX_LEFT); + C3D_RenderTarget *bot = C2D_CreateScreenTarget(GFX_BOTTOM, GFX_LEFT); + textBuf = C2D_TextBufNew(4096); + nnid_init(); + frdswitch_init(); + + const char *server = MBMNET_SERVER; + char msg[256] = ""; + + // Pfad der laufenden App (vom Homebrew Launcher übergeben), damit das Update sie ersetzen kann + const char *selfPath = argc > 0 && strncmp(argv[0], "sdmc:/", 6) == 0 ? argv[0] : "sdmc:/3ds/mbmnet.3dsx"; + update_start(server, selfPath); + UpdateState lastUpd = UPD_IDLE; + int restartIn = 0; // Frames bis zum automatischen Neustart der App nach einem Update + int rebootIn = 0; // Frames bis zum Neustart des 3DS nach dem Umschalten + + // Patches alter Versionen lagen an einer Stelle, an der Luma sie nicht lädt + if (patch_migrate()) + snprintf(msg, sizeof(msg), "Neuer Speicherort für die Patches!\nBitte MBMNET einmal neu antippen."); + PatchState st = patch_state(); + // Nur im MBMNET-Modus ist die verknüpfte NNID ein MBMNET-Konto + admin_start(server, st == STATE_MBMNET ? nnid_pid() : 0); + + // MBMNET aktiv, aber das Freundekonto hat eine fremde Kennung: darauf hinweisen + if (st == STATE_MBMNET && frdswitch_current() == FRIEND_ACCOUNT_MBMNET) { + u32 pid = frdswitch_my_pid(); + if (pid && !frdswitch_pid_is_mbmnet(pid)) + snprintf(msg, sizeof(msg), "Dein MBMNET-Freundekonto hat eine fremde Kennung (%lu).\n" + "Tippe auf MBMNET, um es neu anzulegen.", (unsigned long)pid); + } + // Mitteilungen per SpotPass: bei aktivem MBMNET die Hintergrund-Aufgabe (neu) anmelden + if (st == STATE_MBMNET) { + char ignore[96]; + spotpass_register(server, ignore, sizeof(ignore)); + // Patches auffrischen: neue Versionen bringen neue Ziele mit (z. B. Miiverse ab v2.8.0) + bool changed = false; + char detail[160]; + if (patch_enable(server, &changed, detail, sizeof(detail)) && changed && !msg[0]) + snprintf(msg, sizeof(msg), "Neue MBMNET-Patches (Miiverse) geschrieben.\n" + "Bitte den 3DS einmal neu starten (Werkzeuge: Neustart)."); + } + // Das Hintergrund-Modul ist abgeschaltet (Kernel-Absturz): Reste wegräumen, nie wieder starten + ftpctl_cleanup_module(); + ftpOn = ftpctl_running(); + int ftpCheckIn = 120; + + int selected = st == STATE_MBMNET ? BTN_DISABLE : BTN_ENABLE; + bool toolsToggled = false; + int queued = -1; // Aktion, die nach dem nächsten Bild läuft (damit sofort etwas passiert) + + while (aptMainLoop()) { + hidScanInput(); + u32 down = hidKeysDown(); + if (--ftpCheckIn <= 0) { ftpCheckIn = 120; ftpOn = ftpctl_running(); } + if (down & KEY_START && rebootIn == 0) break; // während des Umschaltens nicht abbrechen + if (down & KEY_SELECT) toolsToggled = !toolsToggled; + // Werkzeuge nur mit SELECT, beim Öffnen immer aus + bool admin = toolsToggled; + if (!admin && selected >= BTN_DIAG) selected = BTN_ENABLE; + + int action = -1; + // Oben die beiden Kacheln, unten (nur mit Werkzeugen) Diagnose / FTP / ID lösen / SpotPass / Neustart + bool left = down & (KEY_LEFT | KEY_CPAD_LEFT), right = down & (KEY_RIGHT | KEY_CPAD_RIGHT); + if (selected < BTN_DIAG) { if (left || right) selected ^= 1; } + else if (left) selected = selected == BTN_DIAG ? BTN_REBOOT : selected - 1; + else if (right) selected = selected == BTN_REBOOT ? BTN_DIAG : selected + 1; + if (admin && down & (KEY_DOWN | KEY_CPAD_DOWN) && selected < BTN_DIAG) selected = selected == BTN_ENABLE ? BTN_DIAG : BTN_REBOOT; + if (down & (KEY_UP | KEY_CPAD_UP) && selected >= BTN_DIAG) selected = selected == BTN_REBOOT ? BTN_DISABLE : BTN_ENABLE; + if (down & KEY_A) action = selected; + if (down & KEY_TOUCH) { + touchPosition tp; + hidTouchRead(&tp); + for (int i = 0; i < (admin ? BTN_COUNT : BTN_DIAG); i++) + if (inside(box_of(i, admin), tp)) selected = action = i; + } + if (queued >= 0) { + int a = queued; + queued = -1; + if (run(a, msg, sizeof(msg))) rebootIn = 45; // ca. 0,75 Sekunden zum Lesen + st = patch_state(); + } else if (action >= 0 && rebootIn == 0) { + queued = action; + snprintf(msg, sizeof(msg), action <= BTN_DISABLE ? "Schalte um ..." : "Einen Moment ..."); + } + + // Update gefunden: gleich laden, egal ob MBMNET oder Nintendo aktiv ist. Nicht während des + // Umschaltens, sonst startet der 3DS mitten in der Installation neu. + UpdateState upd = update_state(); + if (upd == UPD_AVAILABLE && rebootIn == 0 && queued < 0) { + update_download(); + snprintf(msg, sizeof(msg), "Lade Update auf v%s ...", update_new_version()); + upd = update_state(); + } + // Update fertig: kurz anzeigen, dann neu starten + if (upd == UPD_INSTALLED && lastUpd != UPD_INSTALLED) { + snprintf(msg, sizeof(msg), "Update auf v%s installiert!\nDie App startet gleich neu ...", update_new_version()); + restartIn = 90; // ca. 1,5 Sekunden + } + if (upd == UPD_ERROR && lastUpd == UPD_DOWNLOADING) { + char why[96]; + update_error(why, sizeof(why)); + snprintf(msg, sizeof(msg), "Update nach 3 Versuchen fehlgeschlagen:\n%s\nProtokoll: /3ds/mbmnet/update.log", why); + } + lastUpd = upd; + + // SpotPass-Test: jede Sekunde nachsehen + if (spotpassTestFrames >= 0 && ++spotpassTestFrames % 60 == 0 && + !spotpass_test_poll(spotpassTestFrames / 60, msg, sizeof(msg))) + spotpassTestFrames = -1; + + // Neustart erst, wenn die Freunde-Anmeldung durch ist (höchstens ein paar Sekunden) + if (rebootIn > 0 && --rebootIn == 0 && R_FAILED(APT_HardwareResetAsync())) { + snprintf(msg, sizeof(msg), "Neustart fehlgeschlagen.\nBitte den 3DS von Hand neu starten."); + } + + if (restartIn > 0 && --restartIn == 0) { + if (relaunch_prepare(selfPath)) break; + snprintf(msg, sizeof(msg), "Update installiert!\nBitte die App von Hand neu starten (START)."); + } + + C2D_TextBufClear(textBuf); + C3D_FrameBegin(C3D_FRAME_SYNCDRAW); + C2D_TargetClear(top, COL_BG); + C2D_SceneBegin(top); + draw_top(st, msg, admin, admin_is()); + C2D_TargetClear(bot, COL_BG); + C2D_SceneBegin(bot); + draw_bottom(selected, st, admin); + C3D_FrameEnd(0); + } + + ftpctl_stop(NULL, 0); + admin_finish(); + update_finish(); + frdswitch_exit(); + nnid_exit(); + httpcExit(); + if (am) amExit(); + C2D_TextBufDelete(textBuf); + C2D_Fini(); + C3D_Fini(); + gfxExit(); + return 0; +} diff --git a/source/nnid.c b/source/nnid.c new file mode 100644 index 0000000..21224bd --- /dev/null +++ b/source/nnid.c @@ -0,0 +1,217 @@ +// Nintendo Network ID auf dem 3DS: anzeigen und lokal lösen. +// +// Solange eine NNID verknüpft ist, bieten die Systemeinstellungen kein +// "Vorhandene ID verknüpfen" an. Damit man sich mit dem MBMNET-Konto anmelden kann, +// löst die App die Verknüpfung lokal (ohne Server). Name und PID der alten ID werden +// vorher in /3ds/mbmnet/alte-nnid.txt gesichert. +#include <3ds.h> +#include +#include +#include +#include +#include + +#include "nnid.h" + +#define OLD_NNID_FILE "sdmc:/3ds/mbmnet/alte-nnid.txt" +#define LOG_FILE "sdmc:/3ds/mbmnet/konto.log" + +static bool ready; + +Result nnid_init(void) +{ + Result rc = actInit(false); // false = act:a (Verwaltung) + ready = R_SUCCEEDED(rc); + return rc; +} + +void nnid_exit(void) +{ + if (ready) actExit(); +} + +static u8 current_slot(void) +{ + u8 slot = 0; + ACT_GetCommonInfo(&slot, sizeof(slot), INFO_TYPE_COMMON_CURRENT_ACCOUNT_SLOT); + return slot; +} + +bool nnid_linked(char *name, size_t len) +{ + name[0] = 0; + if (!ready) return false; + AccountId id = { 0 }; + if (R_FAILED(ACT_GetAccountInfo(id, sizeof(id), current_slot(), INFO_TYPE_ACCOUNT_ID))) return false; + snprintf(name, len, "%s", id); + return name[0] != 0; +} + +u32 nnid_pid(void) +{ + u32 pid = 0; + char name[20]; + if (nnid_linked(name, sizeof(name))) ACT_GetAccountInfo(&pid, sizeof(pid), current_slot(), INFO_TYPE_PRINCIPAL_ID); + return pid; +} + +// Verknüpfte IDs in ANDEREN Konto-Plätzen (z. B. die Pretendo-ID aus Nimbus' zweitem Platz). +// Eine ID, die dort steht, darf der 3DS nicht noch einmal verknüpfen (Fehler 022-2571). +int nnid_others(char *names, size_t len) +{ + names[0] = 0; + if (!ready) return 0; + u8 count = 0, current = current_slot(); + if (R_FAILED(ACT_GetCommonInfo(&count, sizeof(count), INFO_TYPE_COMMON_NUM_ACCOUNTS))) return 0; + int found = 0; + for (u8 slot = 1; slot <= count; slot++) { + if (slot == current) continue; + AccountId id = { 0 }; + if (R_FAILED(ACT_GetAccountInfo(id, sizeof(id), slot, INFO_TYPE_ACCOUNT_ID)) || !id[0]) continue; + size_t n = strlen(names); + snprintf(names + n, len - n, "%s\"%s\"", found ? ", " : "", id); + found++; + } + return found; +} + +bool nnid_unlink_others(char *msg, size_t msglen) +{ + if (!ready) return false; + u8 count = 0, current = current_slot(); + if (R_FAILED(ACT_GetCommonInfo(&count, sizeof(count), INFO_TYPE_COMMON_NUM_ACCOUNTS))) return false; + + mkdir("sdmc:/3ds/mbmnet", 0777); + FILE *log = fopen(LOG_FILE, "a"); + FILE *old = fopen(OLD_NNID_FILE, "a"); + bool ok = true; + for (u8 slot = 1; slot <= count; slot++) { + if (slot == current) continue; + AccountId id = { 0 }; + u32 pid = 0; + if (R_FAILED(ACT_GetAccountInfo(id, sizeof(id), slot, INFO_TYPE_ACCOUNT_ID)) || !id[0]) continue; + ACT_GetAccountInfo(&pid, sizeof(pid), slot, INFO_TYPE_PRINCIPAL_ID); + if (old) fprintf(old, "Konto-Platz %u ID: %s PID: %lu (anderer Platz, z. B. Pretendo)\n", slot, id, (unsigned long)pid); + Result rc = ACTA_UnbindServerAccount(slot, true); + if (log) fprintf(log, "Platz %u (%s) lösen %08lX\n", slot, id, (unsigned long)rc); + if (R_FAILED(rc)) { + snprintf(msg, msglen, "ID \"%s\" (Platz %u) konnte nicht gelöst werden\n(Fehler %08lX).", id, slot, (unsigned long)rc); + ok = false; + } + } + if (old) fclose(old); + if (log) fclose(log); + return ok; +} + +bool nnid_unlink(char *msg, size_t msglen) +{ + if (!ready) { + snprintf(msg, msglen, "Kontodienst nicht verfügbar.\nIst Luma3DS aktuell?"); + return false; + } + u8 slot = current_slot(); + AccountId id = { 0 }; + u32 pid = 0; + ACT_GetAccountInfo(id, sizeof(id), slot, INFO_TYPE_ACCOUNT_ID); + ACT_GetAccountInfo(&pid, sizeof(pid), slot, INFO_TYPE_PRINCIPAL_ID); + if (!id[0]) return true; // nichts verknüpft + + mkdir("sdmc:/3ds/mbmnet", 0777); + + // Alte ID merken, damit der Name nicht verloren geht + FILE *f = fopen(OLD_NNID_FILE, "a"); + if (f) { + time_t now = time(NULL); + char date[32]; + strftime(date, sizeof(date), "%Y-%m-%d %H:%M", localtime(&now)); + fprintf(f, "%s Konto-Platz %u NNID: %s PID: %lu\n", date, slot, id, (unsigned long)pid); + fclose(f); + } + + FILE *log = fopen(LOG_FILE, "w"); + if (log) fprintf(log, "MBMNET: NNID lösen (App v%s)\nKonto-Platz %u, NNID %s\n\n", APP_VERSION, slot, id); + + Result rc = ACTA_UnbindServerAccount(slot, true); + if (log) fprintf(log, "%-30s %08lX\n", "Verknüpfung lösen", (unsigned long)rc); + if (R_FAILED(rc)) { + // Manche Zustände erlauben das nur bei abgemeldetem Konto: abmelden und erneut versuchen + Result u = ACTA_UnloadConsoleAccount(); + if (log) fprintf(log, "%-30s %08lX\n", "Konto abmelden", (unsigned long)u); + rc = ACTA_UnbindServerAccount(slot, true); + if (log) fprintf(log, "%-30s %08lX\n", "Verknüpfung lösen (2.)", (unsigned long)rc); + } + if (log) { fprintf(log, "\nErgebnis: %s\n", R_SUCCEEDED(rc) ? "OK" : "FEHLER"); fclose(log); } + + if (R_FAILED(rc)) { + snprintf(msg, msglen, "NNID konnte nicht gelöst werden (Fehler %08lX).\nProtokoll: /3ds/mbmnet/konto.log", (unsigned long)rc); + return false; + } + return true; +} + +// Für die Diagnose: alle Konto-Plätze mit ihren Daten +void nnid_dump(FILE *f) +{ + if (!ready) { fprintf(f, " Kontodienst nicht verfügbar\n"); return; } + u8 count = 0, current = 0, def = 0; + ACT_GetCommonInfo(&count, sizeof(count), INFO_TYPE_COMMON_NUM_ACCOUNTS); + ACT_GetCommonInfo(¤t, sizeof(current), INFO_TYPE_COMMON_CURRENT_ACCOUNT_SLOT); + ACT_GetCommonInfo(&def, sizeof(def), INFO_TYPE_COMMON_DEFAULT_ACCOUNT_SLOT); + u8 friendAccount = 0; + FRD_GetMyLocalAccountId(&friendAccount); + fprintf(f, " %u Plätze, aktiv: %u, Standard: %u, geladenes Freundekonto: %u (1 = Nintendo, 3 = MBMNET)\n", + count, current, def, friendAccount); + for (u8 slot = 1; slot <= count; slot++) { + AccountId id = { 0 }, assigned = { 0 }; + u32 pid = 0, assignedPid = 0; + u8 fp = 0; + bool committed = false; + Result r1 = ACT_GetAccountInfo(id, sizeof(id), slot, INFO_TYPE_ACCOUNT_ID); + ACT_GetAccountInfo(assigned, sizeof(assigned), slot, INFO_TYPE_ASSIGNED_ACCOUNT_ID); + ACT_GetAccountInfo(&pid, sizeof(pid), slot, INFO_TYPE_PRINCIPAL_ID); + ACT_GetAccountInfo(&assignedPid, sizeof(assignedPid), slot, INFO_TYPE_ASSIGNED_PRINCIPAL_ID); + ACT_GetAccountInfo(&fp, sizeof(fp), slot, INFO_TYPE_FP_LOCAL_ACCOUNT_ID); + ACT_GetAccountInfo(&committed, sizeof(committed), slot, INFO_TYPE_IS_COMMITTED); + fprintf(f, " Platz %u: ID \"%s\" (Länge %u, Abfrage %08lX) PID %lu zugewiesen \"%s\"/%lu Freunde-Konto %u gespeichert %d\n", + slot, id, (unsigned)strlen(id), (unsigned long)r1, (unsigned long)pid, assigned, + (unsigned long)assignedPid, fp, committed); + } +} + +// Gibt es die ID "name" in einem Konto-Platz außer exceptSlot? +bool nnid_name_elsewhere(const char *name, u8 exceptSlot) +{ + if (!ready || !name[0]) return false; + u8 count = 0; + if (R_FAILED(ACT_GetCommonInfo(&count, sizeof(count), INFO_TYPE_COMMON_NUM_ACCOUNTS))) return false; + for (u8 slot = 1; slot <= count; slot++) { + if (slot == exceptSlot) continue; + AccountId id = { 0 }; + if (R_SUCCEEDED(ACT_GetAccountInfo(id, sizeof(id), slot, INFO_TYPE_ACCOUNT_ID)) && !strcasecmp(id, name)) return true; + } + return false; +} + +// Löst die ID "name" in allen Konto-Plätzen außer exceptSlot (nur auf dem 3DS). false + msg bei Fehler. +bool nnid_unlink_named(const char *name, u8 exceptSlot, char *msg, size_t msglen) +{ + if (!ready) return false; + u8 count = 0; + if (R_FAILED(ACT_GetCommonInfo(&count, sizeof(count), INFO_TYPE_COMMON_NUM_ACCOUNTS))) return false; + FILE *log = fopen(LOG_FILE, "a"); + bool ok = true; + for (u8 slot = 1; slot <= count; slot++) { + if (slot == exceptSlot) continue; + AccountId id = { 0 }; + if (R_FAILED(ACT_GetAccountInfo(id, sizeof(id), slot, INFO_TYPE_ACCOUNT_ID)) || strcasecmp(id, name)) continue; + Result rc = ACTA_UnbindServerAccount(slot, true); + if (log) fprintf(log, "Platz %u (%s) lösen (gleicher Name wie MBMNET) %08lX\n", slot, id, (unsigned long)rc); + if (R_FAILED(rc)) { + snprintf(msg, msglen, "\"%s\" (Platz %u) ließ sich nicht lösen (Fehler %08lX).", id, slot, (unsigned long)rc); + ok = false; + } + } + if (log) fclose(log); + return ok; +} diff --git a/source/nnid.h b/source/nnid.h new file mode 100644 index 0000000..43d8977 --- /dev/null +++ b/source/nnid.h @@ -0,0 +1,23 @@ +#pragma once +#include <3ds/types.h> +#include +#include + +Result nnid_init(void); +void nnid_exit(void); +// true, wenn auf dem aktuellen Konto eine NNID verknüpft ist (Name in name) +bool nnid_linked(char *name, size_t len); +// PID der verknüpften NNID (0 = keine) +u32 nnid_pid(void); +// IDs, die in ANDEREN Konto-Plätzen verknüpft sind (z. B. Pretendo). Anzahl, Namen in names. +int nnid_others(char *names, size_t len); +// Löst diese IDs lokal (Namen werden in /3ds/mbmnet/alte-nnid.txt gesichert) +bool nnid_unlink_others(char *msg, size_t msglen); +// Löst die verknüpfte NNID lokal (Name/PID werden in /3ds/mbmnet/alte-nnid.txt gesichert) +bool nnid_unlink(char *msg, size_t msglen); +// Gibt es die ID "name" in einem Konto-Platz außer exceptSlot? +bool nnid_name_elsewhere(const char *name, u8 exceptSlot); +// Löst die ID "name" in allen Konto-Plätzen außer exceptSlot (nur auf dem 3DS) +bool nnid_unlink_named(const char *name, u8 exceptSlot, char *msg, size_t msglen); +// Schreibt alle Konto-Plätze in die Diagnose +void nnid_dump(FILE *f); diff --git a/source/olvpatch.c b/source/olvpatch.c new file mode 100644 index 0000000..bac27cb --- /dev/null +++ b/source/olvpatch.c @@ -0,0 +1,109 @@ +// Miiverse-Patch: leitet die Miiverse-App auf MBMNET um und lässt sie der MBMNET-Zertifizierungsstelle (CA) +// vertrauen, denn ihre Seiten lädt sie nur per HTTPS. +// +// Die Code-Änderungen stammen aus Pretendos Nimbus (patches/miiverse, GPLv3, nach Stary und Sono): mit armips +// übersetzt, statt Pretendos Discovery-Adresse und GlobalSign-Zertifikat kommen MBMNET-Adresse und -CA hinein. +// Sie gelten für die letzte Version der Miiverse-App (alle Regionen gleich). Vorher wird geprüft, dass die +// Nintendo-Discovery-Adresse genau an der erwarteten Stelle steht - sonst wird nichts gepatcht. +// +// 0x176F28 fügt der HTTP-Verbindung die CA hinzu (httpC:AddRootCA), Länge der CA an Byte 72 +// 0x1D7FF8 / 0x1D80EC / 0x38DC30 SD-Karte zusätzlich einhängen und wieder aushängen +// 0x1E3224 / 0x1E3468 der Browser lädt seine CA aus sdmc:/3ds/mbmnet-ca.pem +// 0x38DCB0 die CA selbst (DER, höchstens 889 Bytes) +#include <3ds.h> +#include +#include + +#include "olvpatch.h" + +#define CODE_BASE 0x100000 +#define DISCOVERY_ADDR 0x15748C +#define DISCOVERY_URL "https://discovery.olv.nintendo.net/v1/endpoint" +#define CA_ADDR 0x38DCB0 +#define CA_MAX 889 +#define CA_PEM_FILE "sdmc:/3ds/mbmnet-ca.pem" + +static const u8 olv_176F28[] = { 0x3C, 0x00, 0x9F, 0xE5, 0x70, 0x4F, 0x1D, 0xEE, 0x0C, 0x10, 0x95, 0xE5, 0x14, 0x80, 0x95, 0xE5, 0x80, 0x00, 0xA4, 0xE5, 0x04, 0x10, 0x84, 0xE5, 0x08, 0x00, 0xA0, 0xE1, 0x24, 0x80, 0x9F, 0xE5, 0x24, 0x10, 0x9F, 0xE5, 0x08, 0x80, 0x84, 0xE5, 0x10, 0x10, 0x84, 0xE5, 0x08, 0x82, 0xA0, 0xE1, 0x0A, 0x80, 0x88, 0xE3, 0x0C, 0x80, 0x84, 0xE5, 0x32, 0x00, 0x00, 0xEF, 0x00, 0x00, 0xA0, 0xE1, 0x08, 0x00, 0x00, 0xEA, 0x82, 0x00, 0x24, 0x00, 0x79, 0x03, 0x00, 0x00, 0xB0, 0xDC, 0x38, 0x00, 0x00, 0x00, 0xA0, 0xE1, 0x00, 0x00, 0xA0, 0xE1, 0x00, 0x00, 0xA0, 0xE1 }; +static const u8 olv_1D7FF8[] = { 0x0C, 0xD7, 0x06, 0xEA }; +static const u8 olv_1D80EC[] = { 0xD4, 0xD6, 0x06, 0xEA }; +static const u8 olv_1E3224[] = { 0x01, 0x20, 0xA0, 0xE3 }; +static const u8 olv_1E3468[] = "3ds/mbmnet-ca.pem"; // mit Nullbyte: 18 Bytes +static const u8 olv_38DC30[] = { 0x00, 0x40, 0x2D, 0xE9, 0x2E, 0x28, 0xF9, 0xEB, 0x18, 0x00, 0x9F, 0xE5, 0x00, 0x40, 0xBD, 0xE8, 0xB6, 0x93, 0xF8, 0xEA, 0x00, 0x40, 0x2D, 0xE9, 0x02, 0x29, 0xF9, 0xEB, 0x04, 0x00, 0x9F, 0xE5, 0x00, 0x40, 0xBD, 0xE8, 0xBB, 0x92, 0xFA, 0xEA, 0x9C, 0x81, 0x1D, 0x00 }; +#define CA_LEN_BYTE 72 // in olv_176F28: Länge der CA (Literal-Pool) + +// Lädt eine Datei vom MBMNET-Server. Gibt die Länge zurück, 0 bei Fehler. +static u32 fetch(const char *server, const char *path, u8 *buf, u32 cap) +{ + char url[160]; + snprintf(url, sizeof(url), "http://%s%s", server, path); + httpcContext ctx; + if (R_FAILED(httpcOpenContext(&ctx, HTTPC_METHOD_GET, url, 1))) return 0; + httpcAddRequestHeaderField(&ctx, "User-Agent", "MBMNET-Switcher/" APP_VERSION); + u32 status = 0, got = 0; + Result rc = httpcBeginRequest(&ctx); + if (R_SUCCEEDED(rc)) rc = httpcGetResponseStatusCodeTimeout(&ctx, &status, 8ULL * 1000 * 1000 * 1000); + if (R_SUCCEEDED(rc) && status == 200) rc = httpcDownloadData(&ctx, buf, cap, &got); + httpcCloseContext(&ctx); + return R_SUCCEEDED(rc) && status == 200 && got < cap ? got : 0; +} + +bool olvpatch_fetch_ca(const char *server, u8 *der, u32 *derLen) +{ + static u8 pem[2048]; + u32 n = fetch(server, "/olv/ca.der", der, CA_MAX + 1); + if (n == 0 || n > CA_MAX) return false; + u32 p = fetch(server, "/olv/ca.pem", pem, sizeof(pem)); + if (p == 0) return false; + // Der Browser der Miiverse-App liest die CA von der SD-Karte + FILE *f = fopen(CA_PEM_FILE, "wb"); + bool ok = f && fwrite(pem, 1, p, f) == p; + if (f) fclose(f); + *derLen = n; + return ok; +} + +bool olvpatch_supported(const u8 *code, u32 size) +{ + u32 off = DISCOVERY_ADDR - CODE_BASE; + return off + sizeof(DISCOVERY_URL) <= size && memcmp(code + off, DISCOVERY_URL, sizeof(DISCOVERY_URL)) == 0; +} + +static u32 ips_record(u8 *out, u32 n, u32 cap, u32 addr, const u8 *data, u32 len) +{ + if (n + 5 + len + 3 > cap) return 0; + u32 off = addr - CODE_BASE; + u8 head[5] = { off >> 16, off >> 8, off, len >> 8, len }; + memcpy(out + n, head, 5); + memcpy(out + n + 5, data, len); + return n + 5 + len; +} + +u32 olvpatch_build(const char *server, const u8 *der, u32 derLen, u8 *out, u32 cap) +{ + // Discovery: "https://discovery.olv.nintendo.net/v1/endpoint" -> "http:///v1/endpoint", Rest Nullbytes + u8 discovery[sizeof(DISCOVERY_URL)] = { 0 }; + int len = snprintf((char *)discovery, sizeof(discovery), "http://%s/v1/endpoint", server); + if (len <= 0 || len >= (int)sizeof(discovery) || derLen == 0 || derLen > CA_MAX) return 0; + + u8 caHook[sizeof(olv_176F28)]; + memcpy(caHook, olv_176F28, sizeof(caHook)); + caHook[CA_LEN_BYTE] = derLen; + caHook[CA_LEN_BYTE + 1] = derLen >> 8; + + u32 n = 5; + memcpy(out, "PATCH", 5); + struct { u32 addr; const u8 *data; u32 len; } recs[] = { + { DISCOVERY_ADDR, discovery, sizeof(discovery) }, + { 0x176F28, caHook, sizeof(caHook) }, + { 0x1D7FF8, olv_1D7FF8, sizeof(olv_1D7FF8) }, + { 0x1D80EC, olv_1D80EC, sizeof(olv_1D80EC) }, + { 0x1E3224, olv_1E3224, sizeof(olv_1E3224) }, + { 0x1E3468, olv_1E3468, sizeof(olv_1E3468) }, + { 0x38DC30, olv_38DC30, sizeof(olv_38DC30) }, + { CA_ADDR, der, derLen }, + }; + for (size_t i = 0; i < sizeof(recs) / sizeof(recs[0]); i++) + if (!(n = ips_record(out, n, cap, recs[i].addr, recs[i].data, recs[i].len))) return 0; + memcpy(out + n, "EOF", 3); + return n + 3; +} diff --git a/source/olvpatch.h b/source/olvpatch.h new file mode 100644 index 0000000..e7a9c12 --- /dev/null +++ b/source/olvpatch.h @@ -0,0 +1,11 @@ +#pragma once +#include <3ds/types.h> + +// Miiverse-Patch (siehe olvpatch.c). Die CA kommt vom MBMNET-Server (/olv/ca.der, /olv/ca.pem). + +// Holt die MBMNET-CA (DER, höchstens 889 Bytes) und legt die PEM-Fassung für den Browser auf die SD. +bool olvpatch_fetch_ca(const char *server, u8 *der, u32 *derLen); +// Ist das genau die Miiverse-Version, für die der Patch gebaut ist? (entpackter .code) +bool olvpatch_supported(const u8 *code, u32 size); +// Baut den IPS-Patch. Gibt die Länge zurück, 0 bei Fehler. +u32 olvpatch_build(const char *server, const u8 *der, u32 derLen, u8 *out, u32 cap); diff --git a/source/patcher.c b/source/patcher.c new file mode 100644 index 0000000..6a5398a --- /dev/null +++ b/source/patcher.c @@ -0,0 +1,885 @@ +// Erzeugt und verwaltet die MBMNET-Patches. +// +// Gepatcht werden zwei Systemmodule: +// Freunde (0004013000003202): https://nasc.nintendowifi.net -> http:// +// Konto (0004013000003802): https://account.nintendo.net -> http:// +// +// Ablauf je Modul: +// 1. .code lesen (direkt aus dem NAND, sonst aus einem Dump auf der SD) +// 2. falls komprimiert: entpacken (Luma patcht die entpackte Version) +// 3. alle Nintendo-Adressen suchen und durch die MBMNET-Adresse ersetzen +// 4. als IPS-Patch nach /luma/titles//code.ips schreiben +// +// Am NAND wird nie etwas verändert. Luma3DS wendet die Patches nur beim Laden an. +#include <3ds.h> +#include +#include +#include +#include +#include + +#include "blz.h" +#include "patcher.h" +#include "lumaconfig.h" +#include "olvpatch.h" +#include "nnid.h" + +#define SYSMODULE_DIR "sdmc:/luma/sysmodules" + +#define MAX_HITS 8 + +// Boot-Splash: Luma zeigt beim Einschalten "MBMNET aktiv" (Bild in splash_data.c) +#define SPLASH_FILE "sdmc:/luma/splash.bin" +#define SPLASH_BACKUP "sdmc:/luma/splash.bin.vor-mbmnet" +#define SPLASH_SIZE (400 * 240 * 3) + +// Zwischenspeicher: fertige Patches und der Splash. Damit ist Umschalten nur noch Umbenennen und +// zwei kleine Dateien schreiben, statt die Module aus dem NAND zu lesen, zu entpacken und zu durchsuchen. +// Ein Patch gilt nur, solange Modul (Größe + Ende der .code), Server und Regeln gleich sind. +#define CACHE_DIR APP_DIR "/cache" +#define SPLASH_CACHE CACHE_DIR "/splash-" APP_VERSION ".bin" +#define RULES_VERSION "1" +extern const u8 splash_rle[]; +extern const u32 splash_rle_size; + +// Eine Ersetzungsregel. Es gibt zwei Arten: +// PREFIX: Text beginnt mit needle -> needle wird zu "http://", der Rest bleibt +// ("https://nasc.nintendowifi.net/ac" -> "http:///ac") +// EXACT: Text ist genau needle -> wird zu "http://" + suffix +// (für Vorlagen mit Platzhaltern, deren Werte der 3DS dann ins Leere schreibt) +typedef enum { RULE_PREFIX, RULE_EXACT } RuleType; + +typedef struct { + RuleType type; + const char *needle; + const char *suffix; // nur EXACT +} Rule; + +#define MAX_RULES 2 + +typedef struct { + u64 tid; + const char *dir; // Luma-Ordner für dieses Modul + const char *label; // Name für Meldungen + Rule rules[MAX_RULES]; + bool optional; // Anwendung statt Systemmodul: nur patchen, wenn installiert und Adresse gefunden +} Target; + +#define TITLES_DIR "sdmc:/luma/titles" + +// Umgelenkt wird die normale Nintendo-Umgebung: Alles, was der 3DS sonst zu +// nasc.nintendowifi.net und account.nintendo.net schickt, geht an MBMNET. +static const Target targets[] = { + { 0x0004013000003202ULL, SYSMODULE_DIR, "Freunde", { + { RULE_PREFIX, "https://nasc.nintendowifi.net" }, + } }, + { 0x0004013000003802ULL, SYSMODULE_DIR, "Konto", { + // Aktuelle Firmware: die beiden %s sind Zusätze für Nintendos Test-Server (sonst leer), + // %u ist die API-Version (immer 1). + { RULE_EXACT, "https://%s%saccount.nintendo.net/v%u/api/", "/v1/api/" }, + { RULE_PREFIX, "https://account.nintendo.net" }, + } }, + // Miiverse (JPN, USA, EUR): fragt zuerst den Discovery-Server, wohin es geht, und lädt dann seine Seiten + // per HTTPS. Gebaut wird der Patch in olvpatch.c (die Regel hier dient nur der Diagnose). Nur die + // installierte Region wird gepatcht. Luma lädt Patches für Anwendungen aus /luma/titles//code.ips (wie Nimbus). + { 0x000400300000BC02ULL, TITLES_DIR, "Miiverse", { { RULE_PREFIX, "https://discovery.olv.nintendo.net" } }, true }, + { 0x000400300000BD02ULL, TITLES_DIR, "Miiverse", { { RULE_PREFIX, "https://discovery.olv.nintendo.net" } }, true }, + { 0x000400300000BE02ULL, TITLES_DIR, "Miiverse", { { RULE_PREFIX, "https://discovery.olv.nintendo.net" } }, true }, +}; +#define TARGET_COUNT (sizeof(targets) / sizeof(targets[0])) + +typedef struct { + u32 offset; + u32 size; // Anzahl Bytes, die geschrieben werden + u8 data[160]; +} Hit; + +typedef struct { + Hit hits[MAX_HITS]; + int count; +} Patch; + +// --- Dateien --------------------------------------------------------------------- + +static bool file_exists(const char *path) +{ + struct stat st; + return stat(path, &st) == 0; +} + +// Luma3DS lädt IPS-Patches für Systemmodule aus /luma/sysmodules/.ips +// (nur wenn "Enable loading external FIRMs and system modules" an ist). +// Daneben legen wir einen Merker .mbmnet und ggf. die Sicherung eines fremden Patches ab. +static void path_in(char *out, size_t len, const Target *t, const char *file) +{ + // Anwendungen: /luma/titles//code.ips (+ mbmnet.txt, code.ips.vor-mbmnet) + if (strcmp(t->dir, TITLES_DIR) == 0) { + snprintf(out, len, "%s/%016llX/%s", t->dir, t->tid, file); + return; + } + const char *ext = strcmp(file, "code.ips") == 0 ? ".ips" + : strcmp(file, "mbmnet.txt") == 0 ? ".mbmnet" + : ".ips.vor-mbmnet"; + snprintf(out, len, "%s/%016llX%s", t->dir, t->tid, ext); +} + +// Bis v2.2.0 lagen die Patches unter /luma/titles//code.ips - dort wendet Luma sie für +// Systemmodule aber nicht an. Alte Dateien entfernen und gesicherte fremde Patches zurückholen. +bool patch_migrate(void) +{ + bool migrated = false; + for (size_t i = 0; i < TARGET_COUNT; i++) { + if (targets[i].optional) continue; // Anwendungen gehören nach /luma/titles + char dir[64], ips[96], marker[96], backup[96]; + snprintf(dir, sizeof(dir), "sdmc:/luma/titles/%016llX", targets[i].tid); + snprintf(ips, sizeof(ips), "%s/code.ips", dir); + snprintf(marker, sizeof(marker), "%s/mbmnet.txt", dir); + snprintf(backup, sizeof(backup), "%s/code.ips.vor-mbmnet", dir); + if (!file_exists(marker)) continue; + remove(ips); + remove(marker); + if (file_exists(backup)) rename(backup, ips); + migrated = true; + } + return migrated; +} + +static void mkdirs(const char *path) +{ + char tmp[256]; + snprintf(tmp, sizeof(tmp), "%s", path); + for (char *p = tmp + strlen("sdmc:/"); *p; p++) { + if (*p == '/') { + *p = 0; + mkdir(tmp, 0777); + *p = '/'; + } + } + mkdir(tmp, 0777); +} + +PatchState patch_state(void) +{ + char path[128]; + bool foreign = false; + for (size_t i = 0; i < TARGET_COUNT; i++) { + path_in(path, sizeof(path), &targets[i], "mbmnet.txt"); + if (file_exists(path)) return STATE_MBMNET; + path_in(path, sizeof(path), &targets[i], "code.ips"); + if (!targets[i].optional && file_exists(path)) foreign = true; + } + return foreign ? STATE_FOREIGN : STATE_ORIGINAL; +} + +// --- .code lesen ------------------------------------------------------------ + +static Result read_from_nand(u64 tid, u8 **out, u32 *outSize) +{ + u32 archPath[4] = { (u32)tid, (u32)(tid >> 32), MEDIATYPE_NAND, 0 }; + // ExeFS-Datei ".code" + static const u32 filePath[5] = { 0, 0, 2, 0x646F632E, 0x00000065 }; + FS_Path arch = { PATH_BINARY, sizeof(archPath), archPath }; + FS_Path file = { PATH_BINARY, sizeof(filePath), filePath }; + + Handle h; + Result rc = FSUSER_OpenFileDirectly(&h, ARCHIVE_SAVEDATA_AND_CONTENT, arch, file, FS_OPEN_READ, 0); + if (R_FAILED(rc)) return rc; + + u64 size = 0; + rc = FSFILE_GetSize(h, &size); + if (R_SUCCEEDED(rc)) { + u8 *buf = malloc(size); + u32 read = 0; + if (!buf) rc = -1; + else rc = FSFILE_Read(h, &read, 0, buf, size); + if (R_SUCCEEDED(rc)) { *out = buf; *outSize = read; } + else free(buf); + } + FSFILE_Close(h); + return rc; +} + +// Ersatzweise ein Dump von der SD: /3ds/mbmnet/.bin +static bool read_from_sd(u64 tid, u8 **out, u32 *outSize) +{ + char path[64]; + snprintf(path, sizeof(path), APP_DIR "/%016llX.bin", tid); + FILE *f = fopen(path, "rb"); + if (!f) return false; + fseek(f, 0, SEEK_END); + long size = ftell(f); + fseek(f, 0, SEEK_SET); + u8 *buf = size > 0 ? malloc(size) : NULL; + bool ok = buf && fread(buf, 1, size, f) == (size_t)size; + fclose(f); + if (!ok) { free(buf); return false; } + *out = buf; + *outSize = size; + return true; +} + +static bool load_code(const Target *t, u8 **out, u32 *outSize, char *msg, size_t msglen) +{ + u8 *buf = NULL; + u32 size = 0; + Result rc = read_from_nand(t->tid, &buf, &size); + if (R_FAILED(rc) && t->optional) return false; // nicht installiert (andere Region) + if (R_FAILED(rc) && !read_from_sd(t->tid, &buf, &size)) { + snprintf(msg, msglen, + "%s-Modul nicht lesbar (Fehler %08lX).\n" + "Lege einen Dump als /3ds/mbmnet/%016llX.bin\nab (siehe Anleitung).", + t->label, (unsigned long)rc, t->tid); + return false; + } + + if (blz_looks_compressed(buf, size)) { + u32 full = blz_decompressed_size(buf, size); + u8 *big = realloc(buf, full); + if (!big) { free(buf); snprintf(msg, msglen, "Zu wenig Speicher."); return false; } + buf = big; + if (!blz_decompress(buf, size)) { + free(buf); + snprintf(msg, msglen, "%s-Modul konnte nicht entpackt werden.", t->label); + return false; + } + size = full; + } + + *out = buf; + *outSize = size; + return true; +} + +// --- Zwischenspeicher ------------------------------------------------------------ + +// Fingerabdruck des Moduls ohne es ganz zu lesen: Größe und die letzten 16 Bytes der .code +// (bei komprimierten Modulen stehen dort die Entpack-Angaben). Leer, wenn nicht lesbar. +static void fingerprint(u64 tid, char *out, size_t len) +{ + u32 archPath[4] = { (u32)tid, (u32)(tid >> 32), MEDIATYPE_NAND, 0 }; + static const u32 filePath[5] = { 0, 0, 2, 0x646F632E, 0x00000065 }; + out[0] = 0; + Handle h; + if (R_FAILED(FSUSER_OpenFileDirectly(&h, ARCHIVE_SAVEDATA_AND_CONTENT, (FS_Path){ PATH_BINARY, sizeof(archPath), archPath }, + (FS_Path){ PATH_BINARY, sizeof(filePath), filePath }, FS_OPEN_READ, 0))) return; + u64 size = 0; + static u8 block[0x400]; + u32 got = 0; + // Nur ab einer 0x200-Grenze lesen: Ein Lesen mitten im Block (Ende - 16) scheitert bei diesen Dateien + u64 start = size; + if (R_SUCCEEDED(FSFILE_GetSize(h, &size)) && size >= 16) { + start = (size - 16) & ~0x1FFULL; + if (R_SUCCEEDED(FSFILE_Read(h, &got, start, block, (u32)(size - start))) && got == size - start) { + const u8 *tail = block + got - 16; + int n = snprintf(out, len, "%llX-", size); + for (int i = 0; i < 16 && n + 2 < (int)len; i++) n += snprintf(out + n, len - n, "%02X", tail[i]); + } + } + FSFILE_Close(h); +} + +static void cache_key(const Target *t, const char *server, char *out, size_t len) +{ + char fp[64]; + fingerprint(t->tid, fp, sizeof(fp)); + if (fp[0]) snprintf(out, len, "%s|%s|" RULES_VERSION, fp, server); + else out[0] = 0; +} + +static u32 cache_load(const Target *t, const char *key, u8 *data, u32 cap) +{ + char path[96], stored[160] = ""; + if (!key[0]) return 0; + snprintf(path, sizeof(path), CACHE_DIR "/%016llX.key", t->tid); + FILE *f = fopen(path, "r"); + if (!f) return 0; + if (!fgets(stored, sizeof(stored), f)) stored[0] = 0; + fclose(f); + stored[strcspn(stored, "\r\n")] = 0; + if (strcmp(stored, key)) return 0; + + snprintf(path, sizeof(path), CACHE_DIR "/%016llX.ips", t->tid); + f = fopen(path, "rb"); + u32 n = f ? fread(data, 1, cap, f) : 0; + if (f) fclose(f); + return n > 8 && !memcmp(data, "PATCH", 5) && !memcmp(data + n - 3, "EOF", 3) ? n : 0; +} + +static void cache_store(const Target *t, const char *key, const u8 *data, u32 n) +{ + char path[96]; + if (!key[0]) return; + mkdir(APP_DIR, 0777); + mkdir(CACHE_DIR, 0777); + snprintf(path, sizeof(path), CACHE_DIR "/%016llX.ips", t->tid); + FILE *f = fopen(path, "wb"); + bool ok = f && fwrite(data, 1, n, f) == n; + if (f) fclose(f); + snprintf(path, sizeof(path), CACHE_DIR "/%016llX.key", t->tid); + f = ok ? fopen(path, "w") : NULL; + if (f) { fprintf(f, "%s\n", key); fclose(f); } +} + +// --- Patch berechnen und schreiben ---------------------------------------------- + +static bool build_patch(const Target *t, const char *server, Patch *p, char *msg, size_t msglen) +{ + u8 *code; + u32 size; + if (!load_code(t, &code, &size, msg, msglen)) return false; + + p->count = 0; + + for (u32 i = 0; i < size && p->count < MAX_HITS; i++) { + for (int r = 0; r < MAX_RULES && t->rules[r].needle; r++) { + const Rule *rule = &t->rules[r]; + size_t needleLen = strlen(rule->needle); + if (i + needleLen >= size || memcmp(code + i, rule->needle, needleLen) != 0) continue; + u32 len = strnlen((const char *)code + i, size - i); + + Hit *h = &p->hits[p->count]; + memset(h, 0, sizeof(*h)); + + if (rule->type == RULE_EXACT && len != needleLen) continue; // Vorlage muss genau passen + { + char repl[128]; + if (rule->type == RULE_EXACT) + snprintf(repl, sizeof(repl), "http://%s%s", server, rule->suffix); + else + snprintf(repl, sizeof(repl), "http://%s%.*s", + server, (int)(len - needleLen), (const char *)code + i + needleLen); + if (len + 1 > sizeof(h->data) || strlen(repl) > len) { + free(code); + snprintf(msg, msglen, "Server-Adresse passt nicht in das %s-Modul\n(zu lang).", t->label); + return false; + } + // Ersatz + Nullbytes bis zur Originallänge (inkl. Terminator) + h->offset = i; + h->size = len + 1; + memcpy(h->data, repl, strlen(repl)); + } + p->count++; + i += len; + break; + } + } + free(code); + + if (p->count == 0 && t->optional) return false; + if (p->count == 0) { + char diag[64]; + patch_diagnose(diag, sizeof(diag)); + snprintf(msg, msglen, "%s-Modul: Nintendo-Adresse nicht gefunden.\n" + "Diagnose gespeichert: /3ds/mbmnet/diagnose.txt\nBitte an den Entwickler schicken.", t->label); + return false; + } + return true; +} + +// Baut den IPS-Patch im Speicher. Gibt die Länge zurück. +static u32 build_ips(const Patch *p, u8 *out, u32 cap) +{ + u32 n = 0; + memcpy(out, "PATCH", 5); + n = 5; + for (int i = 0; i < p->count && n + 5 + p->hits[i].size + 3 <= cap; i++) { + const Hit *h = &p->hits[i]; + u8 rec[5] = { h->offset >> 16, h->offset >> 8, h->offset, h->size >> 8, h->size }; + memcpy(out + n, rec, 5); + memcpy(out + n + 5, h->data, h->size); + n += 5 + h->size; + } + memcpy(out + n, "EOF", 3); + return n + 3; +} + +// Schreibt den Patch. *changed wird true, wenn sich die Datei dadurch geändert hat +// (nur dann muss der 3DS neu starten, denn Luma patcht beim Laden der Module). +#define IPS_CAP 2048 // Miiverse-Patch mit CA: ca. 1100 Bytes + +static bool write_ips(const char *path, const u8 *data, u32 n, bool *changed) +{ + static u8 old[IPS_CAP]; + FILE *f = fopen(path, "rb"); + size_t oldLen = f ? fread(old, 1, sizeof(old), f) : 0; + if (f) fclose(f); + if (oldLen == n && memcmp(old, data, n) == 0) return true; // schon genau so vorhanden + + f = fopen(path, "wb"); + bool ok = f && fwrite(data, 1, n, f) == n; + if (f) fclose(f); + if (ok) *changed = true; + return ok; +} + +// Miiverse-Patch (olvpatch.c): eigene Code-Änderungen + MBMNET-CA statt einfacher Text-Regeln. +// 0 = nicht installiert, andere Version oder CA nicht vom Server zu holen (dann bleibt ein alter Patch stehen). +static u32 build_miiverse(const Target *t, const char *server, u8 *out, u32 cap) +{ + static u8 der[1024]; + static u32 derLen; + static int caState; // 0 = noch nicht geholt, 1 = da, -1 = nicht zu holen + char fp[64]; + fingerprint(t->tid, fp, sizeof(fp)); // leer = kein Zwischenspeicher, gebaut wird trotzdem + if (caState == 0) caState = olvpatch_fetch_ca(server, der, &derLen) ? 1 : -1; + if (caState < 0) return 0; + + u32 sum = 2166136261u; // FNV-1a über die CA: neue CA -> neuer Patch + for (u32 i = 0; i < derLen; i++) sum = (sum ^ der[i]) * 16777619u; + char key[160]; + if (fp[0]) snprintf(key, sizeof(key), "%s|%s|olv1|%08lX", fp, server, (unsigned long)sum); + else key[0] = 0; + u32 n = cache_load(t, key, out, cap); + if (n) return n; + + u8 *code; + u32 size; + char ignore[8]; + if (!load_code(t, &code, &size, ignore, sizeof(ignore))) return 0; + bool supported = olvpatch_supported(code, size); + free(code); + if (!supported) return 0; + n = olvpatch_build(server, der, derLen, out, cap); + if (n) cache_store(t, key, out, n); + return n; +} + +// --- Fremde Patches, die MBMNET stören --------------------------------------------- +// Pretendos Patch für das http-Modul fragt bei jeder Verbindung den Freunde-Dienst nach dem +// aktiven Konto. Stellt der Freunde-Dienst selbst die Anfrage, warten beide aufeinander und +// keine Anfrage kommt bei MBMNET an. Er wird beim Aktivieren beiseitegelegt und beim +// Zurücksetzen zurückgeholt. +static const u64 conflicting[] = { + 0x0004013000002902ULL, // http +}; + +static int park_conflicting(void) +{ + int parked = 0; + for (size_t i = 0; i < sizeof(conflicting) / sizeof(conflicting[0]); i++) { + char ips[96], backup[112]; + snprintf(ips, sizeof(ips), SYSMODULE_DIR "/%016llX.ips", conflicting[i]); + snprintf(backup, sizeof(backup), "%s.vor-mbmnet", ips); + // Liegt hier ein Patch, ist er fremd (MBMNET legt hier keinen an): immer den aktuellen sichern + if (file_exists(ips)) { + remove(backup); + if (rename(ips, backup) == 0) parked++; + } + } + return parked; +} + +static void restore_conflicting(void) +{ + for (size_t i = 0; i < sizeof(conflicting) / sizeof(conflicting[0]); i++) { + char ips[96], backup[112]; + snprintf(ips, sizeof(ips), SYSMODULE_DIR "/%016llX.ips", conflicting[i]); + snprintf(backup, sizeof(backup), "%s.vor-mbmnet", ips); + if (file_exists(backup) && !file_exists(ips)) rename(backup, ips); + } +} + +// --- Boot-Splash -------------------------------------------------------------------- + +static bool install_splash(bool alreadyOurs) +{ + // Eigenen Splash des Nutzers sichern (nur beim ersten Aktivieren) + if (!alreadyOurs && file_exists(SPLASH_FILE) && !file_exists(SPLASH_BACKUP)) rename(SPLASH_FILE, SPLASH_BACKUP); + if (alreadyOurs && file_exists(SPLASH_FILE)) return true; + // Beim Deaktivieren geparkt: nur zurückschieben + if (!file_exists(SPLASH_FILE) && file_exists(SPLASH_CACHE) && rename(SPLASH_CACHE, SPLASH_FILE) == 0) return true; + + u8 *buf = malloc(SPLASH_SIZE); + if (!buf) return false; + u32 out = 0; + for (u32 i = 0; i + 3 < splash_rle_size && out < SPLASH_SIZE; i += 4) { + for (u8 n = splash_rle[i]; n > 0 && out + 3 <= SPLASH_SIZE; n--) { + memcpy(buf + out, &splash_rle[i + 1], 3); + out += 3; + } + } + FILE *f = out == SPLASH_SIZE ? fopen(SPLASH_FILE, "wb") : NULL; + bool ok = f && fwrite(buf, 1, SPLASH_SIZE, f) == SPLASH_SIZE; + if (f) fclose(f); + free(buf); + return ok; +} + +static void remove_splash(void) +{ + // Parken statt löschen, damit das nächste Aktivieren ihn nicht neu schreiben muss + mkdir(APP_DIR, 0777); + mkdir(CACHE_DIR, 0777); + remove(SPLASH_CACHE); + if (rename(SPLASH_FILE, SPLASH_CACHE) != 0) remove(SPLASH_FILE); + if (file_exists(SPLASH_BACKUP)) rename(SPLASH_BACKUP, SPLASH_FILE); +} + +// --- Aktivieren / Deaktivieren ----------------------------------------------- + +bool patch_enable(const char *server, bool *changed, char *msg, size_t msglen) +{ + *changed = false; + if (!server[0]) { + snprintf(msg, msglen, "Bitte zuerst die Server-Adresse eintragen."); + return false; + } + + bool alreadyOurs = patch_state() == STATE_MBMNET; + + // Erst alle Patches bereitlegen (aus dem Zwischenspeicher oder neu berechnet): + // Klappt eines nicht, wird gar nichts geschrieben. + static u8 ips[TARGET_COUNT][IPS_CAP]; + u32 ipsLen[TARGET_COUNT]; + for (size_t i = 0; i < TARGET_COUNT; i++) { + if (targets[i].optional) { // Miiverse + ipsLen[i] = build_miiverse(&targets[i], server, ips[i], IPS_CAP); + continue; + } + char key[160]; + cache_key(&targets[i], server, key, sizeof(key)); + ipsLen[i] = cache_load(&targets[i], key, ips[i], IPS_CAP); + if (ipsLen[i]) continue; + static Patch patch; + if (!build_patch(&targets[i], server, &patch, msg, msglen)) { + if (targets[i].optional) { ipsLen[i] = 0; continue; } // nicht installiert: auslassen + return false; + } + ipsLen[i] = build_ips(&patch, ips[i], IPS_CAP); + cache_store(&targets[i], key, ips[i], ipsLen[i]); + } + + bool backedUp = false, appPatched = false; + for (size_t i = 0; i < TARGET_COUNT; i++) { + const Target *t = &targets[i]; + if (!ipsLen[i]) continue; + char path[128], marker[128], backup[128], dir[96]; + if (t->optional) { + snprintf(dir, sizeof(dir), "%s/%016llX", t->dir, t->tid); + mkdirs(dir); + appPatched = true; + } + path_in(path, sizeof(path), t, "code.ips"); + path_in(marker, sizeof(marker), t, "mbmnet.txt"); + path_in(backup, sizeof(backup), t, "code.ips.vor-mbmnet"); + + mkdirs(t->dir); + // Fremden Patch (z. B. Pretendo) sichern, nicht überschreiben. Immer den aktuellen: Eine ältere Sicherung + // (z. B. von vor einem Nimbus-Update) würde sonst beim Zurückschalten veraltete Patches herstellen + // (bei Pretendo Fehler 002-0122). + if (file_exists(path) && !file_exists(marker)) { + remove(backup); + rename(path, backup); + backedUp = true; + } + if (!write_ips(path, ips[i], ipsLen[i], changed)) { + snprintf(msg, msglen, "Patch konnte nicht auf die SD-Karte geschrieben werden."); + return false; + } + FILE *m = fopen(marker, "w"); + if (m) { + fprintf(m, "MBMNET-Patch aktiv\nServer: %s\n", server); + fclose(m); + } + } + + if (park_conflicting() > 0) *changed = true; // Neustart nötig, damit das http-Modul neu lädt + bool splash = install_splash(alreadyOurs) && lumaconfig_enable_splash(); + lumaconfig_enable_modules(); + if (appPatched && lumaconfig_enable_game_patching()) *changed = true; + + snprintf(msg, msglen, "Patches geschrieben.%s%s", + backedUp ? "\nAlter Patch wurde gesichert." : "", + splash ? "\nLuma zeigt beim Start \"MBMNET aktiv\"." : ""); + return true; +} + +// --- Diagnose --------------------------------------------------------------------- + +static bool has_ci(const char *s, u32 len, const char *word) +{ + size_t wl = strlen(word); + for (u32 i = 0; i + wl <= len; i++) { + size_t k = 0; + while (k < wl && (s[i + k] | 0x20) == word[k]) k++; + if (k == wl) return true; + } + return false; +} + +static bool interesting(const char *s, u32 len) +{ + return has_ci(s, len, "nintendo") || has_ci(s, len, "http") || has_ci(s, len, "nasc") + || has_ci(s, len, "account") || has_ci(s, len, "%s") || has_ci(s, len, ".net"); +} + +static void dump_strings(FILE *f, const u8 *code, u32 size) +{ + int lines = 0, total = 0; + char buf[256]; + + // ASCII-Texte + for (u32 i = 0; i < size;) { + u32 j = i; + while (j < size && code[j] >= 0x20 && code[j] < 0x7F) j++; + u32 len = j - i; + if (len >= 6) total++; + if (len >= 4 && interesting((const char *)code + i, len) && lines < 400) { + fprintf(f, " %06lX %.*s\n", (unsigned long)i, (int)(len > 200 ? 200 : len), (const char *)code + i); + lines++; + } + i = j + 1; + } + + // UTF-16-Texte (ein Zeichen + Nullbyte) + for (u32 i = 0; i + 1 < size;) { + u32 j = i, n = 0; + while (j + 1 < size && code[j] >= 0x20 && code[j] < 0x7F && code[j + 1] == 0 && n < sizeof(buf) - 1) { + buf[n++] = code[j]; + j += 2; + } + if (n >= 6 && interesting(buf, n) && lines < 500) { + fprintf(f, " %06lX [UTF-16] %.*s\n", (unsigned long)i, (int)n, buf); + lines++; + } + i = (j > i) ? j + 2 : i + 1; + } + fprintf(f, " (%d Texte insgesamt, %d passende gezeigt)\n", total, lines); +} + +// Sucht den laufenden Prozess eines Titels (Luma liefert die Titel-ID über Info-Typ 0x10001) +bool patch_find_process(u64 tid, u32 *pidOut) +{ + static u32 pids[0x60]; + s32 n = 0; + if (R_FAILED(svcGetProcessList(&n, pids, 0x60))) return false; + for (s32 i = 0; i < n; i++) { + Handle h; + if (R_FAILED(svcOpenProcess(&h, pids[i]))) continue; + s64 t = 0; + Result r = svcGetProcessInfo(&t, h, 0x10001); + svcCloseHandle(h); + if (R_SUCCEEDED(r) && (u64)t == tid) { *pidOut = pids[i]; return true; } + } + return false; +} + +// Liest aus dem laufenden Modul, welche Adresse dort wirklich im Speicher steht. +// So sieht man, ob Luma den Patch beim Laden angewendet hat. +static void dump_runtime(FILE *f, const char *label, u64 tid, u32 offset) +{ + u32 pid = 0; + if (!patch_find_process(tid, &pid)) { fprintf(f, " %s: Prozess nicht gefunden\n", label); return; } + Handle dbg; + Result r = svcDebugActiveProcess(&dbg, pid); + if (R_FAILED(r)) { fprintf(f, " %s: kein Zugriff (%08lX)\n", label, (unsigned long)r); return; } + DebugEventInfo info; + while (R_SUCCEEDED(svcGetProcessDebugEvent(&info, dbg))) + if (info.flags & 1) svcContinueDebugEvent(dbg, 0); + char buf[64] = { 0 }; + r = svcReadProcessMemory(buf, dbg, 0x100000 + offset, 48); + svcCloseHandle(dbg); + if (R_FAILED(r)) { fprintf(f, " %s: Lesen fehlgeschlagen (%08lX)\n", label, (unsigned long)r); return; } + for (int i = 0; i < 48 && buf[i]; i++) if (buf[i] < 0x20 || buf[i] > 0x7E) buf[i] = '.'; + fprintf(f, " %s (PID %lu) bei %06lX: %s\n", label, (unsigned long)pid, (unsigned long)offset, buf); +} + +bool patch_diagnose(char *msg, size_t msglen) +{ + mkdirs(APP_DIR); + FILE *f = fopen(DIAG_FILE, "w"); + if (!f) { + snprintf(msg, msglen, "Diagnose konnte nicht gespeichert werden."); + return false; + } + fprintf(f, "MBMNET-Diagnose (App v%s)\n\n", APP_VERSION); + + for (size_t i = 0; i < TARGET_COUNT; i++) { + const Target *t = &targets[i]; + u8 *raw = NULL; + u32 rawSize = 0; + Result rc = read_from_nand(t->tid, &raw, &rawSize); + bool fromSd = false; + if (R_FAILED(rc)) fromSd = read_from_sd(t->tid, &raw, &rawSize); + + fprintf(f, "== %s-Modul %016llX\n", t->label, t->tid); + if (!raw) { + fprintf(f, " nicht lesbar (Fehler %08lX)\n\n", (unsigned long)rc); + continue; + } + bool compressed = blz_looks_compressed(raw, rawSize); + fprintf(f, " Quelle: %s, Größe %lu, komprimiert: %s\n", fromSd ? "SD-Dump" : "NAND", + (unsigned long)rawSize, compressed ? "ja" : "nein"); + free(raw); + + char err[160]; + u8 *code; + u32 size; + if (!load_code(t, &code, &size, err, sizeof(err))) { + fprintf(f, " Fehler: %s\n\n", err); + continue; + } + fprintf(f, " entpackt: %lu Bytes\n", (unsigned long)size); + dump_strings(f, code, size); + fprintf(f, "\n"); + free(code); + } + // Installierte Patches: liegen sie auf der SD, und was steht drin? + fprintf(f, "== Installierte Patches\n"); + for (size_t i = 0; i < TARGET_COUNT; i++) { + char ips[128]; + path_in(ips, sizeof(ips), &targets[i], "code.ips"); + FILE *pf = fopen(ips, "rb"); + if (!pf) { fprintf(f, " %s: kein Patch (%s)\n", targets[i].label, ips + 5); continue; } + static u8 buf[4096]; + size_t n = fread(buf, 1, sizeof(buf), pf); + fclose(pf); + fprintf(f, " %s: %s, %lu Bytes\n", targets[i].label, ips + 5, (unsigned long)n); + for (size_t o = 5; o + 5 <= n && memcmp(buf + o, "EOF", 3) != 0;) { + u32 off = (buf[o] << 16) | (buf[o + 1] << 8) | buf[o + 2]; + u32 len = (buf[o + 3] << 8) | buf[o + 4]; + if (o + 5 + len > n) break; + fprintf(f, " bei %06lX: %.*s\n", (unsigned long)off, (int)strnlen((char *)buf + o + 5, len), (char *)buf + o + 5); + o += 5 + len; + } + } + fprintf(f, "\n"); + + // Alles in /luma/sysmodules (auch fremde Patches, z. B. von Pretendo) + fprintf(f, "== Inhalt von /luma/sysmodules\n"); + DIR *dir = opendir(SYSMODULE_DIR); + if (dir) { + struct dirent *e; + while ((e = readdir(dir))) { + char full[300]; + struct stat est; + snprintf(full, sizeof(full), "%s/%s", SYSMODULE_DIR, e->d_name); + if (stat(full, &est) == 0) fprintf(f, " %-40s %8ld Bytes\n", e->d_name, (long)est.st_size); + } + closedir(dir); + } else { + fprintf(f, " (Ordner fehlt)\n"); + } + fprintf(f, "\n"); + + // Konto-Plätze des Kontodienstes (act) + fprintf(f, "== Konto-Plätze\n"); + nnid_dump(f); + fprintf(f, "\n"); + + // Was steht im ARBEITSSPEICHER der laufenden Module? (zeigt, ob Luma die Patches angewendet hat) + fprintf(f, "== Laufende Module (Arbeitsspeicher)\n"); + dump_runtime(f, "Freunde", 0x0004013000003202ULL, 0x61279); + dump_runtime(f, "Konto ", 0x0004013000003802ULL, 0xE564); + fprintf(f, "\n"); + + // Verbindungstest: so, wie die Systemmodule eine Verbindung aufbauen (mit Nintendo-Zertifikaten) + fprintf(f, "== Verbindungstest (wie Freunde-/Konto-Modul)\n"); + httpcContext c; + Result r = httpcOpenContext(&c, HTTPC_METHOD_GET, "http://mbmnetapi.mbm.wtf:81/app/version", 1); + fprintf(f, " Verbindung öffnen (http) %08lX\n", (unsigned long)r); + if (R_SUCCEEDED(r)) { + fprintf(f, " Nintendo-Root-Zertifikat %08lX\n", (unsigned long)httpcAddDefaultCert(&c, SSLC_DefaultRootCert_Nintendo_CA_G3)); + fprintf(f, " Client-Zertifikat %08lX\n", (unsigned long)httpcSetClientCertDefault(&c, SSLC_DefaultClientCert_ClCertA)); + r = httpcBeginRequest(&c); + u32 status = 0; + if (R_SUCCEEDED(r)) httpcGetResponseStatusCodeTimeout(&c, &status, 10ULL * 1000 * 1000 * 1000); + fprintf(f, " Anfrage senden %08lX HTTP %lu\n", (unsigned long)r, (unsigned long)status); + httpcCloseContext(&c); + } + fprintf(f, "\n"); + + // Boot-Splash und Luma-Einstellungen + fprintf(f, "== Boot-Splash / Luma-Einstellungen\n"); + struct stat st; + if (stat(SPLASH_FILE, &st) == 0) + fprintf(f, " /luma/splash.bin: %ld Bytes%s\n", (long)st.st_size, st.st_size == SPLASH_SIZE ? " (richtig)" : " (FALSCHE GRÖSSE, Luma erwartet 288000)"); + else + fprintf(f, " /luma/splash.bin: fehlt\n"); + FILE *cfg = fopen("sdmc:/luma/config.ini", "r"); + if (cfg) { + char line[160]; + while (fgets(line, sizeof(line), cfg)) { + if (strstr(line, "splash_position") || strstr(line, "splash_duration") || strstr(line, "config_version") + || strstr(line, "enable_external_firm_and_modules =")) + fprintf(f, " config.ini: %s", line); + } + fclose(cfg); + } else { + fprintf(f, " /luma/config.ini: fehlt (ältere Luma-Version? Splash dann im Luma-Menü einschalten)\n"); + } + fprintf(f, "\n"); + + // Kontospeicher: Darf die App Systemspeicher öffnen? Scheitert nur der eines laufenden Dienstes + // (act, frd), ist er belegt; scheitern alle, fehlt eine Berechtigung. + fprintf(f, "== Systemspeicher öffnen (für \"Anmeldung merken\")\n"); + static const struct { u32 id; const char *name; } saves[] = { + { 0x00010038, "act (Kontodienst, läuft)" }, + { 0x00010032, "frd (Freunde-Dienst, läuft)" }, + { 0x00010017, "cfg (Systemeinstellungen-Modul, läuft)" }, + { 0x00020082, "HOME-Menü (System-App)" }, + { 0x00020086, "Systemeinstellungen (System-App, läuft nicht)" }, + }; + for (size_t i = 0; i < sizeof(saves) / sizeof(saves[0]); i++) { + u32 path[2] = { MEDIATYPE_NAND, saves[i].id }; + FS_Archive arch; + Result r = FSUSER_OpenArchive(&arch, ARCHIVE_SYSTEM_SAVEDATA, (FS_Path){ PATH_BINARY, sizeof(path), path }); + int files = -1; + if (R_SUCCEEDED(r)) { + Handle dir; + if (R_SUCCEEDED(FSUSER_OpenDirectory(&dir, arch, fsMakePath(PATH_ASCII, "/")))) { + FS_DirectoryEntry e[16]; + u32 n = 0; + files = R_SUCCEEDED(FSDIR_Read(dir, &n, 16, e)) ? (int)n : -2; + FSDIR_Close(dir); + } + FSUSER_CloseArchive(arch); + } + fprintf(f, " %08lX %-44s %08lX%s", (unsigned long)saves[i].id, saves[i].name, (unsigned long)r, R_SUCCEEDED(r) ? " OK" : ""); + if (files >= 0) fprintf(f, ", %d Einträge", files); + fprintf(f, "\n"); + } + fprintf(f, " Als %s gestartet\n", envIsHomebrew() ? "3dsx (Homebrew Launcher)" : "CIA"); + fprintf(f, "\n"); + + fclose(f); + snprintf(msg, msglen, "Diagnose gespeichert:\n/3ds/mbmnet/diagnose.txt\nBitte an den Entwickler schicken."); + return true; +} + +bool patch_disable(char *msg, size_t msglen) +{ + PatchState st = patch_state(); + if (st != STATE_MBMNET) { + snprintf(msg, msglen, st == STATE_FOREIGN + ? "MBMNET ist nicht aktiv.\nDer vorhandene fremde Patch bleibt unverändert." + : "Schon im Originalzustand."); + return false; + } + + remove_splash(); + restore_conflicting(); + lumaconfig_restore_splash(); + lumaconfig_restore_modules(); + lumaconfig_restore_game_patching(); + + bool restored = false; + for (size_t i = 0; i < TARGET_COUNT; i++) { + const Target *t = &targets[i]; + char ips[128], marker[128], backup[128]; + path_in(ips, sizeof(ips), t, "code.ips"); + path_in(marker, sizeof(marker), t, "mbmnet.txt"); + path_in(backup, sizeof(backup), t, "code.ips.vor-mbmnet"); + + if (!file_exists(marker)) continue; + remove(ips); + remove(marker); + if (file_exists(backup)) { + rename(backup, ips); + restored = true; + } + } + + snprintf(msg, msglen, restored ? "Vorheriger Patch wiederhergestellt." : "Patches entfernt."); + return true; +} diff --git a/source/patcher.h b/source/patcher.h new file mode 100644 index 0000000..f405f2e --- /dev/null +++ b/source/patcher.h @@ -0,0 +1,30 @@ +#pragma once +#include <3ds/types.h> + +// Offizieller MBMNET-Server. Über "Server-Adresse" lässt sich ein anderer eintragen (z. B. zum Testen). +// Fester MBMNET-Server: einfaches HTTP über den NetBird-TCP-Service auf Port 81. +// Höchstens 21 Zeichen passen in den Patch. +#define MBMNET_SERVER "mbmnetapi.mbm.wtf:81" + +#define APP_DIR "sdmc:/3ds/mbmnet" +#define DIAG_FILE APP_DIR "/diagnose.txt" + +typedef enum { + STATE_ORIGINAL, // kein Patch: Nintendo-Originalzustand + STATE_MBMNET, // unser Patch ist aktiv + STATE_FOREIGN, // fremder Patch (z. B. Pretendo/Nimbus) ist aktiv +} PatchState; + +PatchState patch_state(void); +// Räumt Patches alter App-Versionen (/luma/titles/...) weg. true, wenn etwas entfernt wurde. +bool patch_migrate(void); + +// Erzeugt die Patches (Freunde + Konto) und aktiviert MBMNET. msg bekommt eine lesbare Meldung. +// *changed: true, wenn sich Patch-Dateien geändert haben (dann ist ein Neustart nötig). +bool patch_enable(const char *server, bool *changed, char *msg, size_t msglen); +// Schreibt alle Adress-Texte aus den Modulen nach DIAG_FILE (zur Fehlersuche). +bool patch_diagnose(char *msg, size_t msglen); +// Entfernt unsere Patches und stellt eventuell gesicherte fremde Patches wieder her. +bool patch_disable(char *msg, size_t msglen); +// Läuft ein Prozess mit dieser Titel-ID? (über Lumas Prozess-Info), PID in pidOut +bool patch_find_process(u64 tid, u32 *pidOut); diff --git a/source/relaunch.c b/source/relaunch.c new file mode 100644 index 0000000..5d91aee --- /dev/null +++ b/source/relaunch.c @@ -0,0 +1,48 @@ +// Startet die App nach einem Update selbst neu. +// +// CIA: aptSetChainloaderToSelf() - das System startet beim Beenden denselben Titel +// (jetzt die neue Version) wieder. +// 3DSX: Die App läuft im Homebrew-Titel von Luma (Rosalina). Über dessen Dienst "hb:ldr" +// legen wir fest, welche .3dsx beim nächsten Start geladen wird - genau so macht es +// auch der Homebrew Launcher. Danach den Homebrew-Titel neu starten lassen. +#include <3ds.h> +#include + +#include "relaunch.h" + +static Result hbldr_call(Handle h, u32 cmd, const void *buf, u32 size, int staticId) +{ + u32 *cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(cmd, 0, 2); + cmdbuf[1] = IPC_Desc_StaticBuffer(size, staticId); + cmdbuf[2] = (u32)buf; + Result rc = svcSendSyncRequest(h); + return R_SUCCEEDED(rc) ? (Result)cmdbuf[1] : rc; +} + +static bool set_homebrew_target(const char *selfPath) +{ + Handle h; + if (R_FAILED(svcConnectToPort(&h, "hb:ldr"))) return false; + + // hb:ldr erwartet den Pfad ohne "sdmc:" + const char *path = strncmp(selfPath, "sdmc:/", 6) == 0 ? selfPath + 5 : selfPath; + Result rc = hbldr_call(h, 2, path, strlen(path) + 1, 0); // SetTarget + + // argv wie beim Homebrew Launcher: u32 Anzahl, dann die Texte + static u32 argBuf[0x400 / 4]; + memset(argBuf, 0, sizeof(argBuf)); + argBuf[0] = 1; + strncpy((char *)&argBuf[1], selfPath, sizeof(argBuf) - 5); + if (R_SUCCEEDED(rc)) rc = hbldr_call(h, 3, argBuf, sizeof(argBuf), 1); // SetArgv + + svcCloseHandle(h); + return R_SUCCEEDED(rc); +} + +bool relaunch_prepare(const char *selfPath) +{ + if (envIsHomebrew() && !set_homebrew_target(selfPath)) return false; + aptSetChainloaderToSelf(); + return true; +} diff --git a/source/relaunch.h b/source/relaunch.h new file mode 100644 index 0000000..de70c35 --- /dev/null +++ b/source/relaunch.h @@ -0,0 +1,6 @@ +#pragma once +#include <3ds/types.h> + +// Bereitet den Neustart der App vor. Danach main() verlassen, dann startet das System +// die (neue) App wieder. false: Neustart nicht möglich, Nutzer muss selbst neu starten. +bool relaunch_prepare(const char *selfPath); diff --git a/source/splash_data.c b/source/splash_data.c new file mode 100644 index 0000000..de00746 --- /dev/null +++ b/source/splash_data.c @@ -0,0 +1,1985 @@ +// Boot-Splash "MBMNET aktiv" für Luma3DS (/luma/splash.bin), erzeugt aus assets/splash.png. +// Format: Lauflängen-kodiert, je Eintrag [Anzahl][B][G][R]; entpackt 400x240 Pixel im +// Framebuffer-Layout (spaltenweise, unten nach oben) = 288000 Bytes. +#include <3ds/types.h> + +const u32 splash_rle_size = 31624; +const u8 splash_rle[] = { + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x45, 0x29, 0x21, 0x1D, + 0x01, 0x34, 0x3F, 0x1D, 0x01, 0x3A, 0x4E, 0x1D, 0x01, 0x34, 0x3F, 0x1D, 0xA3, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x42, 0x29, 0x21, 0x1D, 0x01, 0x2F, 0x30, 0x1C, 0x01, 0x51, 0x85, 0x1E, + 0x01, 0x6B, 0xBE, 0x1A, 0x03, 0x71, 0xCC, 0x1B, 0x01, 0x6B, 0xBE, 0x1A, 0x01, 0x51, 0x85, 0x1E, + 0x01, 0x2F, 0x30, 0x1C, 0xA0, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x41, 0x29, 0x21, 0x1D, + 0x01, 0x38, 0x47, 0x1E, 0x01, 0x69, 0xBA, 0x1B, 0x07, 0x71, 0xCC, 0x1B, 0x01, 0x69, 0xBA, 0x1B, + 0x01, 0x38, 0x47, 0x1E, 0x9F, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x40, 0x29, 0x21, 0x1D, + 0x01, 0x31, 0x38, 0x1D, 0x01, 0x6B, 0xBD, 0x1A, 0x09, 0x71, 0xCC, 0x1B, 0x01, 0x6B, 0xBD, 0x1A, + 0x01, 0x31, 0x38, 0x1D, 0x9E, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x40, 0x29, 0x21, 0x1D, + 0x01, 0x5A, 0x99, 0x1C, 0x0B, 0x71, 0xCC, 0x1B, 0x01, 0x5A, 0x99, 0x1C, 0x9E, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x3F, 0x29, 0x21, 0x1D, 0x01, 0x31, 0x37, 0x1D, 0x01, 0x70, 0xCB, 0x19, + 0x0B, 0x71, 0xCC, 0x1B, 0x01, 0x70, 0xCB, 0x19, 0x01, 0x31, 0x37, 0x1D, 0x9D, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x3F, 0x29, 0x21, 0x1D, 0x01, 0x45, 0x68, 0x1E, 0x0D, 0x71, 0xCC, 0x1B, + 0x01, 0x45, 0x68, 0x1E, 0x9D, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3F, 0x29, 0x21, 0x1D, + 0x01, 0x4D, 0x7A, 0x1E, 0x0D, 0x71, 0xCC, 0x1B, 0x01, 0x4D, 0x7A, 0x1E, 0x9D, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x3F, 0x29, 0x21, 0x1D, 0x01, 0x49, 0x73, 0x1F, 0x0D, 0x71, 0xCC, 0x1B, + 0x01, 0x49, 0x73, 0x1F, 0x9D, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3F, 0x29, 0x21, 0x1D, + 0x01, 0x3C, 0x54, 0x1E, 0x0D, 0x71, 0xCC, 0x1B, 0x01, 0x3C, 0x54, 0x1E, 0x9D, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x3F, 0x29, 0x21, 0x1D, 0x01, 0x29, 0x24, 0x1D, 0x01, 0x6A, 0xBD, 0x1A, + 0x0B, 0x71, 0xCC, 0x1B, 0x01, 0x6A, 0xBD, 0x1A, 0x01, 0x29, 0x24, 0x1D, 0x9D, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x40, 0x29, 0x21, 0x1D, 0x01, 0x47, 0x6C, 0x1E, 0x0B, 0x71, 0xCC, 0x1B, + 0x01, 0x46, 0x6B, 0x1E, 0x9E, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x41, 0x29, 0x21, 0x1D, + 0x01, 0x57, 0x90, 0x1E, 0x09, 0x71, 0xCC, 0x1B, 0x01, 0x57, 0x90, 0x1E, 0x9F, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x42, 0x29, 0x21, 0x1D, 0x01, 0x4D, 0x7A, 0x1E, 0x01, 0x6E, 0xC6, 0x1A, + 0x05, 0x71, 0xCC, 0x1B, 0x01, 0x6E, 0xC6, 0x1A, 0x01, 0x4D, 0x7A, 0x1E, 0xA0, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x43, 0x29, 0x21, 0x1D, 0x01, 0x30, 0x35, 0x1D, 0x01, 0x4B, 0x74, 0x1E, + 0x01, 0x5A, 0x99, 0x1C, 0x01, 0x5F, 0xA4, 0x1C, 0x01, 0x5A, 0x99, 0x1C, 0x01, 0x4B, 0x74, 0x1E, + 0x01, 0x30, 0x35, 0x1D, 0xA1, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, + 0x01, 0x54, 0x4E, 0x4A, 0x14, 0x5C, 0x58, 0x55, 0x01, 0x46, 0x40, 0x3C, 0x9A, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x01, 0xFE, 0xFE, 0xFE, 0x14, 0xFF, 0xFF, 0xFF, + 0x01, 0xCE, 0xCC, 0xCB, 0x9A, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, + 0x15, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, 0x9A, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x3B, 0x29, 0x21, 0x1D, 0x15, 0xFF, 0xFF, 0xFF, 0x01, 0xD3, 0xD1, 0xD1, 0x9A, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x15, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, + 0x9A, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x01, 0xFD, 0xFD, 0xFD, + 0x14, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, 0x9A, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x3B, 0x29, 0x21, 0x1D, 0x01, 0x44, 0x3E, 0x3A, 0x08, 0x4C, 0x46, 0x44, 0x01, 0x4F, 0x4A, 0x46, + 0x01, 0x91, 0x8E, 0x8C, 0x01, 0xDE, 0xDD, 0xDC, 0x09, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, + 0x9A, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x42, 0x29, 0x21, 0x1D, 0x01, 0x4C, 0x45, 0x42, + 0x01, 0xA2, 0x9F, 0x9E, 0x01, 0xEB, 0xEA, 0xEA, 0x0A, 0xFF, 0xFF, 0xFF, 0x01, 0xFD, 0xFD, 0xFD, + 0x01, 0xAC, 0xA9, 0xA8, 0x9A, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3F, 0x29, 0x21, 0x1D, + 0x01, 0x30, 0x28, 0x24, 0x01, 0x7C, 0x78, 0x76, 0x01, 0xCD, 0xCB, 0xCB, 0x01, 0xFE, 0xFE, 0xFE, + 0x0A, 0xFF, 0xFF, 0xFF, 0x01, 0xE4, 0xE4, 0xE4, 0x01, 0x9B, 0x98, 0x96, 0x01, 0x45, 0x3F, 0x3B, + 0x9B, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3D, 0x29, 0x21, 0x1D, 0x01, 0x55, 0x4E, 0x4C, + 0x01, 0xA9, 0xA8, 0xA6, 0x01, 0xF0, 0xF0, 0xEF, 0x0A, 0xFF, 0xFF, 0xFF, 0x01, 0xF7, 0xF7, 0xF6, + 0x01, 0xB8, 0xB7, 0xB6, 0x01, 0x67, 0x63, 0x5F, 0x9E, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x3B, 0x29, 0x21, 0x1D, 0x01, 0x85, 0x81, 0x7F, 0x01, 0xD5, 0xD3, 0xD3, 0x0B, 0xFF, 0xFF, 0xFF, + 0x01, 0xD6, 0xD4, 0xD4, 0x01, 0x88, 0x85, 0x83, 0x01, 0x38, 0x30, 0x2C, 0xA0, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x0A, 0xFF, 0xFF, 0xFF, 0x01, 0xED, 0xED, 0xED, + 0x01, 0xA8, 0xA6, 0xA5, 0x01, 0x54, 0x4E, 0x4A, 0xA3, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x3B, 0x29, 0x21, 0x1D, 0x09, 0xFF, 0xFF, 0xFF, 0x01, 0x81, 0x7D, 0x7B, 0x01, 0x2D, 0x26, 0x21, + 0xA5, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x09, 0xFF, 0xFF, 0xFF, + 0x01, 0xF5, 0xF5, 0xF5, 0x01, 0xB7, 0xB4, 0xB3, 0x01, 0x64, 0x60, 0x5C, 0xA4, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x01, 0xC5, 0xC4, 0xC3, 0x01, 0xFC, 0xFC, 0xFC, + 0x0A, 0xFF, 0xFF, 0xFF, 0x01, 0xE2, 0xE1, 0xE1, 0x01, 0x97, 0x94, 0x92, 0x01, 0x44, 0x3D, 0x39, + 0xA1, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3C, 0x29, 0x21, 0x1D, 0x01, 0x44, 0x3E, 0x3A, + 0x01, 0x9B, 0x98, 0x96, 0x01, 0xE6, 0xE5, 0xE5, 0x0A, 0xFF, 0xFF, 0xFF, 0x01, 0xFC, 0xFC, 0xFC, + 0x01, 0xC6, 0xC5, 0xC4, 0x01, 0x77, 0x73, 0x71, 0x01, 0x2D, 0x26, 0x21, 0x9E, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x3F, 0x29, 0x21, 0x1D, 0x01, 0x6B, 0x66, 0x64, 0x01, 0xBE, 0xBC, 0xBB, + 0x01, 0xF9, 0xF9, 0xF9, 0x0A, 0xFF, 0xFF, 0xFF, 0x01, 0xEE, 0xEE, 0xED, 0x01, 0xA9, 0xA7, 0xA6, + 0x01, 0x55, 0x4E, 0x4C, 0x9C, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x41, 0x29, 0x21, 0x1D, + 0x01, 0x3C, 0x36, 0x32, 0x01, 0x91, 0x8F, 0x8D, 0x01, 0xDF, 0xDE, 0xDD, 0x0B, 0xFF, 0xFF, 0xFF, + 0x01, 0xD6, 0xD6, 0xD5, 0x01, 0x7A, 0x76, 0x74, 0x9A, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x44, 0x29, 0x21, 0x1D, 0x01, 0x62, 0x5C, 0x5A, 0x01, 0xB6, 0xB3, 0xB2, 0x01, 0xF6, 0xF6, 0xF6, + 0x09, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, 0x9A, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x3B, 0x29, 0x21, 0x1D, 0x01, 0xD6, 0xD4, 0xD4, 0x0A, 0xDE, 0xDD, 0xDC, 0x01, 0xE8, 0xE7, 0xE6, + 0x09, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, 0x9A, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x3B, 0x29, 0x21, 0x1D, 0x15, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, 0x9A, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x15, 0xFF, 0xFF, 0xFF, 0x01, 0xD1, 0xD1, 0xD0, + 0x9A, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x15, 0xFF, 0xFF, 0xFF, + 0x01, 0xD0, 0xCF, 0xCE, 0x9A, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, + 0x15, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, 0x9A, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x3B, 0x29, 0x21, 0x1D, 0x01, 0x99, 0x96, 0x94, 0x14, 0xA2, 0x9F, 0x9E, 0x01, 0x7C, 0x78, 0x76, + 0x9A, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x3B, 0x29, 0x21, 0x1D, 0x01, 0xBF, 0xBD, 0xBC, 0x14, 0xC7, 0xC5, 0xC5, 0x01, 0x9A, 0x97, 0x95, + 0x9A, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x15, 0xFF, 0xFF, 0xFF, + 0x01, 0xCF, 0xCD, 0xCC, 0x9A, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, + 0x15, 0xFF, 0xFF, 0xFF, 0x01, 0xD0, 0xCF, 0xCE, 0x9A, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x3B, 0x29, 0x21, 0x1D, 0x16, 0xFF, 0xFF, 0xFF, 0x9A, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x3B, 0x29, 0x21, 0x1D, 0x16, 0xFF, 0xFF, 0xFF, 0x9A, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x3B, 0x29, 0x21, 0x1D, 0x16, 0xFF, 0xFF, 0xFF, 0x9A, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x3B, 0x29, 0x21, 0x1D, 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xC3, 0xC2, 0xC1, 0x04, 0x70, 0x6C, 0x69, + 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0x7B, 0x77, 0x75, 0x03, 0x70, 0x6C, 0x69, 0x01, 0xF4, 0xF4, 0xF4, + 0x03, 0xFF, 0xFF, 0xFF, 0x01, 0xED, 0xED, 0xED, 0x9A, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x3B, 0x29, 0x21, 0x1D, 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0x8B, 0x88, 0x86, 0x04, 0x29, 0x21, 0x1D, + 0x01, 0xF4, 0xF4, 0xF4, 0x03, 0xFF, 0xFF, 0xFF, 0x01, 0x38, 0x30, 0x2C, 0x03, 0x29, 0x21, 0x1D, + 0x01, 0xC0, 0xBF, 0xBE, 0x03, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, 0x9A, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0x8C, 0x88, 0x87, + 0x04, 0x29, 0x21, 0x1D, 0x01, 0xF5, 0xF5, 0xF5, 0x03, 0xFF, 0xFF, 0xFF, 0x01, 0x49, 0x44, 0x40, + 0x03, 0x29, 0x21, 0x1D, 0x01, 0xC3, 0xC1, 0xC0, 0x03, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, + 0x9A, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x04, 0xFF, 0xFF, 0xFF, + 0x01, 0xAE, 0xAB, 0xAA, 0x03, 0x29, 0x21, 0x1D, 0x01, 0x3A, 0x33, 0x2F, 0x04, 0xFF, 0xFF, 0xFF, + 0x01, 0x86, 0x82, 0x80, 0x03, 0x29, 0x21, 0x1D, 0x01, 0xEC, 0xEB, 0xEB, 0x03, 0xFF, 0xFF, 0xFF, + 0x01, 0xCF, 0xCD, 0xCC, 0x9A, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, + 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xE1, 0xE0, 0xDF, 0x03, 0x29, 0x21, 0x1D, 0x01, 0x67, 0x63, 0x5F, + 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xC3, 0xC2, 0xC1, 0x02, 0x29, 0x21, 0x1D, 0x01, 0x61, 0x5B, 0x59, + 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xCE, 0xCC, 0xCB, 0x9A, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x3B, 0x29, 0x21, 0x1D, 0x01, 0xED, 0xED, 0xED, 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0x6E, 0x6A, 0x68, + 0x01, 0x29, 0x21, 0x1D, 0x01, 0x35, 0x2E, 0x2B, 0x01, 0xDB, 0xDB, 0xDB, 0x05, 0xFF, 0xFF, 0xFF, + 0x01, 0xC6, 0xC5, 0xC4, 0x01, 0xBF, 0xBE, 0xBD, 0x01, 0xFA, 0xFA, 0xFA, 0x04, 0xFF, 0xFF, 0xFF, + 0x01, 0xB4, 0xB2, 0xB0, 0x9A, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, + 0x01, 0xCA, 0xC9, 0xC8, 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xFD, 0xFD, 0xFD, 0x01, 0xE3, 0xE2, 0xE2, + 0x01, 0xF9, 0xF8, 0xF8, 0x0D, 0xFF, 0xFF, 0xFF, 0x01, 0x90, 0x8D, 0x8B, 0x9A, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x01, 0xA4, 0xA1, 0xA0, 0x14, 0xFF, 0xFF, 0xFF, + 0x01, 0x68, 0x63, 0x61, 0x9A, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, + 0x01, 0x7B, 0x77, 0x75, 0x0A, 0xFF, 0xFF, 0xFF, 0x01, 0xC1, 0xBF, 0xBF, 0x08, 0xFF, 0xFF, 0xFF, + 0x01, 0xE9, 0xE9, 0xE9, 0x01, 0x36, 0x2F, 0x2B, 0x9A, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x3B, 0x29, 0x21, 0x1D, 0x01, 0x2F, 0x27, 0x22, 0x01, 0xD1, 0xD0, 0xCF, 0x08, 0xFF, 0xFF, 0xFF, + 0x01, 0xFA, 0xFA, 0xFA, 0x01, 0x44, 0x3D, 0x39, 0x01, 0xDB, 0xDB, 0xDB, 0x06, 0xFF, 0xFF, 0xFF, + 0x01, 0xF9, 0xF9, 0xF9, 0x01, 0x5D, 0x59, 0x56, 0x9B, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x3C, 0x29, 0x21, 0x1D, 0x01, 0x3E, 0x38, 0x34, 0x01, 0xE8, 0xE7, 0xE6, 0x06, 0xFF, 0xFF, 0xFF, + 0x01, 0xFD, 0xFD, 0xFD, 0x01, 0x7B, 0x77, 0x75, 0x01, 0x29, 0x21, 0x1D, 0x01, 0x39, 0x31, 0x2D, + 0x01, 0xD0, 0xCF, 0xCE, 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xF4, 0xF4, 0xF4, 0x01, 0x7F, 0x7B, 0x79, + 0x9C, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3D, 0x29, 0x21, 0x1D, 0x01, 0x55, 0x4F, 0x4D, + 0x01, 0xD6, 0xD4, 0xD4, 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xE9, 0xE9, 0xE9, 0x01, 0x81, 0x7E, 0x7C, + 0x04, 0x29, 0x21, 0x1D, 0x01, 0x4B, 0x44, 0x41, 0x01, 0x84, 0x80, 0x7E, 0x01, 0x91, 0x8E, 0x8C, + 0x01, 0x76, 0x72, 0x70, 0x01, 0x39, 0x31, 0x2D, 0x9D, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x3F, 0x29, 0x21, 0x1D, 0x01, 0x54, 0x4E, 0x4A, 0x01, 0x77, 0x73, 0x71, 0x01, 0x84, 0x80, 0x7E, + 0x01, 0x54, 0x4E, 0x4A, 0xA8, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, + 0x01, 0x54, 0x4E, 0x4A, 0x14, 0x5C, 0x58, 0x55, 0x01, 0x46, 0x40, 0x3C, 0x9A, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x01, 0xFE, 0xFE, 0xFE, 0x14, 0xFF, 0xFF, 0xFF, + 0x01, 0xCE, 0xCC, 0xCB, 0x1D, 0x29, 0x21, 0x1D, 0x01, 0x29, 0x20, 0x24, 0x01, 0x28, 0x1A, 0x4D, + 0x01, 0x28, 0x15, 0x72, 0x01, 0x26, 0x15, 0x8A, 0x01, 0x27, 0x17, 0x9E, 0x01, 0x2B, 0x1D, 0xB7, + 0x01, 0x30, 0x25, 0xC9, 0x01, 0x33, 0x2C, 0xD3, 0x01, 0x37, 0x31, 0xDA, 0x01, 0x38, 0x35, 0xDF, + 0x01, 0x39, 0x35, 0xE1, 0x01, 0x39, 0x36, 0xE2, 0x02, 0x39, 0x36, 0xE3, 0x01, 0x3A, 0x37, 0xE4, + 0x01, 0x3A, 0x36, 0xE4, 0x03, 0x3A, 0x37, 0xE4, 0x01, 0x3C, 0x38, 0xE5, 0x01, 0x3D, 0x39, 0xE6, + 0x03, 0x3C, 0x38, 0xE5, 0x01, 0x3D, 0x38, 0xE6, 0x01, 0x3D, 0x39, 0xE7, 0x02, 0x3D, 0x38, 0xE7, + 0x01, 0x3E, 0x39, 0xE8, 0x01, 0x3E, 0x38, 0xE8, 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x3E, 0x39, 0xE8, + 0x03, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x39, 0xE9, 0x01, 0x40, 0x3A, 0xEA, 0x03, 0x40, 0x39, 0xEA, + 0x01, 0x42, 0x3A, 0xEB, 0x01, 0x42, 0x3A, 0xEC, 0x01, 0x42, 0x3A, 0xEB, 0x01, 0x42, 0x39, 0xEC, + 0x01, 0x42, 0x3A, 0xEC, 0x01, 0x42, 0x39, 0xEC, 0x05, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xEE, + 0x01, 0x45, 0x3C, 0xEE, 0x02, 0x44, 0x3B, 0xEE, 0x01, 0x44, 0x3B, 0xEF, 0x01, 0x45, 0x3C, 0xF0, + 0x01, 0x46, 0x3C, 0xF0, 0x02, 0x45, 0x3C, 0xF0, 0x01, 0x46, 0x3C, 0xF0, 0x01, 0x46, 0x3C, 0xF1, + 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x46, 0x3B, 0xF0, 0x01, 0x45, 0x39, 0xEC, 0x01, 0x43, 0x37, 0xE5, + 0x01, 0x3E, 0x30, 0xD4, 0x01, 0x38, 0x2C, 0xB9, 0x01, 0x32, 0x24, 0x81, 0x01, 0x29, 0x22, 0x30, + 0x37, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x15, 0xFF, 0xFF, 0xFF, + 0x01, 0xCF, 0xCD, 0xCC, 0x1B, 0x29, 0x21, 0x1D, 0x01, 0x28, 0x1A, 0x4E, 0x01, 0x26, 0x14, 0x84, + 0x01, 0x27, 0x17, 0xAC, 0x01, 0x27, 0x18, 0xB0, 0x01, 0x2D, 0x1E, 0xBD, 0x01, 0x32, 0x2A, 0xD0, + 0x01, 0x38, 0x35, 0xDF, 0x01, 0x38, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE2, 0x01, 0x39, 0x36, 0xE2, + 0x02, 0x38, 0x36, 0xE2, 0x01, 0x39, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE3, 0x01, 0x39, 0x37, 0xE3, + 0x01, 0x39, 0x36, 0xE3, 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3A, 0x36, 0xE4, + 0x03, 0x3C, 0x37, 0xE4, 0x02, 0x3C, 0x38, 0xE5, 0x02, 0x3D, 0x39, 0xE6, 0x02, 0x3D, 0x38, 0xE6, + 0x01, 0x3E, 0x39, 0xE7, 0x03, 0x3E, 0x39, 0xE8, 0x01, 0x3E, 0x39, 0xE9, 0x01, 0x3F, 0x39, 0xE9, + 0x01, 0x3E, 0x38, 0xE9, 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x39, 0xE9, 0x01, 0x3F, 0x39, 0xE9, + 0x02, 0x40, 0x39, 0xEA, 0x01, 0x40, 0x3A, 0xEA, 0x01, 0x42, 0x3A, 0xEB, 0x02, 0x42, 0x39, 0xEB, + 0x02, 0x42, 0x3A, 0xEC, 0x01, 0x43, 0x3A, 0xEC, 0x01, 0x42, 0x3A, 0xEC, 0x01, 0x43, 0x3B, 0xED, + 0x01, 0x44, 0x3C, 0xED, 0x01, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xEE, + 0x01, 0x44, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xEE, 0x01, 0x44, 0x3B, 0xEE, 0x03, 0x45, 0x3C, 0xEF, + 0x01, 0x45, 0x3B, 0xEF, 0x02, 0x46, 0x3C, 0xF0, 0x02, 0x46, 0x3C, 0xF1, 0x01, 0x46, 0x3C, 0xF2, + 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x46, 0x3C, 0xF2, 0x02, 0x48, 0x3D, 0xF2, 0x01, 0x48, 0x3C, 0xF2, + 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x3E, 0x31, 0xD1, 0x01, 0x32, 0x24, 0x83, + 0x35, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x15, 0xFF, 0xFF, 0xFF, + 0x01, 0xD3, 0xD1, 0xD1, 0x19, 0x29, 0x21, 0x1D, 0x01, 0x28, 0x19, 0x53, 0x01, 0x28, 0x16, 0x98, + 0x02, 0x27, 0x18, 0xB0, 0x01, 0x2B, 0x1F, 0xBF, 0x01, 0x34, 0x2F, 0xD8, 0x02, 0x37, 0x36, 0xE0, + 0x01, 0x38, 0x36, 0xE1, 0x01, 0x38, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE2, 0x01, 0x39, 0x36, 0xE2, + 0x02, 0x38, 0x36, 0xE2, 0x01, 0x39, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE3, 0x01, 0x39, 0x37, 0xE3, + 0x01, 0x39, 0x36, 0xE3, 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3A, 0x36, 0xE4, + 0x03, 0x3C, 0x37, 0xE4, 0x02, 0x3C, 0x38, 0xE5, 0x02, 0x3D, 0x39, 0xE6, 0x02, 0x3D, 0x38, 0xE6, + 0x01, 0x3E, 0x39, 0xE7, 0x03, 0x3E, 0x39, 0xE8, 0x01, 0x3E, 0x39, 0xE9, 0x01, 0x3F, 0x39, 0xE9, + 0x01, 0x3E, 0x38, 0xE9, 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x39, 0xE9, 0x01, 0x3F, 0x39, 0xE9, + 0x02, 0x40, 0x39, 0xEA, 0x01, 0x40, 0x3A, 0xEA, 0x01, 0x42, 0x3A, 0xEB, 0x02, 0x42, 0x39, 0xEB, + 0x02, 0x42, 0x3A, 0xEC, 0x01, 0x43, 0x3A, 0xEC, 0x01, 0x42, 0x3A, 0xEC, 0x01, 0x43, 0x3B, 0xED, + 0x01, 0x44, 0x3C, 0xED, 0x01, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xEE, + 0x01, 0x44, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xEE, 0x01, 0x44, 0x3B, 0xEE, 0x03, 0x45, 0x3C, 0xEF, + 0x01, 0x45, 0x3B, 0xEF, 0x02, 0x46, 0x3C, 0xF0, 0x02, 0x46, 0x3C, 0xF1, 0x01, 0x46, 0x3C, 0xF2, + 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x46, 0x3C, 0xF2, 0x02, 0x48, 0x3D, 0xF2, 0x01, 0x48, 0x3C, 0xF2, + 0x02, 0x49, 0x3D, 0xF3, 0x02, 0x49, 0x3D, 0xF4, 0x01, 0x42, 0x36, 0xE4, 0x01, 0x32, 0x25, 0x8D, + 0x33, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x15, 0xFF, 0xFF, 0xFF, + 0x01, 0xCF, 0xCD, 0xCC, 0x17, 0x29, 0x21, 0x1D, 0x01, 0x29, 0x1E, 0x36, 0x01, 0x26, 0x15, 0x8D, + 0x02, 0x27, 0x18, 0xB0, 0x01, 0x2A, 0x1A, 0xB6, 0x01, 0x32, 0x2C, 0xD3, 0x01, 0x37, 0x35, 0xDF, + 0x03, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xE0, 0x02, 0x38, 0x36, 0xE1, 0x02, 0x38, 0x36, 0xE2, + 0x01, 0x39, 0x37, 0xE2, 0x02, 0x39, 0x36, 0xE2, 0x01, 0x3A, 0x37, 0xE3, 0x01, 0x3A, 0x36, 0xE4, + 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3A, 0x36, 0xE4, 0x01, 0x3A, 0x37, 0xE4, 0x03, 0x3C, 0x37, 0xE4, + 0x01, 0x3C, 0x38, 0xE5, 0x01, 0x3D, 0x38, 0xE6, 0x01, 0x3C, 0x38, 0xE5, 0x02, 0x3D, 0x38, 0xE6, + 0x01, 0x3E, 0x39, 0xE7, 0x01, 0x3D, 0x38, 0xE7, 0x01, 0x3E, 0x38, 0xE7, 0x02, 0x3E, 0x39, 0xE8, + 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x3E, 0x38, 0xE8, 0x03, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x39, 0xE9, + 0x01, 0x3F, 0x39, 0xE9, 0x03, 0x40, 0x39, 0xEA, 0x01, 0x40, 0x39, 0xEB, 0x02, 0x42, 0x3A, 0xEC, + 0x01, 0x42, 0x39, 0xEC, 0x01, 0x43, 0x3B, 0xED, 0x01, 0x43, 0x3A, 0xEC, 0x03, 0x43, 0x3B, 0xED, + 0x01, 0x44, 0x3C, 0xED, 0x01, 0x44, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xEE, 0x01, 0x44, 0x3B, 0xED, + 0x01, 0x44, 0x3C, 0xEE, 0x01, 0x44, 0x3B, 0xEE, 0x01, 0x45, 0x3C, 0xEF, 0x01, 0x45, 0x3B, 0xEF, + 0x01, 0x46, 0x3C, 0xF0, 0x02, 0x45, 0x3C, 0xF0, 0x02, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3C, 0xF2, + 0x01, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x03, 0x48, 0x3C, 0xF2, + 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF3, 0x02, 0x49, 0x3D, 0xF3, 0x01, 0x4A, 0x3D, 0xF4, + 0x01, 0x41, 0x33, 0xDA, 0x01, 0x2D, 0x22, 0x56, 0x31, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x3B, 0x29, 0x21, 0x1D, 0x01, 0xFD, 0xFD, 0xFD, 0x14, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, + 0x16, 0x29, 0x21, 0x1D, 0x01, 0x28, 0x18, 0x57, 0x01, 0x27, 0x17, 0xA9, 0x02, 0x27, 0x18, 0xB0, + 0x01, 0x2D, 0x1F, 0xC0, 0x01, 0x35, 0x33, 0xDC, 0x01, 0x37, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, + 0x03, 0x37, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE1, 0x01, 0x38, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE2, + 0x01, 0x39, 0x36, 0xE2, 0x02, 0x38, 0x36, 0xE2, 0x01, 0x39, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE3, + 0x01, 0x39, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE3, 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3C, 0x37, 0xE4, + 0x01, 0x3A, 0x36, 0xE4, 0x03, 0x3C, 0x37, 0xE4, 0x02, 0x3C, 0x38, 0xE5, 0x02, 0x3D, 0x39, 0xE6, + 0x02, 0x3D, 0x38, 0xE6, 0x01, 0x3E, 0x39, 0xE7, 0x03, 0x3E, 0x39, 0xE8, 0x01, 0x3E, 0x39, 0xE9, + 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x3E, 0x38, 0xE9, 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x39, 0xE9, + 0x01, 0x3F, 0x39, 0xE9, 0x02, 0x40, 0x39, 0xEA, 0x01, 0x40, 0x3A, 0xEA, 0x01, 0x42, 0x3A, 0xEB, + 0x02, 0x42, 0x39, 0xEB, 0x02, 0x42, 0x3A, 0xEC, 0x01, 0x43, 0x3A, 0xEC, 0x01, 0x42, 0x3A, 0xEC, + 0x01, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xED, 0x01, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xED, + 0x01, 0x44, 0x3C, 0xEE, 0x01, 0x44, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xEE, 0x01, 0x44, 0x3B, 0xEE, + 0x03, 0x45, 0x3C, 0xEF, 0x01, 0x45, 0x3B, 0xEF, 0x02, 0x46, 0x3C, 0xF0, 0x02, 0x46, 0x3C, 0xF1, + 0x01, 0x46, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x46, 0x3C, 0xF2, 0x02, 0x48, 0x3D, 0xF2, + 0x01, 0x48, 0x3C, 0xF2, 0x02, 0x49, 0x3D, 0xF3, 0x04, 0x49, 0x3D, 0xF4, 0x01, 0x4A, 0x3E, 0xF5, + 0x01, 0x48, 0x3B, 0xF2, 0x01, 0x35, 0x26, 0x92, 0x30, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x3B, 0x29, 0x21, 0x1D, 0x01, 0x44, 0x3E, 0x3A, 0x08, 0x4C, 0x46, 0x44, 0x01, 0x4F, 0x4A, 0x46, + 0x01, 0x91, 0x8E, 0x8C, 0x01, 0xDE, 0xDD, 0xDC, 0x09, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, + 0x15, 0x29, 0x21, 0x1D, 0x01, 0x28, 0x15, 0x70, 0x03, 0x27, 0x18, 0xB0, 0x01, 0x2E, 0x25, 0xC9, + 0x01, 0x35, 0x35, 0xDF, 0x01, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x35, 0xDF, + 0x03, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xE0, 0x02, 0x38, 0x36, 0xE1, 0x02, 0x38, 0x36, 0xE2, + 0x01, 0x39, 0x37, 0xE2, 0x02, 0x39, 0x36, 0xE2, 0x01, 0x3A, 0x37, 0xE3, 0x01, 0x3A, 0x36, 0xE4, + 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3A, 0x36, 0xE4, 0x01, 0x3A, 0x37, 0xE4, 0x03, 0x3C, 0x37, 0xE4, + 0x01, 0x3C, 0x38, 0xE5, 0x01, 0x3D, 0x38, 0xE6, 0x01, 0x3C, 0x38, 0xE5, 0x02, 0x3D, 0x38, 0xE6, + 0x01, 0x3E, 0x39, 0xE7, 0x01, 0x3D, 0x38, 0xE7, 0x01, 0x3E, 0x38, 0xE7, 0x02, 0x3E, 0x39, 0xE8, + 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x3E, 0x38, 0xE8, 0x03, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x39, 0xE9, + 0x01, 0x3F, 0x39, 0xE9, 0x03, 0x40, 0x39, 0xEA, 0x01, 0x40, 0x39, 0xEB, 0x02, 0x42, 0x3A, 0xEC, + 0x01, 0x42, 0x39, 0xEC, 0x01, 0x43, 0x3B, 0xED, 0x01, 0x43, 0x3A, 0xEC, 0x03, 0x43, 0x3B, 0xED, + 0x01, 0x44, 0x3C, 0xED, 0x01, 0x44, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xEE, 0x01, 0x44, 0x3B, 0xED, + 0x01, 0x44, 0x3C, 0xEE, 0x01, 0x44, 0x3B, 0xEE, 0x01, 0x45, 0x3C, 0xEF, 0x01, 0x45, 0x3B, 0xEF, + 0x01, 0x46, 0x3C, 0xF0, 0x02, 0x45, 0x3C, 0xF0, 0x02, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3C, 0xF2, + 0x01, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x03, 0x48, 0x3C, 0xF2, + 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF3, 0x02, 0x49, 0x3D, 0xF3, 0x02, 0x4A, 0x3D, 0xF4, + 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x39, 0x2C, 0xB9, 0x2F, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x42, 0x29, 0x21, 0x1D, 0x01, 0x4C, 0x45, 0x42, 0x01, 0xA2, 0x9F, 0x9E, + 0x01, 0xEB, 0xEA, 0xEA, 0x0A, 0xFF, 0xFF, 0xFF, 0x01, 0xFD, 0xFD, 0xFD, 0x01, 0xAC, 0xA9, 0xA8, + 0x14, 0x29, 0x21, 0x1D, 0x01, 0x28, 0x14, 0x7A, 0x03, 0x27, 0x18, 0xB0, 0x01, 0x2F, 0x27, 0xCB, + 0x01, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, + 0x01, 0x37, 0x35, 0xDF, 0x03, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xE0, 0x02, 0x38, 0x36, 0xE1, + 0x02, 0x38, 0x36, 0xE2, 0x01, 0x39, 0x37, 0xE2, 0x02, 0x39, 0x36, 0xE2, 0x01, 0x3A, 0x37, 0xE3, + 0x01, 0x3A, 0x36, 0xE4, 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3A, 0x36, 0xE4, 0x01, 0x3A, 0x37, 0xE4, + 0x03, 0x3C, 0x37, 0xE4, 0x01, 0x3C, 0x38, 0xE5, 0x01, 0x3D, 0x38, 0xE6, 0x01, 0x3C, 0x38, 0xE5, + 0x02, 0x3D, 0x38, 0xE6, 0x01, 0x3E, 0x39, 0xE7, 0x01, 0x3D, 0x38, 0xE7, 0x01, 0x3E, 0x38, 0xE7, + 0x02, 0x3E, 0x39, 0xE8, 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x3E, 0x38, 0xE8, 0x03, 0x3F, 0x39, 0xE9, + 0x01, 0x40, 0x39, 0xE9, 0x01, 0x3F, 0x39, 0xE9, 0x03, 0x40, 0x39, 0xEA, 0x01, 0x40, 0x39, 0xEB, + 0x02, 0x42, 0x3A, 0xEC, 0x01, 0x42, 0x39, 0xEC, 0x01, 0x43, 0x3B, 0xED, 0x01, 0x43, 0x3A, 0xEC, + 0x03, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xED, 0x01, 0x44, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xEE, + 0x01, 0x44, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xEE, 0x01, 0x44, 0x3B, 0xEE, 0x01, 0x45, 0x3C, 0xEF, + 0x01, 0x45, 0x3B, 0xEF, 0x01, 0x46, 0x3C, 0xF0, 0x02, 0x45, 0x3C, 0xF0, 0x02, 0x46, 0x3C, 0xF1, + 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, + 0x03, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF3, 0x02, 0x49, 0x3D, 0xF3, + 0x02, 0x4A, 0x3D, 0xF4, 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4A, 0x3E, 0xF5, + 0x01, 0x3D, 0x2E, 0xC6, 0x2E, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3F, 0x29, 0x21, 0x1D, + 0x01, 0x30, 0x28, 0x24, 0x01, 0x7C, 0x78, 0x76, 0x01, 0xCD, 0xCB, 0xCB, 0x01, 0xFE, 0xFE, 0xFE, + 0x0A, 0xFF, 0xFF, 0xFF, 0x01, 0xE4, 0xE4, 0xE4, 0x01, 0x9B, 0x98, 0x96, 0x01, 0x45, 0x3F, 0x3B, + 0x14, 0x29, 0x21, 0x1D, 0x01, 0x28, 0x15, 0x70, 0x03, 0x27, 0x18, 0xB0, 0x01, 0x2E, 0x25, 0xC8, + 0x01, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x35, 0xDF, + 0x03, 0x37, 0x36, 0xDF, 0x01, 0x37, 0x35, 0xDF, 0x02, 0x38, 0x36, 0xE0, 0x01, 0x37, 0x36, 0xE0, + 0x01, 0x38, 0x36, 0xE1, 0x01, 0x39, 0x36, 0xE2, 0x02, 0x38, 0x36, 0xE2, 0x01, 0x39, 0x36, 0xE3, + 0x01, 0x39, 0x36, 0xE2, 0x01, 0x3A, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE3, 0x01, 0x3A, 0x36, 0xE4, + 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3C, 0x37, 0xE4, 0x02, 0x3A, 0x37, 0xE4, 0x04, 0x3C, 0x38, 0xE5, + 0x01, 0x3D, 0x39, 0xE6, 0x02, 0x3D, 0x38, 0xE6, 0x01, 0x3E, 0x39, 0xE7, 0x01, 0x3D, 0x38, 0xE7, + 0x01, 0x3E, 0x39, 0xE8, 0x02, 0x3E, 0x38, 0xE8, 0x04, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x3A, 0xEA, + 0x01, 0x40, 0x39, 0xEA, 0x01, 0x40, 0x39, 0xE9, 0x01, 0x40, 0x39, 0xEA, 0x02, 0x42, 0x3A, 0xEB, + 0x01, 0x40, 0x39, 0xEB, 0x01, 0x42, 0x3A, 0xEC, 0x01, 0x42, 0x39, 0xEC, 0x01, 0x43, 0x3A, 0xEC, + 0x01, 0x42, 0x39, 0xEC, 0x01, 0x42, 0x3A, 0xED, 0x01, 0x43, 0x3B, 0xED, 0x02, 0x44, 0x3B, 0xED, + 0x01, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xEE, 0x02, 0x44, 0x3B, 0xEE, 0x01, 0x44, 0x3B, 0xEF, + 0x02, 0x45, 0x3C, 0xEF, 0x01, 0x45, 0x3B, 0xEF, 0x01, 0x46, 0x3C, 0xF0, 0x01, 0x45, 0x3C, 0xF0, + 0x03, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x02, 0x48, 0x3C, 0xF2, + 0x01, 0x49, 0x3D, 0xF2, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF3, + 0x02, 0x49, 0x3D, 0xF4, 0x01, 0x49, 0x3C, 0xF4, 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x4A, 0x3E, 0xF5, + 0x01, 0x4B, 0x3E, 0xF5, 0x02, 0x4A, 0x3E, 0xF5, 0x01, 0x3B, 0x2C, 0xB9, 0x2D, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x3D, 0x29, 0x21, 0x1D, 0x01, 0x55, 0x4E, 0x4C, 0x01, 0xA9, 0xA8, 0xA6, + 0x01, 0xF0, 0xF0, 0xEF, 0x0A, 0xFF, 0xFF, 0xFF, 0x01, 0xF7, 0xF7, 0xF6, 0x01, 0xB8, 0xB7, 0xB6, + 0x01, 0x67, 0x63, 0x5F, 0x16, 0x29, 0x21, 0x1D, 0x01, 0x28, 0x18, 0x57, 0x03, 0x27, 0x18, 0xB0, + 0x01, 0x2D, 0x1F, 0xC0, 0x02, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, + 0x01, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x35, 0xDF, 0x03, 0x37, 0x36, 0xE0, + 0x01, 0x37, 0x35, 0xE0, 0x02, 0x38, 0x36, 0xE1, 0x02, 0x38, 0x36, 0xE2, 0x01, 0x39, 0x37, 0xE2, + 0x02, 0x39, 0x36, 0xE2, 0x01, 0x3A, 0x37, 0xE3, 0x01, 0x3A, 0x36, 0xE4, 0x01, 0x3A, 0x37, 0xE4, + 0x01, 0x3A, 0x36, 0xE4, 0x01, 0x3A, 0x37, 0xE4, 0x03, 0x3C, 0x37, 0xE4, 0x01, 0x3C, 0x38, 0xE5, + 0x01, 0x3D, 0x38, 0xE6, 0x01, 0x3C, 0x38, 0xE5, 0x02, 0x3D, 0x38, 0xE6, 0x01, 0x3E, 0x39, 0xE7, + 0x01, 0x3D, 0x38, 0xE7, 0x01, 0x3E, 0x38, 0xE7, 0x02, 0x3E, 0x39, 0xE8, 0x01, 0x3F, 0x39, 0xE9, + 0x01, 0x3E, 0x38, 0xE8, 0x03, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x39, 0xE9, 0x01, 0x3F, 0x39, 0xE9, + 0x03, 0x40, 0x39, 0xEA, 0x01, 0x40, 0x39, 0xEB, 0x02, 0x42, 0x3A, 0xEC, 0x01, 0x42, 0x39, 0xEC, + 0x01, 0x43, 0x3B, 0xED, 0x01, 0x43, 0x3A, 0xEC, 0x03, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xED, + 0x01, 0x44, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xEE, 0x01, 0x44, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xEE, + 0x01, 0x44, 0x3B, 0xEE, 0x01, 0x45, 0x3C, 0xEF, 0x01, 0x45, 0x3B, 0xEF, 0x01, 0x46, 0x3C, 0xF0, + 0x02, 0x45, 0x3C, 0xF0, 0x02, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x46, 0x3C, 0xF1, + 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x03, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF3, + 0x01, 0x49, 0x3C, 0xF3, 0x02, 0x49, 0x3D, 0xF3, 0x02, 0x4A, 0x3D, 0xF4, 0x01, 0x4A, 0x3E, 0xF5, + 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4A, 0x3E, 0xF6, + 0x01, 0x35, 0x26, 0x93, 0x2C, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, + 0x01, 0x85, 0x81, 0x7F, 0x01, 0xD5, 0xD3, 0xD3, 0x0B, 0xFF, 0xFF, 0xFF, 0x01, 0xD6, 0xD4, 0xD4, + 0x01, 0x88, 0x85, 0x83, 0x01, 0x38, 0x30, 0x2C, 0x17, 0x29, 0x21, 0x1D, 0x01, 0x29, 0x1E, 0x36, + 0x01, 0x27, 0x17, 0xA9, 0x02, 0x27, 0x18, 0xB0, 0x01, 0x29, 0x1A, 0xB6, 0x01, 0x34, 0x32, 0xDA, + 0x02, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x35, 0xDF, + 0x03, 0x37, 0x36, 0xDF, 0x01, 0x37, 0x35, 0xDF, 0x02, 0x38, 0x36, 0xE0, 0x01, 0x37, 0x36, 0xE0, + 0x01, 0x38, 0x36, 0xE1, 0x01, 0x39, 0x36, 0xE2, 0x02, 0x38, 0x36, 0xE2, 0x01, 0x39, 0x36, 0xE3, + 0x01, 0x39, 0x36, 0xE2, 0x01, 0x3A, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE3, 0x01, 0x3A, 0x36, 0xE4, + 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3C, 0x37, 0xE4, 0x02, 0x3A, 0x37, 0xE4, 0x04, 0x3C, 0x38, 0xE5, + 0x01, 0x3D, 0x39, 0xE6, 0x02, 0x3D, 0x38, 0xE6, 0x01, 0x3E, 0x39, 0xE7, 0x01, 0x3D, 0x38, 0xE7, + 0x01, 0x3E, 0x39, 0xE8, 0x02, 0x3E, 0x38, 0xE8, 0x04, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x3A, 0xEA, + 0x01, 0x40, 0x39, 0xEA, 0x01, 0x40, 0x39, 0xE9, 0x01, 0x40, 0x39, 0xEA, 0x02, 0x42, 0x3A, 0xEB, + 0x01, 0x40, 0x39, 0xEB, 0x01, 0x42, 0x3A, 0xEC, 0x01, 0x42, 0x39, 0xEC, 0x01, 0x43, 0x3A, 0xEC, + 0x01, 0x42, 0x39, 0xEC, 0x01, 0x42, 0x3A, 0xED, 0x01, 0x43, 0x3B, 0xED, 0x02, 0x44, 0x3B, 0xED, + 0x01, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xEE, 0x02, 0x44, 0x3B, 0xEE, 0x01, 0x44, 0x3B, 0xEF, + 0x02, 0x45, 0x3C, 0xEF, 0x01, 0x45, 0x3B, 0xEF, 0x01, 0x46, 0x3C, 0xF0, 0x01, 0x45, 0x3C, 0xF0, + 0x03, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x02, 0x48, 0x3C, 0xF2, + 0x01, 0x49, 0x3D, 0xF2, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF3, + 0x02, 0x49, 0x3D, 0xF4, 0x01, 0x49, 0x3C, 0xF4, 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x4A, 0x3E, 0xF5, + 0x01, 0x4B, 0x3E, 0xF5, 0x02, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x49, 0x3C, 0xF3, + 0x01, 0x2D, 0x22, 0x56, 0x2B, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, + 0x0A, 0xFF, 0xFF, 0xFF, 0x01, 0xED, 0xED, 0xED, 0x01, 0xA8, 0xA6, 0xA5, 0x01, 0x54, 0x4E, 0x4A, + 0x1A, 0x29, 0x21, 0x1D, 0x01, 0x26, 0x15, 0x8D, 0x03, 0x27, 0x18, 0xB0, 0x01, 0x30, 0x2B, 0xD1, + 0x01, 0x34, 0x35, 0xDD, 0x02, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x34, 0x35, 0xDE, + 0x01, 0x35, 0x35, 0xDF, 0x03, 0x37, 0x36, 0xDF, 0x01, 0x37, 0x35, 0xDF, 0x02, 0x38, 0x36, 0xE0, + 0x01, 0x37, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE1, 0x01, 0x39, 0x36, 0xE2, 0x02, 0x38, 0x36, 0xE2, + 0x01, 0x39, 0x36, 0xE3, 0x01, 0x39, 0x36, 0xE2, 0x01, 0x3A, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE3, + 0x01, 0x3A, 0x36, 0xE4, 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3C, 0x37, 0xE4, 0x02, 0x3A, 0x37, 0xE4, + 0x04, 0x3C, 0x38, 0xE5, 0x01, 0x3D, 0x39, 0xE6, 0x02, 0x3D, 0x38, 0xE6, 0x01, 0x3E, 0x39, 0xE7, + 0x01, 0x3D, 0x38, 0xE7, 0x01, 0x3E, 0x39, 0xE8, 0x02, 0x3E, 0x38, 0xE8, 0x04, 0x3F, 0x39, 0xE9, + 0x01, 0x40, 0x3A, 0xEA, 0x01, 0x40, 0x39, 0xEA, 0x01, 0x40, 0x39, 0xE9, 0x01, 0x40, 0x39, 0xEA, + 0x02, 0x42, 0x3A, 0xEB, 0x01, 0x40, 0x39, 0xEB, 0x01, 0x42, 0x3A, 0xEC, 0x01, 0x42, 0x39, 0xEC, + 0x01, 0x43, 0x3A, 0xEC, 0x01, 0x42, 0x39, 0xEC, 0x01, 0x42, 0x3A, 0xED, 0x01, 0x43, 0x3B, 0xED, + 0x02, 0x44, 0x3B, 0xED, 0x01, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xEE, 0x02, 0x44, 0x3B, 0xEE, + 0x01, 0x44, 0x3B, 0xEF, 0x02, 0x45, 0x3C, 0xEF, 0x01, 0x45, 0x3B, 0xEF, 0x01, 0x46, 0x3C, 0xF0, + 0x01, 0x45, 0x3C, 0xF0, 0x03, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, + 0x02, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF2, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x48, 0x3C, 0xF2, + 0x01, 0x49, 0x3D, 0xF3, 0x02, 0x49, 0x3D, 0xF4, 0x01, 0x49, 0x3C, 0xF4, 0x01, 0x4A, 0x3D, 0xF4, + 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3E, 0xF5, 0x02, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3E, 0xF6, + 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x42, 0x33, 0xDC, 0x2B, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x3B, 0x29, 0x21, 0x1D, 0x09, 0xFF, 0xFF, 0xFF, 0x01, 0x81, 0x7D, 0x7B, 0x01, 0x2D, 0x26, 0x21, + 0x1B, 0x29, 0x21, 0x1D, 0x01, 0x28, 0x19, 0x53, 0x03, 0x27, 0x18, 0xB0, 0x01, 0x2B, 0x1F, 0xBE, + 0x03, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x35, 0x35, 0xDE, 0x02, 0x35, 0x35, 0xDF, + 0x01, 0x37, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xDF, + 0x01, 0x38, 0x36, 0xE0, 0x01, 0x37, 0x36, 0xE0, 0x03, 0x38, 0x36, 0xE1, 0x01, 0x39, 0x37, 0xE2, + 0x02, 0x39, 0x36, 0xE2, 0x01, 0x39, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE3, 0x01, 0x3A, 0x37, 0xE4, + 0x01, 0x3A, 0x36, 0xE4, 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3A, 0x36, 0xE4, 0x01, 0x3C, 0x37, 0xE4, + 0x01, 0x3A, 0x36, 0xE4, 0x02, 0x3C, 0x38, 0xE5, 0x01, 0x3D, 0x39, 0xE6, 0x02, 0x3D, 0x38, 0xE6, + 0x02, 0x3D, 0x39, 0xE7, 0x01, 0x3D, 0x38, 0xE7, 0x04, 0x3E, 0x39, 0xE8, 0x01, 0x3F, 0x39, 0xE9, + 0x01, 0x3E, 0x38, 0xE9, 0x02, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x3A, 0xEA, 0x01, 0x40, 0x39, 0xE9, + 0x02, 0x40, 0x3A, 0xEA, 0x01, 0x40, 0x39, 0xEA, 0x01, 0x42, 0x3A, 0xEB, 0x01, 0x42, 0x3A, 0xEC, + 0x01, 0x42, 0x3A, 0xEB, 0x01, 0x43, 0x3A, 0xEC, 0x01, 0x42, 0x3A, 0xEC, 0x02, 0x43, 0x3B, 0xED, + 0x01, 0x44, 0x3B, 0xED, 0x01, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xED, 0x01, 0x43, 0x3B, 0xED, + 0x01, 0x44, 0x3C, 0xEE, 0x01, 0x44, 0x3B, 0xEE, 0x02, 0x45, 0x3C, 0xEF, 0x01, 0x45, 0x3B, 0xEF, + 0x03, 0x45, 0x3C, 0xF0, 0x01, 0x46, 0x3C, 0xF1, 0x01, 0x46, 0x3C, 0xF0, 0x02, 0x46, 0x3C, 0xF1, + 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x46, 0x3C, 0xF2, 0x02, 0x48, 0x3C, 0xF2, 0x02, 0x49, 0x3D, 0xF2, + 0x03, 0x49, 0x3D, 0xF3, 0x03, 0x4A, 0x3D, 0xF4, 0x03, 0x4A, 0x3E, 0xF5, 0x01, 0x4A, 0x3E, 0xF6, + 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x33, 0x25, 0x8D, + 0x2A, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x09, 0xFF, 0xFF, 0xFF, + 0x01, 0xF5, 0xF5, 0xF5, 0x01, 0xB7, 0xB4, 0xB3, 0x01, 0x64, 0x60, 0x5C, 0x1A, 0x29, 0x21, 0x1D, + 0x01, 0x28, 0x16, 0x98, 0x03, 0x27, 0x18, 0xB0, 0x01, 0x33, 0x2E, 0xD4, 0x02, 0x34, 0x35, 0xDD, + 0x02, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x35, 0xDF, + 0x03, 0x37, 0x36, 0xDF, 0x01, 0x37, 0x35, 0xDF, 0x02, 0x38, 0x36, 0xE0, 0x01, 0x37, 0x36, 0xE0, + 0x01, 0x38, 0x36, 0xE1, 0x01, 0x39, 0x36, 0xE2, 0x02, 0x38, 0x36, 0xE2, 0x01, 0x39, 0x36, 0xE3, + 0x01, 0x39, 0x36, 0xE2, 0x01, 0x3A, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE3, 0x01, 0x3A, 0x36, 0xE4, + 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3C, 0x37, 0xE4, 0x02, 0x3A, 0x37, 0xE4, 0x04, 0x3C, 0x38, 0xE5, + 0x01, 0x3D, 0x39, 0xE6, 0x02, 0x3D, 0x38, 0xE6, 0x01, 0x3E, 0x39, 0xE7, 0x01, 0x3D, 0x38, 0xE7, + 0x01, 0x3E, 0x39, 0xE8, 0x02, 0x3E, 0x38, 0xE8, 0x04, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x3A, 0xEA, + 0x01, 0x40, 0x39, 0xEA, 0x01, 0x40, 0x39, 0xE9, 0x01, 0x40, 0x39, 0xEA, 0x02, 0x42, 0x3A, 0xEB, + 0x01, 0x40, 0x39, 0xEB, 0x01, 0x42, 0x3A, 0xEC, 0x01, 0x42, 0x39, 0xEC, 0x01, 0x43, 0x3A, 0xEC, + 0x01, 0x42, 0x39, 0xEC, 0x01, 0x42, 0x3A, 0xED, 0x01, 0x43, 0x3B, 0xED, 0x02, 0x44, 0x3B, 0xED, + 0x01, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xEE, 0x02, 0x44, 0x3B, 0xEE, 0x01, 0x44, 0x3B, 0xEF, + 0x02, 0x45, 0x3C, 0xEF, 0x01, 0x45, 0x3B, 0xEF, 0x01, 0x46, 0x3C, 0xF0, 0x01, 0x45, 0x3C, 0xF0, + 0x03, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x02, 0x48, 0x3C, 0xF2, + 0x01, 0x49, 0x3D, 0xF2, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF3, + 0x02, 0x49, 0x3D, 0xF4, 0x01, 0x49, 0x3C, 0xF4, 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x4A, 0x3E, 0xF5, + 0x01, 0x4B, 0x3E, 0xF5, 0x02, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4B, 0x3F, 0xF6, + 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x44, 0x37, 0xE7, 0x2A, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x3B, 0x29, 0x21, 0x1D, 0x01, 0xC5, 0xC4, 0xC3, 0x01, 0xFC, 0xFC, 0xFC, 0x0A, 0xFF, 0xFF, 0xFF, + 0x01, 0xE2, 0xE1, 0xE1, 0x01, 0x97, 0x94, 0x92, 0x01, 0x44, 0x3D, 0x39, 0x16, 0x29, 0x21, 0x1D, + 0x01, 0x28, 0x1A, 0x4E, 0x03, 0x27, 0x18, 0xB0, 0x01, 0x2B, 0x1D, 0xBC, 0x01, 0x33, 0x34, 0xDC, + 0x03, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x35, 0x35, 0xDE, 0x02, 0x35, 0x35, 0xDF, + 0x01, 0x37, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xDF, + 0x01, 0x38, 0x36, 0xE0, 0x01, 0x37, 0x36, 0xE0, 0x03, 0x38, 0x36, 0xE1, 0x01, 0x39, 0x37, 0xE2, + 0x02, 0x39, 0x36, 0xE2, 0x01, 0x39, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE3, 0x01, 0x3A, 0x37, 0xE4, + 0x01, 0x3A, 0x36, 0xE4, 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3A, 0x36, 0xE4, 0x01, 0x3C, 0x37, 0xE4, + 0x01, 0x3A, 0x36, 0xE4, 0x02, 0x3C, 0x38, 0xE5, 0x01, 0x3D, 0x39, 0xE6, 0x02, 0x3D, 0x38, 0xE6, + 0x02, 0x3D, 0x39, 0xE7, 0x01, 0x3D, 0x38, 0xE7, 0x04, 0x3E, 0x39, 0xE8, 0x01, 0x3F, 0x39, 0xE9, + 0x01, 0x3E, 0x38, 0xE9, 0x02, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x3A, 0xEA, 0x01, 0x40, 0x39, 0xE9, + 0x02, 0x40, 0x3A, 0xEA, 0x01, 0x40, 0x39, 0xEA, 0x01, 0x42, 0x3A, 0xEB, 0x01, 0x42, 0x3A, 0xEC, + 0x01, 0x42, 0x3A, 0xEB, 0x01, 0x43, 0x3A, 0xEC, 0x01, 0x42, 0x3A, 0xEC, 0x02, 0x43, 0x3B, 0xED, + 0x01, 0x44, 0x3B, 0xED, 0x01, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xED, 0x01, 0x43, 0x3B, 0xED, + 0x01, 0x44, 0x3C, 0xEE, 0x01, 0x44, 0x3B, 0xEE, 0x02, 0x45, 0x3C, 0xEF, 0x01, 0x45, 0x3B, 0xEF, + 0x03, 0x45, 0x3C, 0xF0, 0x01, 0x46, 0x3C, 0xF1, 0x01, 0x46, 0x3C, 0xF0, 0x02, 0x46, 0x3C, 0xF1, + 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x46, 0x3C, 0xF2, 0x02, 0x48, 0x3C, 0xF2, 0x02, 0x49, 0x3D, 0xF2, + 0x03, 0x49, 0x3D, 0xF3, 0x03, 0x4A, 0x3D, 0xF4, 0x03, 0x4A, 0x3E, 0xF5, 0x01, 0x4A, 0x3E, 0xF6, + 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, + 0x01, 0x34, 0x24, 0x84, 0x29, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3C, 0x29, 0x21, 0x1D, + 0x01, 0x44, 0x3E, 0x3A, 0x01, 0x9B, 0x98, 0x96, 0x01, 0xE6, 0xE5, 0xE5, 0x0A, 0xFF, 0xFF, 0xFF, + 0x01, 0xFC, 0xFC, 0xFC, 0x01, 0xC6, 0xC5, 0xC4, 0x01, 0x77, 0x73, 0x71, 0x01, 0x2D, 0x26, 0x21, + 0x13, 0x29, 0x21, 0x1D, 0x01, 0x26, 0x14, 0x84, 0x03, 0x27, 0x18, 0xB0, 0x01, 0x2F, 0x29, 0xCE, + 0x01, 0x33, 0x34, 0xDC, 0x03, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x35, 0x35, 0xDE, + 0x02, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xE0, + 0x01, 0x37, 0x35, 0xDF, 0x01, 0x38, 0x36, 0xE0, 0x01, 0x37, 0x36, 0xE0, 0x03, 0x38, 0x36, 0xE1, + 0x01, 0x39, 0x37, 0xE2, 0x02, 0x39, 0x36, 0xE2, 0x01, 0x39, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE3, + 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3A, 0x36, 0xE4, 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3A, 0x36, 0xE4, + 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3A, 0x36, 0xE4, 0x02, 0x3C, 0x38, 0xE5, 0x01, 0x3D, 0x39, 0xE6, + 0x02, 0x3D, 0x38, 0xE6, 0x02, 0x3D, 0x39, 0xE7, 0x01, 0x3D, 0x38, 0xE7, 0x04, 0x3E, 0x39, 0xE8, + 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x3E, 0x38, 0xE9, 0x02, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x3A, 0xEA, + 0x01, 0x40, 0x39, 0xE9, 0x02, 0x40, 0x3A, 0xEA, 0x01, 0x40, 0x39, 0xEA, 0x01, 0x42, 0x3A, 0xEB, + 0x01, 0x42, 0x3A, 0xEC, 0x01, 0x42, 0x3A, 0xEB, 0x01, 0x43, 0x3A, 0xEC, 0x01, 0x42, 0x3A, 0xEC, + 0x02, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xED, 0x01, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xED, + 0x01, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xEE, 0x01, 0x44, 0x3B, 0xEE, 0x02, 0x45, 0x3C, 0xEF, + 0x01, 0x45, 0x3B, 0xEF, 0x03, 0x45, 0x3C, 0xF0, 0x01, 0x46, 0x3C, 0xF1, 0x01, 0x46, 0x3C, 0xF0, + 0x02, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x46, 0x3C, 0xF2, 0x02, 0x48, 0x3C, 0xF2, + 0x02, 0x49, 0x3D, 0xF2, 0x03, 0x49, 0x3D, 0xF3, 0x03, 0x4A, 0x3D, 0xF4, 0x03, 0x4A, 0x3E, 0xF5, + 0x01, 0x4A, 0x3E, 0xF6, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4B, 0x3F, 0xF6, + 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x41, 0x32, 0xD3, 0x29, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x3F, 0x29, 0x21, 0x1D, 0x01, 0x6B, 0x66, 0x64, 0x01, 0xBE, 0xBC, 0xBB, 0x01, 0xF9, 0xF9, 0xF9, + 0x0A, 0xFF, 0xFF, 0xFF, 0x01, 0xEE, 0xEE, 0xED, 0x01, 0xA9, 0xA7, 0xA6, 0x01, 0x55, 0x4E, 0x4C, + 0x10, 0x29, 0x21, 0x1D, 0x01, 0x29, 0x20, 0x24, 0x01, 0x27, 0x17, 0xAC, 0x02, 0x27, 0x18, 0xB0, + 0x01, 0x29, 0x18, 0xB2, 0x01, 0x33, 0x33, 0xDA, 0x01, 0x33, 0x33, 0xDC, 0x02, 0x34, 0x35, 0xDD, + 0x01, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x36, 0xDF, 0x01, 0x34, 0x35, 0xDE, 0x02, 0x35, 0x36, 0xDF, + 0x01, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, 0x01, 0x37, 0x35, 0xDF, 0x02, 0x37, 0x36, 0xE0, + 0x01, 0x38, 0x36, 0xE1, 0x01, 0x37, 0x36, 0xE0, 0x02, 0x38, 0x36, 0xE1, 0x01, 0x39, 0x36, 0xE2, + 0x01, 0x75, 0x71, 0xEA, 0x01, 0xB9, 0xB7, 0xF4, 0x01, 0xE4, 0xE3, 0xFB, 0x02, 0xF7, 0xF6, 0xFE, + 0x01, 0xE4, 0xE3, 0xFB, 0x01, 0xB9, 0xB7, 0xF4, 0x01, 0x77, 0x72, 0xEB, 0x01, 0x3A, 0x37, 0xE4, + 0x02, 0x3C, 0x37, 0xE4, 0x01, 0x3D, 0x38, 0xE5, 0x01, 0x3C, 0x38, 0xE5, 0x01, 0x3D, 0x38, 0xE6, + 0x01, 0x3C, 0x38, 0xE6, 0x02, 0x3D, 0x38, 0xE6, 0x01, 0x3D, 0x38, 0xE7, 0x01, 0x3E, 0x39, 0xE8, + 0x01, 0x3E, 0x38, 0xE7, 0x01, 0x3F, 0x39, 0xE8, 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x3E, 0x39, 0xE8, + 0x02, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x39, 0xE9, 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x3A, 0xEA, + 0x01, 0x40, 0x39, 0xE9, 0x02, 0x40, 0x39, 0xEA, 0x01, 0x42, 0x3A, 0xEB, 0x01, 0x40, 0x39, 0xEB, + 0x01, 0x42, 0x3A, 0xEC, 0x01, 0x43, 0x3A, 0xEC, 0x01, 0x42, 0x39, 0xEC, 0x05, 0x43, 0x3B, 0xED, + 0x01, 0x44, 0x3B, 0xED, 0x01, 0x7D, 0x74, 0xF2, 0x01, 0xBC, 0xB8, 0xF8, 0x01, 0xE6, 0xE4, 0xFC, + 0x02, 0xF7, 0xF6, 0xFE, 0x01, 0xE6, 0xE4, 0xFC, 0x01, 0xBD, 0xB8, 0xF8, 0x01, 0x7D, 0x74, 0xF4, + 0x01, 0x46, 0x3C, 0xF1, 0x01, 0x45, 0x3C, 0xF0, 0x02, 0x48, 0x3C, 0xF2, 0x01, 0x46, 0x3C, 0xF1, + 0x02, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF3, + 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF3, 0x02, 0x49, 0x3D, 0xF4, + 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x4B, 0x3F, 0xF5, 0x01, 0x4A, 0x3E, 0xF5, 0x02, 0x4B, 0x3F, 0xF6, + 0x01, 0x4A, 0x3E, 0xF6, 0x02, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3F, 0xF6, 0x01, 0x4A, 0x3D, 0xF4, + 0x01, 0x2B, 0x22, 0x30, 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x41, 0x29, 0x21, 0x1D, + 0x01, 0x3C, 0x36, 0x32, 0x01, 0x91, 0x8F, 0x8D, 0x01, 0xDF, 0xDE, 0xDD, 0x0B, 0xFF, 0xFF, 0xFF, + 0x01, 0xD6, 0xD6, 0xD5, 0x01, 0x7A, 0x76, 0x74, 0x0E, 0x29, 0x21, 0x1D, 0x01, 0x28, 0x1A, 0x4D, + 0x03, 0x27, 0x18, 0xB0, 0x01, 0x2B, 0x1D, 0xBC, 0x01, 0x33, 0x34, 0xDD, 0x01, 0x33, 0x34, 0xDC, + 0x03, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x35, 0x35, 0xDE, 0x02, 0x35, 0x35, 0xDF, + 0x01, 0x37, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xDF, + 0x01, 0x38, 0x36, 0xE0, 0x01, 0x37, 0x36, 0xE0, 0x02, 0x38, 0x36, 0xE1, 0x01, 0x5B, 0x57, 0xE5, + 0x01, 0xD4, 0xD2, 0xF8, 0x08, 0xFF, 0xFF, 0xFF, 0x01, 0xD5, 0xD2, 0xF9, 0x01, 0x5D, 0x57, 0xE8, + 0x02, 0x3C, 0x38, 0xE5, 0x01, 0x3D, 0x39, 0xE6, 0x02, 0x3D, 0x38, 0xE6, 0x02, 0x3D, 0x39, 0xE7, + 0x01, 0x3D, 0x38, 0xE7, 0x04, 0x3E, 0x39, 0xE8, 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x3E, 0x38, 0xE9, + 0x02, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x3A, 0xEA, 0x01, 0x40, 0x39, 0xE9, 0x02, 0x40, 0x3A, 0xEA, + 0x01, 0x40, 0x39, 0xEA, 0x01, 0x42, 0x3A, 0xEB, 0x01, 0x42, 0x3A, 0xEC, 0x01, 0x42, 0x3A, 0xEB, + 0x01, 0x43, 0x3A, 0xEC, 0x01, 0x42, 0x3A, 0xEC, 0x02, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xED, + 0x01, 0x43, 0x3B, 0xED, 0x01, 0x64, 0x5B, 0xF0, 0x01, 0xD5, 0xD3, 0xFA, 0x08, 0xFF, 0xFF, 0xFF, + 0x01, 0xD6, 0xD3, 0xFB, 0x01, 0x67, 0x5B, 0xF2, 0x02, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3D, 0xF2, + 0x01, 0x46, 0x3C, 0xF2, 0x02, 0x48, 0x3C, 0xF2, 0x02, 0x49, 0x3D, 0xF2, 0x03, 0x49, 0x3D, 0xF3, + 0x03, 0x4A, 0x3D, 0xF4, 0x03, 0x4A, 0x3E, 0xF5, 0x01, 0x4A, 0x3E, 0xF6, 0x01, 0x4B, 0x3F, 0xF6, + 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3F, 0xF7, + 0x01, 0x34, 0x24, 0x82, 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x44, 0x29, 0x21, 0x1D, + 0x01, 0x62, 0x5C, 0x5A, 0x01, 0xB6, 0xB3, 0xB2, 0x01, 0xF6, 0xF6, 0xF6, 0x09, 0xFF, 0xFF, 0xFF, + 0x01, 0xCF, 0xCD, 0xCC, 0x0E, 0x29, 0x21, 0x1D, 0x01, 0x28, 0x15, 0x72, 0x03, 0x27, 0x18, 0xB0, + 0x01, 0x2C, 0x24, 0xC8, 0x01, 0x33, 0x34, 0xDC, 0x01, 0x33, 0x33, 0xDC, 0x02, 0x34, 0x35, 0xDD, + 0x01, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x36, 0xDF, 0x01, 0x34, 0x35, 0xDE, 0x02, 0x35, 0x36, 0xDF, + 0x01, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, 0x01, 0x37, 0x35, 0xDF, 0x02, 0x37, 0x36, 0xE0, + 0x01, 0x38, 0x36, 0xE1, 0x01, 0x37, 0x36, 0xE0, 0x01, 0x70, 0x6C, 0xE8, 0x01, 0xF3, 0xF3, 0xFD, + 0x0A, 0xFF, 0xFF, 0xFF, 0x01, 0xF4, 0xF3, 0xFD, 0x01, 0x72, 0x6D, 0xEB, 0x01, 0x3D, 0x38, 0xE5, + 0x01, 0x3C, 0x38, 0xE5, 0x01, 0x3D, 0x38, 0xE6, 0x01, 0x3C, 0x38, 0xE6, 0x02, 0x3D, 0x38, 0xE6, + 0x01, 0x3D, 0x38, 0xE7, 0x01, 0x3E, 0x39, 0xE8, 0x01, 0x3E, 0x38, 0xE7, 0x01, 0x3F, 0x39, 0xE8, + 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x3E, 0x39, 0xE8, 0x02, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x39, 0xE9, + 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x3A, 0xEA, 0x01, 0x40, 0x39, 0xE9, 0x02, 0x40, 0x39, 0xEA, + 0x01, 0x42, 0x3A, 0xEB, 0x01, 0x40, 0x39, 0xEB, 0x01, 0x42, 0x3A, 0xEC, 0x01, 0x43, 0x3A, 0xEC, + 0x01, 0x42, 0x39, 0xEC, 0x03, 0x43, 0x3B, 0xED, 0x01, 0x77, 0x6E, 0xF1, 0x01, 0xF4, 0xF3, 0xFE, + 0x0A, 0xFF, 0xFF, 0xFF, 0x01, 0xF4, 0xF3, 0xFE, 0x01, 0x7A, 0x6F, 0xF4, 0x01, 0x48, 0x3C, 0xF2, + 0x01, 0x46, 0x3C, 0xF1, 0x02, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x48, 0x3C, 0xF2, + 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF3, + 0x02, 0x49, 0x3D, 0xF4, 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x4B, 0x3F, 0xF5, 0x01, 0x4A, 0x3E, 0xF5, + 0x02, 0x4B, 0x3F, 0xF6, 0x01, 0x4A, 0x3E, 0xF6, 0x02, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3F, 0xF6, + 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x3C, 0x2C, 0xBB, 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x3B, 0x29, 0x21, 0x1D, 0x01, 0xD6, 0xD4, 0xD4, 0x0A, 0xDE, 0xDD, 0xDC, 0x01, 0xE8, 0xE7, 0xE6, + 0x09, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, 0x0E, 0x29, 0x21, 0x1D, 0x01, 0x26, 0x15, 0x8A, + 0x03, 0x27, 0x18, 0xB0, 0x01, 0x2F, 0x29, 0xCF, 0x01, 0x33, 0x34, 0xDC, 0x01, 0x33, 0x33, 0xDC, + 0x02, 0x34, 0x35, 0xDD, 0x01, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x36, 0xDF, 0x01, 0x34, 0x35, 0xDE, + 0x02, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, 0x01, 0x37, 0x35, 0xDF, + 0x02, 0x37, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE1, 0x01, 0x5A, 0x57, 0xE4, 0x01, 0xF3, 0xF3, 0xFD, + 0x0C, 0xFF, 0xFF, 0xFF, 0x01, 0xF4, 0xF3, 0xFD, 0x01, 0x5F, 0x58, 0xE9, 0x01, 0x3C, 0x38, 0xE5, + 0x01, 0x3D, 0x38, 0xE6, 0x01, 0x3C, 0x38, 0xE6, 0x02, 0x3D, 0x38, 0xE6, 0x01, 0x3D, 0x38, 0xE7, + 0x01, 0x3E, 0x39, 0xE8, 0x01, 0x3E, 0x38, 0xE7, 0x01, 0x3F, 0x39, 0xE8, 0x01, 0x3F, 0x39, 0xE9, + 0x01, 0x3E, 0x39, 0xE8, 0x02, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x39, 0xE9, 0x01, 0x3F, 0x39, 0xE9, + 0x01, 0x40, 0x3A, 0xEA, 0x01, 0x40, 0x39, 0xE9, 0x02, 0x40, 0x39, 0xEA, 0x01, 0x42, 0x3A, 0xEB, + 0x01, 0x40, 0x39, 0xEB, 0x01, 0x42, 0x3A, 0xEC, 0x01, 0x43, 0x3A, 0xEC, 0x01, 0x42, 0x39, 0xEC, + 0x02, 0x43, 0x3B, 0xED, 0x01, 0x63, 0x5B, 0xEF, 0x01, 0xF4, 0xF3, 0xFE, 0x0C, 0xFF, 0xFF, 0xFF, + 0x01, 0xF4, 0xF3, 0xFE, 0x01, 0x67, 0x5B, 0xF3, 0x01, 0x46, 0x3C, 0xF1, 0x02, 0x48, 0x3C, 0xF2, + 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x48, 0x3C, 0xF2, + 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF3, 0x02, 0x49, 0x3D, 0xF4, 0x01, 0x4A, 0x3D, 0xF4, + 0x01, 0x4B, 0x3F, 0xF5, 0x01, 0x4A, 0x3E, 0xF5, 0x02, 0x4B, 0x3F, 0xF6, 0x01, 0x4A, 0x3E, 0xF6, + 0x02, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x42, 0x33, 0xD8, + 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x15, 0xFF, 0xFF, 0xFF, + 0x01, 0xCF, 0xCD, 0xCC, 0x0E, 0x29, 0x21, 0x1D, 0x01, 0x27, 0x16, 0x9C, 0x03, 0x27, 0x18, 0xB0, + 0x01, 0x32, 0x2F, 0xD5, 0x01, 0x34, 0x35, 0xDD, 0x01, 0x33, 0x34, 0xDD, 0x01, 0x34, 0x35, 0xDE, + 0x01, 0x34, 0x35, 0xDD, 0x01, 0x35, 0x35, 0xDE, 0x01, 0x34, 0x35, 0xDE, 0x03, 0x35, 0x35, 0xDF, + 0x01, 0x37, 0x36, 0xDF, 0x01, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xE0, + 0x01, 0x37, 0x35, 0xE0, 0x01, 0x38, 0x36, 0xE0, 0x01, 0xD4, 0xD2, 0xF7, 0x0E, 0xFF, 0xFF, 0xFF, + 0x01, 0xD5, 0xD2, 0xF9, 0x01, 0x3C, 0x38, 0xE5, 0x02, 0x3D, 0x38, 0xE6, 0x01, 0x3D, 0x39, 0xE7, + 0x01, 0x3D, 0x38, 0xE6, 0x01, 0x3E, 0x39, 0xE7, 0x01, 0x3D, 0x38, 0xE7, 0x01, 0x3E, 0x39, 0xE8, + 0x01, 0x3E, 0x38, 0xE8, 0x01, 0x3E, 0x39, 0xE8, 0x05, 0x3F, 0x39, 0xE9, 0x02, 0x40, 0x39, 0xEA, + 0x01, 0x40, 0x3A, 0xEA, 0x01, 0x40, 0x39, 0xEA, 0x01, 0x42, 0x3A, 0xEB, 0x01, 0x42, 0x39, 0xEB, + 0x01, 0x42, 0x3A, 0xEC, 0x01, 0x42, 0x39, 0xEC, 0x01, 0x43, 0x3A, 0xEC, 0x01, 0x42, 0x3A, 0xEC, + 0x01, 0x43, 0x3B, 0xED, 0x01, 0xD5, 0xD3, 0xFA, 0x0E, 0xFF, 0xFF, 0xFF, 0x01, 0xD6, 0xD3, 0xFB, + 0x02, 0x48, 0x3D, 0xF2, 0x03, 0x48, 0x3C, 0xF2, 0x04, 0x49, 0x3D, 0xF3, 0x01, 0x4A, 0x3D, 0xF4, + 0x01, 0x49, 0x3D, 0xF4, 0x04, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3E, 0xF6, 0x02, 0x4B, 0x3F, 0xF6, + 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x48, 0x39, 0xEA, + 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x15, 0xFF, 0xFF, 0xFF, + 0x01, 0xD1, 0xD1, 0xD0, 0x0E, 0x29, 0x21, 0x1D, 0x01, 0x26, 0x17, 0xA7, 0x03, 0x27, 0x18, 0xB0, + 0x01, 0x32, 0x31, 0xD9, 0x01, 0x33, 0x34, 0xDC, 0x01, 0x33, 0x33, 0xDC, 0x02, 0x34, 0x35, 0xDD, + 0x01, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x36, 0xDF, 0x01, 0x34, 0x35, 0xDE, 0x02, 0x35, 0x36, 0xDF, + 0x01, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, 0x01, 0x37, 0x35, 0xDF, 0x02, 0x37, 0x36, 0xE0, + 0x01, 0x75, 0x71, 0xE9, 0x10, 0xFF, 0xFF, 0xFF, 0x01, 0xBE, 0xBC, 0xF5, 0x05, 0xA7, 0xA3, 0xF3, + 0x01, 0xA7, 0xA4, 0xF4, 0x01, 0xA7, 0xA3, 0xF3, 0x02, 0xA8, 0xA4, 0xF4, 0x01, 0xA7, 0xA4, 0xF4, + 0x02, 0xA8, 0xA4, 0xF4, 0x06, 0xA8, 0xA4, 0xF5, 0x01, 0xA9, 0xA4, 0xF5, 0x01, 0xA8, 0xA4, 0xF5, + 0x03, 0xA9, 0xA4, 0xF5, 0x01, 0xA9, 0xA4, 0xF6, 0x01, 0xC0, 0xBD, 0xF8, 0x10, 0xFF, 0xFF, 0xFF, + 0x01, 0x7E, 0x74, 0xF4, 0x02, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x48, 0x3C, 0xF2, + 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF3, + 0x02, 0x49, 0x3D, 0xF4, 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x4B, 0x3F, 0xF5, 0x01, 0x4A, 0x3E, 0xF5, + 0x02, 0x4B, 0x3F, 0xF6, 0x01, 0x4A, 0x3E, 0xF6, 0x02, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3F, 0xF6, + 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4A, 0x3B, 0xF2, 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x3B, 0x29, 0x21, 0x1D, 0x15, 0xFF, 0xFF, 0xFF, 0x01, 0xD0, 0xCF, 0xCE, 0x0E, 0x29, 0x21, 0x1D, + 0x01, 0x27, 0x17, 0xAD, 0x03, 0x27, 0x18, 0xB0, 0x01, 0x33, 0x33, 0xDB, 0x01, 0x34, 0x35, 0xDD, + 0x01, 0x33, 0x34, 0xDD, 0x01, 0x34, 0x35, 0xDE, 0x01, 0x34, 0x35, 0xDD, 0x01, 0x35, 0x35, 0xDE, + 0x01, 0x34, 0x35, 0xDE, 0x03, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, 0x01, 0x37, 0x36, 0xE0, + 0x01, 0x37, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xE0, 0x01, 0xB9, 0xB7, 0xF3, + 0x3A, 0xFF, 0xFF, 0xFF, 0x01, 0xBE, 0xB9, 0xFA, 0x01, 0x48, 0x3D, 0xF2, 0x03, 0x48, 0x3C, 0xF2, + 0x04, 0x49, 0x3D, 0xF3, 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x49, 0x3D, 0xF4, 0x04, 0x4A, 0x3E, 0xF5, + 0x01, 0x4B, 0x3E, 0xF6, 0x02, 0x4B, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4B, 0x3F, 0xF6, + 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3E, 0xF6, 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x3B, 0x29, 0x21, 0x1D, 0x15, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, 0x0E, 0x29, 0x21, 0x1D, + 0x04, 0x27, 0x18, 0xB0, 0x01, 0x33, 0x34, 0xDC, 0x01, 0x34, 0x35, 0xDD, 0x01, 0x33, 0x34, 0xDD, + 0x01, 0x34, 0x35, 0xDE, 0x01, 0x34, 0x35, 0xDD, 0x01, 0x35, 0x35, 0xDE, 0x01, 0x34, 0x35, 0xDE, + 0x03, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, 0x01, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xDF, + 0x01, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xE0, 0x01, 0xE4, 0xE3, 0xFA, 0x3A, 0xFF, 0xFF, 0xFF, + 0x01, 0xE6, 0xE4, 0xFC, 0x01, 0x48, 0x3D, 0xF2, 0x03, 0x48, 0x3C, 0xF2, 0x04, 0x49, 0x3D, 0xF3, + 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x49, 0x3D, 0xF4, 0x04, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3E, 0xF6, + 0x02, 0x4B, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, + 0x01, 0x4C, 0x3F, 0xF7, 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, + 0x01, 0x99, 0x96, 0x94, 0x14, 0xA2, 0x9F, 0x9E, 0x01, 0x7C, 0x78, 0x76, 0x0E, 0x29, 0x21, 0x1D, + 0x04, 0x27, 0x18, 0xB0, 0x01, 0x33, 0x33, 0xDC, 0x01, 0x34, 0x35, 0xDD, 0x01, 0x33, 0x33, 0xDC, + 0x03, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x35, 0xDE, 0x01, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, + 0x01, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, 0x03, 0x37, 0x36, 0xE0, + 0x01, 0xF7, 0xF6, 0xFE, 0x3A, 0xFF, 0xFF, 0xFF, 0x01, 0xF7, 0xF6, 0xFE, 0x01, 0x48, 0x3C, 0xF2, + 0x03, 0x48, 0x3D, 0xF2, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF3, + 0x01, 0x49, 0x3C, 0xF3, 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x49, 0x3D, 0xF4, 0x01, 0x4A, 0x3D, 0xF4, + 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, + 0x01, 0x4A, 0x3E, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4B, 0x3F, 0xF6, 0x03, 0x4C, 0x3F, 0xF7, + 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x5F, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, + 0x01, 0x33, 0x34, 0xDC, 0x01, 0x34, 0x35, 0xDD, 0x01, 0x33, 0x34, 0xDD, 0x01, 0x34, 0x35, 0xDE, + 0x01, 0x34, 0x35, 0xDD, 0x01, 0x35, 0x35, 0xDE, 0x01, 0x34, 0x35, 0xDE, 0x03, 0x35, 0x35, 0xDF, + 0x01, 0x37, 0x36, 0xDF, 0x01, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xE0, + 0x01, 0x37, 0x35, 0xE0, 0x01, 0xF7, 0xF6, 0xFE, 0x3A, 0xFF, 0xFF, 0xFF, 0x01, 0xF7, 0xF6, 0xFE, + 0x01, 0x48, 0x3D, 0xF2, 0x03, 0x48, 0x3C, 0xF2, 0x04, 0x49, 0x3D, 0xF3, 0x01, 0x4A, 0x3D, 0xF4, + 0x01, 0x49, 0x3D, 0xF4, 0x04, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3E, 0xF6, 0x02, 0x4B, 0x3F, 0xF6, + 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3F, 0xF7, + 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x5F, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, + 0x01, 0x33, 0x33, 0xDC, 0x01, 0x34, 0x35, 0xDD, 0x01, 0x33, 0x33, 0xDC, 0x03, 0x34, 0x35, 0xDE, + 0x01, 0x35, 0x35, 0xDE, 0x01, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x35, 0x36, 0xDF, + 0x01, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, 0x03, 0x37, 0x36, 0xE0, 0x01, 0xE4, 0xE3, 0xFA, + 0x3A, 0xFF, 0xFF, 0xFF, 0x01, 0xE6, 0xE4, 0xFC, 0x01, 0x48, 0x3C, 0xF2, 0x03, 0x48, 0x3D, 0xF2, + 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF3, + 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x49, 0x3D, 0xF4, 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x4A, 0x3E, 0xF5, + 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4A, 0x3E, 0xF6, + 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4B, 0x3F, 0xF6, 0x03, 0x4C, 0x3F, 0xF7, 0x28, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x5F, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, 0x01, 0x33, 0x33, 0xDC, + 0x01, 0x34, 0x35, 0xDD, 0x01, 0x33, 0x33, 0xDC, 0x03, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x35, 0xDE, + 0x01, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, + 0x01, 0x37, 0x36, 0xDF, 0x03, 0x37, 0x36, 0xE0, 0x01, 0xB9, 0xB7, 0xF4, 0x3A, 0xFF, 0xFF, 0xFF, + 0x01, 0xBD, 0xB8, 0xF9, 0x01, 0x48, 0x3C, 0xF2, 0x03, 0x48, 0x3D, 0xF2, 0x01, 0x49, 0x3D, 0xF3, + 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF3, 0x01, 0x4A, 0x3D, 0xF4, + 0x01, 0x49, 0x3D, 0xF4, 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, + 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4A, 0x3E, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, + 0x01, 0x4B, 0x3F, 0xF6, 0x03, 0x4C, 0x3F, 0xF7, 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x3B, 0x29, 0x21, 0x1D, 0x01, 0xBF, 0xBD, 0xBC, 0x14, 0xC7, 0xC5, 0xC5, 0x01, 0x9A, 0x97, 0x95, + 0x0E, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, 0x01, 0x33, 0x33, 0xDC, 0x01, 0x33, 0x34, 0xDD, + 0x02, 0x34, 0x35, 0xDD, 0x02, 0x35, 0x35, 0xDE, 0x02, 0x34, 0x35, 0xDE, 0x02, 0x35, 0x35, 0xDF, + 0x01, 0x37, 0x36, 0xDF, 0x02, 0x37, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xE0, + 0x01, 0x74, 0x71, 0xE8, 0x10, 0xFF, 0xFF, 0xFF, 0x01, 0xBE, 0xBC, 0xF5, 0x03, 0xA7, 0xA3, 0xF3, + 0x02, 0xA7, 0xA4, 0xF3, 0x02, 0xA7, 0xA3, 0xF3, 0x01, 0xA7, 0xA4, 0xF4, 0x01, 0xA7, 0xA3, 0xF4, + 0x03, 0xA8, 0xA4, 0xF4, 0x07, 0xA8, 0xA4, 0xF5, 0x05, 0xA9, 0xA4, 0xF5, 0x01, 0xED, 0xEB, 0xFC, + 0x10, 0xFF, 0xFF, 0xFF, 0x01, 0x7F, 0x75, 0xF5, 0x02, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, + 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF2, 0x01, 0x49, 0x3C, 0xF3, 0x03, 0x49, 0x3D, 0xF3, + 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4A, 0x3D, 0xF4, 0x03, 0x4A, 0x3E, 0xF5, + 0x01, 0x4B, 0x3F, 0xF6, 0x02, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3F, 0xF7, 0x01, 0x4B, 0x3E, 0xF6, + 0x01, 0x4C, 0x3F, 0xF7, 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, + 0x15, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, 0x0E, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, + 0x01, 0x33, 0x33, 0xDC, 0x01, 0x34, 0x35, 0xDD, 0x01, 0x33, 0x33, 0xDC, 0x03, 0x34, 0x35, 0xDE, + 0x01, 0x35, 0x35, 0xDE, 0x01, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x35, 0x36, 0xDF, + 0x01, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, 0x03, 0x37, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE1, + 0x01, 0xD4, 0xD2, 0xF7, 0x0E, 0xFF, 0xFF, 0xFF, 0x01, 0xD5, 0xD3, 0xF9, 0x01, 0x3C, 0x38, 0xE5, + 0x01, 0x3D, 0x39, 0xE6, 0x01, 0x3C, 0x38, 0xE6, 0x01, 0x3D, 0x38, 0xE6, 0x02, 0x3D, 0x38, 0xE7, + 0x03, 0x3E, 0x39, 0xE8, 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x3E, 0x38, 0xE8, 0x02, 0x3F, 0x39, 0xE9, + 0x02, 0x40, 0x39, 0xE9, 0x01, 0x40, 0x3A, 0xEA, 0x01, 0x40, 0x39, 0xE9, 0x01, 0x40, 0x3A, 0xEA, + 0x01, 0x40, 0x39, 0xEA, 0x03, 0x42, 0x3A, 0xEB, 0x01, 0x42, 0x3A, 0xEC, 0x01, 0x43, 0x3B, 0xED, + 0x01, 0xA0, 0x9A, 0xF5, 0x10, 0xFF, 0xFF, 0xFF, 0x01, 0xD6, 0xD3, 0xFC, 0x01, 0x46, 0x3C, 0xF1, + 0x01, 0x48, 0x3C, 0xF2, 0x03, 0x48, 0x3D, 0xF2, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x48, 0x3C, 0xF2, + 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF3, 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x49, 0x3D, 0xF4, + 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4A, 0x3E, 0xF5, + 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4A, 0x3E, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4B, 0x3F, 0xF6, + 0x03, 0x4C, 0x3F, 0xF7, 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, + 0x15, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, 0x0E, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, + 0x01, 0x33, 0x33, 0xDC, 0x01, 0x33, 0x34, 0xDD, 0x02, 0x34, 0x35, 0xDD, 0x02, 0x35, 0x35, 0xDE, + 0x02, 0x34, 0x35, 0xDE, 0x02, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, 0x02, 0x37, 0x35, 0xDF, + 0x01, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xE0, 0x01, 0x37, 0x36, 0xE0, 0x01, 0x5A, 0x57, 0xE4, + 0x01, 0xF3, 0xF3, 0xFD, 0x0C, 0xFF, 0xFF, 0xFF, 0x01, 0xF4, 0xF3, 0xFD, 0x01, 0x5E, 0x58, 0xE9, + 0x01, 0x3C, 0x38, 0xE5, 0x03, 0x3D, 0x38, 0xE6, 0x02, 0x3E, 0x39, 0xE7, 0x01, 0x3D, 0x38, 0xE7, + 0x01, 0x3E, 0x38, 0xE7, 0x01, 0x3E, 0x39, 0xE8, 0x01, 0x3E, 0x38, 0xE8, 0x03, 0x3F, 0x39, 0xE9, + 0x01, 0x40, 0x39, 0xE9, 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x39, 0xE9, 0x03, 0x40, 0x39, 0xEA, + 0x01, 0x40, 0x39, 0xEB, 0x02, 0x42, 0x3A, 0xEC, 0x01, 0x42, 0x39, 0xEC, 0x01, 0xA0, 0x9A, 0xF5, + 0x10, 0xFF, 0xFF, 0xFF, 0x01, 0xF4, 0xF3, 0xFE, 0x01, 0x67, 0x5B, 0xF3, 0x01, 0x48, 0x3D, 0xF2, + 0x02, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF2, + 0x01, 0x49, 0x3C, 0xF3, 0x03, 0x49, 0x3D, 0xF3, 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x4A, 0x3E, 0xF5, + 0x01, 0x4A, 0x3D, 0xF4, 0x03, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, 0x02, 0x4B, 0x3E, 0xF6, + 0x01, 0x4C, 0x3F, 0xF7, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3F, 0xF7, 0x28, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x15, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, + 0x0E, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, 0x01, 0x33, 0x33, 0xDC, 0x01, 0x33, 0x34, 0xDD, + 0x02, 0x34, 0x35, 0xDD, 0x02, 0x35, 0x35, 0xDE, 0x02, 0x34, 0x35, 0xDE, 0x02, 0x35, 0x35, 0xDF, + 0x01, 0x37, 0x36, 0xDF, 0x02, 0x37, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xE0, + 0x02, 0x37, 0x36, 0xE0, 0x01, 0x70, 0x6C, 0xE8, 0x01, 0xF3, 0xF3, 0xFD, 0x0A, 0xFF, 0xFF, 0xFF, + 0x01, 0xF4, 0xF3, 0xFD, 0x01, 0x72, 0x6C, 0xEB, 0x02, 0x3C, 0x38, 0xE5, 0x03, 0x3D, 0x38, 0xE6, + 0x02, 0x3E, 0x39, 0xE7, 0x01, 0x3D, 0x38, 0xE7, 0x01, 0x3E, 0x38, 0xE7, 0x01, 0x3E, 0x39, 0xE8, + 0x01, 0x3E, 0x38, 0xE8, 0x03, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x39, 0xE9, 0x01, 0x3F, 0x39, 0xE9, + 0x01, 0x40, 0x39, 0xE9, 0x03, 0x40, 0x39, 0xEA, 0x01, 0x40, 0x39, 0xEB, 0x02, 0x42, 0x3A, 0xEC, + 0x01, 0xA0, 0x9A, 0xF5, 0x10, 0xFF, 0xFF, 0xFF, 0x01, 0xF4, 0xF3, 0xFE, 0x01, 0x79, 0x6F, 0xF4, + 0x01, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3D, 0xF2, 0x02, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, + 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF2, 0x01, 0x49, 0x3C, 0xF3, 0x03, 0x49, 0x3D, 0xF3, + 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4A, 0x3D, 0xF4, 0x03, 0x4A, 0x3E, 0xF5, + 0x01, 0x4B, 0x3F, 0xF6, 0x02, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3F, 0xF7, 0x01, 0x4B, 0x3E, 0xF6, + 0x01, 0x4C, 0x3F, 0xF7, 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, + 0x15, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, 0x0E, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, + 0x02, 0x33, 0x34, 0xDC, 0x03, 0x34, 0x35, 0xDD, 0x01, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x35, 0xDE, + 0x01, 0x35, 0x35, 0xDF, 0x01, 0x35, 0x36, 0xDF, 0x02, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, + 0x01, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE0, + 0x02, 0x38, 0x36, 0xE1, 0x01, 0x5C, 0x58, 0xE6, 0x01, 0xD4, 0xD2, 0xF8, 0x08, 0xFF, 0xFF, 0xFF, + 0x01, 0xD5, 0xD2, 0xF9, 0x01, 0x5D, 0x58, 0xE8, 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3C, 0x38, 0xE5, + 0x01, 0x3D, 0x38, 0xE6, 0x01, 0x3C, 0x38, 0xE5, 0x01, 0x3D, 0x39, 0xE6, 0x02, 0x3D, 0x38, 0xE6, + 0x01, 0x3D, 0x38, 0xE7, 0x02, 0x3E, 0x39, 0xE8, 0x01, 0x3F, 0x39, 0xE8, 0x01, 0x3E, 0x39, 0xE8, + 0x01, 0x3E, 0x39, 0xE9, 0x04, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x39, 0xEA, 0x01, 0x40, 0x3A, 0xEA, + 0x01, 0x40, 0x39, 0xEA, 0x01, 0x42, 0x3A, 0xEB, 0x02, 0x40, 0x39, 0xEB, 0x01, 0xA0, 0x9A, 0xF5, + 0x10, 0xFF, 0xFF, 0xFF, 0x01, 0xD6, 0xD3, 0xFB, 0x01, 0x67, 0x5B, 0xF3, 0x01, 0x46, 0x3C, 0xF1, + 0x02, 0x46, 0x3C, 0xF2, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x02, 0x48, 0x3C, 0xF2, + 0x03, 0x49, 0x3D, 0xF3, 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF3, + 0x01, 0x4A, 0x3D, 0xF4, 0x02, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, 0x02, 0x4B, 0x3E, 0xF6, + 0x02, 0x4B, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3F, 0xF6, 0x01, 0x4C, 0x3F, 0xF7, + 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x15, 0xFF, 0xFF, 0xFF, + 0x01, 0xA7, 0xA4, 0xA3, 0x0E, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, 0x01, 0x33, 0x33, 0xDC, + 0x01, 0x33, 0x34, 0xDD, 0x02, 0x34, 0x35, 0xDD, 0x02, 0x35, 0x35, 0xDE, 0x02, 0x34, 0x35, 0xDE, + 0x02, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, 0x02, 0x37, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xE0, + 0x01, 0x37, 0x35, 0xE0, 0x02, 0x37, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE1, 0x01, 0x38, 0x36, 0xE2, + 0x01, 0x38, 0x36, 0xE1, 0x01, 0x76, 0x72, 0xEA, 0x01, 0xB9, 0xB7, 0xF4, 0x01, 0xE4, 0xE3, 0xFB, + 0x02, 0xF7, 0xF6, 0xFE, 0x01, 0xE4, 0xE3, 0xFB, 0x01, 0xB9, 0xB7, 0xF4, 0x01, 0x77, 0x72, 0xEB, + 0x01, 0x3A, 0x36, 0xE4, 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3A, 0x36, 0xE4, 0x02, 0x3C, 0x38, 0xE5, + 0x03, 0x3D, 0x38, 0xE6, 0x02, 0x3E, 0x39, 0xE7, 0x01, 0x3D, 0x38, 0xE7, 0x01, 0x3E, 0x38, 0xE7, + 0x01, 0x3E, 0x39, 0xE8, 0x01, 0x3E, 0x38, 0xE8, 0x03, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x39, 0xE9, + 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x39, 0xE9, 0x03, 0x40, 0x39, 0xEA, 0x01, 0x40, 0x39, 0xEB, + 0x01, 0xA0, 0x9A, 0xF5, 0x09, 0xFF, 0xFF, 0xFF, 0x01, 0xBA, 0xB6, 0xF8, 0x01, 0xBC, 0xB8, 0xF8, + 0x01, 0xE6, 0xE4, 0xFC, 0x02, 0xF7, 0xF6, 0xFE, 0x01, 0xE6, 0xE4, 0xFC, 0x01, 0xBD, 0xB8, 0xF9, + 0x01, 0x7E, 0x74, 0xF4, 0x02, 0x45, 0x3C, 0xF0, 0x02, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3D, 0xF2, + 0x02, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF2, + 0x01, 0x49, 0x3C, 0xF3, 0x03, 0x49, 0x3D, 0xF3, 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x4A, 0x3E, 0xF5, + 0x01, 0x4A, 0x3D, 0xF4, 0x03, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, 0x02, 0x4B, 0x3E, 0xF6, + 0x01, 0x4C, 0x3F, 0xF7, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3F, 0xF7, 0x28, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x01, 0x64, 0x60, 0x5C, 0x09, 0x6E, 0x6A, 0x68, + 0x01, 0x80, 0x7C, 0x7A, 0x01, 0xF4, 0xF4, 0xF4, 0x07, 0xFF, 0xFF, 0xFF, 0x01, 0xF1, 0xF0, 0xF0, + 0x01, 0x7A, 0x75, 0x73, 0x0F, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, 0x02, 0x33, 0x34, 0xDC, + 0x03, 0x34, 0x35, 0xDD, 0x01, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x35, 0xDE, 0x01, 0x35, 0x35, 0xDF, + 0x01, 0x35, 0x36, 0xDF, 0x02, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, 0x01, 0x37, 0x36, 0xE0, + 0x01, 0x37, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE0, 0x02, 0x38, 0x36, 0xE1, + 0x01, 0x39, 0x37, 0xE2, 0x02, 0x38, 0x36, 0xE2, 0x01, 0x39, 0x36, 0xE2, 0x01, 0x39, 0x37, 0xE3, + 0x01, 0x39, 0x36, 0xE3, 0x04, 0x3A, 0x37, 0xE4, 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3A, 0x37, 0xE4, + 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3C, 0x38, 0xE5, 0x01, 0x3D, 0x38, 0xE6, 0x01, 0x3C, 0x38, 0xE5, + 0x01, 0x3D, 0x39, 0xE6, 0x02, 0x3D, 0x38, 0xE6, 0x01, 0x3D, 0x38, 0xE7, 0x02, 0x3E, 0x39, 0xE8, + 0x01, 0x3F, 0x39, 0xE8, 0x01, 0x3E, 0x39, 0xE8, 0x01, 0x3E, 0x39, 0xE9, 0x04, 0x3F, 0x39, 0xE9, + 0x01, 0x40, 0x39, 0xEA, 0x01, 0x40, 0x3A, 0xEA, 0x01, 0x40, 0x39, 0xEA, 0x01, 0x42, 0x3A, 0xEB, + 0x01, 0x9F, 0x9A, 0xF4, 0x09, 0xFF, 0xFF, 0xFF, 0x01, 0xA0, 0x9A, 0xF6, 0x01, 0x44, 0x3B, 0xED, + 0x01, 0x44, 0x3C, 0xEE, 0x01, 0x45, 0x3C, 0xEF, 0x01, 0x44, 0x3B, 0xEF, 0x01, 0x45, 0x3C, 0xF0, + 0x02, 0x45, 0x3B, 0xEF, 0x01, 0x45, 0x3C, 0xF0, 0x01, 0x46, 0x3C, 0xF0, 0x02, 0x46, 0x3C, 0xF1, + 0x02, 0x46, 0x3C, 0xF2, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x02, 0x48, 0x3C, 0xF2, + 0x03, 0x49, 0x3D, 0xF3, 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF3, + 0x01, 0x4A, 0x3D, 0xF4, 0x02, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, 0x02, 0x4B, 0x3E, 0xF6, + 0x02, 0x4B, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3F, 0xF6, 0x01, 0x4C, 0x3F, 0xF7, + 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x44, 0x29, 0x21, 0x1D, 0x01, 0x73, 0x6F, 0x6D, + 0x01, 0xED, 0xED, 0xED, 0x07, 0xFF, 0xFF, 0xFF, 0x01, 0xC9, 0xC7, 0xC6, 0x01, 0x44, 0x3D, 0x39, + 0x10, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, 0x02, 0x33, 0x34, 0xDC, 0x03, 0x34, 0x35, 0xDD, + 0x01, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x35, 0xDE, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x35, 0x36, 0xDF, + 0x02, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, 0x01, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xDF, + 0x01, 0x37, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE0, 0x02, 0x38, 0x36, 0xE1, 0x01, 0x39, 0x37, 0xE2, + 0x02, 0x38, 0x36, 0xE2, 0x01, 0x39, 0x36, 0xE2, 0x01, 0x39, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE3, + 0x04, 0x3A, 0x37, 0xE4, 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3C, 0x37, 0xE4, + 0x01, 0x3C, 0x38, 0xE5, 0x01, 0x3D, 0x38, 0xE6, 0x01, 0x3C, 0x38, 0xE5, 0x01, 0x3D, 0x39, 0xE6, + 0x02, 0x3D, 0x38, 0xE6, 0x01, 0x3D, 0x38, 0xE7, 0x02, 0x3E, 0x39, 0xE8, 0x01, 0x3F, 0x39, 0xE8, + 0x01, 0x3E, 0x39, 0xE8, 0x01, 0x3E, 0x39, 0xE9, 0x04, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x39, 0xEA, + 0x01, 0x40, 0x3A, 0xEA, 0x01, 0x40, 0x39, 0xEA, 0x01, 0xA0, 0x9A, 0xF4, 0x09, 0xFF, 0xFF, 0xFF, + 0x01, 0xA1, 0x9A, 0xF6, 0x01, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xEE, + 0x01, 0x45, 0x3C, 0xEF, 0x01, 0x44, 0x3B, 0xEF, 0x01, 0x45, 0x3C, 0xF0, 0x02, 0x45, 0x3B, 0xEF, + 0x01, 0x45, 0x3C, 0xF0, 0x01, 0x46, 0x3C, 0xF0, 0x02, 0x46, 0x3C, 0xF1, 0x02, 0x46, 0x3C, 0xF2, + 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x02, 0x48, 0x3C, 0xF2, 0x03, 0x49, 0x3D, 0xF3, + 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF3, 0x01, 0x4A, 0x3D, 0xF4, + 0x02, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, 0x02, 0x4B, 0x3E, 0xF6, 0x02, 0x4B, 0x3F, 0xF6, + 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3F, 0xF6, 0x01, 0x4C, 0x3F, 0xF7, 0x28, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x42, 0x29, 0x21, 0x1D, 0x01, 0x36, 0x2F, 0x2B, 0x01, 0xB5, 0xB2, 0xB1, + 0x07, 0xFF, 0xFF, 0xFF, 0x01, 0xF7, 0xF7, 0xF6, 0x01, 0x8B, 0x88, 0x86, 0x12, 0x29, 0x21, 0x1D, + 0x04, 0x27, 0x18, 0xB0, 0x01, 0x33, 0x33, 0xDC, 0x01, 0x34, 0x35, 0xDD, 0x01, 0x33, 0x34, 0xDD, + 0x04, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x35, 0x36, 0xDF, + 0x01, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xE0, + 0x01, 0x38, 0x36, 0xE0, 0x01, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xE0, 0x01, 0x38, 0x36, 0xE1, + 0x01, 0x38, 0x36, 0xE2, 0x04, 0x39, 0x36, 0xE2, 0x01, 0x3A, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE3, + 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3A, 0x36, 0xE4, 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3A, 0x37, 0xE4, + 0x01, 0x3C, 0x37, 0xE4, 0x03, 0x3C, 0x38, 0xE5, 0x02, 0x3D, 0x38, 0xE6, 0x01, 0x3D, 0x39, 0xE7, + 0x02, 0x3D, 0x38, 0xE7, 0x01, 0x3E, 0x38, 0xE7, 0x01, 0x3E, 0x39, 0xE8, 0x01, 0x3E, 0x38, 0xE8, + 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x3E, 0x38, 0xE8, 0x03, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x3A, 0xEA, + 0x02, 0x3F, 0x39, 0xE9, 0x01, 0x9F, 0x9A, 0xF4, 0x09, 0xFF, 0xFF, 0xFF, 0x01, 0xA1, 0x9B, 0xF6, + 0x01, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xEE, 0x02, 0x44, 0x3B, 0xEE, + 0x02, 0x45, 0x3C, 0xEF, 0x04, 0x45, 0x3C, 0xF0, 0x02, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3C, 0xF2, + 0x01, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3D, 0xF2, 0x02, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF2, + 0x02, 0x48, 0x3C, 0xF2, 0x02, 0x49, 0x3D, 0xF3, 0x03, 0x4A, 0x3D, 0xF4, 0x01, 0x4A, 0x3E, 0xF5, + 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4A, 0x3E, 0xF6, + 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3F, 0xF6, 0x01, 0x4C, 0x3F, 0xF7, + 0x01, 0x4C, 0x3E, 0xF6, 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x41, 0x29, 0x21, 0x1D, + 0x01, 0x66, 0x62, 0x5E, 0x01, 0xE7, 0xE6, 0xE5, 0x07, 0xFF, 0xFF, 0xFF, 0x01, 0xD6, 0xD4, 0xD4, + 0x01, 0x4E, 0x48, 0x45, 0x13, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, 0x02, 0x33, 0x34, 0xDC, + 0x03, 0x34, 0x35, 0xDD, 0x01, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x35, 0xDE, 0x01, 0x35, 0x35, 0xDF, + 0x01, 0x35, 0x36, 0xDF, 0x02, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, 0x01, 0x37, 0x36, 0xE0, + 0x01, 0x37, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE0, 0x02, 0x38, 0x36, 0xE1, + 0x01, 0x39, 0x37, 0xE2, 0x02, 0x38, 0x36, 0xE2, 0x01, 0x39, 0x36, 0xE2, 0x01, 0x39, 0x37, 0xE3, + 0x01, 0x39, 0x36, 0xE3, 0x04, 0x3A, 0x37, 0xE4, 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3A, 0x37, 0xE4, + 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3C, 0x38, 0xE5, 0x01, 0x3D, 0x38, 0xE6, 0x01, 0x3C, 0x38, 0xE5, + 0x01, 0x3D, 0x39, 0xE6, 0x02, 0x3D, 0x38, 0xE6, 0x01, 0x3D, 0x38, 0xE7, 0x02, 0x3E, 0x39, 0xE8, + 0x01, 0x3F, 0x39, 0xE8, 0x01, 0x3E, 0x39, 0xE8, 0x01, 0x3E, 0x39, 0xE9, 0x04, 0x3F, 0x39, 0xE9, + 0x01, 0x40, 0x39, 0xEA, 0x01, 0x9F, 0x9A, 0xF4, 0x09, 0xFF, 0xFF, 0xFF, 0x01, 0xA0, 0x9A, 0xF5, + 0x01, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xED, 0x01, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xED, + 0x01, 0x44, 0x3C, 0xEE, 0x01, 0x45, 0x3C, 0xEF, 0x01, 0x44, 0x3B, 0xEF, 0x01, 0x45, 0x3C, 0xF0, + 0x02, 0x45, 0x3B, 0xEF, 0x01, 0x45, 0x3C, 0xF0, 0x01, 0x46, 0x3C, 0xF0, 0x02, 0x46, 0x3C, 0xF1, + 0x02, 0x46, 0x3C, 0xF2, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x02, 0x48, 0x3C, 0xF2, + 0x03, 0x49, 0x3D, 0xF3, 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF3, + 0x01, 0x4A, 0x3D, 0xF4, 0x02, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, 0x02, 0x4B, 0x3E, 0xF6, + 0x02, 0x4B, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3F, 0xF6, 0x01, 0x4C, 0x3F, 0xF7, + 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3F, 0x29, 0x21, 0x1D, 0x01, 0x30, 0x28, 0x24, + 0x01, 0xA8, 0xA5, 0xA4, 0x01, 0xFD, 0xFD, 0xFD, 0x06, 0xFF, 0xFF, 0xFF, 0x01, 0xFB, 0xFB, 0xFB, + 0x01, 0x9C, 0x99, 0x97, 0x01, 0x2C, 0x24, 0x20, 0x14, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, + 0x01, 0x33, 0x33, 0xDC, 0x01, 0x34, 0x35, 0xDD, 0x01, 0x33, 0x34, 0xDD, 0x04, 0x34, 0x35, 0xDE, + 0x01, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, + 0x01, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE0, + 0x01, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xE0, 0x01, 0x38, 0x36, 0xE1, 0x01, 0x38, 0x36, 0xE2, + 0x04, 0x39, 0x36, 0xE2, 0x01, 0x3A, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE3, 0x01, 0x3A, 0x37, 0xE4, + 0x01, 0x3A, 0x36, 0xE4, 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3C, 0x37, 0xE4, + 0x03, 0x3C, 0x38, 0xE5, 0x02, 0x3D, 0x38, 0xE6, 0x01, 0x3D, 0x39, 0xE7, 0x02, 0x3D, 0x38, 0xE7, + 0x01, 0x3E, 0x38, 0xE7, 0x01, 0x3E, 0x39, 0xE8, 0x01, 0x3E, 0x38, 0xE8, 0x01, 0x3F, 0x39, 0xE9, + 0x01, 0x3E, 0x38, 0xE8, 0x03, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x3A, 0xEA, 0x01, 0x9E, 0x9A, 0xF3, + 0x09, 0xFF, 0xFF, 0xFF, 0x01, 0xA0, 0x9A, 0xF5, 0x01, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xED, + 0x01, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xEE, 0x02, 0x44, 0x3B, 0xEE, + 0x02, 0x45, 0x3C, 0xEF, 0x04, 0x45, 0x3C, 0xF0, 0x02, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3C, 0xF2, + 0x01, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3D, 0xF2, 0x02, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF2, + 0x02, 0x48, 0x3C, 0xF2, 0x02, 0x49, 0x3D, 0xF3, 0x03, 0x4A, 0x3D, 0xF4, 0x01, 0x4A, 0x3E, 0xF5, + 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4A, 0x3E, 0xF6, + 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3F, 0xF6, 0x01, 0x4C, 0x3F, 0xF7, + 0x01, 0x4C, 0x3E, 0xF6, 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3E, 0x29, 0x21, 0x1D, + 0x01, 0x5A, 0x55, 0x51, 0x01, 0xDE, 0xDD, 0xDC, 0x07, 0xFF, 0xFF, 0xFF, 0x01, 0xE1, 0xE0, 0xDF, + 0x01, 0x5C, 0x57, 0x54, 0x16, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, 0x01, 0x33, 0x33, 0xDC, + 0x01, 0x34, 0x35, 0xDD, 0x01, 0x33, 0x34, 0xDD, 0x04, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x36, 0xDF, + 0x01, 0x35, 0x35, 0xDF, 0x01, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xE0, + 0x01, 0x37, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE0, 0x01, 0x37, 0x36, 0xE0, + 0x01, 0x37, 0x35, 0xE0, 0x01, 0x38, 0x36, 0xE1, 0x01, 0x38, 0x36, 0xE2, 0x04, 0x39, 0x36, 0xE2, + 0x01, 0x3A, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE3, 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3A, 0x36, 0xE4, + 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3C, 0x37, 0xE4, 0x03, 0x3C, 0x38, 0xE5, + 0x02, 0x3D, 0x38, 0xE6, 0x01, 0x3D, 0x39, 0xE7, 0x02, 0x3D, 0x38, 0xE7, 0x01, 0x3E, 0x38, 0xE7, + 0x01, 0x3E, 0x39, 0xE8, 0x01, 0x3E, 0x38, 0xE8, 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x3E, 0x38, 0xE8, + 0x03, 0x3F, 0x39, 0xE9, 0x01, 0x9F, 0x9A, 0xF4, 0x09, 0xFF, 0xFF, 0xFF, 0x01, 0xA0, 0x9A, 0xF5, + 0x02, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xED, 0x01, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xED, + 0x01, 0x44, 0x3C, 0xEE, 0x02, 0x44, 0x3B, 0xEE, 0x02, 0x45, 0x3C, 0xEF, 0x04, 0x45, 0x3C, 0xF0, + 0x02, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3D, 0xF2, + 0x02, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF2, 0x02, 0x48, 0x3C, 0xF2, 0x02, 0x49, 0x3D, 0xF3, + 0x03, 0x4A, 0x3D, 0xF4, 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4A, 0x3E, 0xF5, + 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4A, 0x3E, 0xF6, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, + 0x01, 0x4C, 0x3F, 0xF6, 0x01, 0x4C, 0x3F, 0xF7, 0x01, 0x4C, 0x3E, 0xF6, 0x28, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x3C, 0x29, 0x21, 0x1D, 0x01, 0x2C, 0x24, 0x20, 0x01, 0x9A, 0x97, 0x95, + 0x01, 0xFA, 0xFA, 0xFA, 0x06, 0xFF, 0xFF, 0xFF, 0x01, 0xFE, 0xFE, 0xFE, 0x01, 0xAB, 0xA9, 0xA8, + 0x01, 0x33, 0x2B, 0x27, 0x17, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, 0x02, 0x33, 0x34, 0xDC, + 0x01, 0x33, 0x33, 0xDC, 0x02, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x36, 0xDE, 0x01, 0x34, 0x35, 0xDE, + 0x01, 0x35, 0x35, 0xDE, 0x03, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, + 0x02, 0x37, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE0, 0x03, 0x38, 0x36, 0xE1, 0x01, 0x39, 0x37, 0xE2, + 0x01, 0x39, 0x36, 0xE2, 0x01, 0x39, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE2, 0x01, 0x39, 0x36, 0xE3, + 0x01, 0x3A, 0x37, 0xE4, 0x02, 0x3A, 0x36, 0xE4, 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3A, 0x36, 0xE4, + 0x01, 0x3C, 0x38, 0xE5, 0x01, 0x3C, 0x37, 0xE4, 0x02, 0x3C, 0x38, 0xE5, 0x02, 0x3C, 0x38, 0xE6, + 0x01, 0x3D, 0x39, 0xE7, 0x01, 0x3D, 0x38, 0xE6, 0x01, 0x3E, 0x39, 0xE7, 0x01, 0x3D, 0x38, 0xE7, + 0x04, 0x3E, 0x39, 0xE8, 0x02, 0x3F, 0x39, 0xE9, 0x01, 0x9F, 0x9A, 0xF3, 0x09, 0xFF, 0xFF, 0xFF, + 0x01, 0xA0, 0x9A, 0xF5, 0x05, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xEE, 0x03, 0x44, 0x3B, 0xEE, + 0x01, 0x45, 0x3B, 0xEF, 0x01, 0x44, 0x3B, 0xEF, 0x02, 0x45, 0x3C, 0xF0, 0x01, 0x46, 0x3C, 0xF0, + 0x01, 0x45, 0x3B, 0xF0, 0x01, 0x46, 0x3C, 0xF0, 0x03, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3C, 0xF2, + 0x01, 0x46, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x48, 0x3C, 0xF2, 0x03, 0x49, 0x3D, 0xF3, + 0x01, 0x49, 0x3C, 0xF3, 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x49, 0x3D, 0xF4, 0x01, 0x4A, 0x3E, 0xF5, + 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4A, 0x3E, 0xF6, + 0x03, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3F, 0xF7, 0x01, 0x4C, 0x3F, 0xF6, 0x01, 0x4C, 0x3F, 0xF7, + 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x01, 0x4E, 0x48, 0x45, + 0x01, 0xD5, 0xD3, 0xD3, 0x08, 0xFF, 0xFF, 0xFF, 0x01, 0xE5, 0xE4, 0xE4, 0x0A, 0xB4, 0xB2, 0xB0, + 0x01, 0x8A, 0x87, 0x85, 0x0E, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, 0x01, 0x33, 0x33, 0xDC, + 0x01, 0x34, 0x35, 0xDD, 0x01, 0x33, 0x34, 0xDD, 0x04, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x36, 0xDF, + 0x01, 0x35, 0x35, 0xDF, 0x01, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xE0, + 0x01, 0x37, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE0, 0x01, 0x37, 0x36, 0xE0, + 0x01, 0x37, 0x35, 0xE0, 0x01, 0x38, 0x36, 0xE1, 0x01, 0x38, 0x36, 0xE2, 0x04, 0x39, 0x36, 0xE2, + 0x01, 0x3A, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE3, 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3A, 0x36, 0xE4, + 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3C, 0x37, 0xE4, 0x03, 0x3C, 0x38, 0xE5, + 0x02, 0x3D, 0x38, 0xE6, 0x01, 0x3D, 0x39, 0xE7, 0x02, 0x3D, 0x38, 0xE7, 0x01, 0x3E, 0x38, 0xE7, + 0x01, 0x3E, 0x39, 0xE8, 0x01, 0x3E, 0x38, 0xE8, 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x3E, 0x38, 0xE8, + 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x9E, 0x9A, 0xF2, 0x09, 0xFF, 0xFF, 0xFF, 0x01, 0xA0, 0x9A, 0xF5, + 0x01, 0x43, 0x3B, 0xED, 0x01, 0x42, 0x3A, 0xEC, 0x02, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xED, + 0x01, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xEE, 0x02, 0x44, 0x3B, 0xEE, + 0x02, 0x45, 0x3C, 0xEF, 0x04, 0x45, 0x3C, 0xF0, 0x02, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3C, 0xF2, + 0x01, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3D, 0xF2, 0x02, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF2, + 0x02, 0x48, 0x3C, 0xF2, 0x02, 0x49, 0x3D, 0xF3, 0x03, 0x4A, 0x3D, 0xF4, 0x01, 0x4A, 0x3E, 0xF5, + 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4A, 0x3E, 0xF6, + 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3F, 0xF6, 0x01, 0x4C, 0x3F, 0xF7, + 0x01, 0x4C, 0x3E, 0xF6, 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, + 0x01, 0xF7, 0xF7, 0xF6, 0x14, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, 0x0E, 0x29, 0x21, 0x1D, + 0x04, 0x27, 0x18, 0xB0, 0x02, 0x33, 0x34, 0xDC, 0x01, 0x33, 0x33, 0xDC, 0x02, 0x34, 0x35, 0xDE, + 0x01, 0x35, 0x36, 0xDE, 0x01, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x35, 0xDE, 0x03, 0x35, 0x35, 0xDF, + 0x01, 0x37, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, 0x02, 0x37, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE0, + 0x03, 0x38, 0x36, 0xE1, 0x01, 0x39, 0x37, 0xE2, 0x01, 0x39, 0x36, 0xE2, 0x01, 0x39, 0x37, 0xE3, + 0x01, 0x39, 0x36, 0xE2, 0x01, 0x39, 0x36, 0xE3, 0x01, 0x3A, 0x37, 0xE4, 0x02, 0x3A, 0x36, 0xE4, + 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3A, 0x36, 0xE4, 0x01, 0x3C, 0x38, 0xE5, 0x01, 0x3C, 0x37, 0xE4, + 0x02, 0x3C, 0x38, 0xE5, 0x02, 0x3C, 0x38, 0xE6, 0x01, 0x3D, 0x39, 0xE7, 0x01, 0x78, 0x72, 0xEC, + 0x01, 0xBB, 0xB7, 0xF5, 0x01, 0xE5, 0xE3, 0xFB, 0x02, 0xF7, 0xF6, 0xFE, 0x01, 0xE5, 0xE4, 0xFC, + 0x01, 0xBB, 0xB7, 0xF6, 0x01, 0xB8, 0xB6, 0xF5, 0x09, 0xFF, 0xFF, 0xFF, 0x01, 0xA0, 0x9A, 0xF5, + 0x01, 0x42, 0x39, 0xEB, 0x01, 0x42, 0x3A, 0xEC, 0x05, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xEE, + 0x03, 0x44, 0x3B, 0xEE, 0x01, 0x45, 0x3B, 0xEF, 0x01, 0x44, 0x3B, 0xEF, 0x02, 0x45, 0x3C, 0xF0, + 0x01, 0x46, 0x3C, 0xF0, 0x01, 0x45, 0x3B, 0xF0, 0x01, 0x46, 0x3C, 0xF0, 0x03, 0x46, 0x3C, 0xF1, + 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x46, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x48, 0x3C, 0xF2, + 0x03, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF3, 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x49, 0x3D, 0xF4, + 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3E, 0xF6, + 0x01, 0x4A, 0x3E, 0xF6, 0x03, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3F, 0xF7, 0x01, 0x4C, 0x3F, 0xF6, + 0x01, 0x4C, 0x3F, 0xF7, 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, + 0x15, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, 0x0E, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, + 0x02, 0x33, 0x34, 0xDC, 0x01, 0x33, 0x33, 0xDC, 0x02, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x36, 0xDE, + 0x01, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x35, 0xDE, 0x03, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, + 0x01, 0x35, 0x35, 0xDF, 0x02, 0x37, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE0, 0x03, 0x38, 0x36, 0xE1, + 0x01, 0x39, 0x37, 0xE2, 0x01, 0x39, 0x36, 0xE2, 0x01, 0x39, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE2, + 0x01, 0x39, 0x36, 0xE3, 0x01, 0x3A, 0x37, 0xE4, 0x02, 0x3A, 0x36, 0xE4, 0x01, 0x3A, 0x37, 0xE4, + 0x01, 0x3A, 0x36, 0xE4, 0x01, 0x3C, 0x38, 0xE5, 0x01, 0x3C, 0x37, 0xE4, 0x02, 0x3C, 0x38, 0xE5, + 0x01, 0x3C, 0x38, 0xE6, 0x01, 0x5E, 0x58, 0xE9, 0x01, 0xD5, 0xD3, 0xF9, 0x10, 0xFF, 0xFF, 0xFF, + 0x01, 0xA0, 0x9A, 0xF4, 0x01, 0x42, 0x3A, 0xEC, 0x01, 0x42, 0x39, 0xEB, 0x01, 0x42, 0x3A, 0xEC, + 0x05, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xEE, 0x03, 0x44, 0x3B, 0xEE, 0x01, 0x45, 0x3B, 0xEF, + 0x01, 0x44, 0x3B, 0xEF, 0x02, 0x45, 0x3C, 0xF0, 0x01, 0x46, 0x3C, 0xF0, 0x01, 0x45, 0x3B, 0xF0, + 0x01, 0x46, 0x3C, 0xF0, 0x03, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x46, 0x3C, 0xF2, + 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x48, 0x3C, 0xF2, 0x03, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF3, + 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x49, 0x3D, 0xF4, 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4A, 0x3D, 0xF4, + 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4A, 0x3E, 0xF6, 0x03, 0x4B, 0x3E, 0xF6, + 0x01, 0x4C, 0x3F, 0xF7, 0x01, 0x4C, 0x3F, 0xF6, 0x01, 0x4C, 0x3F, 0xF7, 0x28, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x15, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, + 0x0E, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, 0x01, 0x33, 0x33, 0xDC, 0x04, 0x34, 0x35, 0xDD, + 0x01, 0x34, 0x35, 0xDE, 0x02, 0x35, 0x35, 0xDF, 0x01, 0x34, 0x35, 0xDE, 0x03, 0x37, 0x36, 0xDF, + 0x02, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xE0, 0x01, 0x38, 0x36, 0xE1, 0x01, 0x37, 0x36, 0xE0, + 0x01, 0x39, 0x36, 0xE2, 0x03, 0x38, 0x36, 0xE2, 0x01, 0x39, 0x36, 0xE3, 0x01, 0x39, 0x37, 0xE3, + 0x02, 0x39, 0x36, 0xE3, 0x02, 0x3A, 0x37, 0xE4, 0x02, 0x3C, 0x37, 0xE4, 0x02, 0x3A, 0x37, 0xE4, + 0x01, 0x3D, 0x38, 0xE5, 0x01, 0x3C, 0x38, 0xE5, 0x01, 0x73, 0x6E, 0xEC, 0x01, 0xF4, 0xF3, 0xFD, + 0x10, 0xFF, 0xFF, 0xFF, 0x01, 0x9F, 0x9A, 0xF4, 0x01, 0x40, 0x39, 0xEB, 0x01, 0x42, 0x3A, 0xEC, + 0x01, 0x43, 0x3A, 0xEC, 0x01, 0x42, 0x3A, 0xEC, 0x01, 0x42, 0x39, 0xEC, 0x02, 0x43, 0x3B, 0xED, + 0x04, 0x44, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xEE, 0x01, 0x44, 0x3B, 0xEE, 0x03, 0x45, 0x3C, 0xEF, + 0x01, 0x45, 0x3B, 0xEF, 0x01, 0x46, 0x3C, 0xF0, 0x03, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3D, 0xF2, + 0x01, 0x48, 0x3C, 0xF2, 0x02, 0x48, 0x3D, 0xF2, 0x02, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF3, + 0x01, 0x49, 0x3C, 0xF3, 0x02, 0x49, 0x3D, 0xF4, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF4, + 0x01, 0x4A, 0x3D, 0xF4, 0x03, 0x4A, 0x3E, 0xF5, 0x04, 0x4B, 0x3F, 0xF6, 0x02, 0x4B, 0x3E, 0xF6, + 0x01, 0x4C, 0x3F, 0xF7, 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, + 0x15, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, 0x0E, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, + 0x02, 0x33, 0x34, 0xDC, 0x01, 0x33, 0x33, 0xDC, 0x02, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x36, 0xDE, + 0x01, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x35, 0xDE, 0x03, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, + 0x01, 0x35, 0x35, 0xDF, 0x02, 0x37, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE0, 0x03, 0x38, 0x36, 0xE1, + 0x01, 0x39, 0x37, 0xE2, 0x01, 0x39, 0x36, 0xE2, 0x01, 0x39, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE2, + 0x01, 0x39, 0x36, 0xE3, 0x01, 0x3A, 0x37, 0xE4, 0x02, 0x3A, 0x36, 0xE4, 0x01, 0x3A, 0x37, 0xE4, + 0x01, 0x3A, 0x36, 0xE4, 0x01, 0x3C, 0x38, 0xE5, 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3C, 0x38, 0xE5, + 0x01, 0x5E, 0x58, 0xE9, 0x01, 0xF4, 0xF3, 0xFD, 0x10, 0xFF, 0xFF, 0xFF, 0x01, 0x9F, 0x9A, 0xF4, + 0x02, 0x42, 0x3A, 0xEB, 0x01, 0x42, 0x3A, 0xEC, 0x01, 0x42, 0x39, 0xEB, 0x01, 0x42, 0x3A, 0xEC, + 0x05, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xEE, 0x03, 0x44, 0x3B, 0xEE, 0x01, 0x45, 0x3B, 0xEF, + 0x01, 0x44, 0x3B, 0xEF, 0x02, 0x45, 0x3C, 0xF0, 0x01, 0x46, 0x3C, 0xF0, 0x01, 0x45, 0x3B, 0xF0, + 0x01, 0x46, 0x3C, 0xF0, 0x03, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x46, 0x3C, 0xF2, + 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x48, 0x3C, 0xF2, 0x03, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF3, + 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x49, 0x3D, 0xF4, 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4A, 0x3D, 0xF4, + 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4A, 0x3E, 0xF6, 0x03, 0x4B, 0x3E, 0xF6, + 0x01, 0x4C, 0x3F, 0xF7, 0x01, 0x4C, 0x3F, 0xF6, 0x01, 0x4C, 0x3F, 0xF7, 0x28, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x15, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, + 0x0E, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, 0x01, 0x33, 0x33, 0xDC, 0x04, 0x34, 0x35, 0xDD, + 0x01, 0x34, 0x35, 0xDE, 0x02, 0x35, 0x35, 0xDF, 0x01, 0x34, 0x35, 0xDE, 0x03, 0x37, 0x36, 0xDF, + 0x02, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xE0, 0x01, 0x38, 0x36, 0xE1, 0x01, 0x37, 0x36, 0xE0, + 0x01, 0x39, 0x36, 0xE2, 0x03, 0x38, 0x36, 0xE2, 0x01, 0x39, 0x36, 0xE3, 0x01, 0x39, 0x37, 0xE3, + 0x02, 0x39, 0x36, 0xE3, 0x02, 0x3A, 0x37, 0xE4, 0x02, 0x3C, 0x37, 0xE4, 0x02, 0x3A, 0x37, 0xE4, + 0x01, 0x3D, 0x38, 0xE5, 0x01, 0xD5, 0xD2, 0xF9, 0x10, 0xFF, 0xFF, 0xFF, 0x01, 0xA0, 0x9A, 0xF4, + 0x01, 0x40, 0x3A, 0xEB, 0x02, 0x40, 0x39, 0xEB, 0x01, 0x42, 0x3A, 0xEC, 0x01, 0x43, 0x3A, 0xEC, + 0x01, 0x42, 0x3A, 0xEC, 0x01, 0x42, 0x39, 0xEC, 0x02, 0x43, 0x3B, 0xED, 0x04, 0x44, 0x3B, 0xED, + 0x01, 0x44, 0x3C, 0xEE, 0x01, 0x44, 0x3B, 0xEE, 0x03, 0x45, 0x3C, 0xEF, 0x01, 0x45, 0x3B, 0xEF, + 0x01, 0x46, 0x3C, 0xF0, 0x03, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x48, 0x3C, 0xF2, + 0x02, 0x48, 0x3D, 0xF2, 0x02, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF3, + 0x02, 0x49, 0x3D, 0xF4, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF4, 0x01, 0x4A, 0x3D, 0xF4, + 0x03, 0x4A, 0x3E, 0xF5, 0x04, 0x4B, 0x3F, 0xF6, 0x02, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3F, 0xF7, + 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x01, 0x7A, 0x76, 0x74, + 0x14, 0x85, 0x81, 0x7F, 0x01, 0x64, 0x60, 0x5C, 0x0E, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, + 0x01, 0x33, 0x33, 0xDC, 0x04, 0x34, 0x35, 0xDD, 0x01, 0x34, 0x35, 0xDE, 0x02, 0x35, 0x35, 0xDF, + 0x01, 0x34, 0x35, 0xDE, 0x03, 0x37, 0x36, 0xDF, 0x02, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xE0, + 0x01, 0x38, 0x36, 0xE1, 0x01, 0x37, 0x36, 0xE0, 0x01, 0x39, 0x36, 0xE2, 0x03, 0x38, 0x36, 0xE2, + 0x01, 0x39, 0x36, 0xE3, 0x01, 0x39, 0x37, 0xE3, 0x02, 0x39, 0x36, 0xE3, 0x02, 0x3A, 0x37, 0xE4, + 0x02, 0x3C, 0x37, 0xE4, 0x02, 0x3A, 0x37, 0xE4, 0x01, 0x78, 0x72, 0xEC, 0x05, 0xFF, 0xFF, 0xFF, + 0x01, 0xE5, 0xE1, 0xFC, 0x01, 0x81, 0x6A, 0xF2, 0x02, 0x44, 0x29, 0xED, 0x01, 0x81, 0x6A, 0xF2, + 0x01, 0xE5, 0xE1, 0xFC, 0x05, 0xFF, 0xFF, 0xFF, 0x01, 0xB9, 0xB6, 0xF7, 0x01, 0x42, 0x3A, 0xEB, + 0x01, 0x40, 0x3A, 0xEB, 0x02, 0x40, 0x39, 0xEB, 0x01, 0x42, 0x3A, 0xEC, 0x01, 0x43, 0x3A, 0xEC, + 0x01, 0x42, 0x3A, 0xEC, 0x01, 0x42, 0x39, 0xEC, 0x02, 0x43, 0x3B, 0xED, 0x04, 0x44, 0x3B, 0xED, + 0x01, 0x44, 0x3C, 0xEE, 0x01, 0x44, 0x3B, 0xEE, 0x03, 0x45, 0x3C, 0xEF, 0x01, 0x45, 0x3B, 0xEF, + 0x01, 0x46, 0x3C, 0xF0, 0x03, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x48, 0x3C, 0xF2, + 0x02, 0x48, 0x3D, 0xF2, 0x02, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF3, + 0x02, 0x49, 0x3D, 0xF4, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF4, 0x01, 0x4A, 0x3D, 0xF4, + 0x03, 0x4A, 0x3E, 0xF5, 0x04, 0x4B, 0x3F, 0xF6, 0x02, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3F, 0xF7, + 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x5F, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, + 0x02, 0x33, 0x34, 0xDC, 0x01, 0x33, 0x33, 0xDC, 0x04, 0x34, 0x35, 0xDE, 0x04, 0x35, 0x35, 0xDF, + 0x01, 0x37, 0x36, 0xDF, 0x01, 0x37, 0x35, 0xDF, 0x02, 0x38, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xE0, + 0x03, 0x38, 0x36, 0xE1, 0x04, 0x39, 0x36, 0xE2, 0x01, 0x3A, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE3, + 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3A, 0x36, 0xE4, 0x02, 0x3A, 0x37, 0xE4, 0x02, 0x3C, 0x38, 0xE5, + 0x01, 0xBA, 0xB7, 0xF5, 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xE5, 0xE1, 0xFC, 0x01, 0x48, 0x2B, 0xED, + 0x04, 0x38, 0x23, 0xEC, 0x01, 0x48, 0x2B, 0xED, 0x01, 0xE5, 0xE1, 0xFC, 0x04, 0xFF, 0xFF, 0xFF, + 0x01, 0xBB, 0xB8, 0xF7, 0x02, 0x40, 0x39, 0xEA, 0x02, 0x42, 0x3A, 0xEB, 0x01, 0x42, 0x39, 0xEB, + 0x01, 0x42, 0x39, 0xEC, 0x01, 0x43, 0x3A, 0xEC, 0x01, 0x42, 0x3A, 0xEC, 0x04, 0x43, 0x3B, 0xED, + 0x02, 0x44, 0x3C, 0xEE, 0x01, 0x44, 0x3B, 0xED, 0x02, 0x45, 0x3C, 0xEF, 0x01, 0x44, 0x3B, 0xEF, + 0x04, 0x45, 0x3C, 0xF0, 0x04, 0x46, 0x3C, 0xF1, 0x02, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF2, + 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x48, 0x3C, 0xF2, 0x02, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF3, + 0x02, 0x4A, 0x3D, 0xF4, 0x01, 0x49, 0x3D, 0xF4, 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3E, 0xF5, + 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4A, 0x3E, 0xF6, 0x02, 0x4B, 0x3E, 0xF6, + 0x02, 0x4C, 0x3F, 0xF7, 0x01, 0x4B, 0x3E, 0xF6, 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x5F, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, 0x01, 0x33, 0x33, 0xDC, 0x04, 0x34, 0x35, 0xDD, + 0x01, 0x34, 0x35, 0xDE, 0x02, 0x35, 0x35, 0xDF, 0x01, 0x34, 0x35, 0xDE, 0x03, 0x37, 0x36, 0xDF, + 0x02, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xE0, 0x01, 0x38, 0x36, 0xE1, 0x01, 0x37, 0x36, 0xE0, + 0x01, 0x39, 0x36, 0xE2, 0x03, 0x38, 0x36, 0xE2, 0x01, 0x39, 0x36, 0xE3, 0x01, 0x39, 0x37, 0xE3, + 0x02, 0x39, 0x36, 0xE3, 0x02, 0x3A, 0x37, 0xE4, 0x02, 0x3C, 0x37, 0xE4, 0x02, 0x3A, 0x37, 0xE4, + 0x01, 0xE5, 0xE3, 0xFB, 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0x81, 0x6A, 0xF2, 0x06, 0x38, 0x23, 0xEC, + 0x01, 0x81, 0x6A, 0xF2, 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xE5, 0xE4, 0xFC, 0x01, 0x42, 0x3A, 0xEB, + 0x01, 0x40, 0x3A, 0xEB, 0x02, 0x40, 0x39, 0xEB, 0x01, 0x42, 0x3A, 0xEC, 0x01, 0x43, 0x3A, 0xEC, + 0x01, 0x42, 0x3A, 0xEC, 0x01, 0x42, 0x39, 0xEC, 0x02, 0x43, 0x3B, 0xED, 0x04, 0x44, 0x3B, 0xED, + 0x01, 0x44, 0x3C, 0xEE, 0x01, 0x44, 0x3B, 0xEE, 0x03, 0x45, 0x3C, 0xEF, 0x01, 0x45, 0x3B, 0xEF, + 0x01, 0x46, 0x3C, 0xF0, 0x03, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x48, 0x3C, 0xF2, + 0x02, 0x48, 0x3D, 0xF2, 0x02, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF3, + 0x02, 0x49, 0x3D, 0xF4, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF4, 0x01, 0x4A, 0x3D, 0xF4, + 0x03, 0x4A, 0x3E, 0xF5, 0x04, 0x4B, 0x3F, 0xF6, 0x02, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3F, 0xF7, + 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x5F, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, + 0x02, 0x33, 0x34, 0xDC, 0x01, 0x33, 0x33, 0xDC, 0x04, 0x34, 0x35, 0xDE, 0x04, 0x35, 0x35, 0xDF, + 0x01, 0x37, 0x36, 0xDF, 0x01, 0x37, 0x35, 0xDF, 0x02, 0x38, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xE0, + 0x03, 0x38, 0x36, 0xE1, 0x04, 0x39, 0x36, 0xE2, 0x01, 0x3A, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE3, + 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3A, 0x36, 0xE4, 0x02, 0x3A, 0x37, 0xE4, 0x02, 0x3C, 0x38, 0xE5, + 0x01, 0xF7, 0xF6, 0xFE, 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0x44, 0x29, 0xED, 0x06, 0x38, 0x23, 0xEC, + 0x01, 0x44, 0x29, 0xED, 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xF7, 0xF6, 0xFE, 0x02, 0x40, 0x39, 0xEA, + 0x02, 0x42, 0x3A, 0xEB, 0x01, 0x42, 0x39, 0xEB, 0x01, 0x42, 0x39, 0xEC, 0x01, 0x43, 0x3A, 0xEC, + 0x01, 0x42, 0x3A, 0xEC, 0x04, 0x43, 0x3B, 0xED, 0x02, 0x44, 0x3C, 0xEE, 0x01, 0x44, 0x3B, 0xED, + 0x02, 0x45, 0x3C, 0xEF, 0x01, 0x44, 0x3B, 0xEF, 0x04, 0x45, 0x3C, 0xF0, 0x04, 0x46, 0x3C, 0xF1, + 0x02, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x48, 0x3C, 0xF2, + 0x02, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF3, 0x02, 0x4A, 0x3D, 0xF4, 0x01, 0x49, 0x3D, 0xF4, + 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3E, 0xF5, 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3E, 0xF6, + 0x01, 0x4A, 0x3E, 0xF6, 0x02, 0x4B, 0x3E, 0xF6, 0x02, 0x4C, 0x3F, 0xF7, 0x01, 0x4B, 0x3E, 0xF6, + 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x01, 0xBF, 0xBD, 0xBC, + 0x14, 0xC7, 0xC5, 0xC5, 0x01, 0x9A, 0x97, 0x95, 0x0E, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, + 0x02, 0x33, 0x34, 0xDC, 0x01, 0x33, 0x33, 0xDC, 0x04, 0x34, 0x35, 0xDE, 0x04, 0x35, 0x35, 0xDF, + 0x01, 0x37, 0x36, 0xDF, 0x01, 0x37, 0x35, 0xDF, 0x02, 0x38, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xE0, + 0x03, 0x38, 0x36, 0xE1, 0x04, 0x39, 0x36, 0xE2, 0x01, 0x3A, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE3, + 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3A, 0x36, 0xE4, 0x02, 0x3A, 0x37, 0xE4, 0x02, 0x3C, 0x38, 0xE5, + 0x01, 0xF7, 0xF6, 0xFE, 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0x44, 0x29, 0xED, 0x06, 0x38, 0x23, 0xEC, + 0x01, 0x44, 0x29, 0xED, 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xF7, 0xF6, 0xFE, 0x02, 0x40, 0x39, 0xEA, + 0x02, 0x42, 0x3A, 0xEB, 0x01, 0x42, 0x39, 0xEB, 0x01, 0x42, 0x39, 0xEC, 0x01, 0x43, 0x3A, 0xEC, + 0x01, 0x42, 0x3A, 0xEC, 0x04, 0x43, 0x3B, 0xED, 0x02, 0x44, 0x3C, 0xEE, 0x01, 0x44, 0x3B, 0xED, + 0x02, 0x45, 0x3C, 0xEF, 0x01, 0x44, 0x3B, 0xEF, 0x04, 0x45, 0x3C, 0xF0, 0x04, 0x46, 0x3C, 0xF1, + 0x02, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x48, 0x3C, 0xF2, + 0x02, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF3, 0x02, 0x4A, 0x3D, 0xF4, 0x01, 0x49, 0x3D, 0xF4, + 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3E, 0xF5, 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3E, 0xF6, + 0x01, 0x4A, 0x3E, 0xF6, 0x02, 0x4B, 0x3E, 0xF6, 0x02, 0x4C, 0x3F, 0xF7, 0x01, 0x4B, 0x3E, 0xF6, + 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x15, 0xFF, 0xFF, 0xFF, + 0x01, 0xCF, 0xCD, 0xCC, 0x0E, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, 0x01, 0x33, 0x33, 0xDC, + 0x01, 0x33, 0x34, 0xDD, 0x02, 0x34, 0x35, 0xDD, 0x01, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x36, 0xDE, + 0x02, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, + 0x01, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, 0x02, 0x37, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE0, + 0x01, 0x37, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE1, 0x01, 0x39, 0x36, 0xE2, 0x01, 0x38, 0x36, 0xE2, + 0x01, 0x39, 0x36, 0xE2, 0x01, 0x39, 0x37, 0xE3, 0x02, 0x39, 0x36, 0xE3, 0x03, 0x3A, 0x37, 0xE4, + 0x01, 0x3A, 0x36, 0xE4, 0x03, 0x3C, 0x37, 0xE4, 0x01, 0xE5, 0xE3, 0xFB, 0x04, 0xFF, 0xFF, 0xFF, + 0x01, 0x81, 0x6A, 0xF2, 0x06, 0x38, 0x23, 0xEC, 0x01, 0x81, 0x6A, 0xF2, 0x04, 0xFF, 0xFF, 0xFF, + 0x01, 0xE5, 0xE4, 0xFC, 0x01, 0x40, 0x3A, 0xEA, 0x01, 0x42, 0x3A, 0xEB, 0x01, 0x40, 0x39, 0xEB, + 0x01, 0x42, 0x3A, 0xEB, 0x03, 0x42, 0x3A, 0xEC, 0x02, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xED, + 0x01, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xEE, 0x01, 0x44, 0x3B, 0xED, + 0x02, 0x44, 0x3B, 0xEE, 0x02, 0x45, 0x3C, 0xEF, 0x01, 0x45, 0x3B, 0xEF, 0x01, 0x45, 0x3C, 0xF0, + 0x02, 0x46, 0x3C, 0xF0, 0x01, 0x45, 0x3C, 0xF0, 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x46, 0x3C, 0xF2, + 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x46, 0x3C, 0xF2, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, + 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF3, 0x01, 0x49, 0x3D, 0xF3, + 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3D, 0xF4, 0x03, 0x4A, 0x3E, 0xF5, + 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, + 0x01, 0x4B, 0x3F, 0xF6, 0x02, 0x4C, 0x3F, 0xF6, 0x01, 0x4C, 0x3F, 0xF7, 0x28, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x15, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, + 0x0E, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, 0x02, 0x33, 0x34, 0xDC, 0x01, 0x33, 0x33, 0xDC, + 0x04, 0x34, 0x35, 0xDE, 0x04, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, 0x01, 0x37, 0x35, 0xDF, + 0x02, 0x38, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xE0, 0x03, 0x38, 0x36, 0xE1, 0x04, 0x39, 0x36, 0xE2, + 0x01, 0x3A, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE3, 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3A, 0x36, 0xE4, + 0x02, 0x3A, 0x37, 0xE4, 0x02, 0x3C, 0x38, 0xE5, 0x01, 0xBA, 0xB7, 0xF5, 0x04, 0xFF, 0xFF, 0xFF, + 0x01, 0xE5, 0xE1, 0xFC, 0x01, 0x48, 0x2B, 0xED, 0x04, 0x38, 0x23, 0xEC, 0x01, 0x48, 0x2B, 0xED, + 0x01, 0xE5, 0xE1, 0xFC, 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xBB, 0xB8, 0xF7, 0x02, 0x40, 0x39, 0xEA, + 0x02, 0x42, 0x3A, 0xEB, 0x01, 0x42, 0x39, 0xEB, 0x01, 0x42, 0x39, 0xEC, 0x01, 0x43, 0x3A, 0xEC, + 0x01, 0x42, 0x3A, 0xEC, 0x04, 0x43, 0x3B, 0xED, 0x02, 0x44, 0x3C, 0xEE, 0x01, 0x44, 0x3B, 0xED, + 0x02, 0x45, 0x3C, 0xEF, 0x01, 0x44, 0x3B, 0xEF, 0x04, 0x45, 0x3C, 0xF0, 0x04, 0x46, 0x3C, 0xF1, + 0x02, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x48, 0x3C, 0xF2, + 0x02, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF3, 0x02, 0x4A, 0x3D, 0xF4, 0x01, 0x49, 0x3D, 0xF4, + 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3E, 0xF5, 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3E, 0xF6, + 0x01, 0x4A, 0x3E, 0xF6, 0x02, 0x4B, 0x3E, 0xF6, 0x02, 0x4C, 0x3F, 0xF7, 0x01, 0x4B, 0x3E, 0xF6, + 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x15, 0xFF, 0xFF, 0xFF, + 0x01, 0xCF, 0xCD, 0xCC, 0x0E, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, 0x01, 0x33, 0x33, 0xDC, + 0x01, 0x33, 0x34, 0xDD, 0x02, 0x34, 0x35, 0xDD, 0x01, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x36, 0xDE, + 0x02, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, + 0x01, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, 0x02, 0x37, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE0, + 0x01, 0x37, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE1, 0x01, 0x39, 0x36, 0xE2, 0x01, 0x38, 0x36, 0xE2, + 0x01, 0x39, 0x36, 0xE2, 0x01, 0x39, 0x37, 0xE3, 0x02, 0x39, 0x36, 0xE3, 0x03, 0x3A, 0x37, 0xE4, + 0x01, 0x3A, 0x36, 0xE4, 0x03, 0x3C, 0x37, 0xE4, 0x01, 0x77, 0x72, 0xEC, 0x05, 0xFF, 0xFF, 0xFF, + 0x01, 0xE5, 0xE1, 0xFC, 0x01, 0x81, 0x6A, 0xF2, 0x02, 0x44, 0x29, 0xED, 0x01, 0x81, 0x6A, 0xF2, + 0x01, 0xE5, 0xE1, 0xFC, 0x05, 0xFF, 0xFF, 0xFF, 0x01, 0xB9, 0xB6, 0xF7, 0x01, 0x40, 0x3A, 0xEA, + 0x01, 0x42, 0x3A, 0xEB, 0x01, 0x40, 0x39, 0xEB, 0x01, 0x42, 0x3A, 0xEB, 0x03, 0x42, 0x3A, 0xEC, + 0x02, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xED, 0x01, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xED, + 0x01, 0x44, 0x3C, 0xEE, 0x01, 0x44, 0x3B, 0xED, 0x02, 0x44, 0x3B, 0xEE, 0x02, 0x45, 0x3C, 0xEF, + 0x01, 0x45, 0x3B, 0xEF, 0x01, 0x45, 0x3C, 0xF0, 0x02, 0x46, 0x3C, 0xF0, 0x01, 0x45, 0x3C, 0xF0, + 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x46, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x46, 0x3C, 0xF2, + 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF3, + 0x01, 0x49, 0x3C, 0xF3, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x49, 0x3D, 0xF3, + 0x01, 0x49, 0x3D, 0xF4, 0x03, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, + 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4B, 0x3F, 0xF6, 0x02, 0x4C, 0x3F, 0xF6, + 0x01, 0x4C, 0x3F, 0xF7, 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, + 0x15, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, 0x0E, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, + 0x01, 0x33, 0x33, 0xDC, 0x01, 0x33, 0x34, 0xDD, 0x02, 0x34, 0x35, 0xDD, 0x01, 0x34, 0x35, 0xDE, + 0x01, 0x35, 0x36, 0xDE, 0x02, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, + 0x01, 0x37, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, 0x02, 0x37, 0x36, 0xE0, + 0x01, 0x38, 0x36, 0xE0, 0x01, 0x37, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE1, 0x01, 0x39, 0x36, 0xE2, + 0x01, 0x38, 0x36, 0xE2, 0x01, 0x39, 0x36, 0xE2, 0x01, 0x39, 0x37, 0xE3, 0x02, 0x39, 0x36, 0xE3, + 0x03, 0x3A, 0x37, 0xE4, 0x01, 0x3A, 0x36, 0xE4, 0x03, 0x3C, 0x37, 0xE4, 0x01, 0x3C, 0x38, 0xE5, + 0x01, 0xD5, 0xD2, 0xF9, 0x10, 0xFF, 0xFF, 0xFF, 0x01, 0x9F, 0x9A, 0xF4, 0x01, 0x42, 0x3A, 0xEB, + 0x01, 0x40, 0x39, 0xEB, 0x01, 0x42, 0x3A, 0xEB, 0x03, 0x42, 0x3A, 0xEC, 0x02, 0x43, 0x3B, 0xED, + 0x01, 0x44, 0x3B, 0xED, 0x01, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xEE, + 0x01, 0x44, 0x3B, 0xED, 0x02, 0x44, 0x3B, 0xEE, 0x02, 0x45, 0x3C, 0xEF, 0x01, 0x45, 0x3B, 0xEF, + 0x01, 0x45, 0x3C, 0xF0, 0x02, 0x46, 0x3C, 0xF0, 0x01, 0x45, 0x3C, 0xF0, 0x01, 0x48, 0x3D, 0xF2, + 0x01, 0x46, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x46, 0x3C, 0xF2, 0x01, 0x48, 0x3C, 0xF2, + 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF3, + 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3D, 0xF4, + 0x03, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4B, 0x3F, 0xF6, + 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4B, 0x3F, 0xF6, 0x02, 0x4C, 0x3F, 0xF6, 0x01, 0x4C, 0x3F, 0xF7, + 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x15, 0xFF, 0xFF, 0xFF, + 0x01, 0xCF, 0xCD, 0xCC, 0x0E, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, 0x01, 0x33, 0x33, 0xDC, + 0x01, 0x33, 0x34, 0xDC, 0x01, 0x33, 0x34, 0xDD, 0x03, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x35, 0xDE, + 0x01, 0x35, 0x36, 0xDF, 0x02, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, 0x01, 0x37, 0x35, 0xDF, + 0x01, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE1, + 0x01, 0x37, 0x35, 0xE0, 0x02, 0x38, 0x36, 0xE1, 0x01, 0x39, 0x37, 0xE2, 0x01, 0x39, 0x36, 0xE2, + 0x01, 0x38, 0x36, 0xE2, 0x01, 0x39, 0x37, 0xE3, 0x01, 0x3A, 0x37, 0xE3, 0x01, 0x3A, 0x37, 0xE4, + 0x01, 0x3A, 0x36, 0xE4, 0x02, 0x3A, 0x37, 0xE4, 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3A, 0x36, 0xE4, + 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3D, 0x38, 0xE5, 0x01, 0x5E, 0x58, 0xE9, 0x01, 0xF4, 0xF3, 0xFD, + 0x10, 0xFF, 0xFF, 0xFF, 0x01, 0x9F, 0x9A, 0xF4, 0x02, 0x42, 0x3A, 0xEB, 0x01, 0x42, 0x39, 0xEB, + 0x01, 0x42, 0x3A, 0xEC, 0x02, 0x43, 0x3B, 0xED, 0x01, 0x42, 0x3A, 0xEC, 0x02, 0x43, 0x3B, 0xED, + 0x01, 0x44, 0x3C, 0xED, 0x01, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xEE, + 0x01, 0x44, 0x3B, 0xEE, 0x01, 0x45, 0x3C, 0xEF, 0x01, 0x45, 0x3B, 0xEF, 0x01, 0x46, 0x3C, 0xF0, + 0x01, 0x45, 0x3C, 0xF0, 0x01, 0x45, 0x3B, 0xF0, 0x01, 0x46, 0x3C, 0xF0, 0x03, 0x46, 0x3C, 0xF1, + 0x02, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x02, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF3, + 0x01, 0x48, 0x3C, 0xF2, 0x02, 0x49, 0x3D, 0xF3, 0x02, 0x4A, 0x3D, 0xF4, 0x01, 0x49, 0x3D, 0xF4, + 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, 0x02, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, + 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3E, 0xF6, + 0x01, 0x4C, 0x3F, 0xF7, 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, + 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xFE, 0xFE, 0xFE, 0x03, 0x70, 0x6C, 0x69, 0x01, 0xB7, 0xB5, 0xB4, + 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0x9F, 0x9D, 0x9C, 0x02, 0x70, 0x6C, 0x69, 0x01, 0x96, 0x93, 0x91, + 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, 0x0E, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, + 0x01, 0x33, 0x33, 0xDC, 0x01, 0x33, 0x34, 0xDD, 0x02, 0x34, 0x35, 0xDD, 0x01, 0x34, 0x35, 0xDE, + 0x01, 0x35, 0x36, 0xDE, 0x02, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, + 0x01, 0x37, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, 0x02, 0x37, 0x36, 0xE0, + 0x01, 0x38, 0x36, 0xE0, 0x01, 0x37, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE1, 0x01, 0x39, 0x36, 0xE2, + 0x01, 0x38, 0x36, 0xE2, 0x01, 0x39, 0x36, 0xE2, 0x01, 0x39, 0x37, 0xE3, 0x02, 0x39, 0x36, 0xE3, + 0x03, 0x3A, 0x37, 0xE4, 0x01, 0x3A, 0x36, 0xE4, 0x03, 0x3C, 0x37, 0xE4, 0x02, 0x3C, 0x38, 0xE5, + 0x01, 0x73, 0x6D, 0xEC, 0x01, 0xF4, 0xF3, 0xFD, 0x10, 0xFF, 0xFF, 0xFF, 0x01, 0x9F, 0x9A, 0xF4, + 0x01, 0x42, 0x3A, 0xEB, 0x03, 0x42, 0x3A, 0xEC, 0x02, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xED, + 0x01, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xEE, 0x01, 0x44, 0x3B, 0xED, + 0x02, 0x44, 0x3B, 0xEE, 0x02, 0x45, 0x3C, 0xEF, 0x01, 0x45, 0x3B, 0xEF, 0x01, 0x45, 0x3C, 0xF0, + 0x02, 0x46, 0x3C, 0xF0, 0x01, 0x45, 0x3C, 0xF0, 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x46, 0x3C, 0xF2, + 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x46, 0x3C, 0xF2, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, + 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF3, 0x01, 0x49, 0x3D, 0xF3, + 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3D, 0xF4, 0x03, 0x4A, 0x3E, 0xF5, + 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, + 0x01, 0x4B, 0x3F, 0xF6, 0x02, 0x4C, 0x3F, 0xF6, 0x01, 0x4C, 0x3F, 0xF7, 0x28, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xF2, 0xF1, 0xF1, + 0x03, 0x29, 0x21, 0x1D, 0x01, 0x8C, 0x88, 0x87, 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0x68, 0x63, 0x61, + 0x02, 0x29, 0x21, 0x1D, 0x01, 0x5B, 0x56, 0x52, 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, + 0x0E, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, 0x01, 0x33, 0x33, 0xDC, 0x01, 0x33, 0x34, 0xDC, + 0x01, 0x33, 0x34, 0xDD, 0x03, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x35, 0xDE, 0x01, 0x35, 0x36, 0xDF, + 0x02, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, 0x01, 0x37, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xE0, + 0x01, 0x37, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE1, 0x01, 0x37, 0x35, 0xE0, + 0x02, 0x38, 0x36, 0xE1, 0x01, 0x39, 0x37, 0xE2, 0x01, 0x39, 0x36, 0xE2, 0x01, 0x38, 0x36, 0xE2, + 0x01, 0x39, 0x37, 0xE3, 0x01, 0x3A, 0x37, 0xE3, 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3A, 0x36, 0xE4, + 0x02, 0x3A, 0x37, 0xE4, 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3A, 0x36, 0xE4, 0x01, 0x3C, 0x37, 0xE4, + 0x01, 0x3D, 0x38, 0xE5, 0x01, 0x3C, 0x38, 0xE5, 0x01, 0x3D, 0x38, 0xE6, 0x01, 0x5F, 0x58, 0xE9, + 0x01, 0xD5, 0xD3, 0xF9, 0x10, 0xFF, 0xFF, 0xFF, 0x01, 0xA0, 0x9A, 0xF4, 0x01, 0x42, 0x39, 0xEB, + 0x01, 0x42, 0x3A, 0xEC, 0x02, 0x43, 0x3B, 0xED, 0x01, 0x42, 0x3A, 0xEC, 0x02, 0x43, 0x3B, 0xED, + 0x01, 0x44, 0x3C, 0xED, 0x01, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xEE, + 0x01, 0x44, 0x3B, 0xEE, 0x01, 0x45, 0x3C, 0xEF, 0x01, 0x45, 0x3B, 0xEF, 0x01, 0x46, 0x3C, 0xF0, + 0x01, 0x45, 0x3C, 0xF0, 0x01, 0x45, 0x3B, 0xF0, 0x01, 0x46, 0x3C, 0xF0, 0x03, 0x46, 0x3C, 0xF1, + 0x02, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x02, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF3, + 0x01, 0x48, 0x3C, 0xF2, 0x02, 0x49, 0x3D, 0xF3, 0x02, 0x4A, 0x3D, 0xF4, 0x01, 0x49, 0x3D, 0xF4, + 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, 0x02, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, + 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3E, 0xF6, + 0x01, 0x4C, 0x3F, 0xF7, 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, + 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xF2, 0xF1, 0xF1, 0x03, 0x29, 0x21, 0x1D, 0x01, 0x8C, 0x88, 0x87, + 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0x68, 0x63, 0x61, 0x02, 0x29, 0x21, 0x1D, 0x01, 0x5B, 0x56, 0x52, + 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, 0x0E, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, + 0x01, 0x33, 0x33, 0xDC, 0x01, 0x33, 0x34, 0xDC, 0x01, 0x33, 0x34, 0xDD, 0x03, 0x34, 0x35, 0xDE, + 0x01, 0x35, 0x35, 0xDE, 0x01, 0x35, 0x36, 0xDF, 0x02, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, + 0x01, 0x37, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xE0, + 0x01, 0x38, 0x36, 0xE1, 0x01, 0x37, 0x35, 0xE0, 0x02, 0x38, 0x36, 0xE1, 0x01, 0x39, 0x37, 0xE2, + 0x01, 0x39, 0x36, 0xE2, 0x01, 0x38, 0x36, 0xE2, 0x01, 0x39, 0x37, 0xE3, 0x01, 0x3A, 0x37, 0xE3, + 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3A, 0x36, 0xE4, 0x02, 0x3A, 0x37, 0xE4, 0x01, 0x3C, 0x37, 0xE4, + 0x01, 0x3A, 0x36, 0xE4, 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3D, 0x38, 0xE5, 0x01, 0x3C, 0x38, 0xE5, + 0x02, 0x3D, 0x38, 0xE6, 0x01, 0x3D, 0x39, 0xE7, 0x01, 0x78, 0x72, 0xED, 0x01, 0xBA, 0xB7, 0xF5, + 0x01, 0xE5, 0xE4, 0xFC, 0x02, 0xF7, 0xF6, 0xFE, 0x01, 0xE5, 0xE3, 0xFC, 0x01, 0xBB, 0xB7, 0xF6, + 0x01, 0xB8, 0xB6, 0xF5, 0x09, 0xFF, 0xFF, 0xFF, 0x01, 0xA0, 0x9A, 0xF4, 0x01, 0x42, 0x3A, 0xEC, + 0x02, 0x43, 0x3B, 0xED, 0x01, 0x42, 0x3A, 0xEC, 0x02, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xED, + 0x01, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xEE, 0x01, 0x44, 0x3B, 0xEE, + 0x01, 0x45, 0x3C, 0xEF, 0x01, 0x45, 0x3B, 0xEF, 0x01, 0x46, 0x3C, 0xF0, 0x01, 0x45, 0x3C, 0xF0, + 0x01, 0x45, 0x3B, 0xF0, 0x01, 0x46, 0x3C, 0xF0, 0x03, 0x46, 0x3C, 0xF1, 0x02, 0x48, 0x3C, 0xF2, + 0x01, 0x48, 0x3D, 0xF2, 0x02, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x48, 0x3C, 0xF2, + 0x02, 0x49, 0x3D, 0xF3, 0x02, 0x4A, 0x3D, 0xF4, 0x01, 0x49, 0x3D, 0xF4, 0x01, 0x4A, 0x3E, 0xF5, + 0x01, 0x4B, 0x3F, 0xF6, 0x02, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, + 0x01, 0x4C, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3E, 0xF6, 0x01, 0x4C, 0x3F, 0xF7, + 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x04, 0xFF, 0xFF, 0xFF, + 0x01, 0xF2, 0xF1, 0xF1, 0x03, 0x29, 0x21, 0x1D, 0x01, 0x8C, 0x88, 0x87, 0x04, 0xFF, 0xFF, 0xFF, + 0x01, 0x68, 0x63, 0x61, 0x02, 0x29, 0x21, 0x1D, 0x01, 0x5B, 0x56, 0x52, 0x04, 0xFF, 0xFF, 0xFF, + 0x01, 0xCF, 0xCD, 0xCC, 0x0E, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, 0x01, 0x33, 0x34, 0xDC, + 0x02, 0x33, 0x33, 0xDC, 0x01, 0x34, 0x35, 0xDD, 0x03, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x35, 0xDE, + 0x01, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, 0x02, 0x37, 0x36, 0xDF, + 0x01, 0x37, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xE0, 0x04, 0x38, 0x36, 0xE1, 0x01, 0x39, 0x36, 0xE2, + 0x01, 0x39, 0x37, 0xE2, 0x02, 0x39, 0x36, 0xE2, 0x02, 0x39, 0x36, 0xE3, 0x01, 0x3A, 0x37, 0xE4, + 0x01, 0x3A, 0x36, 0xE4, 0x03, 0x3A, 0x37, 0xE4, 0x01, 0x3C, 0x38, 0xE5, 0x01, 0x3D, 0x39, 0xE6, + 0x03, 0x3C, 0x38, 0xE5, 0x01, 0x3D, 0x38, 0xE6, 0x01, 0x3D, 0x39, 0xE7, 0x02, 0x3D, 0x38, 0xE7, + 0x01, 0x3E, 0x39, 0xE8, 0x01, 0x3E, 0x38, 0xE8, 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x3E, 0x39, 0xE8, + 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x9E, 0x9A, 0xF2, 0x09, 0xFF, 0xFF, 0xFF, 0x01, 0xA0, 0x9A, 0xF5, + 0x01, 0x42, 0x3A, 0xEC, 0x01, 0x42, 0x39, 0xEC, 0x05, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xEE, + 0x01, 0x45, 0x3C, 0xEE, 0x02, 0x44, 0x3B, 0xEE, 0x01, 0x44, 0x3B, 0xEF, 0x01, 0x45, 0x3C, 0xF0, + 0x01, 0x46, 0x3C, 0xF0, 0x02, 0x45, 0x3C, 0xF0, 0x01, 0x46, 0x3C, 0xF0, 0x01, 0x46, 0x3C, 0xF1, + 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x46, 0x3C, 0xF2, 0x03, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, + 0x02, 0x49, 0x3D, 0xF3, 0x02, 0x49, 0x3C, 0xF3, 0x01, 0x49, 0x3D, 0xF4, 0x03, 0x4A, 0x3D, 0xF4, + 0x02, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, 0x04, 0x4B, 0x3E, 0xF6, 0x02, 0x4C, 0x3F, 0xF7, + 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x04, 0xFF, 0xFF, 0xFF, + 0x01, 0xF2, 0xF1, 0xF1, 0x03, 0x29, 0x21, 0x1D, 0x01, 0x8C, 0x88, 0x87, 0x04, 0xFF, 0xFF, 0xFF, + 0x01, 0x68, 0x63, 0x61, 0x02, 0x29, 0x21, 0x1D, 0x01, 0x5B, 0x56, 0x52, 0x04, 0xFF, 0xFF, 0xFF, + 0x01, 0xCF, 0xCD, 0xCC, 0x0E, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, 0x01, 0x33, 0x33, 0xDC, + 0x01, 0x33, 0x34, 0xDC, 0x01, 0x33, 0x34, 0xDD, 0x03, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x35, 0xDE, + 0x01, 0x35, 0x36, 0xDF, 0x02, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, 0x01, 0x37, 0x35, 0xDF, + 0x01, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE1, + 0x01, 0x37, 0x35, 0xE0, 0x02, 0x38, 0x36, 0xE1, 0x01, 0x39, 0x37, 0xE2, 0x01, 0x39, 0x36, 0xE2, + 0x01, 0x38, 0x36, 0xE2, 0x01, 0x39, 0x37, 0xE3, 0x01, 0x3A, 0x37, 0xE3, 0x01, 0x3A, 0x37, 0xE4, + 0x01, 0x3A, 0x36, 0xE4, 0x02, 0x3A, 0x37, 0xE4, 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3A, 0x36, 0xE4, + 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3D, 0x38, 0xE5, 0x01, 0x3C, 0x38, 0xE5, 0x02, 0x3D, 0x38, 0xE6, + 0x01, 0x3D, 0x39, 0xE7, 0x01, 0x3D, 0x38, 0xE7, 0x01, 0x3D, 0x38, 0xE6, 0x03, 0x3E, 0x39, 0xE8, + 0x01, 0x3E, 0x38, 0xE8, 0x03, 0x3F, 0x39, 0xE9, 0x01, 0x9E, 0x9A, 0xF3, 0x09, 0xFF, 0xFF, 0xFF, + 0x01, 0xA0, 0x9A, 0xF5, 0x01, 0x43, 0x3B, 0xED, 0x01, 0x42, 0x3A, 0xEC, 0x02, 0x43, 0x3B, 0xED, + 0x01, 0x44, 0x3C, 0xED, 0x01, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xEE, + 0x01, 0x44, 0x3B, 0xEE, 0x01, 0x45, 0x3C, 0xEF, 0x01, 0x45, 0x3B, 0xEF, 0x01, 0x46, 0x3C, 0xF0, + 0x01, 0x45, 0x3C, 0xF0, 0x01, 0x45, 0x3B, 0xF0, 0x01, 0x46, 0x3C, 0xF0, 0x03, 0x46, 0x3C, 0xF1, + 0x02, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x02, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF3, + 0x01, 0x48, 0x3C, 0xF2, 0x02, 0x49, 0x3D, 0xF3, 0x02, 0x4A, 0x3D, 0xF4, 0x01, 0x49, 0x3D, 0xF4, + 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, 0x02, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, + 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3E, 0xF6, + 0x01, 0x4C, 0x3F, 0xF7, 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, + 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xF2, 0xF1, 0xF1, 0x03, 0x29, 0x21, 0x1D, 0x01, 0x8C, 0x88, 0x87, + 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0x68, 0x63, 0x61, 0x02, 0x29, 0x21, 0x1D, 0x01, 0x5B, 0x56, 0x52, + 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, 0x0E, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, + 0x01, 0x33, 0x34, 0xDC, 0x02, 0x33, 0x33, 0xDC, 0x01, 0x34, 0x35, 0xDD, 0x03, 0x34, 0x35, 0xDE, + 0x01, 0x35, 0x35, 0xDE, 0x01, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, + 0x02, 0x37, 0x36, 0xDF, 0x01, 0x37, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xE0, 0x04, 0x38, 0x36, 0xE1, + 0x01, 0x39, 0x36, 0xE2, 0x01, 0x39, 0x37, 0xE2, 0x02, 0x39, 0x36, 0xE2, 0x02, 0x39, 0x36, 0xE3, + 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3A, 0x36, 0xE4, 0x03, 0x3A, 0x37, 0xE4, 0x01, 0x3C, 0x38, 0xE5, + 0x01, 0x3D, 0x39, 0xE6, 0x03, 0x3C, 0x38, 0xE5, 0x01, 0x3D, 0x38, 0xE6, 0x01, 0x3D, 0x39, 0xE7, + 0x02, 0x3D, 0x38, 0xE7, 0x01, 0x3E, 0x39, 0xE8, 0x01, 0x3E, 0x38, 0xE8, 0x01, 0x3F, 0x39, 0xE9, + 0x01, 0x3E, 0x39, 0xE8, 0x03, 0x3F, 0x39, 0xE9, 0x01, 0x9F, 0x9A, 0xF3, 0x09, 0xFF, 0xFF, 0xFF, + 0x01, 0xA0, 0x9A, 0xF5, 0x05, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xEE, 0x01, 0x45, 0x3C, 0xEE, + 0x02, 0x44, 0x3B, 0xEE, 0x01, 0x44, 0x3B, 0xEF, 0x01, 0x45, 0x3C, 0xF0, 0x01, 0x46, 0x3C, 0xF0, + 0x02, 0x45, 0x3C, 0xF0, 0x01, 0x46, 0x3C, 0xF0, 0x01, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3C, 0xF2, + 0x01, 0x46, 0x3C, 0xF2, 0x03, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x02, 0x49, 0x3D, 0xF3, + 0x02, 0x49, 0x3C, 0xF3, 0x01, 0x49, 0x3D, 0xF4, 0x03, 0x4A, 0x3D, 0xF4, 0x02, 0x4A, 0x3E, 0xF5, + 0x01, 0x4B, 0x3F, 0xF6, 0x04, 0x4B, 0x3E, 0xF6, 0x02, 0x4C, 0x3F, 0xF7, 0x28, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xF2, 0xF1, 0xF1, + 0x03, 0x29, 0x21, 0x1D, 0x01, 0x8C, 0x88, 0x87, 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0x68, 0x63, 0x61, + 0x02, 0x29, 0x21, 0x1D, 0x01, 0x5B, 0x56, 0x52, 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, + 0x0E, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, 0x01, 0x33, 0x34, 0xDC, 0x02, 0x33, 0x33, 0xDC, + 0x01, 0x34, 0x35, 0xDD, 0x03, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x35, 0xDE, 0x01, 0x34, 0x35, 0xDE, + 0x01, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, 0x02, 0x37, 0x36, 0xDF, 0x01, 0x37, 0x35, 0xDF, + 0x01, 0x37, 0x36, 0xE0, 0x04, 0x38, 0x36, 0xE1, 0x01, 0x39, 0x36, 0xE2, 0x01, 0x39, 0x37, 0xE2, + 0x02, 0x39, 0x36, 0xE2, 0x02, 0x39, 0x36, 0xE3, 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3A, 0x36, 0xE4, + 0x03, 0x3A, 0x37, 0xE4, 0x01, 0x3C, 0x38, 0xE5, 0x01, 0x3D, 0x39, 0xE6, 0x03, 0x3C, 0x38, 0xE5, + 0x01, 0x3D, 0x38, 0xE6, 0x01, 0x3D, 0x39, 0xE7, 0x02, 0x3D, 0x38, 0xE7, 0x01, 0x3E, 0x39, 0xE8, + 0x01, 0x3E, 0x38, 0xE8, 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x3E, 0x39, 0xE8, 0x03, 0x3F, 0x39, 0xE9, + 0x01, 0x40, 0x39, 0xE9, 0x01, 0x9F, 0x9A, 0xF4, 0x09, 0xFF, 0xFF, 0xFF, 0x01, 0xA0, 0x9A, 0xF5, + 0x04, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xEE, 0x01, 0x45, 0x3C, 0xEE, 0x02, 0x44, 0x3B, 0xEE, + 0x01, 0x44, 0x3B, 0xEF, 0x01, 0x45, 0x3C, 0xF0, 0x01, 0x46, 0x3C, 0xF0, 0x02, 0x45, 0x3C, 0xF0, + 0x01, 0x46, 0x3C, 0xF0, 0x01, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x46, 0x3C, 0xF2, + 0x03, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x02, 0x49, 0x3D, 0xF3, 0x02, 0x49, 0x3C, 0xF3, + 0x01, 0x49, 0x3D, 0xF4, 0x03, 0x4A, 0x3D, 0xF4, 0x02, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, + 0x04, 0x4B, 0x3E, 0xF6, 0x02, 0x4C, 0x3F, 0xF7, 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x3B, 0x29, 0x21, 0x1D, 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xF2, 0xF1, 0xF1, 0x03, 0x29, 0x21, 0x1D, + 0x01, 0x8C, 0x88, 0x87, 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0x68, 0x63, 0x61, 0x02, 0x29, 0x21, 0x1D, + 0x01, 0x5B, 0x56, 0x52, 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, 0x0E, 0x29, 0x21, 0x1D, + 0x04, 0x27, 0x18, 0xB0, 0x01, 0x33, 0x34, 0xDC, 0x04, 0x34, 0x35, 0xDD, 0x01, 0x35, 0x36, 0xDE, + 0x01, 0x35, 0x35, 0xDE, 0x03, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, + 0x03, 0x37, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE1, 0x01, 0x38, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE2, + 0x01, 0x39, 0x36, 0xE2, 0x02, 0x38, 0x36, 0xE2, 0x01, 0x39, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE3, + 0x01, 0x39, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE3, 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3C, 0x37, 0xE4, + 0x01, 0x3A, 0x36, 0xE4, 0x03, 0x3C, 0x37, 0xE4, 0x02, 0x3C, 0x38, 0xE5, 0x02, 0x3D, 0x39, 0xE6, + 0x02, 0x3D, 0x38, 0xE6, 0x01, 0x3E, 0x39, 0xE7, 0x03, 0x3E, 0x39, 0xE8, 0x01, 0x3E, 0x39, 0xE9, + 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x3E, 0x38, 0xE9, 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x39, 0xE9, + 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x39, 0xEA, 0x01, 0x9F, 0x9A, 0xF4, 0x09, 0xFF, 0xFF, 0xFF, + 0x01, 0xA1, 0x9B, 0xF6, 0x01, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xEE, + 0x01, 0x44, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xEE, 0x01, 0x44, 0x3B, 0xEE, 0x03, 0x45, 0x3C, 0xEF, + 0x01, 0x45, 0x3B, 0xEF, 0x02, 0x46, 0x3C, 0xF0, 0x02, 0x46, 0x3C, 0xF1, 0x01, 0x46, 0x3C, 0xF2, + 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x46, 0x3C, 0xF2, 0x02, 0x48, 0x3D, 0xF2, 0x01, 0x48, 0x3C, 0xF2, + 0x02, 0x49, 0x3D, 0xF3, 0x04, 0x49, 0x3D, 0xF4, 0x04, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3E, 0xF6, + 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4C, 0x3F, 0xF7, + 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3F, 0xF7, 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x3B, 0x29, 0x21, 0x1D, 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xF2, 0xF1, 0xF1, 0x03, 0x29, 0x21, 0x1D, + 0x01, 0x74, 0x70, 0x6E, 0x03, 0xE4, 0xE3, 0xE3, 0x01, 0xE3, 0xE2, 0xE2, 0x01, 0x55, 0x4F, 0x4D, + 0x02, 0x29, 0x21, 0x1D, 0x01, 0x5B, 0x56, 0x52, 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, + 0x0E, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, 0x01, 0x33, 0x34, 0xDC, 0x02, 0x33, 0x33, 0xDC, + 0x01, 0x34, 0x35, 0xDD, 0x03, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x35, 0xDE, 0x01, 0x34, 0x35, 0xDE, + 0x01, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, 0x02, 0x37, 0x36, 0xDF, 0x01, 0x37, 0x35, 0xDF, + 0x01, 0x37, 0x36, 0xE0, 0x04, 0x38, 0x36, 0xE1, 0x01, 0x39, 0x36, 0xE2, 0x01, 0x39, 0x37, 0xE2, + 0x02, 0x39, 0x36, 0xE2, 0x02, 0x39, 0x36, 0xE3, 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3A, 0x36, 0xE4, + 0x03, 0x3A, 0x37, 0xE4, 0x01, 0x3C, 0x38, 0xE5, 0x01, 0x3D, 0x39, 0xE6, 0x03, 0x3C, 0x38, 0xE5, + 0x01, 0x3D, 0x38, 0xE6, 0x01, 0x3D, 0x39, 0xE7, 0x02, 0x3D, 0x38, 0xE7, 0x01, 0x3E, 0x39, 0xE8, + 0x01, 0x3E, 0x38, 0xE8, 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x3E, 0x39, 0xE8, 0x03, 0x3F, 0x39, 0xE9, + 0x01, 0x40, 0x39, 0xE9, 0x01, 0x40, 0x3A, 0xEA, 0x01, 0x40, 0x39, 0xEA, 0x01, 0x9F, 0x9A, 0xF4, + 0x09, 0xFF, 0xFF, 0xFF, 0x01, 0xA0, 0x9A, 0xF6, 0x02, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xEE, + 0x01, 0x45, 0x3C, 0xEE, 0x02, 0x44, 0x3B, 0xEE, 0x01, 0x44, 0x3B, 0xEF, 0x01, 0x45, 0x3C, 0xF0, + 0x01, 0x46, 0x3C, 0xF0, 0x02, 0x45, 0x3C, 0xF0, 0x01, 0x46, 0x3C, 0xF0, 0x01, 0x46, 0x3C, 0xF1, + 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x46, 0x3C, 0xF2, 0x03, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, + 0x02, 0x49, 0x3D, 0xF3, 0x02, 0x49, 0x3C, 0xF3, 0x01, 0x49, 0x3D, 0xF4, 0x03, 0x4A, 0x3D, 0xF4, + 0x02, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, 0x04, 0x4B, 0x3E, 0xF6, 0x02, 0x4C, 0x3F, 0xF7, + 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x01, 0x7F, 0x7B, 0x79, + 0x03, 0x88, 0x85, 0x83, 0x01, 0x79, 0x75, 0x73, 0x0B, 0x29, 0x21, 0x1D, 0x01, 0x33, 0x2C, 0x28, + 0x01, 0x88, 0x84, 0x82, 0x03, 0x88, 0x85, 0x83, 0x01, 0x68, 0x63, 0x61, 0x0E, 0x29, 0x21, 0x1D, + 0x04, 0x27, 0x18, 0xB0, 0x01, 0x33, 0x34, 0xDC, 0x04, 0x34, 0x35, 0xDD, 0x01, 0x35, 0x36, 0xDE, + 0x01, 0x35, 0x35, 0xDE, 0x03, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, + 0x03, 0x37, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE1, 0x01, 0x38, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE2, + 0x01, 0x39, 0x36, 0xE2, 0x02, 0x38, 0x36, 0xE2, 0x01, 0x39, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE3, + 0x01, 0x39, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE3, 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3C, 0x37, 0xE4, + 0x01, 0x3A, 0x36, 0xE4, 0x03, 0x3C, 0x37, 0xE4, 0x02, 0x3C, 0x38, 0xE5, 0x02, 0x3D, 0x39, 0xE6, + 0x02, 0x3D, 0x38, 0xE6, 0x01, 0x3E, 0x39, 0xE7, 0x03, 0x3E, 0x39, 0xE8, 0x01, 0x3E, 0x39, 0xE9, + 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x3E, 0x38, 0xE9, 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x39, 0xE9, + 0x01, 0x3F, 0x39, 0xE9, 0x02, 0x40, 0x39, 0xEA, 0x01, 0x40, 0x3A, 0xEA, 0x01, 0xA0, 0x9A, 0xF4, + 0x09, 0xFF, 0xFF, 0xFF, 0x01, 0xA1, 0x9A, 0xF6, 0x01, 0x44, 0x3C, 0xEE, 0x01, 0x44, 0x3B, 0xED, + 0x01, 0x44, 0x3C, 0xEE, 0x01, 0x44, 0x3B, 0xEE, 0x03, 0x45, 0x3C, 0xEF, 0x01, 0x45, 0x3B, 0xEF, + 0x02, 0x46, 0x3C, 0xF0, 0x02, 0x46, 0x3C, 0xF1, 0x01, 0x46, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, + 0x01, 0x46, 0x3C, 0xF2, 0x02, 0x48, 0x3D, 0xF2, 0x01, 0x48, 0x3C, 0xF2, 0x02, 0x49, 0x3D, 0xF3, + 0x04, 0x49, 0x3D, 0xF4, 0x04, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4B, 0x3F, 0xF6, + 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4C, 0x3F, 0xF7, 0x01, 0x4B, 0x3E, 0xF6, + 0x01, 0x4C, 0x3F, 0xF7, 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x5F, 0x29, 0x21, 0x1D, + 0x04, 0x27, 0x18, 0xB0, 0x01, 0x33, 0x34, 0xDC, 0x04, 0x34, 0x35, 0xDD, 0x01, 0x35, 0x36, 0xDE, + 0x01, 0x35, 0x35, 0xDE, 0x03, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, + 0x03, 0x37, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE1, 0x01, 0x38, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE2, + 0x01, 0x39, 0x36, 0xE2, 0x02, 0x38, 0x36, 0xE2, 0x01, 0x39, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE3, + 0x01, 0x39, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE3, 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3C, 0x37, 0xE4, + 0x01, 0x3A, 0x36, 0xE4, 0x03, 0x3C, 0x37, 0xE4, 0x02, 0x3C, 0x38, 0xE5, 0x02, 0x3D, 0x39, 0xE6, + 0x02, 0x3D, 0x38, 0xE6, 0x01, 0x3E, 0x39, 0xE7, 0x03, 0x3E, 0x39, 0xE8, 0x01, 0x3E, 0x39, 0xE9, + 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x3E, 0x38, 0xE9, 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x39, 0xE9, + 0x01, 0x3F, 0x39, 0xE9, 0x02, 0x40, 0x39, 0xEA, 0x01, 0x40, 0x3A, 0xEA, 0x01, 0x42, 0x3A, 0xEB, + 0x01, 0xA0, 0x9A, 0xF4, 0x09, 0xFF, 0xFF, 0xFF, 0x01, 0xA1, 0x9B, 0xF6, 0x01, 0x44, 0x3B, 0xED, + 0x01, 0x44, 0x3C, 0xEE, 0x01, 0x44, 0x3B, 0xEE, 0x03, 0x45, 0x3C, 0xEF, 0x01, 0x45, 0x3B, 0xEF, + 0x02, 0x46, 0x3C, 0xF0, 0x02, 0x46, 0x3C, 0xF1, 0x01, 0x46, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, + 0x01, 0x46, 0x3C, 0xF2, 0x02, 0x48, 0x3D, 0xF2, 0x01, 0x48, 0x3C, 0xF2, 0x02, 0x49, 0x3D, 0xF3, + 0x04, 0x49, 0x3D, 0xF4, 0x04, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4B, 0x3F, 0xF6, + 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4C, 0x3F, 0xF7, 0x01, 0x4B, 0x3E, 0xF6, + 0x01, 0x4C, 0x3F, 0xF7, 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x5F, 0x29, 0x21, 0x1D, + 0x04, 0x27, 0x18, 0xB0, 0x01, 0x33, 0x34, 0xDC, 0x01, 0x33, 0x33, 0xDC, 0x02, 0x34, 0x35, 0xDD, + 0x03, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x35, 0x36, 0xDF, + 0x01, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x35, 0xDF, 0x03, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xE0, + 0x02, 0x38, 0x36, 0xE1, 0x02, 0x38, 0x36, 0xE2, 0x01, 0x76, 0x72, 0xEA, 0x01, 0xB9, 0xB7, 0xF4, + 0x01, 0xE4, 0xE3, 0xFB, 0x02, 0xF7, 0xF6, 0xFE, 0x01, 0xE4, 0xE3, 0xFB, 0x01, 0xB9, 0xB7, 0xF4, + 0x01, 0x77, 0x72, 0xEB, 0x03, 0x3C, 0x37, 0xE4, 0x01, 0x3C, 0x38, 0xE5, 0x01, 0x3D, 0x38, 0xE6, + 0x01, 0x3C, 0x38, 0xE5, 0x02, 0x3D, 0x38, 0xE6, 0x01, 0x3E, 0x39, 0xE7, 0x01, 0x3D, 0x38, 0xE7, + 0x01, 0x3E, 0x38, 0xE7, 0x02, 0x3E, 0x39, 0xE8, 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x3E, 0x38, 0xE8, + 0x03, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x39, 0xE9, 0x01, 0x3F, 0x39, 0xE9, 0x03, 0x40, 0x39, 0xEA, + 0x01, 0x40, 0x39, 0xEB, 0x01, 0xA0, 0x9A, 0xF5, 0x09, 0xFF, 0xFF, 0xFF, 0x01, 0xBB, 0xB6, 0xF8, + 0x01, 0xBC, 0xB8, 0xF8, 0x01, 0xE6, 0xE4, 0xFC, 0x02, 0xF7, 0xF6, 0xFE, 0x01, 0xE6, 0xE4, 0xFC, + 0x01, 0xBD, 0xB8, 0xF9, 0x01, 0x7D, 0x74, 0xF4, 0x01, 0x45, 0x3C, 0xF0, 0x02, 0x46, 0x3C, 0xF1, + 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, + 0x03, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF3, 0x02, 0x49, 0x3D, 0xF3, + 0x02, 0x4A, 0x3D, 0xF4, 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4A, 0x3E, 0xF5, + 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4A, 0x3E, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3F, 0xF6, + 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3F, 0xF7, 0x01, 0x4B, 0x3E, 0xF6, 0x28, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x4B, 0x29, 0x21, 0x1D, 0x01, 0x3F, 0x39, 0x35, 0x01, 0xB8, 0xB6, 0xB5, + 0x03, 0xB8, 0xB7, 0xB6, 0x01, 0x8F, 0x8B, 0x89, 0x0E, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, + 0x01, 0x33, 0x34, 0xDC, 0x04, 0x34, 0x35, 0xDD, 0x01, 0x35, 0x36, 0xDE, 0x01, 0x35, 0x35, 0xDE, + 0x03, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, 0x03, 0x37, 0x36, 0xE0, + 0x01, 0x38, 0x36, 0xE1, 0x01, 0x38, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE2, 0x01, 0x5C, 0x57, 0xE6, + 0x01, 0xD4, 0xD2, 0xF8, 0x08, 0xFF, 0xFF, 0xFF, 0x01, 0xD5, 0xD2, 0xF9, 0x01, 0x5E, 0x58, 0xE8, + 0x01, 0x3C, 0x37, 0xE4, 0x02, 0x3C, 0x38, 0xE5, 0x02, 0x3D, 0x39, 0xE6, 0x02, 0x3D, 0x38, 0xE6, + 0x01, 0x3E, 0x39, 0xE7, 0x03, 0x3E, 0x39, 0xE8, 0x01, 0x3E, 0x39, 0xE9, 0x01, 0x3F, 0x39, 0xE9, + 0x01, 0x3E, 0x38, 0xE9, 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x39, 0xE9, 0x01, 0x3F, 0x39, 0xE9, + 0x02, 0x40, 0x39, 0xEA, 0x01, 0x40, 0x3A, 0xEA, 0x01, 0x42, 0x3A, 0xEB, 0x02, 0x42, 0x39, 0xEB, + 0x01, 0xA0, 0x9A, 0xF5, 0x10, 0xFF, 0xFF, 0xFF, 0x01, 0xD6, 0xD3, 0xFB, 0x01, 0x67, 0x5B, 0xF3, + 0x01, 0x46, 0x3C, 0xF1, 0x01, 0x46, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x46, 0x3C, 0xF2, + 0x02, 0x48, 0x3D, 0xF2, 0x01, 0x48, 0x3C, 0xF2, 0x02, 0x49, 0x3D, 0xF3, 0x04, 0x49, 0x3D, 0xF4, + 0x04, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, + 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4C, 0x3F, 0xF7, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3F, 0xF7, + 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x4B, 0x29, 0x21, 0x1D, 0x01, 0x5B, 0x56, 0x52, + 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, 0x0E, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, + 0x01, 0x33, 0x34, 0xDC, 0x01, 0x33, 0x33, 0xDC, 0x02, 0x34, 0x35, 0xDD, 0x03, 0x34, 0x35, 0xDE, + 0x01, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, + 0x01, 0x37, 0x35, 0xDF, 0x03, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xE0, 0x01, 0x38, 0x36, 0xE1, + 0x01, 0x70, 0x6C, 0xE8, 0x01, 0xF3, 0xF3, 0xFD, 0x0A, 0xFF, 0xFF, 0xFF, 0x01, 0xF4, 0xF3, 0xFD, + 0x01, 0x72, 0x6D, 0xEB, 0x01, 0x3C, 0x38, 0xE5, 0x01, 0x3D, 0x38, 0xE6, 0x01, 0x3C, 0x38, 0xE5, + 0x02, 0x3D, 0x38, 0xE6, 0x01, 0x3E, 0x39, 0xE7, 0x01, 0x3D, 0x38, 0xE7, 0x01, 0x3E, 0x38, 0xE7, + 0x02, 0x3E, 0x39, 0xE8, 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x3E, 0x38, 0xE8, 0x03, 0x3F, 0x39, 0xE9, + 0x01, 0x40, 0x39, 0xE9, 0x01, 0x3F, 0x39, 0xE9, 0x03, 0x40, 0x39, 0xEA, 0x01, 0x40, 0x39, 0xEB, + 0x02, 0x42, 0x3A, 0xEC, 0x01, 0xA0, 0x9A, 0xF5, 0x10, 0xFF, 0xFF, 0xFF, 0x01, 0xF4, 0xF3, 0xFE, + 0x01, 0x79, 0x6F, 0xF4, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3C, 0xF2, + 0x01, 0x48, 0x3D, 0xF2, 0x03, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF3, + 0x02, 0x49, 0x3D, 0xF3, 0x02, 0x4A, 0x3D, 0xF4, 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, + 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4A, 0x3E, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, + 0x01, 0x4C, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3F, 0xF7, 0x01, 0x4B, 0x3E, 0xF6, + 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x4B, 0x29, 0x21, 0x1D, 0x01, 0x5B, 0x56, 0x52, + 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, 0x0E, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, + 0x01, 0x33, 0x34, 0xDC, 0x01, 0x33, 0x33, 0xDC, 0x02, 0x34, 0x35, 0xDD, 0x03, 0x34, 0x35, 0xDE, + 0x01, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, + 0x01, 0x37, 0x35, 0xDF, 0x03, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xE0, 0x01, 0x5B, 0x57, 0xE5, + 0x01, 0xF3, 0xF3, 0xFD, 0x0C, 0xFF, 0xFF, 0xFF, 0x01, 0xF4, 0xF3, 0xFD, 0x01, 0x5E, 0x58, 0xE9, + 0x01, 0x3D, 0x38, 0xE6, 0x01, 0x3C, 0x38, 0xE5, 0x02, 0x3D, 0x38, 0xE6, 0x01, 0x3E, 0x39, 0xE7, + 0x01, 0x3D, 0x38, 0xE7, 0x01, 0x3E, 0x38, 0xE7, 0x02, 0x3E, 0x39, 0xE8, 0x01, 0x3F, 0x39, 0xE9, + 0x01, 0x3E, 0x38, 0xE8, 0x03, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x39, 0xE9, 0x01, 0x3F, 0x39, 0xE9, + 0x03, 0x40, 0x39, 0xEA, 0x01, 0x40, 0x39, 0xEB, 0x02, 0x42, 0x3A, 0xEC, 0x01, 0x42, 0x39, 0xEC, + 0x01, 0xA0, 0x9A, 0xF5, 0x10, 0xFF, 0xFF, 0xFF, 0x01, 0xF4, 0xF3, 0xFE, 0x01, 0x67, 0x5B, 0xF3, + 0x01, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x03, 0x48, 0x3C, 0xF2, + 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF3, 0x02, 0x49, 0x3D, 0xF3, 0x02, 0x4A, 0x3D, 0xF4, + 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, + 0x01, 0x4A, 0x3E, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, + 0x01, 0x4C, 0x3F, 0xF7, 0x01, 0x4B, 0x3E, 0xF6, 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x4B, 0x29, 0x21, 0x1D, 0x01, 0x5B, 0x56, 0x52, 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, + 0x0E, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, 0x01, 0x33, 0x33, 0xDC, 0x01, 0x33, 0x34, 0xDC, + 0x03, 0x34, 0x35, 0xDD, 0x02, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x34, 0x35, 0xDE, + 0x01, 0x35, 0x35, 0xDF, 0x03, 0x37, 0x36, 0xDF, 0x01, 0x37, 0x35, 0xDF, 0x02, 0x38, 0x36, 0xE0, + 0x01, 0xD4, 0xD2, 0xF7, 0x0E, 0xFF, 0xFF, 0xFF, 0x01, 0xD5, 0xD2, 0xF9, 0x02, 0x3C, 0x38, 0xE5, + 0x01, 0x3D, 0x39, 0xE6, 0x02, 0x3D, 0x38, 0xE6, 0x01, 0x3E, 0x39, 0xE7, 0x01, 0x3D, 0x38, 0xE7, + 0x01, 0x3E, 0x39, 0xE8, 0x02, 0x3E, 0x38, 0xE8, 0x04, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x3A, 0xEA, + 0x01, 0x40, 0x39, 0xEA, 0x01, 0x40, 0x39, 0xE9, 0x01, 0x40, 0x39, 0xEA, 0x02, 0x42, 0x3A, 0xEB, + 0x01, 0x40, 0x39, 0xEB, 0x01, 0x42, 0x3A, 0xEC, 0x01, 0x42, 0x39, 0xEC, 0x01, 0x43, 0x3A, 0xEC, + 0x01, 0xA0, 0x9A, 0xF5, 0x10, 0xFF, 0xFF, 0xFF, 0x01, 0xD6, 0xD3, 0xFB, 0x01, 0x48, 0x3C, 0xF2, + 0x01, 0x48, 0x3D, 0xF2, 0x02, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF2, 0x01, 0x49, 0x3D, 0xF3, + 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF3, 0x02, 0x49, 0x3D, 0xF4, 0x01, 0x49, 0x3C, 0xF4, + 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3E, 0xF5, 0x02, 0x4A, 0x3E, 0xF5, + 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4B, 0x3F, 0xF6, 0x02, 0x4B, 0x3E, 0xF6, 0x02, 0x4C, 0x3F, 0xF7, + 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x4B, 0x29, 0x21, 0x1D, 0x01, 0x5B, 0x56, 0x52, + 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, 0x0E, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, + 0x01, 0x33, 0x34, 0xDC, 0x01, 0x33, 0x33, 0xDC, 0x02, 0x34, 0x35, 0xDD, 0x03, 0x34, 0x35, 0xDE, + 0x01, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, + 0x01, 0x37, 0x35, 0xDF, 0x03, 0x37, 0x36, 0xE0, 0x01, 0x74, 0x71, 0xE8, 0x10, 0xFF, 0xFF, 0xFF, + 0x01, 0xBF, 0xBC, 0xF6, 0x01, 0xA7, 0xA3, 0xF2, 0x02, 0xA7, 0xA3, 0xF3, 0x01, 0xA7, 0xA4, 0xF3, + 0x02, 0xA7, 0xA3, 0xF3, 0x02, 0xA7, 0xA4, 0xF4, 0x01, 0xA8, 0xA4, 0xF4, 0x01, 0xA7, 0xA3, 0xF4, + 0x01, 0xA8, 0xA4, 0xF4, 0x08, 0xA8, 0xA4, 0xF5, 0x03, 0xA9, 0xA4, 0xF5, 0x01, 0xA9, 0xA4, 0xF6, + 0x01, 0xA9, 0xA4, 0xF5, 0x01, 0xED, 0xEB, 0xFD, 0x10, 0xFF, 0xFF, 0xFF, 0x01, 0x7E, 0x74, 0xF4, + 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x03, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF3, + 0x01, 0x49, 0x3C, 0xF3, 0x02, 0x49, 0x3D, 0xF3, 0x02, 0x4A, 0x3D, 0xF4, 0x01, 0x4A, 0x3E, 0xF5, + 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4A, 0x3E, 0xF6, + 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3F, 0xF7, + 0x01, 0x4B, 0x3E, 0xF6, 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x4B, 0x29, 0x21, 0x1D, + 0x01, 0x5B, 0x56, 0x52, 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, 0x0E, 0x29, 0x21, 0x1D, + 0x04, 0x27, 0x18, 0xB0, 0x01, 0x33, 0x33, 0xDC, 0x01, 0x33, 0x34, 0xDC, 0x03, 0x34, 0x35, 0xDD, + 0x02, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x35, 0xDF, + 0x03, 0x37, 0x36, 0xDF, 0x01, 0x37, 0x35, 0xDF, 0x01, 0x38, 0x36, 0xE0, 0x01, 0xB9, 0xB7, 0xF3, + 0x3A, 0xFF, 0xFF, 0xFF, 0x01, 0xBE, 0xB8, 0xFA, 0x01, 0x48, 0x3D, 0xF2, 0x02, 0x48, 0x3C, 0xF2, + 0x01, 0x49, 0x3D, 0xF2, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF3, + 0x02, 0x49, 0x3D, 0xF4, 0x01, 0x49, 0x3C, 0xF4, 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x4A, 0x3E, 0xF5, + 0x01, 0x4B, 0x3E, 0xF5, 0x02, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4B, 0x3F, 0xF6, + 0x02, 0x4B, 0x3E, 0xF6, 0x02, 0x4C, 0x3F, 0xF7, 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x3B, 0x29, 0x21, 0x1D, 0x01, 0xD2, 0xD1, 0xD0, 0x0F, 0xDB, 0xDA, 0xDA, 0x01, 0xE9, 0xE9, 0xE8, + 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, 0x0E, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, + 0x01, 0x33, 0x33, 0xDC, 0x01, 0x33, 0x34, 0xDC, 0x03, 0x34, 0x35, 0xDD, 0x02, 0x34, 0x35, 0xDE, + 0x01, 0x35, 0x35, 0xDF, 0x01, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x35, 0xDF, 0x03, 0x37, 0x36, 0xDF, + 0x01, 0x37, 0x35, 0xDF, 0x01, 0x38, 0x36, 0xE0, 0x01, 0xE4, 0xE3, 0xFA, 0x3A, 0xFF, 0xFF, 0xFF, + 0x01, 0xE6, 0xE4, 0xFC, 0x01, 0x48, 0x3D, 0xF2, 0x02, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF2, + 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF3, 0x02, 0x49, 0x3D, 0xF4, + 0x01, 0x49, 0x3C, 0xF4, 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3E, 0xF5, + 0x02, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4B, 0x3F, 0xF6, 0x02, 0x4B, 0x3E, 0xF6, + 0x02, 0x4C, 0x3F, 0xF7, 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, + 0x15, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, 0x0E, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, + 0x01, 0x34, 0x35, 0xDD, 0x01, 0x33, 0x34, 0xDD, 0x01, 0x33, 0x34, 0xDC, 0x03, 0x34, 0x35, 0xDE, + 0x01, 0x35, 0x35, 0xDF, 0x01, 0x35, 0x35, 0xDE, 0x02, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, + 0x01, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xDF, 0x01, 0x38, 0x36, 0xE0, + 0x01, 0xF6, 0xF6, 0xFE, 0x3A, 0xFF, 0xFF, 0xFF, 0x01, 0xF7, 0xF6, 0xFE, 0x01, 0x46, 0x3C, 0xF2, + 0x02, 0x48, 0x3C, 0xF2, 0x02, 0x49, 0x3D, 0xF2, 0x03, 0x49, 0x3D, 0xF3, 0x03, 0x4A, 0x3D, 0xF4, + 0x03, 0x4A, 0x3E, 0xF5, 0x01, 0x4A, 0x3E, 0xF6, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, + 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, 0x02, 0x4C, 0x3F, 0xF7, 0x28, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x15, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, + 0x0E, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, 0x01, 0x33, 0x33, 0xDC, 0x01, 0x33, 0x34, 0xDC, + 0x03, 0x34, 0x35, 0xDD, 0x02, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x34, 0x35, 0xDE, + 0x01, 0x35, 0x35, 0xDF, 0x03, 0x37, 0x36, 0xDF, 0x01, 0x37, 0x35, 0xDF, 0x01, 0x38, 0x36, 0xE0, + 0x01, 0xF7, 0xF6, 0xFE, 0x3A, 0xFF, 0xFF, 0xFF, 0x01, 0xF7, 0xF6, 0xFE, 0x01, 0x48, 0x3D, 0xF2, + 0x02, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF2, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x48, 0x3C, 0xF2, + 0x01, 0x49, 0x3D, 0xF3, 0x02, 0x49, 0x3D, 0xF4, 0x01, 0x49, 0x3C, 0xF4, 0x01, 0x4A, 0x3D, 0xF4, + 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3E, 0xF5, 0x02, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3E, 0xF6, + 0x01, 0x4B, 0x3F, 0xF6, 0x02, 0x4B, 0x3E, 0xF6, 0x02, 0x4C, 0x3F, 0xF7, 0x28, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x15, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, + 0x0E, 0x29, 0x21, 0x1D, 0x04, 0x27, 0x18, 0xB0, 0x01, 0x34, 0x35, 0xDD, 0x01, 0x33, 0x34, 0xDD, + 0x01, 0x33, 0x34, 0xDC, 0x03, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x35, 0x35, 0xDE, + 0x02, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xE0, + 0x01, 0x37, 0x35, 0xDF, 0x01, 0x38, 0x36, 0xE0, 0x01, 0xE4, 0xE3, 0xFA, 0x3A, 0xFF, 0xFF, 0xFF, + 0x01, 0xE6, 0xE4, 0xFC, 0x01, 0x46, 0x3C, 0xF2, 0x02, 0x48, 0x3C, 0xF2, 0x02, 0x49, 0x3D, 0xF2, + 0x03, 0x49, 0x3D, 0xF3, 0x03, 0x4A, 0x3D, 0xF4, 0x03, 0x4A, 0x3E, 0xF5, 0x01, 0x4A, 0x3E, 0xF6, + 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, + 0x02, 0x4C, 0x3F, 0xF7, 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, + 0x15, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, 0x0E, 0x29, 0x21, 0x1D, 0x01, 0x27, 0x17, 0xAD, + 0x03, 0x27, 0x18, 0xB0, 0x01, 0x34, 0x33, 0xDC, 0x01, 0x33, 0x34, 0xDD, 0x01, 0x33, 0x34, 0xDC, + 0x03, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x35, 0x35, 0xDE, 0x02, 0x35, 0x35, 0xDF, + 0x01, 0x37, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xDF, + 0x01, 0x38, 0x36, 0xE0, 0x01, 0xB8, 0xB6, 0xF3, 0x3A, 0xFF, 0xFF, 0xFF, 0x01, 0xBE, 0xB9, 0xFA, + 0x01, 0x46, 0x3C, 0xF2, 0x02, 0x48, 0x3C, 0xF2, 0x02, 0x49, 0x3D, 0xF2, 0x03, 0x49, 0x3D, 0xF3, + 0x03, 0x4A, 0x3D, 0xF4, 0x03, 0x4A, 0x3E, 0xF5, 0x01, 0x4A, 0x3E, 0xF6, 0x01, 0x4B, 0x3F, 0xF6, + 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3F, 0xF7, + 0x01, 0x4C, 0x3E, 0xF6, 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, + 0x01, 0xFE, 0xFE, 0xFE, 0x14, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, 0x0E, 0x29, 0x21, 0x1D, + 0x01, 0x26, 0x17, 0xA7, 0x03, 0x27, 0x18, 0xB0, 0x01, 0x32, 0x31, 0xD9, 0x01, 0x33, 0x34, 0xDC, + 0x01, 0x33, 0x33, 0xDC, 0x02, 0x34, 0x35, 0xDD, 0x01, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x36, 0xDF, + 0x01, 0x34, 0x35, 0xDE, 0x02, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, + 0x01, 0x37, 0x35, 0xDF, 0x02, 0x37, 0x36, 0xE0, 0x01, 0x75, 0x71, 0xE9, 0x10, 0xFF, 0xFF, 0xFF, + 0x01, 0xBE, 0xBC, 0xF5, 0x05, 0xA7, 0xA3, 0xF3, 0x01, 0xA7, 0xA4, 0xF4, 0x01, 0xA7, 0xA3, 0xF3, + 0x02, 0xA8, 0xA4, 0xF4, 0x01, 0xA7, 0xA4, 0xF4, 0x02, 0xA8, 0xA4, 0xF4, 0x06, 0xA8, 0xA4, 0xF5, + 0x01, 0xA9, 0xA4, 0xF5, 0x01, 0xA8, 0xA4, 0xF5, 0x03, 0xA9, 0xA4, 0xF5, 0x01, 0xA9, 0xA4, 0xF6, + 0x01, 0xC0, 0xBD, 0xF8, 0x10, 0xFF, 0xFF, 0xFF, 0x01, 0x7E, 0x74, 0xF4, 0x02, 0x48, 0x3C, 0xF2, + 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x48, 0x3C, 0xF2, + 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF3, 0x02, 0x49, 0x3D, 0xF4, 0x01, 0x4A, 0x3D, 0xF4, + 0x01, 0x4B, 0x3F, 0xF5, 0x01, 0x4A, 0x3E, 0xF5, 0x02, 0x4B, 0x3F, 0xF6, 0x01, 0x4A, 0x3E, 0xF6, + 0x02, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4A, 0x3B, 0xF2, + 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x01, 0x4E, 0x48, 0x45, + 0x0F, 0x58, 0x53, 0x50, 0x01, 0x83, 0x7F, 0x7D, 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, + 0x0E, 0x29, 0x21, 0x1D, 0x01, 0x27, 0x16, 0x9C, 0x03, 0x27, 0x18, 0xB0, 0x01, 0x33, 0x2F, 0xD6, + 0x01, 0x33, 0x34, 0xDD, 0x01, 0x33, 0x34, 0xDC, 0x03, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x35, 0xDF, + 0x01, 0x35, 0x35, 0xDE, 0x02, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, + 0x01, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xDF, 0x01, 0x38, 0x36, 0xE0, 0x01, 0x37, 0x36, 0xE0, + 0x01, 0xD4, 0xD2, 0xF8, 0x0E, 0xFF, 0xFF, 0xFF, 0x01, 0xD5, 0xD2, 0xF9, 0x01, 0x3D, 0x39, 0xE6, + 0x02, 0x3D, 0x38, 0xE6, 0x02, 0x3D, 0x39, 0xE7, 0x01, 0x3D, 0x38, 0xE7, 0x04, 0x3E, 0x39, 0xE8, + 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x3E, 0x38, 0xE9, 0x02, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x3A, 0xEA, + 0x01, 0x40, 0x39, 0xE9, 0x02, 0x40, 0x3A, 0xEA, 0x01, 0x40, 0x39, 0xEA, 0x01, 0x42, 0x3A, 0xEB, + 0x01, 0x42, 0x3A, 0xEC, 0x01, 0x42, 0x3A, 0xEB, 0x01, 0x43, 0x3A, 0xEC, 0x01, 0x42, 0x3A, 0xEC, + 0x02, 0x43, 0x3B, 0xED, 0x01, 0xD6, 0xD3, 0xFA, 0x0E, 0xFF, 0xFF, 0xFF, 0x01, 0xD6, 0xD3, 0xFB, + 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x46, 0x3C, 0xF2, 0x02, 0x48, 0x3C, 0xF2, 0x02, 0x49, 0x3D, 0xF2, + 0x03, 0x49, 0x3D, 0xF3, 0x03, 0x4A, 0x3D, 0xF4, 0x03, 0x4A, 0x3E, 0xF5, 0x01, 0x4A, 0x3E, 0xF6, + 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, + 0x01, 0x4C, 0x3F, 0xF7, 0x01, 0x48, 0x39, 0xEA, 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x4B, 0x29, 0x21, 0x1D, 0x01, 0x5B, 0x56, 0x52, 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, + 0x0E, 0x29, 0x21, 0x1D, 0x01, 0x26, 0x15, 0x8A, 0x03, 0x27, 0x18, 0xB0, 0x01, 0x2F, 0x29, 0xCF, + 0x01, 0x33, 0x34, 0xDC, 0x01, 0x33, 0x33, 0xDC, 0x02, 0x34, 0x35, 0xDD, 0x01, 0x34, 0x35, 0xDE, + 0x01, 0x35, 0x36, 0xDF, 0x01, 0x34, 0x35, 0xDE, 0x02, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, + 0x01, 0x37, 0x36, 0xDF, 0x01, 0x37, 0x35, 0xDF, 0x02, 0x37, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE1, + 0x01, 0x5A, 0x57, 0xE4, 0x01, 0xF3, 0xF3, 0xFD, 0x0C, 0xFF, 0xFF, 0xFF, 0x01, 0xF4, 0xF3, 0xFD, + 0x01, 0x5F, 0x58, 0xE9, 0x01, 0x3C, 0x38, 0xE5, 0x01, 0x3D, 0x38, 0xE6, 0x01, 0x3C, 0x38, 0xE6, + 0x02, 0x3D, 0x38, 0xE6, 0x01, 0x3D, 0x38, 0xE7, 0x01, 0x3E, 0x39, 0xE8, 0x01, 0x3E, 0x38, 0xE7, + 0x01, 0x3F, 0x39, 0xE8, 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x3E, 0x39, 0xE8, 0x02, 0x3F, 0x39, 0xE9, + 0x01, 0x40, 0x39, 0xE9, 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x3A, 0xEA, 0x01, 0x40, 0x39, 0xE9, + 0x02, 0x40, 0x39, 0xEA, 0x01, 0x42, 0x3A, 0xEB, 0x01, 0x40, 0x39, 0xEB, 0x01, 0x42, 0x3A, 0xEC, + 0x01, 0x43, 0x3A, 0xEC, 0x01, 0x42, 0x39, 0xEC, 0x02, 0x43, 0x3B, 0xED, 0x01, 0x63, 0x5B, 0xEF, + 0x01, 0xF4, 0xF3, 0xFE, 0x0C, 0xFF, 0xFF, 0xFF, 0x01, 0xF4, 0xF3, 0xFE, 0x01, 0x67, 0x5B, 0xF3, + 0x01, 0x46, 0x3C, 0xF1, 0x02, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x48, 0x3C, 0xF2, + 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF3, + 0x02, 0x49, 0x3D, 0xF4, 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x4B, 0x3F, 0xF5, 0x01, 0x4A, 0x3E, 0xF5, + 0x02, 0x4B, 0x3F, 0xF6, 0x01, 0x4A, 0x3E, 0xF6, 0x02, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3F, 0xF6, + 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x42, 0x33, 0xD8, 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x4B, 0x29, 0x21, 0x1D, 0x01, 0x5B, 0x56, 0x52, 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, + 0x0E, 0x29, 0x21, 0x1D, 0x01, 0x28, 0x15, 0x72, 0x03, 0x27, 0x18, 0xB0, 0x01, 0x2C, 0x24, 0xC8, + 0x01, 0x33, 0x34, 0xDC, 0x01, 0x33, 0x33, 0xDC, 0x02, 0x34, 0x35, 0xDD, 0x01, 0x34, 0x35, 0xDE, + 0x01, 0x35, 0x36, 0xDF, 0x01, 0x34, 0x35, 0xDE, 0x02, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, + 0x01, 0x37, 0x36, 0xDF, 0x01, 0x37, 0x35, 0xDF, 0x02, 0x37, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE1, + 0x01, 0x37, 0x36, 0xE0, 0x01, 0x70, 0x6C, 0xE8, 0x01, 0xF3, 0xF3, 0xFD, 0x0A, 0xFF, 0xFF, 0xFF, + 0x01, 0xF4, 0xF3, 0xFD, 0x01, 0x72, 0x6D, 0xEB, 0x01, 0x3D, 0x38, 0xE5, 0x01, 0x3C, 0x38, 0xE5, + 0x01, 0x3D, 0x38, 0xE6, 0x01, 0x3C, 0x38, 0xE6, 0x02, 0x3D, 0x38, 0xE6, 0x01, 0x3D, 0x38, 0xE7, + 0x01, 0x3E, 0x39, 0xE8, 0x01, 0x3E, 0x38, 0xE7, 0x01, 0x3F, 0x39, 0xE8, 0x01, 0x3F, 0x39, 0xE9, + 0x01, 0x3E, 0x39, 0xE8, 0x02, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x39, 0xE9, 0x01, 0x3F, 0x39, 0xE9, + 0x01, 0x40, 0x3A, 0xEA, 0x01, 0x40, 0x39, 0xE9, 0x02, 0x40, 0x39, 0xEA, 0x01, 0x42, 0x3A, 0xEB, + 0x01, 0x40, 0x39, 0xEB, 0x01, 0x42, 0x3A, 0xEC, 0x01, 0x43, 0x3A, 0xEC, 0x01, 0x42, 0x39, 0xEC, + 0x03, 0x43, 0x3B, 0xED, 0x01, 0x77, 0x6E, 0xF1, 0x01, 0xF4, 0xF3, 0xFE, 0x0A, 0xFF, 0xFF, 0xFF, + 0x01, 0xF4, 0xF3, 0xFE, 0x01, 0x7A, 0x6F, 0xF4, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x46, 0x3C, 0xF1, + 0x02, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF3, + 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF3, 0x02, 0x49, 0x3D, 0xF4, + 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x4B, 0x3F, 0xF5, 0x01, 0x4A, 0x3E, 0xF5, 0x02, 0x4B, 0x3F, 0xF6, + 0x01, 0x4A, 0x3E, 0xF6, 0x02, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, + 0x01, 0x3C, 0x2C, 0xBB, 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x4B, 0x29, 0x21, 0x1D, + 0x01, 0x5B, 0x56, 0x52, 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, 0x0E, 0x29, 0x21, 0x1D, + 0x01, 0x28, 0x1A, 0x4D, 0x03, 0x27, 0x18, 0xB0, 0x01, 0x2B, 0x1D, 0xBC, 0x01, 0x34, 0x35, 0xDD, + 0x01, 0x33, 0x34, 0xDD, 0x01, 0x34, 0x35, 0xDE, 0x01, 0x34, 0x35, 0xDD, 0x01, 0x35, 0x35, 0xDE, + 0x01, 0x34, 0x35, 0xDE, 0x03, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, 0x01, 0x37, 0x36, 0xE0, + 0x01, 0x37, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xE0, 0x02, 0x38, 0x36, 0xE0, + 0x01, 0x38, 0x36, 0xE1, 0x01, 0x5B, 0x57, 0xE5, 0x01, 0xD4, 0xD2, 0xF8, 0x08, 0xFF, 0xFF, 0xFF, + 0x01, 0xD5, 0xD2, 0xF9, 0x01, 0x5E, 0x58, 0xE8, 0x01, 0x3A, 0x37, 0xE4, 0x02, 0x3C, 0x38, 0xE5, + 0x02, 0x3D, 0x38, 0xE6, 0x01, 0x3D, 0x39, 0xE7, 0x01, 0x3D, 0x38, 0xE6, 0x01, 0x3E, 0x39, 0xE7, + 0x01, 0x3D, 0x38, 0xE7, 0x01, 0x3E, 0x39, 0xE8, 0x01, 0x3E, 0x38, 0xE8, 0x01, 0x3E, 0x39, 0xE8, + 0x05, 0x3F, 0x39, 0xE9, 0x02, 0x40, 0x39, 0xEA, 0x01, 0x40, 0x3A, 0xEA, 0x01, 0x40, 0x39, 0xEA, + 0x01, 0x42, 0x3A, 0xEB, 0x01, 0x42, 0x39, 0xEB, 0x01, 0x42, 0x3A, 0xEC, 0x01, 0x42, 0x39, 0xEC, + 0x01, 0x43, 0x3A, 0xEC, 0x01, 0x42, 0x3A, 0xEC, 0x02, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xED, + 0x01, 0x63, 0x5B, 0xF0, 0x01, 0xD6, 0xD3, 0xFA, 0x08, 0xFF, 0xFF, 0xFF, 0x01, 0xD6, 0xD3, 0xFB, + 0x01, 0x67, 0x5B, 0xF3, 0x02, 0x46, 0x3C, 0xF1, 0x02, 0x48, 0x3D, 0xF2, 0x03, 0x48, 0x3C, 0xF2, + 0x04, 0x49, 0x3D, 0xF3, 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x49, 0x3D, 0xF4, 0x04, 0x4A, 0x3E, 0xF5, + 0x01, 0x4B, 0x3E, 0xF6, 0x02, 0x4B, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4B, 0x3F, 0xF6, + 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x34, 0x24, 0x82, 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x4B, 0x29, 0x21, 0x1D, 0x01, 0x5B, 0x56, 0x52, 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, + 0x0E, 0x29, 0x21, 0x1D, 0x01, 0x29, 0x20, 0x24, 0x01, 0x27, 0x17, 0xAC, 0x02, 0x27, 0x18, 0xB0, + 0x01, 0x29, 0x18, 0xB2, 0x01, 0x33, 0x33, 0xDA, 0x01, 0x33, 0x33, 0xDC, 0x02, 0x34, 0x35, 0xDD, + 0x01, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x36, 0xDF, 0x01, 0x34, 0x35, 0xDE, 0x02, 0x35, 0x36, 0xDF, + 0x01, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, 0x01, 0x37, 0x35, 0xDF, 0x02, 0x37, 0x36, 0xE0, + 0x01, 0x38, 0x36, 0xE1, 0x01, 0x37, 0x36, 0xE0, 0x02, 0x38, 0x36, 0xE1, 0x01, 0x39, 0x36, 0xE2, + 0x01, 0x75, 0x71, 0xEA, 0x01, 0xB9, 0xB7, 0xF4, 0x01, 0xE4, 0xE3, 0xFB, 0x02, 0xF7, 0xF6, 0xFE, + 0x01, 0xE4, 0xE3, 0xFB, 0x01, 0xB9, 0xB7, 0xF4, 0x01, 0x77, 0x72, 0xEB, 0x01, 0x3A, 0x37, 0xE4, + 0x02, 0x3C, 0x37, 0xE4, 0x01, 0x3D, 0x38, 0xE5, 0x01, 0x3C, 0x38, 0xE5, 0x01, 0x3D, 0x38, 0xE6, + 0x01, 0x3C, 0x38, 0xE6, 0x02, 0x3D, 0x38, 0xE6, 0x01, 0x3D, 0x38, 0xE7, 0x01, 0x3E, 0x39, 0xE8, + 0x01, 0x3E, 0x38, 0xE7, 0x01, 0x3F, 0x39, 0xE8, 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x3E, 0x39, 0xE8, + 0x02, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x39, 0xE9, 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x3A, 0xEA, + 0x01, 0x40, 0x39, 0xE9, 0x02, 0x40, 0x39, 0xEA, 0x01, 0x42, 0x3A, 0xEB, 0x01, 0x40, 0x39, 0xEB, + 0x01, 0x42, 0x3A, 0xEC, 0x01, 0x43, 0x3A, 0xEC, 0x01, 0x42, 0x39, 0xEC, 0x05, 0x43, 0x3B, 0xED, + 0x01, 0x44, 0x3B, 0xED, 0x01, 0x7D, 0x74, 0xF2, 0x01, 0xBC, 0xB8, 0xF8, 0x01, 0xE6, 0xE4, 0xFC, + 0x02, 0xF7, 0xF6, 0xFE, 0x01, 0xE6, 0xE4, 0xFC, 0x01, 0xBD, 0xB8, 0xF8, 0x01, 0x7D, 0x74, 0xF4, + 0x01, 0x46, 0x3C, 0xF1, 0x01, 0x45, 0x3C, 0xF0, 0x02, 0x48, 0x3C, 0xF2, 0x01, 0x46, 0x3C, 0xF1, + 0x02, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF3, + 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF3, 0x02, 0x49, 0x3D, 0xF4, + 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x4B, 0x3F, 0xF5, 0x01, 0x4A, 0x3E, 0xF5, 0x02, 0x4B, 0x3F, 0xF6, + 0x01, 0x4A, 0x3E, 0xF6, 0x02, 0x4B, 0x3E, 0xF6, 0x01, 0x4C, 0x3F, 0xF6, 0x01, 0x4A, 0x3D, 0xF4, + 0x01, 0x2B, 0x22, 0x30, 0x28, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x4B, 0x29, 0x21, 0x1D, + 0x01, 0x51, 0x4C, 0x48, 0x01, 0xFE, 0xFE, 0xFE, 0x03, 0xFF, 0xFF, 0xFF, 0x01, 0xC6, 0xC5, 0xC4, + 0x0F, 0x29, 0x21, 0x1D, 0x01, 0x26, 0x14, 0x84, 0x03, 0x27, 0x18, 0xB0, 0x01, 0x30, 0x29, 0xCE, + 0x01, 0x33, 0x34, 0xDD, 0x01, 0x34, 0x35, 0xDE, 0x01, 0x34, 0x35, 0xDD, 0x01, 0x35, 0x35, 0xDE, + 0x01, 0x34, 0x35, 0xDE, 0x03, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, 0x01, 0x37, 0x36, 0xE0, + 0x01, 0x37, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xE0, 0x02, 0x38, 0x36, 0xE0, + 0x02, 0x38, 0x36, 0xE1, 0x01, 0x39, 0x37, 0xE2, 0x01, 0x38, 0x36, 0xE2, 0x01, 0x39, 0x37, 0xE3, + 0x01, 0x39, 0x36, 0xE2, 0x01, 0x39, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE3, 0x02, 0x3A, 0x37, 0xE4, + 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3A, 0x37, 0xE4, + 0x02, 0x3C, 0x38, 0xE5, 0x02, 0x3D, 0x38, 0xE6, 0x01, 0x3D, 0x39, 0xE7, 0x01, 0x3D, 0x38, 0xE6, + 0x01, 0x3E, 0x39, 0xE7, 0x01, 0x3D, 0x38, 0xE7, 0x01, 0x3E, 0x39, 0xE8, 0x01, 0x3E, 0x38, 0xE8, + 0x01, 0x3E, 0x39, 0xE8, 0x05, 0x3F, 0x39, 0xE9, 0x02, 0x40, 0x39, 0xEA, 0x01, 0x40, 0x3A, 0xEA, + 0x01, 0x40, 0x39, 0xEA, 0x01, 0x42, 0x3A, 0xEB, 0x01, 0x42, 0x39, 0xEB, 0x01, 0x42, 0x3A, 0xEC, + 0x01, 0x42, 0x39, 0xEC, 0x01, 0x43, 0x3A, 0xEC, 0x01, 0x42, 0x3A, 0xEC, 0x02, 0x43, 0x3B, 0xED, + 0x01, 0x44, 0x3C, 0xED, 0x01, 0x43, 0x3B, 0xED, 0x02, 0x44, 0x3B, 0xED, 0x02, 0x44, 0x3B, 0xEE, + 0x02, 0x45, 0x3C, 0xEF, 0x01, 0x45, 0x3C, 0xF0, 0x01, 0x45, 0x3C, 0xEF, 0x01, 0x46, 0x3C, 0xF0, + 0x01, 0x45, 0x3C, 0xF0, 0x03, 0x46, 0x3C, 0xF1, 0x02, 0x48, 0x3D, 0xF2, 0x03, 0x48, 0x3C, 0xF2, + 0x04, 0x49, 0x3D, 0xF3, 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x49, 0x3D, 0xF4, 0x04, 0x4A, 0x3E, 0xF5, + 0x01, 0x4B, 0x3E, 0xF6, 0x02, 0x4B, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4B, 0x3F, 0xF6, + 0x01, 0x3F, 0x31, 0xD3, 0x29, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x60, 0x29, 0x21, 0x1D, + 0x01, 0x28, 0x1A, 0x4E, 0x03, 0x27, 0x18, 0xB0, 0x01, 0x2B, 0x1D, 0xBC, 0x01, 0x33, 0x34, 0xDD, + 0x01, 0x34, 0x35, 0xDE, 0x01, 0x34, 0x35, 0xDD, 0x01, 0x35, 0x35, 0xDE, 0x01, 0x34, 0x35, 0xDE, + 0x03, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, 0x01, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xDF, + 0x01, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xE0, 0x02, 0x38, 0x36, 0xE0, 0x02, 0x38, 0x36, 0xE1, + 0x01, 0x39, 0x37, 0xE2, 0x01, 0x38, 0x36, 0xE2, 0x01, 0x39, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE2, + 0x01, 0x39, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE3, 0x02, 0x3A, 0x37, 0xE4, 0x01, 0x3C, 0x37, 0xE4, + 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3A, 0x37, 0xE4, 0x02, 0x3C, 0x38, 0xE5, + 0x02, 0x3D, 0x38, 0xE6, 0x01, 0x3D, 0x39, 0xE7, 0x01, 0x3D, 0x38, 0xE6, 0x01, 0x3E, 0x39, 0xE7, + 0x01, 0x3D, 0x38, 0xE7, 0x01, 0x3E, 0x39, 0xE8, 0x01, 0x3E, 0x38, 0xE8, 0x01, 0x3E, 0x39, 0xE8, + 0x05, 0x3F, 0x39, 0xE9, 0x02, 0x40, 0x39, 0xEA, 0x01, 0x40, 0x3A, 0xEA, 0x01, 0x40, 0x39, 0xEA, + 0x01, 0x42, 0x3A, 0xEB, 0x01, 0x42, 0x39, 0xEB, 0x01, 0x42, 0x3A, 0xEC, 0x01, 0x42, 0x39, 0xEC, + 0x01, 0x43, 0x3A, 0xEC, 0x01, 0x42, 0x3A, 0xEC, 0x02, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xED, + 0x01, 0x43, 0x3B, 0xED, 0x02, 0x44, 0x3B, 0xED, 0x02, 0x44, 0x3B, 0xEE, 0x02, 0x45, 0x3C, 0xEF, + 0x01, 0x45, 0x3C, 0xF0, 0x01, 0x45, 0x3C, 0xEF, 0x01, 0x46, 0x3C, 0xF0, 0x01, 0x45, 0x3C, 0xF0, + 0x03, 0x46, 0x3C, 0xF1, 0x02, 0x48, 0x3D, 0xF2, 0x03, 0x48, 0x3C, 0xF2, 0x04, 0x49, 0x3D, 0xF3, + 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x49, 0x3D, 0xF4, 0x04, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3E, 0xF6, + 0x02, 0x4B, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x34, 0x24, 0x84, + 0x29, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x61, 0x29, 0x21, 0x1D, 0x01, 0x28, 0x16, 0x98, + 0x03, 0x27, 0x18, 0xB0, 0x01, 0x32, 0x2E, 0xD4, 0x03, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x35, 0xDE, + 0x01, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, + 0x01, 0x37, 0x36, 0xDF, 0x03, 0x37, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE1, 0x01, 0x37, 0x36, 0xE0, + 0x01, 0x38, 0x36, 0xE2, 0x01, 0x38, 0x36, 0xE1, 0x03, 0x39, 0x36, 0xE2, 0x01, 0x39, 0x36, 0xE3, + 0x01, 0x3A, 0x37, 0xE3, 0x02, 0x3A, 0x37, 0xE4, 0x01, 0x3A, 0x36, 0xE4, 0x01, 0x3A, 0x37, 0xE4, + 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3C, 0x38, 0xE5, 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3D, 0x39, 0xE6, + 0x01, 0x3C, 0x38, 0xE5, 0x01, 0x3D, 0x39, 0xE6, 0x01, 0x3C, 0x38, 0xE6, 0x01, 0x3D, 0x38, 0xE6, + 0x02, 0x3D, 0x38, 0xE7, 0x03, 0x3E, 0x39, 0xE8, 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x3E, 0x38, 0xE8, + 0x02, 0x3F, 0x39, 0xE9, 0x02, 0x40, 0x39, 0xE9, 0x01, 0x40, 0x3A, 0xEA, 0x01, 0x40, 0x39, 0xE9, + 0x01, 0x40, 0x3A, 0xEA, 0x01, 0x40, 0x39, 0xEA, 0x03, 0x42, 0x3A, 0xEB, 0x01, 0x42, 0x3A, 0xEC, + 0x05, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xEE, 0x01, 0x44, 0x3B, 0xEE, + 0x01, 0x45, 0x3C, 0xEE, 0x01, 0x44, 0x3B, 0xEE, 0x01, 0x45, 0x3C, 0xEF, 0x01, 0x44, 0x3B, 0xEF, + 0x03, 0x45, 0x3C, 0xF0, 0x01, 0x46, 0x3C, 0xF0, 0x02, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3C, 0xF2, + 0x01, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3C, 0xF2, 0x03, 0x48, 0x3D, 0xF2, 0x01, 0x49, 0x3D, 0xF3, + 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF3, 0x01, 0x4A, 0x3D, 0xF4, + 0x01, 0x49, 0x3D, 0xF4, 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, + 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4A, 0x3E, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, + 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x45, 0x37, 0xE7, 0x2A, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x61, 0x29, 0x21, 0x1D, 0x01, 0x28, 0x19, 0x53, 0x03, 0x27, 0x18, 0xB0, 0x01, 0x2B, 0x1F, 0xBF, + 0x01, 0x34, 0x35, 0xDE, 0x01, 0x34, 0x35, 0xDD, 0x01, 0x35, 0x35, 0xDE, 0x01, 0x34, 0x35, 0xDE, + 0x03, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, 0x01, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xDF, + 0x01, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xE0, 0x02, 0x38, 0x36, 0xE0, 0x02, 0x38, 0x36, 0xE1, + 0x01, 0x39, 0x37, 0xE2, 0x01, 0x38, 0x36, 0xE2, 0x01, 0x39, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE2, + 0x01, 0x39, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE3, 0x02, 0x3A, 0x37, 0xE4, 0x01, 0x3C, 0x37, 0xE4, + 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3A, 0x37, 0xE4, 0x02, 0x3C, 0x38, 0xE5, + 0x02, 0x3D, 0x38, 0xE6, 0x01, 0x3D, 0x39, 0xE7, 0x01, 0x3D, 0x38, 0xE6, 0x01, 0x3E, 0x39, 0xE7, + 0x01, 0x3D, 0x38, 0xE7, 0x01, 0x3E, 0x39, 0xE8, 0x01, 0x3E, 0x38, 0xE8, 0x01, 0x3E, 0x39, 0xE8, + 0x05, 0x3F, 0x39, 0xE9, 0x02, 0x40, 0x39, 0xEA, 0x01, 0x40, 0x3A, 0xEA, 0x01, 0x40, 0x39, 0xEA, + 0x01, 0x42, 0x3A, 0xEB, 0x01, 0x42, 0x39, 0xEB, 0x01, 0x42, 0x3A, 0xEC, 0x01, 0x42, 0x39, 0xEC, + 0x01, 0x43, 0x3A, 0xEC, 0x01, 0x42, 0x3A, 0xEC, 0x02, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xED, + 0x01, 0x43, 0x3B, 0xED, 0x02, 0x44, 0x3B, 0xED, 0x02, 0x44, 0x3B, 0xEE, 0x02, 0x45, 0x3C, 0xEF, + 0x01, 0x45, 0x3C, 0xF0, 0x01, 0x45, 0x3C, 0xEF, 0x01, 0x46, 0x3C, 0xF0, 0x01, 0x45, 0x3C, 0xF0, + 0x03, 0x46, 0x3C, 0xF1, 0x02, 0x48, 0x3D, 0xF2, 0x03, 0x48, 0x3C, 0xF2, 0x04, 0x49, 0x3D, 0xF3, + 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x49, 0x3D, 0xF4, 0x04, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3E, 0xF6, + 0x02, 0x4B, 0x3F, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x33, 0x25, 0x8D, 0x2A, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x62, 0x29, 0x21, 0x1D, 0x01, 0x26, 0x15, 0x8D, 0x03, 0x27, 0x18, 0xB0, + 0x01, 0x30, 0x2C, 0xD2, 0x02, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x35, 0xDE, 0x01, 0x35, 0x36, 0xDF, + 0x01, 0x35, 0x35, 0xDF, 0x01, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, + 0x03, 0x37, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE1, 0x01, 0x37, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE2, + 0x01, 0x38, 0x36, 0xE1, 0x03, 0x39, 0x36, 0xE2, 0x01, 0x39, 0x36, 0xE3, 0x01, 0x3A, 0x37, 0xE3, + 0x02, 0x3A, 0x37, 0xE4, 0x01, 0x3A, 0x36, 0xE4, 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3C, 0x37, 0xE4, + 0x01, 0x3C, 0x38, 0xE5, 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3D, 0x39, 0xE6, 0x01, 0x3C, 0x38, 0xE5, + 0x01, 0x3D, 0x39, 0xE6, 0x01, 0x3C, 0x38, 0xE6, 0x01, 0x3D, 0x38, 0xE6, 0x02, 0x3D, 0x38, 0xE7, + 0x03, 0x3E, 0x39, 0xE8, 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x3E, 0x38, 0xE8, 0x02, 0x3F, 0x39, 0xE9, + 0x02, 0x40, 0x39, 0xE9, 0x01, 0x40, 0x3A, 0xEA, 0x01, 0x40, 0x39, 0xE9, 0x01, 0x40, 0x3A, 0xEA, + 0x01, 0x40, 0x39, 0xEA, 0x03, 0x42, 0x3A, 0xEB, 0x01, 0x42, 0x3A, 0xEC, 0x05, 0x43, 0x3B, 0xED, + 0x01, 0x44, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xEE, 0x01, 0x44, 0x3B, 0xEE, 0x01, 0x45, 0x3C, 0xEE, + 0x01, 0x44, 0x3B, 0xEE, 0x01, 0x45, 0x3C, 0xEF, 0x01, 0x44, 0x3B, 0xEF, 0x03, 0x45, 0x3C, 0xF0, + 0x01, 0x46, 0x3C, 0xF0, 0x02, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x46, 0x3C, 0xF1, + 0x01, 0x48, 0x3C, 0xF2, 0x03, 0x48, 0x3D, 0xF2, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x48, 0x3C, 0xF2, + 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF3, 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x49, 0x3D, 0xF4, + 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4A, 0x3E, 0xF5, + 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4A, 0x3E, 0xF6, 0x01, 0x4B, 0x3E, 0xF6, 0x01, 0x42, 0x34, 0xDC, + 0x2B, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x62, 0x29, 0x21, 0x1D, 0x01, 0x29, 0x1E, 0x36, + 0x01, 0x27, 0x17, 0xA9, 0x02, 0x27, 0x18, 0xB0, 0x01, 0x29, 0x1A, 0xB6, 0x01, 0x34, 0x32, 0xDB, + 0x01, 0x34, 0x35, 0xDE, 0x01, 0x35, 0x35, 0xDE, 0x01, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, + 0x01, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, 0x03, 0x37, 0x36, 0xE0, + 0x01, 0x38, 0x36, 0xE1, 0x01, 0x37, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE2, 0x01, 0x38, 0x36, 0xE1, + 0x03, 0x39, 0x36, 0xE2, 0x01, 0x39, 0x36, 0xE3, 0x01, 0x3A, 0x37, 0xE3, 0x02, 0x3A, 0x37, 0xE4, + 0x01, 0x3A, 0x36, 0xE4, 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3C, 0x38, 0xE5, + 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3D, 0x39, 0xE6, 0x01, 0x3C, 0x38, 0xE5, 0x01, 0x3D, 0x39, 0xE6, + 0x01, 0x3C, 0x38, 0xE6, 0x01, 0x3D, 0x38, 0xE6, 0x02, 0x3D, 0x38, 0xE7, 0x03, 0x3E, 0x39, 0xE8, + 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x3E, 0x38, 0xE8, 0x02, 0x3F, 0x39, 0xE9, 0x02, 0x40, 0x39, 0xE9, + 0x01, 0x40, 0x3A, 0xEA, 0x01, 0x40, 0x39, 0xE9, 0x01, 0x40, 0x3A, 0xEA, 0x01, 0x40, 0x39, 0xEA, + 0x03, 0x42, 0x3A, 0xEB, 0x01, 0x42, 0x3A, 0xEC, 0x05, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xED, + 0x01, 0x44, 0x3C, 0xEE, 0x01, 0x44, 0x3B, 0xEE, 0x01, 0x45, 0x3C, 0xEE, 0x01, 0x44, 0x3B, 0xEE, + 0x01, 0x45, 0x3C, 0xEF, 0x01, 0x44, 0x3B, 0xEF, 0x03, 0x45, 0x3C, 0xF0, 0x01, 0x46, 0x3C, 0xF0, + 0x02, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3C, 0xF2, + 0x03, 0x48, 0x3D, 0xF2, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF3, + 0x01, 0x49, 0x3C, 0xF3, 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x49, 0x3D, 0xF4, 0x01, 0x4A, 0x3D, 0xF4, + 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, + 0x01, 0x4A, 0x3E, 0xF6, 0x01, 0x49, 0x3B, 0xF2, 0x01, 0x2D, 0x22, 0x56, 0x2B, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x63, 0x29, 0x21, 0x1D, 0x01, 0x28, 0x18, 0x57, 0x03, 0x27, 0x18, 0xB0, + 0x01, 0x2D, 0x1F, 0xC0, 0x01, 0x35, 0x35, 0xDE, 0x02, 0x34, 0x35, 0xDE, 0x02, 0x35, 0x35, 0xDF, + 0x01, 0x37, 0x36, 0xDF, 0x02, 0x37, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xE0, + 0x02, 0x37, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE1, 0x01, 0x38, 0x36, 0xE2, 0x01, 0x38, 0x36, 0xE1, + 0x02, 0x39, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE2, 0x02, 0x39, 0x36, 0xE3, 0x01, 0x3A, 0x36, 0xE4, + 0x02, 0x3A, 0x37, 0xE4, 0x01, 0x3A, 0x36, 0xE4, 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3A, 0x36, 0xE4, + 0x02, 0x3C, 0x38, 0xE5, 0x03, 0x3D, 0x38, 0xE6, 0x02, 0x3E, 0x39, 0xE7, 0x01, 0x3D, 0x38, 0xE7, + 0x01, 0x3E, 0x38, 0xE7, 0x01, 0x3E, 0x39, 0xE8, 0x01, 0x3E, 0x38, 0xE8, 0x03, 0x3F, 0x39, 0xE9, + 0x01, 0x40, 0x39, 0xE9, 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x39, 0xE9, 0x03, 0x40, 0x39, 0xEA, + 0x01, 0x40, 0x39, 0xEB, 0x02, 0x42, 0x3A, 0xEC, 0x02, 0x42, 0x39, 0xEC, 0x02, 0x42, 0x3A, 0xEC, + 0x01, 0x44, 0x3B, 0xED, 0x02, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xEE, 0x01, 0x43, 0x3B, 0xED, + 0x02, 0x44, 0x3B, 0xEE, 0x02, 0x45, 0x3C, 0xEF, 0x01, 0x45, 0x3B, 0xEF, 0x02, 0x46, 0x3C, 0xF0, + 0x02, 0x45, 0x3C, 0xF0, 0x02, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3D, 0xF2, 0x02, 0x48, 0x3C, 0xF2, + 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF2, 0x01, 0x49, 0x3C, 0xF3, + 0x03, 0x49, 0x3D, 0xF3, 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4A, 0x3D, 0xF4, + 0x03, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x35, 0x26, 0x93, 0x2C, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x64, 0x29, 0x21, 0x1D, 0x01, 0x28, 0x15, 0x70, 0x03, 0x27, 0x18, 0xB0, + 0x01, 0x2E, 0x25, 0xC8, 0x01, 0x35, 0x35, 0xDE, 0x01, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, + 0x01, 0x35, 0x36, 0xDF, 0x01, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, 0x03, 0x37, 0x36, 0xE0, + 0x01, 0x38, 0x36, 0xE1, 0x01, 0x37, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE2, 0x01, 0x38, 0x36, 0xE1, + 0x03, 0x39, 0x36, 0xE2, 0x01, 0x39, 0x36, 0xE3, 0x01, 0x3A, 0x37, 0xE3, 0x02, 0x3A, 0x37, 0xE4, + 0x01, 0x3A, 0x36, 0xE4, 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3C, 0x38, 0xE5, + 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3D, 0x39, 0xE6, 0x01, 0x3C, 0x38, 0xE5, 0x01, 0x3D, 0x39, 0xE6, + 0x01, 0x3C, 0x38, 0xE6, 0x01, 0x3D, 0x38, 0xE6, 0x02, 0x3D, 0x38, 0xE7, 0x03, 0x3E, 0x39, 0xE8, + 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x3E, 0x38, 0xE8, 0x02, 0x3F, 0x39, 0xE9, 0x02, 0x40, 0x39, 0xE9, + 0x01, 0x40, 0x3A, 0xEA, 0x01, 0x40, 0x39, 0xE9, 0x01, 0x40, 0x3A, 0xEA, 0x01, 0x40, 0x39, 0xEA, + 0x03, 0x42, 0x3A, 0xEB, 0x01, 0x42, 0x3A, 0xEC, 0x05, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xED, + 0x01, 0x44, 0x3C, 0xEE, 0x01, 0x44, 0x3B, 0xEE, 0x01, 0x45, 0x3C, 0xEE, 0x01, 0x44, 0x3B, 0xEE, + 0x01, 0x45, 0x3C, 0xEF, 0x01, 0x44, 0x3B, 0xEF, 0x03, 0x45, 0x3C, 0xF0, 0x01, 0x46, 0x3C, 0xF0, + 0x02, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3C, 0xF2, + 0x03, 0x48, 0x3D, 0xF2, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF3, + 0x01, 0x49, 0x3C, 0xF3, 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x49, 0x3D, 0xF4, 0x01, 0x4A, 0x3D, 0xF4, + 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4B, 0x3F, 0xF6, + 0x01, 0x39, 0x2C, 0xB9, 0x2D, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x65, 0x29, 0x21, 0x1D, + 0x01, 0x28, 0x14, 0x7A, 0x03, 0x27, 0x18, 0xB0, 0x01, 0x2F, 0x27, 0xCB, 0x01, 0x34, 0x35, 0xDE, + 0x02, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, 0x02, 0x37, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xE0, + 0x01, 0x37, 0x35, 0xE0, 0x02, 0x37, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE1, 0x01, 0x38, 0x36, 0xE2, + 0x01, 0x38, 0x36, 0xE1, 0x02, 0x39, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE2, 0x02, 0x39, 0x36, 0xE3, + 0x01, 0x3A, 0x36, 0xE4, 0x02, 0x3A, 0x37, 0xE4, 0x01, 0x3A, 0x36, 0xE4, 0x01, 0x3C, 0x37, 0xE4, + 0x01, 0x3A, 0x36, 0xE4, 0x02, 0x3C, 0x38, 0xE5, 0x03, 0x3D, 0x38, 0xE6, 0x02, 0x3E, 0x39, 0xE7, + 0x01, 0x3D, 0x38, 0xE7, 0x01, 0x3E, 0x38, 0xE7, 0x01, 0x3E, 0x39, 0xE8, 0x01, 0x3E, 0x38, 0xE8, + 0x03, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x39, 0xE9, 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x39, 0xE9, + 0x03, 0x40, 0x39, 0xEA, 0x01, 0x40, 0x39, 0xEB, 0x02, 0x42, 0x3A, 0xEC, 0x02, 0x42, 0x39, 0xEC, + 0x02, 0x42, 0x3A, 0xEC, 0x01, 0x44, 0x3B, 0xED, 0x02, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xEE, + 0x01, 0x43, 0x3B, 0xED, 0x02, 0x44, 0x3B, 0xEE, 0x02, 0x45, 0x3C, 0xEF, 0x01, 0x45, 0x3B, 0xEF, + 0x02, 0x46, 0x3C, 0xF0, 0x02, 0x45, 0x3C, 0xF0, 0x02, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3D, 0xF2, + 0x02, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF2, + 0x01, 0x49, 0x3C, 0xF3, 0x03, 0x49, 0x3D, 0xF3, 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x4A, 0x3E, 0xF5, + 0x01, 0x4A, 0x3D, 0xF4, 0x02, 0x4A, 0x3E, 0xF5, 0x01, 0x3C, 0x2D, 0xC6, 0x2E, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x66, 0x29, 0x21, 0x1D, 0x01, 0x28, 0x15, 0x70, 0x03, 0x27, 0x18, 0xB0, + 0x01, 0x2E, 0x25, 0xC8, 0x02, 0x35, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xDF, 0x02, 0x37, 0x35, 0xDF, + 0x01, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xE0, 0x02, 0x37, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE1, + 0x01, 0x38, 0x36, 0xE2, 0x01, 0x38, 0x36, 0xE1, 0x02, 0x39, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE2, + 0x02, 0x39, 0x36, 0xE3, 0x01, 0x3A, 0x36, 0xE4, 0x02, 0x3A, 0x37, 0xE4, 0x01, 0x3A, 0x36, 0xE4, + 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3A, 0x36, 0xE4, 0x02, 0x3C, 0x38, 0xE5, 0x03, 0x3D, 0x38, 0xE6, + 0x02, 0x3E, 0x39, 0xE7, 0x01, 0x3D, 0x38, 0xE7, 0x01, 0x3E, 0x38, 0xE7, 0x01, 0x3E, 0x39, 0xE8, + 0x01, 0x3E, 0x38, 0xE8, 0x03, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x39, 0xE9, 0x01, 0x3F, 0x39, 0xE9, + 0x01, 0x40, 0x39, 0xE9, 0x03, 0x40, 0x39, 0xEA, 0x01, 0x40, 0x39, 0xEB, 0x02, 0x42, 0x3A, 0xEC, + 0x02, 0x42, 0x39, 0xEC, 0x02, 0x42, 0x3A, 0xEC, 0x01, 0x44, 0x3B, 0xED, 0x02, 0x43, 0x3B, 0xED, + 0x01, 0x44, 0x3C, 0xEE, 0x01, 0x43, 0x3B, 0xED, 0x02, 0x44, 0x3B, 0xEE, 0x02, 0x45, 0x3C, 0xEF, + 0x01, 0x45, 0x3B, 0xEF, 0x02, 0x46, 0x3C, 0xF0, 0x02, 0x45, 0x3C, 0xF0, 0x02, 0x46, 0x3C, 0xF1, + 0x01, 0x48, 0x3D, 0xF2, 0x02, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x48, 0x3C, 0xF2, + 0x01, 0x49, 0x3D, 0xF2, 0x01, 0x49, 0x3C, 0xF3, 0x03, 0x49, 0x3D, 0xF3, 0x01, 0x4A, 0x3D, 0xF4, + 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x4A, 0x3E, 0xF5, 0x01, 0x39, 0x2C, 0xB9, + 0x2F, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3D, 0x29, 0x21, 0x1D, 0x01, 0x40, 0x39, 0x36, + 0x01, 0x80, 0x7C, 0x7A, 0x01, 0xB5, 0xB2, 0xB1, 0x01, 0xAD, 0xAA, 0xA9, 0x01, 0x6F, 0x6B, 0x68, + 0x01, 0x31, 0x2A, 0x25, 0x24, 0x29, 0x21, 0x1D, 0x01, 0x28, 0x18, 0x57, 0x01, 0x27, 0x17, 0xA9, + 0x02, 0x27, 0x18, 0xB0, 0x01, 0x2D, 0x20, 0xC0, 0x01, 0x35, 0x33, 0xDC, 0x01, 0x35, 0x35, 0xDF, + 0x01, 0x37, 0x36, 0xDF, 0x01, 0x37, 0x36, 0xE0, 0x01, 0x37, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xE0, + 0x01, 0x38, 0x36, 0xE0, 0x02, 0x38, 0x36, 0xE1, 0x01, 0x39, 0x37, 0xE2, 0x02, 0x38, 0x36, 0xE2, + 0x01, 0x39, 0x36, 0xE2, 0x01, 0x39, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE3, 0x04, 0x3A, 0x37, 0xE4, + 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3C, 0x38, 0xE5, + 0x01, 0x3D, 0x38, 0xE6, 0x01, 0x3C, 0x38, 0xE5, 0x01, 0x3D, 0x39, 0xE6, 0x02, 0x3D, 0x38, 0xE6, + 0x01, 0x3D, 0x38, 0xE7, 0x02, 0x3E, 0x39, 0xE8, 0x01, 0x3F, 0x39, 0xE8, 0x01, 0x3E, 0x39, 0xE8, + 0x01, 0x3E, 0x39, 0xE9, 0x04, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x39, 0xEA, 0x01, 0x40, 0x3A, 0xEA, + 0x01, 0x40, 0x39, 0xEA, 0x01, 0x42, 0x3A, 0xEB, 0x02, 0x40, 0x39, 0xEB, 0x03, 0x42, 0x3A, 0xEC, + 0x04, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xED, 0x01, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xED, + 0x01, 0x44, 0x3C, 0xEE, 0x01, 0x45, 0x3C, 0xEF, 0x01, 0x44, 0x3B, 0xEF, 0x01, 0x45, 0x3C, 0xF0, + 0x02, 0x45, 0x3B, 0xEF, 0x01, 0x45, 0x3C, 0xF0, 0x01, 0x46, 0x3C, 0xF0, 0x02, 0x46, 0x3C, 0xF1, + 0x02, 0x46, 0x3C, 0xF2, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x02, 0x48, 0x3C, 0xF2, + 0x03, 0x49, 0x3D, 0xF3, 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x49, 0x3C, 0xF3, + 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x48, 0x3B, 0xF2, 0x01, 0x35, 0x26, 0x92, 0x30, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x3C, 0x29, 0x21, 0x1D, 0x01, 0x79, 0x75, 0x73, 0x01, 0xFD, 0xFD, 0xFD, + 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xF2, 0xF1, 0xF1, 0x01, 0x4E, 0x48, 0x45, 0x01, 0x29, 0x21, 0x1D, + 0x01, 0x3E, 0x38, 0x34, 0x01, 0xDA, 0xD9, 0xD8, 0x01, 0xA9, 0xA8, 0xA6, 0x01, 0x58, 0x53, 0x50, + 0x1F, 0x29, 0x21, 0x1D, 0x01, 0x29, 0x1E, 0x36, 0x01, 0x26, 0x15, 0x8D, 0x02, 0x27, 0x18, 0xB0, + 0x01, 0x2A, 0x1A, 0xB6, 0x01, 0x33, 0x2D, 0xD3, 0x02, 0x37, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xE0, + 0x01, 0x37, 0x35, 0xE0, 0x02, 0x37, 0x36, 0xE0, 0x01, 0x38, 0x36, 0xE1, 0x01, 0x38, 0x36, 0xE2, + 0x01, 0x38, 0x36, 0xE1, 0x02, 0x39, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE2, 0x02, 0x39, 0x36, 0xE3, + 0x01, 0x3A, 0x36, 0xE4, 0x02, 0x3A, 0x37, 0xE4, 0x01, 0x3A, 0x36, 0xE4, 0x01, 0x3C, 0x37, 0xE4, + 0x01, 0x3A, 0x36, 0xE4, 0x02, 0x3C, 0x38, 0xE5, 0x03, 0x3D, 0x38, 0xE6, 0x02, 0x3E, 0x39, 0xE7, + 0x01, 0x3D, 0x38, 0xE7, 0x01, 0x3E, 0x38, 0xE7, 0x01, 0x3E, 0x39, 0xE8, 0x01, 0x3E, 0x38, 0xE8, + 0x03, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x39, 0xE9, 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x39, 0xE9, + 0x03, 0x40, 0x39, 0xEA, 0x01, 0x40, 0x39, 0xEB, 0x02, 0x42, 0x3A, 0xEC, 0x02, 0x42, 0x39, 0xEC, + 0x02, 0x42, 0x3A, 0xEC, 0x01, 0x44, 0x3B, 0xED, 0x02, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xEE, + 0x01, 0x43, 0x3B, 0xED, 0x02, 0x44, 0x3B, 0xEE, 0x02, 0x45, 0x3C, 0xEF, 0x01, 0x45, 0x3B, 0xEF, + 0x02, 0x46, 0x3C, 0xF0, 0x02, 0x45, 0x3C, 0xF0, 0x02, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3D, 0xF2, + 0x02, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x49, 0x3D, 0xF2, + 0x01, 0x49, 0x3C, 0xF3, 0x03, 0x49, 0x3D, 0xF3, 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x41, 0x33, 0xDA, + 0x01, 0x2D, 0x22, 0x56, 0x31, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, + 0x01, 0x68, 0x63, 0x61, 0x01, 0xF9, 0xF9, 0xF9, 0x06, 0xFF, 0xFF, 0xFF, 0x01, 0xDB, 0xDB, 0xDB, + 0x01, 0x33, 0x2B, 0x27, 0x01, 0x4C, 0x45, 0x42, 0x03, 0xFF, 0xFF, 0xFF, 0x01, 0xB8, 0xB7, 0xB6, + 0x20, 0x29, 0x21, 0x1D, 0x01, 0x28, 0x19, 0x53, 0x01, 0x28, 0x16, 0x98, 0x02, 0x27, 0x18, 0xB0, + 0x01, 0x2D, 0x1F, 0xBF, 0x01, 0x34, 0x2F, 0xD8, 0x01, 0x37, 0x35, 0xDF, 0x01, 0x37, 0x36, 0xE0, + 0x01, 0x38, 0x36, 0xE0, 0x02, 0x38, 0x36, 0xE1, 0x01, 0x39, 0x37, 0xE2, 0x02, 0x38, 0x36, 0xE2, + 0x01, 0x39, 0x36, 0xE2, 0x01, 0x39, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE3, 0x04, 0x3A, 0x37, 0xE4, + 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3C, 0x38, 0xE5, + 0x01, 0x3D, 0x38, 0xE6, 0x01, 0x3C, 0x38, 0xE5, 0x01, 0x3D, 0x39, 0xE6, 0x02, 0x3D, 0x38, 0xE6, + 0x01, 0x3D, 0x38, 0xE7, 0x02, 0x3E, 0x39, 0xE8, 0x01, 0x3F, 0x39, 0xE8, 0x01, 0x3E, 0x39, 0xE8, + 0x01, 0x3E, 0x39, 0xE9, 0x04, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x39, 0xEA, 0x01, 0x40, 0x3A, 0xEA, + 0x01, 0x40, 0x39, 0xEA, 0x01, 0x42, 0x3A, 0xEB, 0x02, 0x40, 0x39, 0xEB, 0x03, 0x42, 0x3A, 0xEC, + 0x04, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xED, 0x01, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xED, + 0x01, 0x44, 0x3C, 0xEE, 0x01, 0x45, 0x3C, 0xEF, 0x01, 0x44, 0x3B, 0xEF, 0x01, 0x45, 0x3C, 0xF0, + 0x02, 0x45, 0x3B, 0xEF, 0x01, 0x45, 0x3C, 0xF0, 0x01, 0x46, 0x3C, 0xF0, 0x02, 0x46, 0x3C, 0xF1, + 0x02, 0x46, 0x3C, 0xF2, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x02, 0x48, 0x3C, 0xF2, + 0x03, 0x49, 0x3D, 0xF3, 0x01, 0x4A, 0x3D, 0xF4, 0x01, 0x42, 0x36, 0xE4, 0x01, 0x32, 0x24, 0x8C, + 0x33, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x01, 0xCC, 0xCB, 0xCB, + 0x08, 0xFF, 0xFF, 0xFF, 0x01, 0x97, 0x94, 0x92, 0x01, 0x4C, 0x45, 0x42, 0x04, 0xFF, 0xFF, 0xFF, + 0x01, 0x87, 0x83, 0x81, 0x21, 0x29, 0x21, 0x1D, 0x01, 0x28, 0x1A, 0x4E, 0x01, 0x26, 0x14, 0x84, + 0x01, 0x27, 0x17, 0xAC, 0x01, 0x27, 0x18, 0xB0, 0x01, 0x2D, 0x1D, 0xBD, 0x01, 0x32, 0x2A, 0xD0, + 0x01, 0x38, 0x35, 0xDF, 0x02, 0x38, 0x36, 0xE1, 0x01, 0x39, 0x37, 0xE2, 0x02, 0x38, 0x36, 0xE2, + 0x01, 0x39, 0x36, 0xE2, 0x01, 0x39, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE3, 0x04, 0x3A, 0x37, 0xE4, + 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3C, 0x38, 0xE5, + 0x01, 0x3D, 0x38, 0xE6, 0x01, 0x3C, 0x38, 0xE5, 0x01, 0x3D, 0x39, 0xE6, 0x02, 0x3D, 0x38, 0xE6, + 0x01, 0x3D, 0x38, 0xE7, 0x02, 0x3E, 0x39, 0xE8, 0x01, 0x3F, 0x39, 0xE8, 0x01, 0x3E, 0x39, 0xE8, + 0x01, 0x3E, 0x39, 0xE9, 0x04, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x39, 0xEA, 0x01, 0x40, 0x3A, 0xEA, + 0x01, 0x40, 0x39, 0xEA, 0x01, 0x42, 0x3A, 0xEB, 0x02, 0x40, 0x39, 0xEB, 0x03, 0x42, 0x3A, 0xEC, + 0x04, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xED, 0x01, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3B, 0xED, + 0x01, 0x44, 0x3C, 0xEE, 0x01, 0x45, 0x3C, 0xEF, 0x01, 0x44, 0x3B, 0xEF, 0x01, 0x45, 0x3C, 0xF0, + 0x02, 0x45, 0x3B, 0xEF, 0x01, 0x45, 0x3C, 0xF0, 0x01, 0x46, 0x3C, 0xF0, 0x02, 0x46, 0x3C, 0xF1, + 0x02, 0x46, 0x3C, 0xF2, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x48, 0x3D, 0xF2, 0x02, 0x48, 0x3C, 0xF2, + 0x01, 0x49, 0x3D, 0xF3, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x3E, 0x31, 0xD0, 0x01, 0x32, 0x24, 0x83, + 0x35, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3A, 0x29, 0x21, 0x1D, 0x01, 0x2B, 0x23, 0x1E, + 0x01, 0xF4, 0xF4, 0xF4, 0x08, 0xFF, 0xFF, 0xFF, 0x01, 0xC6, 0xC5, 0xC4, 0x01, 0x4C, 0x45, 0x42, + 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xF8, 0xF7, 0xF7, 0x01, 0x4C, 0x45, 0x42, 0x22, 0x29, 0x21, 0x1D, + 0x01, 0x29, 0x20, 0x24, 0x01, 0x28, 0x1A, 0x4D, 0x01, 0x28, 0x15, 0x72, 0x01, 0x26, 0x15, 0x8A, + 0x01, 0x27, 0x17, 0x9E, 0x01, 0x2B, 0x1D, 0xB7, 0x01, 0x30, 0x25, 0xC9, 0x01, 0x33, 0x2C, 0xD4, + 0x01, 0x37, 0x31, 0xDA, 0x01, 0x38, 0x34, 0xDF, 0x01, 0x39, 0x35, 0xE1, 0x01, 0x39, 0x36, 0xE2, + 0x01, 0x3A, 0x37, 0xE3, 0x01, 0x39, 0x36, 0xE3, 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3A, 0x36, 0xE4, + 0x01, 0x3C, 0x37, 0xE4, 0x01, 0x3A, 0x37, 0xE4, 0x01, 0x3C, 0x37, 0xE4, 0x03, 0x3C, 0x38, 0xE5, + 0x02, 0x3D, 0x38, 0xE6, 0x01, 0x3D, 0x39, 0xE7, 0x02, 0x3D, 0x38, 0xE7, 0x01, 0x3E, 0x38, 0xE7, + 0x01, 0x3E, 0x39, 0xE8, 0x01, 0x3E, 0x38, 0xE8, 0x01, 0x3F, 0x39, 0xE9, 0x01, 0x3E, 0x38, 0xE8, + 0x03, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x3A, 0xEA, 0x02, 0x3F, 0x39, 0xE9, 0x01, 0x40, 0x3A, 0xEA, + 0x01, 0x40, 0x39, 0xEA, 0x03, 0x42, 0x3A, 0xEB, 0x01, 0x42, 0x39, 0xEC, 0x01, 0x43, 0x3B, 0xED, + 0x01, 0x42, 0x3A, 0xEC, 0x02, 0x43, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xED, 0x01, 0x43, 0x3B, 0xED, + 0x01, 0x44, 0x3B, 0xED, 0x01, 0x44, 0x3C, 0xEE, 0x02, 0x44, 0x3B, 0xEE, 0x02, 0x45, 0x3C, 0xEF, + 0x04, 0x45, 0x3C, 0xF0, 0x02, 0x46, 0x3C, 0xF1, 0x01, 0x48, 0x3C, 0xF2, 0x01, 0x46, 0x3B, 0xEF, + 0x01, 0x45, 0x3A, 0xED, 0x01, 0x43, 0x37, 0xE5, 0x01, 0x3E, 0x30, 0xD4, 0x01, 0x39, 0x2C, 0xB9, + 0x01, 0x32, 0x24, 0x81, 0x01, 0x29, 0x22, 0x30, 0x37, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x3A, 0x29, 0x21, 0x1D, 0x01, 0x4C, 0x46, 0x44, 0x09, 0xFF, 0xFF, 0xFF, 0x01, 0xEE, 0xEE, 0xED, + 0x01, 0x4C, 0x45, 0x42, 0x05, 0xFF, 0xFF, 0xFF, 0x01, 0x86, 0x82, 0x80, 0x9F, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x3A, 0x29, 0x21, 0x1D, 0x01, 0x4F, 0x4A, 0x46, 0x01, 0xFE, 0xFE, 0xFE, + 0x03, 0xFF, 0xFF, 0xFF, 0x01, 0xBF, 0xBE, 0xBD, 0x01, 0x86, 0x82, 0x80, 0x01, 0xF3, 0xF2, 0xF2, + 0x03, 0xFF, 0xFF, 0xFF, 0x01, 0x56, 0x50, 0x4E, 0x01, 0xD4, 0xD2, 0xD2, 0x04, 0xFF, 0xFF, 0xFF, + 0x01, 0xA9, 0xA8, 0xA6, 0x9F, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3A, 0x29, 0x21, 0x1D, + 0x01, 0x36, 0x2F, 0x2B, 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0x55, 0x4F, 0x4D, 0x01, 0x29, 0x21, 0x1D, + 0x01, 0xB9, 0xB8, 0xB7, 0x03, 0xFF, 0xFF, 0xFF, 0x01, 0x64, 0x5F, 0x5C, 0x01, 0x2B, 0x23, 0x1E, + 0x01, 0xE7, 0xE6, 0xE5, 0x03, 0xFF, 0xFF, 0xFF, 0x01, 0xCB, 0xCA, 0xCA, 0x9F, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x01, 0xD6, 0xD5, 0xD4, 0x03, 0xFF, 0xFF, 0xFF, + 0x01, 0x57, 0x52, 0x4F, 0x01, 0x29, 0x21, 0x1D, 0x01, 0x8A, 0x87, 0x85, 0x03, 0xFF, 0xFF, 0xFF, + 0x01, 0x73, 0x6E, 0x6C, 0x01, 0x29, 0x21, 0x1D, 0x01, 0xC9, 0xC7, 0xC6, 0x03, 0xFF, 0xFF, 0xFF, + 0x01, 0xE8, 0xE7, 0xE6, 0x9F, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, + 0x01, 0x65, 0x61, 0x5D, 0x01, 0xFD, 0xFD, 0xFD, 0x02, 0xFF, 0xFF, 0xFF, 0x01, 0xC1, 0xBF, 0xBF, + 0x01, 0x29, 0x21, 0x1D, 0x01, 0x7A, 0x75, 0x73, 0x03, 0xFF, 0xFF, 0xFF, 0x01, 0x81, 0x7D, 0x7B, + 0x01, 0x33, 0x2B, 0x27, 0x01, 0xEF, 0xEF, 0xEE, 0x03, 0xFF, 0xFF, 0xFF, 0x01, 0xDD, 0xDC, 0xDC, + 0x9F, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x01, 0xAA, 0xA9, 0xA7, + 0x01, 0xE8, 0xE8, 0xE7, 0x03, 0xFF, 0xFF, 0xFF, 0x01, 0xE3, 0xE2, 0xE2, 0x01, 0xE7, 0xE6, 0xE5, + 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xF1, 0xF1, 0xF1, 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xBB, 0xB9, 0xB8, + 0x9F, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x10, 0xFF, 0xFF, 0xFF, + 0x01, 0x96, 0x93, 0x91, 0x9F, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, + 0x10, 0xFF, 0xFF, 0xFF, 0x01, 0x6D, 0x69, 0x67, 0x9F, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x3B, 0x29, 0x21, 0x1D, 0x0F, 0xFF, 0xFF, 0xFF, 0x01, 0xC8, 0xC6, 0xC5, 0xA0, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x0E, 0xFF, 0xFF, 0xFF, 0x01, 0xE8, 0xE8, 0xE7, + 0x01, 0x3B, 0x35, 0x31, 0xA0, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, + 0x01, 0xFE, 0xFE, 0xFE, 0x0C, 0xFF, 0xFF, 0xFF, 0x01, 0xCE, 0xCC, 0xCB, 0x01, 0x55, 0x4F, 0x4D, + 0xA1, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x01, 0x55, 0x4E, 0x4C, + 0x0A, 0x5D, 0x59, 0x56, 0x01, 0x5A, 0x55, 0x51, 0x01, 0x39, 0x31, 0x2D, 0xA3, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x01, 0x8B, 0x88, 0x86, 0x14, 0x94, 0x91, 0x90, + 0x01, 0x71, 0x6C, 0x6A, 0x9A, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, + 0x15, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, 0x9A, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x3B, 0x29, 0x21, 0x1D, 0x15, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, 0x9A, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x15, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, + 0x9A, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x15, 0xFF, 0xFF, 0xFF, + 0x01, 0xCF, 0xCD, 0xCC, 0x9A, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, + 0x15, 0xFF, 0xFF, 0xFF, 0x01, 0xCF, 0xCD, 0xCC, 0x9A, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x3B, 0x29, 0x21, 0x1D, 0x01, 0x77, 0x73, 0x71, 0x03, 0x81, 0x7D, 0x7B, 0x01, 0x99, 0x96, 0x94, + 0x06, 0xFF, 0xFF, 0xFF, 0x01, 0xD0, 0xCF, 0xCE, 0x09, 0x81, 0x7D, 0x7B, 0x01, 0x62, 0x5C, 0x5A, + 0x9A, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3F, 0x29, 0x21, 0x1D, 0x01, 0x7A, 0x75, 0x73, + 0x01, 0xF5, 0xF5, 0xF5, 0x06, 0xFF, 0xFF, 0xFF, 0x01, 0xBB, 0xB9, 0xB8, 0x01, 0x35, 0x2E, 0x2B, + 0xA2, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3D, 0x29, 0x21, 0x1D, 0x01, 0x44, 0x3E, 0x3A, + 0x01, 0xC3, 0xC2, 0xC1, 0x09, 0xFF, 0xFF, 0xFF, 0x01, 0xE1, 0xE0, 0xDF, 0x01, 0x55, 0x4F, 0x4D, + 0xA1, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3C, 0x29, 0x21, 0x1D, 0x01, 0x89, 0x86, 0x84, + 0x01, 0xF3, 0xF3, 0xF3, 0x0B, 0xFF, 0xFF, 0xFF, 0x01, 0xF8, 0xF7, 0xF7, 0x01, 0x84, 0x80, 0x7E, + 0xA0, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x01, 0xD0, 0xCF, 0xCE, + 0x0F, 0xFF, 0xFF, 0xFF, 0x01, 0x91, 0x8F, 0x8D, 0x9F, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x3B, 0x29, 0x21, 0x1D, 0x08, 0xFF, 0xFF, 0xFF, 0x01, 0xF1, 0xF0, 0xF0, 0x01, 0xE2, 0xE1, 0xE1, + 0x01, 0xFE, 0xFE, 0xFE, 0x05, 0xFF, 0xFF, 0xFF, 0x01, 0xAA, 0xA9, 0xA7, 0x9F, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x07, 0xFF, 0xFF, 0xFF, 0x01, 0xBD, 0xBB, 0xBA, + 0x01, 0x3E, 0x38, 0x34, 0x01, 0x29, 0x21, 0x1D, 0x01, 0x7B, 0x77, 0x75, 0x01, 0xF8, 0xF7, 0xF7, + 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xAA, 0xA9, 0xA7, 0x9F, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x3B, 0x29, 0x21, 0x1D, 0x05, 0xFF, 0xFF, 0xFF, 0x01, 0xEC, 0xEB, 0xEB, 0x01, 0x74, 0x70, 0x6E, + 0x04, 0x29, 0x21, 0x1D, 0x01, 0x5B, 0x56, 0x52, 0x01, 0xE9, 0xE9, 0xE9, 0x03, 0xFF, 0xFF, 0xFF, + 0x01, 0xAA, 0xA9, 0xA7, 0x9F, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, + 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xB5, 0xB2, 0xB1, 0x01, 0x3A, 0x33, 0x2F, 0x06, 0x29, 0x21, 0x1D, + 0x01, 0x41, 0x3A, 0x37, 0x01, 0xD5, 0xD3, 0xD3, 0x02, 0xFF, 0xFF, 0xFF, 0x01, 0xAA, 0xA9, 0xA7, + 0x9F, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x02, 0xFF, 0xFF, 0xFF, + 0x01, 0xE8, 0xE7, 0xE6, 0x01, 0x6B, 0x67, 0x65, 0x09, 0x29, 0x21, 0x1D, 0x01, 0x30, 0x28, 0x24, + 0x01, 0xB7, 0xB5, 0xB4, 0x01, 0xFF, 0xFF, 0xFF, 0x01, 0xAA, 0xA9, 0xA7, 0x9F, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x01, 0xF9, 0xF9, 0xF9, 0x01, 0xAD, 0xAA, 0xA9, + 0x01, 0x35, 0x2E, 0x2B, 0x0C, 0x29, 0x21, 0x1D, 0x01, 0x92, 0x90, 0x8E, 0x01, 0x82, 0x7E, 0x7D, + 0x9F, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x01, 0x34, 0x2D, 0x29, + 0xAF, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x47, 0x29, 0x21, 0x1D, 0x01, 0xD0, 0xCF, 0xCE, + 0x03, 0xF0, 0xF0, 0xEF, 0x01, 0x98, 0x95, 0x93, 0x9F, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x47, 0x29, 0x21, 0x1D, 0x01, 0xE6, 0xE5, 0xE5, 0x03, 0xFF, 0xFF, 0xFF, 0x01, 0xAA, 0xA9, 0xA7, + 0x9F, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3C, 0x29, 0x21, 0x1D, 0x01, 0x30, 0x28, 0x24, + 0x01, 0x8C, 0x88, 0x87, 0x01, 0xB1, 0xAF, 0xAE, 0x01, 0xCC, 0xCB, 0xCB, 0x07, 0xD2, 0xD1, 0xD0, + 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xF3, 0xF3, 0xF3, 0x02, 0xD2, 0xD1, 0xD0, 0x01, 0xD1, 0xD1, 0xD0, + 0x01, 0x4C, 0x46, 0x44, 0x9B, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, + 0x01, 0x4B, 0x44, 0x41, 0x01, 0xDF, 0xDE, 0xDD, 0x12, 0xFF, 0xFF, 0xFF, 0x01, 0x65, 0x61, 0x5D, + 0x9B, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x01, 0xB8, 0xB7, 0xB6, + 0x13, 0xFF, 0xFF, 0xFF, 0x01, 0x65, 0x61, 0x5D, 0x9B, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x3A, 0x29, 0x21, 0x1D, 0x01, 0x39, 0x31, 0x2D, 0x01, 0xFC, 0xFC, 0xFC, 0x13, 0xFF, 0xFF, 0xFF, + 0x01, 0x65, 0x61, 0x5D, 0x9B, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3A, 0x29, 0x21, 0x1D, + 0x01, 0x59, 0x54, 0x51, 0x14, 0xFF, 0xFF, 0xFF, 0x01, 0x65, 0x61, 0x5D, 0x9B, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x3A, 0x29, 0x21, 0x1D, 0x01, 0x72, 0x6D, 0x6B, 0x14, 0xFF, 0xFF, 0xFF, + 0x01, 0x5F, 0x59, 0x57, 0x9B, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3A, 0x29, 0x21, 0x1D, + 0x01, 0x69, 0x64, 0x62, 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xC6, 0xC5, 0xC4, 0x01, 0x61, 0x5B, 0x59, + 0x06, 0x3B, 0x34, 0x30, 0x01, 0xEB, 0xEA, 0xEA, 0x03, 0xFF, 0xFF, 0xFF, 0x01, 0xB4, 0xB2, 0xB0, + 0x02, 0x3B, 0x34, 0x30, 0x01, 0x3A, 0x33, 0x2F, 0x9C, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x3A, 0x29, 0x21, 0x1D, 0x01, 0x73, 0x6F, 0x6D, 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0x63, 0x5E, 0x5B, + 0x07, 0x29, 0x21, 0x1D, 0x01, 0xE6, 0xE5, 0xE5, 0x03, 0xFF, 0xFF, 0xFF, 0x01, 0xAA, 0xA9, 0xA7, + 0x9F, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3A, 0x29, 0x21, 0x1D, 0x01, 0x5B, 0x56, 0x52, + 0x03, 0xF1, 0xF0, 0xF0, 0x01, 0xED, 0xEC, 0xEC, 0x01, 0x3B, 0x34, 0x30, 0x07, 0x29, 0x21, 0x1D, + 0x01, 0xD1, 0xD0, 0xCF, 0x03, 0xF1, 0xF0, 0xF0, 0x01, 0x98, 0x95, 0x93, 0x9F, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x10, 0x2B, 0x23, 0x1E, 0x04, 0x29, 0x21, 0x1D, + 0x01, 0x36, 0x2F, 0x2B, 0x9B, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, + 0x01, 0xF8, 0xF7, 0xF7, 0x0F, 0xFF, 0xFF, 0xFF, 0x01, 0xA2, 0x9F, 0x9E, 0x01, 0x29, 0x21, 0x1D, + 0x01, 0x6B, 0x67, 0x65, 0x01, 0xD2, 0xD1, 0xD0, 0x01, 0xFF, 0xFF, 0xFF, 0x01, 0xD6, 0xD6, 0xD5, + 0x01, 0x73, 0x6F, 0x6D, 0x99, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, + 0x10, 0xFF, 0xFF, 0xFF, 0x01, 0xAA, 0xA9, 0xA7, 0x01, 0x2C, 0x24, 0x20, 0x01, 0xEA, 0xE9, 0xE9, + 0x03, 0xFF, 0xFF, 0xFF, 0x01, 0xF2, 0xF1, 0xF1, 0x01, 0x31, 0x2A, 0x25, 0x98, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x10, 0xFF, 0xFF, 0xFF, 0x01, 0xAA, 0xA9, 0xA7, + 0x01, 0x5C, 0x57, 0x54, 0x05, 0xFF, 0xFF, 0xFF, 0x01, 0x7A, 0x75, 0x73, 0x98, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x10, 0xFF, 0xFF, 0xFF, 0x01, 0xAA, 0xA9, 0xA7, + 0x01, 0x59, 0x54, 0x51, 0x05, 0xFF, 0xFF, 0xFF, 0x01, 0x6B, 0x67, 0x65, 0x98, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x10, 0xFF, 0xFF, 0xFF, 0x01, 0xAA, 0xA9, 0xA7, + 0x01, 0x29, 0x21, 0x1D, 0x01, 0xDB, 0xDB, 0xDB, 0x03, 0xFF, 0xFF, 0xFF, 0x01, 0xE6, 0xE5, 0xE5, + 0x99, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x01, 0xD0, 0xCF, 0xCE, + 0x0F, 0xD8, 0xD7, 0xD6, 0x01, 0x89, 0x86, 0x84, 0x01, 0x29, 0x21, 0x1D, 0x01, 0x48, 0x43, 0x3F, + 0x01, 0xA6, 0xA3, 0xA2, 0x01, 0xDF, 0xDE, 0xDD, 0x01, 0xAB, 0xA9, 0xA8, 0x01, 0x4D, 0x47, 0x45, + 0x99, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x4A, 0x29, 0x21, 0x1D, 0x01, 0x59, 0x54, 0x51, 0x01, 0x44, 0x3D, 0x39, 0x9F, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x47, 0x29, 0x21, 0x1D, 0x01, 0x58, 0x53, 0x50, 0x01, 0xA3, 0xA0, 0x9E, + 0x01, 0xE3, 0xE2, 0xE2, 0x01, 0xFF, 0xFF, 0xFF, 0x01, 0xAA, 0xA9, 0xA7, 0x9F, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x44, 0x29, 0x21, 0x1D, 0x01, 0x57, 0x52, 0x4F, 0x01, 0xA2, 0x9F, 0x9E, + 0x01, 0xE2, 0xE1, 0xE1, 0x04, 0xFF, 0xFF, 0xFF, 0x01, 0xAA, 0xA9, 0xA7, 0x9F, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x41, 0x29, 0x21, 0x1D, 0x01, 0x56, 0x50, 0x4E, 0x01, 0xA1, 0x9F, 0x9D, + 0x01, 0xE1, 0xE1, 0xE0, 0x07, 0xFF, 0xFF, 0xFF, 0x01, 0xAA, 0xA9, 0xA7, 0x9F, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x3E, 0x29, 0x21, 0x1D, 0x01, 0x55, 0x4F, 0x4D, 0x01, 0x9F, 0x9D, 0x9C, + 0x01, 0xE1, 0xE0, 0xDF, 0x0A, 0xFF, 0xFF, 0xFF, 0x01, 0xAA, 0xA9, 0xA7, 0x9F, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x01, 0x55, 0x4E, 0x4C, 0x01, 0x9E, 0x9C, 0x9B, + 0x01, 0xE0, 0xE0, 0xDF, 0x0D, 0xFF, 0xFF, 0xFF, 0x01, 0xAA, 0xA9, 0xA7, 0x9F, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x10, 0xFF, 0xFF, 0xFF, 0x01, 0xA2, 0x9F, 0x9E, + 0x9F, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, 0x0B, 0xFF, 0xFF, 0xFF, + 0x01, 0xFE, 0xFE, 0xFE, 0x01, 0xE0, 0xDF, 0xDE, 0x01, 0xB1, 0xB0, 0xAF, 0x01, 0x80, 0x7C, 0x7A, + 0x01, 0x46, 0x40, 0x3C, 0xA0, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, + 0x07, 0xFF, 0xFF, 0xFF, 0x01, 0xFB, 0xFB, 0xFB, 0x01, 0xD7, 0xD6, 0xD6, 0x01, 0xA9, 0xA7, 0xA6, + 0x01, 0x76, 0x72, 0x70, 0x01, 0x3C, 0x36, 0x32, 0xA4, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x3B, 0x29, 0x21, 0x1D, 0x06, 0xFF, 0xFF, 0xFF, 0x01, 0xD3, 0xD1, 0xD1, 0x01, 0x76, 0x72, 0x70, + 0x01, 0x35, 0x2E, 0x2B, 0xA7, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3B, 0x29, 0x21, 0x1D, + 0x08, 0xFF, 0xFF, 0xFF, 0x01, 0xFC, 0xFC, 0xFC, 0x01, 0xDA, 0xD9, 0xD8, 0x01, 0xAC, 0xA9, 0xA8, + 0x01, 0x7A, 0x76, 0x74, 0x01, 0x42, 0x3B, 0x39, 0xA3, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x3B, 0x29, 0x21, 0x1D, 0x0D, 0xFF, 0xFF, 0xFF, 0x01, 0xE5, 0xE4, 0xE4, 0x01, 0xB8, 0xB7, 0xB6, + 0x01, 0x88, 0x84, 0x82, 0x01, 0x47, 0x41, 0x3E, 0x9F, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x3B, 0x29, 0x21, 0x1D, 0x01, 0xD7, 0xD6, 0xD6, 0x0F, 0xFF, 0xFF, 0xFF, 0x01, 0xAA, 0xA9, 0xA7, + 0x9F, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3C, 0x29, 0x21, 0x1D, 0x01, 0x49, 0x44, 0x40, + 0x01, 0x95, 0x92, 0x91, 0x01, 0xD6, 0xD5, 0xD4, 0x01, 0xFE, 0xFE, 0xFE, 0x0B, 0xFF, 0xFF, 0xFF, + 0x01, 0xAA, 0xA9, 0xA7, 0x9F, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x3F, 0x29, 0x21, 0x1D, + 0x01, 0x47, 0x41, 0x3E, 0x01, 0x93, 0x91, 0x8F, 0x01, 0xD5, 0xD3, 0xD3, 0x01, 0xFE, 0xFE, 0xFE, + 0x08, 0xFF, 0xFF, 0xFF, 0x01, 0xAA, 0xA9, 0xA7, 0x9F, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, + 0x42, 0x29, 0x21, 0x1D, 0x01, 0x46, 0x40, 0x3C, 0x01, 0x91, 0x8F, 0x8D, 0x01, 0xD4, 0xD2, 0xD2, + 0x01, 0xFD, 0xFD, 0xFD, 0x05, 0xFF, 0xFF, 0xFF, 0x01, 0xAA, 0xA9, 0xA7, 0x9F, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0x45, 0x29, 0x21, 0x1D, 0x01, 0x44, 0x3E, 0x3A, 0x01, 0x90, 0x8D, 0x8B, + 0x01, 0xD2, 0xD1, 0xD0, 0x01, 0xFD, 0xFD, 0xFD, 0x02, 0xFF, 0xFF, 0xFF, 0x01, 0xAA, 0xA9, 0xA7, + 0x9F, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0x48, 0x29, 0x21, 0x1D, 0x01, 0x44, 0x3D, 0x39, + 0x01, 0x8F, 0x8B, 0x89, 0x01, 0xD1, 0xD0, 0xCF, 0x01, 0x8D, 0x89, 0x88, 0x9F, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D, + 0x05, 0x38, 0x23, 0xEC, 0xEB, 0x29, 0x21, 0x1D +}; diff --git a/source/spotpass.c b/source/spotpass.c new file mode 100644 index 0000000..8514d52 --- /dev/null +++ b/source/spotpass.c @@ -0,0 +1,249 @@ +// SpotPass (BOSS) für MBMNET-Mitteilungen, siehe spotpass.h. +// +// Wie in der libctru-Vorlage (examples/network/boss): eigene Aufgabe mit HTTP-URL. Der Server liefert einen +// BOSS-Container, dessen Inhalt an das News-Modul (0004013000003502) geht. Die Nintendo-Signatur darin ist +// leer, Luma schaltet ihre Prüfung ab. +#include <3ds.h> +#include +#include + +#include "spotpass.h" + +#define TASK_NEWS "mbmnews" +#define TASK_TEST "mbmtest" +#define NEWS_INTERVAL (2 * 60) // Sekunden zwischen zwei Abrufen + +// SpotPass braucht für jede Anwendung mit Aufgaben einen angemeldeten Speicher (Extdata), wie bei Spielen. +// Die Mitteilungen selbst landen im News-Modul, der Speicher bleibt praktisch leer. +#define EXTDATA_ID 0xFB4E0ULL // = Unique ID der App (cia.rsf: ExtSaveDataId) +#define BOSS_STORAGE 0x100000 // 1 MB + +// Policy-Liste: SpotPass lädt sie vor jeder Aufgabe von Nintendo (nppl.c.app.nintendowifi.net). Der Server +// antwortet nicht mehr, ohne Liste bricht jede Aufgabe ab. Darum auf MBMNET umstellen (wie Pretendo). +// boss:P-Befehl 0x0427 SetPolicyListUrl, leerer Text = wieder Nintendos Adresse. Klappt nur mit boss:P. +static Result set_policy_url(const char *url) +{ + u32 size = strlen(url) + 1; + u32 *cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = IPC_MakeHeader(0x427, 1, 2); // 0x04270042 + cmdbuf[1] = size; + cmdbuf[2] = IPC_Desc_Buffer(size, IPC_BUFFER_R); + cmdbuf[3] = (u32)url; + Result rc = svcSendSyncRequest(bossGetSessionHandle()); + return R_SUCCEEDED(rc) ? (Result)cmdbuf[1] : rc; +} + +static Result use_mbmnet_policy(const char *server) +{ + char url[128]; + snprintf(url, sizeof(url), "http://%s/p01/policylist", server); + return set_policy_url(url); +} + +// Gibt es die Extdata? Sonst anlegen (mit Ordner /boss, in den SpotPass schreibt). bossSetStorageInfo +// prüft das nicht - ohne Extdata scheitert erst die Aufgabe (Fehler 004-6006). +static Result ensure_extdata(void) +{ + u32 lowHigh[3] = { MEDIATYPE_SD, (u32)EXTDATA_ID, (u32)(EXTDATA_ID >> 32) }; + FS_Path path = { PATH_BINARY, sizeof(lowHigh), lowHigh }; + FS_Archive arch; + Result rc = fsInit(); + if (R_FAILED(rc)) return rc; + rc = FSUSER_OpenArchive(&arch, ARCHIVE_EXTDATA, path); + if (R_FAILED(rc)) { + FS_ExtSaveDataInfo info = { .mediaType = MEDIATYPE_SD, .saveId = EXTDATA_ID }; + rc = FSUSER_CreateExtSaveData(info, 32, 256, 0, 0, NULL); + if (R_FAILED(rc)) { + // Manche Systemversionen wollen ein Icon (SMDH) dazu: leeres mit Kennung reicht + static u8 smdh[0x36C0]; + memcpy(smdh, "SMDH", 4); + rc = FSUSER_CreateExtSaveData(info, 32, 256, 0, sizeof(smdh), smdh); + } + if (R_SUCCEEDED(rc)) rc = FSUSER_OpenArchive(&arch, ARCHIVE_EXTDATA, path); + } + if (R_SUCCEEDED(rc)) { + FSUSER_CreateDirectory(arch, fsMakePath(PATH_ASCII, "/boss"), 0); // gibt es ihn schon: egal + FSUSER_CloseArchive(arch); + } + fsExit(); + return rc; +} + +static Result ensure_storage(void) +{ + return bossSetStorageInfo(EXTDATA_ID, BOSS_STORAGE, MEDIATYPE_SD); +} + +static bool url_for(const char *server, const char *file, char *url, size_t len) +{ + u32 device = 0; + bool ok = R_SUCCEEDED(amInit()); + if (ok) { + s32 internal = 0; + ok = R_SUCCEEDED(AM_GetDeviceId(&internal, &device)) && internal >= 0 && device; + amExit(); + } + if (ok) snprintf(url, len, "http://%s/spotpass/%lu/%s", server, (unsigned long)device, file); + return ok; +} + +// step bekommt den Namen des Schritts, der fehlschlug +static Result setup_task(const char *server, const char *task, const char *url, u32 interval, const char **step) +{ + bool once = strcmp(task, TASK_TEST) == 0; + *step = "Policy-Liste umstellen"; + Result rc = use_mbmnet_policy(server); + if (R_FAILED(rc)) return rc; + *step = "Speicher anlegen"; + rc = ensure_extdata(); + if (R_FAILED(rc)) return rc; + *step = "Speicher anmelden"; + rc = ensure_storage(); + if (R_FAILED(rc)) return rc; + bossDeleteTask(task, 0); + bossContext ctx; + bossSetupContextDefault(&ctx, interval, url); + ctx.property[0x4] = once ? 1 : 0; // Count: 0 = dauerhaft (Standard wären 100 Läufe), Test nur einmal + *step = "Einstellungen senden"; + rc = bossSendContextConfig(&ctx); + if (R_FAILED(rc)) return rc; + *step = "Aufgabe anmelden"; + return bossRegisterTask(task, 0, 0); +} + +bool spotpass_register(const char *server, char *msg, size_t msglen) +{ + char url[256]; + if (!url_for(server, "news.boss", url, sizeof(url))) { + snprintf(msg, msglen, "SpotPass: Geräte-ID nicht lesbar"); + return false; + } + const char *step = "BOSS starten"; + Result rc = bossInit(0, false); + if (R_SUCCEEDED(rc)) { + rc = setup_task(server, TASK_NEWS, url, NEWS_INTERVAL, &step); + if (R_SUCCEEDED(rc)) bossStartBgImmediate(TASK_NEWS); // gleich einmal abholen + bossExit(); + } + if (R_FAILED(rc)) snprintf(msg, msglen, "SpotPass anmelden fehlgeschlagen bei: %s (%08lX)", step, (unsigned long)rc); + return R_SUCCEEDED(rc); +} + +void spotpass_unregister(void) +{ + if (R_FAILED(bossInit(0, false))) return; + bossDeleteTask(TASK_NEWS, 0); + set_policy_url(""); // wieder Nintendos Policy-Liste + bossExit(); +} + +// --- Fehlerauswertung (BOSSU-Befehle, die libctru nicht hat) --------------------------------------- +static Result boss_send(u32 *cmdbuf) +{ + Result rc = svcSendSyncRequest(bossGetSessionHandle()); + return R_SUCCEEDED(rc) ? (Result)cmdbuf[1] : rc; +} + +// Befehl mit Task-ID-Puffer; extra = Werte zwischen Größe und Puffer +static Result boss_task_cmd(u16 id, const char *task, int nextra, u32 e1, u32 e2, u32 *out) +{ + u32 size = strlen(task) + 1; + u32 *cmd = getThreadCommandBuffer(); + cmd[0] = IPC_MakeHeader(id, 1 + nextra, 2); + cmd[1] = size; + if (nextra > 0) cmd[2] = e1; + if (nextra > 1) cmd[3] = e2; + cmd[2 + nextra] = IPC_Desc_Buffer(size, IPC_BUFFER_R); + cmd[3 + nextra] = (u32)task; + Result rc = boss_send(cmd); + if (out) *out = cmd[2]; + return rc; +} + +static Result boss_receive_property(u16 property, void *buf, u32 size) +{ + u32 *cmd = getThreadCommandBuffer(); + cmd[0] = IPC_MakeHeader(0x16, 2, 2); // ReceiveProperty + cmd[1] = property; + cmd[2] = size; + cmd[3] = IPC_Desc_Buffer(size, IPC_BUFFER_W); + cmd[4] = (u32)buf; + return boss_send(cmd); +} + +// Fehler einer Aufgabe als Text: Nintendo-Fehlercode 004-XXXX, Ergebnis, Dienststatus, HTTP-Code +static void task_error_text(const char *task, char *out, size_t len) +{ + u8 result = 0, service = 0, taskErr = 0; + u32 http = 0, code = 0; + boss_task_cmd(0x23, task, 2, 0, 0, NULL); // GetTaskStatus: lädt die Status-Eigenschaften + boss_receive_property(0x20, &result, 1); // TaskResultCode + boss_receive_property(0x21, &service, 1); // TaskServiceStatus + boss_task_cmd(0x24, task, 1, 0, 0, NULL); // GetTaskError: lädt Eigenschaft 0x30 + boss_receive_property(0x30, &taskErr, 1); + boss_task_cmd(0x22, task, 0, 0, 0, &http); // GetTaskCommErrorCode (HTTP-Status) + u32 *cmd = getThreadCommandBuffer(); + cmd[0] = IPC_MakeHeader(0x2E, 1, 0); // GetErrorCode: Ergebnis -> 004-XXXX + cmd[1] = result; + if (R_SUCCEEDED(boss_send(cmd))) code = cmd[2]; + snprintf(out, len, "Fehler %03lu-%04lu (Ergebnis 0x%02X, Dienst 0x%02X, Aufgabe 0x%02X, HTTP %lu)", + (unsigned long)(code / 10000), (unsigned long)(code % 10000), result, service, taskErr, (unsigned long)http); +} + +static char testUrl[256]; +static bool testSeenRunning; + +bool spotpass_test_start(const char *server, char *msg, size_t msglen) +{ + if (!url_for(server, "test.boss", testUrl, sizeof(testUrl))) { + snprintf(msg, msglen, "SpotPass-Test: Geräte-ID nicht lesbar"); + return false; + } + Result rc = bossInit(0, false); + if (R_FAILED(rc)) { + snprintf(msg, msglen, "SpotPass-Test: BOSS nicht verfügbar (%08lX)", (unsigned long)rc); + return false; + } + const char *step = ""; + rc = setup_task(server, TASK_TEST, testUrl, 60, &step); + if (R_SUCCEEDED(rc)) { step = "Aufgabe starten"; rc = bossStartTaskImmediate(TASK_TEST); } + bossExit(); + if (R_FAILED(rc)) { + snprintf(msg, msglen, "SpotPass-Test fehlgeschlagen bei: %s (%08lX)", step, (unsigned long)rc); + return false; + } + testSeenRunning = false; + snprintf(msg, msglen, "SpotPass-Test gestartet ..."); + return true; +} + +bool spotpass_test_poll(int seconds, char *msg, size_t msglen) +{ + if (R_FAILED(bossInit(0, false))) return true; + u8 status = 0, out2 = 0; + u32 out1 = 0; + Result rc = bossGetTaskState(TASK_TEST, 0, &status, &out1, &out2); + bool running = R_SUCCEEDED(rc) && status != BOSSTASKSTATUS_ERROR && !(testSeenRunning && status != BOSSTASKSTATUS_STARTED); + if (status == BOSSTASKSTATUS_STARTED) testSeenRunning = true; + if (running && seconds < 180) { + snprintf(msg, msglen, "SpotPass-Test läuft ... %d s (Status %u)", seconds, status); + bossExit(); + return true; + } + if (R_FAILED(rc)) + snprintf(msg, msglen, "SpotPass-Test: Status nicht lesbar (%08lX)", (unsigned long)rc); + else if (running) + snprintf(msg, msglen, "SpotPass-Test nach 3 Min. noch nicht fertig (Status %u).\n" + "Er läuft im Hintergrund weiter. Später in die Mitteilungen schauen.", status); + else if (status == BOSSTASKSTATUS_ERROR) { + char why[128]; + task_error_text(TASK_TEST, why, sizeof(why)); + snprintf(msg, msglen, "SpotPass-Test: Abruf fehlgeschlagen.\n%s\n%s", why, testUrl); + } + else + snprintf(msg, msglen, "SpotPass-Test abgeholt (Status %u, %lu, %u).\nSteht \"MBMNET SpotPass-Test\" in den Mitteilungen?", + status, (unsigned long)out1, out2); + if (!running) bossDeleteTask(TASK_TEST, 0); // nur löschen, wenn wirklich fertig + bossExit(); + return false; +} diff --git a/source/spotpass.h b/source/spotpass.h new file mode 100644 index 0000000..e58e6ad --- /dev/null +++ b/source/spotpass.h @@ -0,0 +1,17 @@ +#pragma once +#include <3ds/types.h> +#include + +// SpotPass (BOSS): Der 3DS holt MBMNET-Nachrichten und Ankündigungen selbst im Hintergrund ab (auch im +// Standby, ohne App) und zeigt sie als Mitteilung im HOME-Menü. Die Aufgabe ruft alle 2 Minuten +// http:///spotpass//news.boss ab (MBMNET Accounting, spotpass.js). + +// Hintergrund-Aufgabe anmelden (bei aktivem MBMNET). false + msg bei Fehler. +bool spotpass_register(const char *server, char *msg, size_t msglen); +// Hintergrund-Aufgabe abmelden (beim Wechsel zu Nintendo) +void spotpass_unregister(void); +// Test für die Werkzeuge: startet den sofortigen Abruf einer Test-Mitteilung. true = läuft, +// danach jede Sekunde spotpass_test_poll aufrufen. +bool spotpass_test_start(const char *server, char *msg, size_t msglen); +// true = Test noch nicht fertig. msg bekommt den Stand bzw. das Ergebnis. +bool spotpass_test_poll(int seconds, char *msg, size_t msglen); diff --git a/source/update.c b/source/update.c new file mode 100644 index 0000000..e940586 --- /dev/null +++ b/source/update.c @@ -0,0 +1,277 @@ +// Auto-Update. Die App fragt den MBMNET-Server (per HTTP, das kann der 3DS zuverlässig): +// GET /app/version -> z. B. "1.2.0" +// GET /app/mbmnet.3dsx -> die neue App (Homebrew-Launcher-Version) +// GET /app/mbmnet.cia -> die neue App (installierte CIA-Version) +// Der Server holt beides von deinem Git-Server (siehe config.json / README). +#include <3ds.h> +#include +#include +#include +#include +#include + +#include "update.h" + +#define MAX_DOWNLOAD (8 * 1024 * 1024) + +static volatile UpdateState state = UPD_IDLE; +static char server[64]; +static char selfPath[256]; +static char newVersion[32]; +static Thread thread; +static bool runningAsCia; + +// Fehlersuche: Schritt und Code des letzten Fehlers, dazu ein Protokoll auf der SD +#define LOG_FILE "sdmc:/3ds/mbmnet/update.log" +static char errStep[48]; +static Result errCode; +static volatile int downloadAttempt; // laufender Versuch (für die Anzeige) + +static void ulog(const char *fmt, ...) +{ + FILE *f = fopen(LOG_FILE, "a"); + if (!f) return; + va_list ap; + va_start(ap, fmt); + vfprintf(f, fmt, ap); + va_end(ap); + fputc('\n', f); + fclose(f); +} + +// Merkt sich den Fehler. Den Zustand setzt erst der Worker, wenn alle Versuche erfolglos waren. +static void fail(const char *stepName, Result rc) +{ + snprintf(errStep, sizeof(errStep), "%s", stepName); + errCode = rc; + ulog("FEHLER bei %s: %08lX", stepName, (unsigned long)rc); +} + +#define ATTEMPTS 3 +static void pause_seconds(int s) { svcSleepThread((s64)s * 1000 * 1000 * 1000); } + +int update_attempt(void) { return downloadAttempt; } + +void update_error(char *out, size_t len) +{ + snprintf(out, len, "%s (Fehler %08lX)", errStep[0] ? errStep : "?", (unsigned long)errCode); +} + +UpdateState update_state(void) { return state; } +const char *update_new_version(void) { return newVersion; } + +// Lädt eine URL komplett in den Speicher. Gibt den HTTP-Status zurück (0 bei Netzwerkfehler). +static Result lastHttpRc; // Fehlercode, falls http_get 0 zurückgibt + +static u32 http_get(const char *url, u8 **out, u32 *outSize) +{ + httpcContext ctx; + u32 status = 0; + *out = NULL; + *outSize = 0; + + lastHttpRc = httpcOpenContext(&ctx, HTTPC_METHOD_GET, url, 1); + if (R_FAILED(lastHttpRc)) return 0; + httpcAddRequestHeaderField(&ctx, "User-Agent", "MBMNET-Switcher/" APP_VERSION); + httpcSetKeepAlive(&ctx, HTTPC_KEEPALIVE_DISABLED); + + if (R_SUCCEEDED(lastHttpRc = httpcBeginRequest(&ctx)) && + R_SUCCEEDED(lastHttpRc = httpcGetResponseStatusCodeTimeout(&ctx, &status, 10ULL * 1000 * 1000 * 1000)) && + status == 200) { + u32 cap = 64 * 1024, size = 0, got; + u8 *buf = malloc(cap); + Result rc; + do { + if (!buf) break; + if (size == cap) { + if (cap >= MAX_DOWNLOAD) { free(buf); buf = NULL; break; } + u8 *bigger = realloc(buf, cap * 2); + if (!bigger) { free(buf); buf = NULL; break; } + buf = bigger; + cap *= 2; + } + got = 0; + rc = httpcDownloadData(&ctx, buf + size, cap - size, &got); + size += got; + } while (rc == (Result)HTTPC_RESULTCODE_DOWNLOADPENDING); + + if (buf && R_SUCCEEDED(rc)) { + *out = buf; + *outSize = size; + } else { + lastHttpRc = buf ? rc : -2; // -2 = zu wenig Speicher + *outSize = size; + free(buf); + status = 0; + } + } + httpcCloseContext(&ctx); + return status; +} + +// Installiert eine CIA über den Systemdienst am:net (wie FBI) +static bool install_cia(const u8 *data, u32 size) +{ + Handle h; + Result rc = AM_StartCiaInstall(MEDIATYPE_SD, &h); + ulog("CIA-Installation starten: %08lX", (unsigned long)rc); + if (R_FAILED(rc)) { fail("CIA-Installation starten", rc); return false; } + for (u32 off = 0; off < size;) { + u32 chunk = size - off > 0x10000 ? 0x10000 : size - off; + u32 written = 0; + rc = FSFILE_Write(h, &written, off, data + off, chunk, 0); + if (R_FAILED(rc) || written != chunk) { + ulog("Schreiben bei %lu: %08lX (%lu von %lu Bytes)", (unsigned long)off, (unsigned long)rc, + (unsigned long)written, (unsigned long)chunk); + AM_CancelCIAInstall(h); + fail("CIA schreiben", rc); + return false; + } + off += chunk; + } + rc = AM_FinishCiaInstall(h); + ulog("CIA-Installation abschließen: %08lX", (unsigned long)rc); + if (R_FAILED(rc)) { fail("CIA-Installation abschließen", rc); return false; } + return true; +} + +// Schreibt die neue .3dsx über die laufende +static bool install_3dsx(const u8 *data, u32 size) +{ + char tmpPath[sizeof(selfPath) + 8]; + snprintf(tmpPath, sizeof(tmpPath), "%s.neu", selfPath); + FILE *f = fopen(tmpPath, "wb"); + bool ok = f && fwrite(data, 1, size, f) == size; + if (f) fclose(f); + ulog("3DSX schreiben nach %s: %s", tmpPath, ok ? "OK" : "FEHLER"); + if (!ok) { fail("3DSX schreiben", -1); return false; } + // Erst komplett schreiben, dann austauschen: so bleibt bei einem Abbruch die alte App heil. + remove(selfPath); + ok = rename(tmpPath, selfPath) == 0; + ulog("3DSX austauschen (%s): %s", selfPath, ok ? "OK" : "FEHLER"); + if (!ok) fail("3DSX austauschen", -1); + return ok; +} + +static bool is_newer(const char *remote, const char *local) +{ + int r[3] = { 0 }, l[3] = { 0 }; + sscanf(remote, "%d.%d.%d", &r[0], &r[1], &r[2]); + sscanf(local, "%d.%d.%d", &l[0], &l[1], &l[2]); + for (int i = 0; i < 3; i++) { + if (r[i] != l[i]) return r[i] > l[i]; + } + return false; +} + +// Schritt 1: gibt es eine neuere Version? (bei Netzwerkfehlern bis zu 3 Versuche) +static void check_worker(void *arg) +{ + char url[128]; + u8 *data; + u32 size; + + snprintf(url, sizeof(url), "http://%s/app/version", server); + for (int attempt = 1; attempt <= ATTEMPTS; attempt++) { + u32 status = http_get(url, &data, &size); + if (status == 404) { state = UPD_NONE; return; } + if (status == 200) { + snprintf(newVersion, sizeof(newVersion), "%.*s", (int)(size < 31 ? size : 31), (char *)data); + newVersion[strcspn(newVersion, " \r\n")] = 0; + if (newVersion[0] == 'v') memmove(newVersion, newVersion + 1, strlen(newVersion)); + free(data); + state = is_newer(newVersion, APP_VERSION) ? UPD_AVAILABLE : UPD_LATEST; + return; + } + free(data); + if (attempt < ATTEMPTS) pause_seconds(2); + } + state = UPD_ERROR; +} + +// Ein Versuch: laden, prüfen, installieren +static bool download_and_install(const char *url) +{ + u8 *data; + u32 size; + u32 status = http_get(url, &data, &size); + ulog("Download: HTTP %lu, %lu Bytes", (unsigned long)status, (unsigned long)size); + if (status != 200) { + free(data); + fail(status ? "Herunterladen (HTTP-Status)" : "Herunterladen", status ? (Result)status : lastHttpRc); + return false; + } + + // Nur echte Dateien installieren: CIA beginnt mit Headergröße 0x2020, 3DSX mit "3DSX" + bool valid = size >= 32 && (runningAsCia + ? data[0] == 0x20 && data[1] == 0x20 && data[2] == 0 && data[3] == 0 + : memcmp(data, "3DSX", 4) == 0); + if (!valid) { free(data); fail("Datei prüfen", -1); return false; } + bool ok = runningAsCia ? install_cia(data, size) : install_3dsx(data, size); + free(data); + return ok; +} + +// Schritt 2: neue Version laden und installieren (bei Fehlern bis zu 3 Versuche) +static void download_worker(void *arg) +{ + char url[128]; + mkdir("sdmc:/3ds/mbmnet", 0777); + remove(LOG_FILE); + errStep[0] = 0; + snprintf(url, sizeof(url), "http://%s/app/%s", server, runningAsCia ? "mbmnet.cia" : "mbmnet.3dsx"); + ulog("MBMNET-Update v%s -> v%s (%s)", APP_VERSION, newVersion, runningAsCia ? "CIA" : "3DSX"); + ulog("Lade %s", url); + + for (int attempt = 1; attempt <= ATTEMPTS; attempt++) { + if (attempt > 1) ulog("--- Versuch %d von %d", attempt, ATTEMPTS); + downloadAttempt = attempt; + if (download_and_install(url)) { + ulog("Ergebnis: OK"); + state = UPD_INSTALLED; + return; + } + if (attempt < ATTEMPTS) pause_seconds(3); + } + ulog("Ergebnis: FEHLER nach %d Versuchen", ATTEMPTS); + state = UPD_ERROR; +} + +static void start_thread(ThreadFunc fn) +{ + if (thread) { threadJoin(thread, U64_MAX); threadFree(thread); thread = NULL; } + s32 prio = 0x30; + svcGetThreadPriority(&prio, CUR_THREAD_HANDLE); + thread = threadCreate(fn, NULL, 32 * 1024, prio + 1, -2, false); + if (!thread) state = UPD_ERROR; +} + +void update_start(const char *srv, const char *self) +{ + if (!srv[0] || state == UPD_CHECKING || state == UPD_DOWNLOADING) return; + snprintf(server, sizeof(server), "%s", srv); + snprintf(selfPath, sizeof(selfPath), "%s", self); + runningAsCia = !envIsHomebrew(); + state = UPD_CHECKING; + start_thread(check_worker); +} + +void update_download(void) +{ + if (state != UPD_AVAILABLE) return; + state = UPD_DOWNLOADING; + start_thread(download_worker); +} + +bool update_pending(void) +{ + return state == UPD_AVAILABLE || state == UPD_DOWNLOADING || state == UPD_INSTALLED; +} + +void update_finish(void) +{ + if (!thread) return; + // Läuft der Download noch, nicht freigeben: Die App beendet sich ohnehin. + if (R_SUCCEEDED(threadJoin(thread, 3ULL * 1000 * 1000 * 1000))) threadFree(thread); + thread = NULL; +} diff --git a/source/update.h b/source/update.h new file mode 100644 index 0000000..ae04962 --- /dev/null +++ b/source/update.h @@ -0,0 +1,28 @@ +#pragma once +#include <3ds/types.h> +#include + +typedef enum { + UPD_IDLE, // noch nicht geprüft + UPD_CHECKING, // fragt den Server + UPD_LATEST, // schon die neueste Version + UPD_AVAILABLE, // neue Version gefunden, wartet auf update_download() + UPD_DOWNLOADING, // lädt neue Version + UPD_INSTALLED, // neue Version liegt auf der SD, App neu starten + UPD_NONE, // Server bietet keine Updates an + UPD_ERROR, // Server nicht erreichbar o. Ä. +} UpdateState; + +// Startet die Prüfung im Hintergrund. selfPath = Pfad der laufenden .3dsx. +void update_start(const char *server, const char *selfPath); +// Lädt und installiert die gefundene neue Version (nur im Zustand UPD_AVAILABLE). +void update_download(void); +// true, solange ein Update ansteht, lädt oder auf den Neustart wartet +bool update_pending(void); +UpdateState update_state(void); +const char *update_new_version(void); +void update_finish(void); +// Laufender Download-Versuch (1-3) +int update_attempt(void); +// Beschreibung des letzten Fehlers (Schritt und Code) +void update_error(char *out, size_t len); diff --git a/tools/Dockerfile b/tools/Dockerfile new file mode 100644 index 0000000..730a230 --- /dev/null +++ b/tools/Dockerfile @@ -0,0 +1,20 @@ +# Build-Umgebung für die MBMNET-App: devkitARM + makerom + bannertool (für die CIA) +FROM devkitpro/devkitarm + +# makerom (Project_CTR) aus dem Quellcode bauen +RUN git clone --depth 1 https://github.com/3DSGuy/Project_CTR.git /tmp/ctr \ + && make -C /tmp/ctr/makerom deps \ + && make -C /tmp/ctr/makerom \ + && find /tmp/ctr/makerom -type f -name makerom -perm -u+x -exec cp {} /usr/local/bin/makerom \; \ + && rm -rf /tmp/ctr + +# bannertool aus dem Quellcode bauen (direkt kompiliert, die mitgelieferten +# Build-Skripte kennen ARM-Rechner wie Apple Silicon nicht) +RUN git clone --depth 1 https://github.com/diasurgical/bannertool.git /tmp/bt \ + && cd /tmp/bt && mkdir o \ + && for f in $(find source -name '*.c'); do gcc -O2 -Isource -c "$f" -o "o/$(basename $f).o"; done \ + && for f in $(find source -name '*.cpp'); do g++ -std=gnu++11 -O2 -Isource -DVERSION_MAJOR=1 -DVERSION_MINOR=2 -DVERSION_MICRO=0 -c "$f" -o "o/$(basename $f).o"; done \ + && g++ o/*.o -o /usr/local/bin/bannertool \ + && rm -rf /tmp/bt + +RUN makerom -version || true; bannertool 2>&1 | head -1 || true