pax_global_header00006660000000000000000000000064147301366260014522gustar00rootroot0000000000000052 comment=ee831a676b847b8767d25caeadd9a18723f52605 UxPlay-1.71.1/000077500000000000000000000000001473013662600130335ustar00rootroot00000000000000UxPlay-1.71.1/.gitignore000066400000000000000000000000171473013662600150210ustar00rootroot00000000000000build/ .vscode/UxPlay-1.71.1/CMakeLists.txt000066400000000000000000000037701473013662600156020ustar00rootroot00000000000000if ( APPLE ) cmake_minimum_required( VERSION 3.13 ) else () cmake_minimum_required( VERSION 3.10 ) endif () project( uxplay ) message( STATUS "Project name: " ${PROJECT_NAME} ) include(GNUInstallDirs) set ( CMAKE_CXX_STANDARD 11 ) if (ZOOMFIX ) message (STATUS "cmake option ZOOMFIX is no longer used (if needed, ZOOMFIX is automatically applied if X11 libraries are present)" ) endif() if ( ( UNIX AND NOT APPLE ) OR USE_X11 ) if ( NOT NO_X11_DEPS ) find_package( X11 ) if ( X11_FOUND ) message (STATUS "Will compile using X11 Libraries (use cmake option -DNO_X11_DEPS=ON if X11 dependence is not wanted)" ) link_libraries( ${X11_LIBRARIES} ) include_directories( ${X11_INCLUDE_DIR} ) else () message (STATUS "X11 libraries not found, will compile without X11 dependence" ) endif () else() message (STATUS "will compile without X11 dependence" ) endif() endif() if( UNIX AND NOT APPLE ) add_definitions( -DSUPPRESS_AVAHI_COMPAT_WARNING ) else() set( CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE ) endif() add_subdirectory( lib/llhttp ) add_subdirectory( lib/playfair ) add_subdirectory( lib ) add_subdirectory( renderers ) if ( GST_MACOS ) add_definitions( -DGST_MACOS ) message ( STATUS "define GST_MACOS" ) endif() add_executable( uxplay uxplay.cpp ) target_link_libraries( uxplay renderers airplay ) install( TARGETS uxplay RUNTIME DESTINATION bin ) install( FILES uxplay.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 ) install( FILES README.md README.txt README.html LICENSE DESTINATION ${CMAKE_INSTALL_DOCDIR} ) install( FILES lib/llhttp/LICENSE-MIT DESTINATION ${CMAKE_INSTALL_DOCDIR}/llhttp ) # uninstall target if(NOT TARGET uninstall) configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY) add_custom_target(uninstall COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) endif() UxPlay-1.71.1/LICENSE000066400000000000000000001045151473013662600140460ustar00rootroot00000000000000 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 . UxPlay-1.71.1/README.html000066400000000000000000003356671473013662600147020ustar00rootroot00000000000000

UxPlay 1.71: AirPlay-Mirror and AirPlay-Audio server for Linux, macOS, and Unix (now also runs on Windows).

Now developed at the GitHub site https://github.com/FDH2/UxPlay (where ALL user issues should be posted, and latest versions can be found).

  • NEW in v1.71: Support for (YouTube) HLS (HTTP Live Streaming) video with the new “-hls” option. Click on the airplay icon in the YouTube app to stream video. (You may need to wait until advertisements have finished or been skipped before clicking the YouTube airplay icon.) Please report any issues with this new feature of UxPlay.

Highlights:

  • GPLv3, open source.
  • Originally supported only AirPlay Mirror protocol, now has added support for AirPlay Audio-only (Apple Lossless ALAC) streaming from current iOS/iPadOS clients. Now with support for Airplay HLS video-streaming (currently only YouTube video).
  • macOS computers (2011 or later, both Intel and “Apple Silicon” M1/M2 systems) can act either as AirPlay clients, or as the server running UxPlay. Using AirPlay, UxPlay can emulate a second display for macOS clients.
  • Support for older iOS clients (such as 32-bit iPad 2nd gen., iPod Touch 5th gen. and iPhone 4S, when upgraded to iOS 9.3.5, or later 64-bit devices), plus a Windows AirPlay-client emulator, AirMyPC.
  • Uses GStreamer plugins for audio and video rendering (with options to select different hardware-appropriate output “videosinks” and “audiosinks”, and a fully-user-configurable video streaming pipeline).
  • Support for server behind a firewall.
  • Raspberry Pi support both with and without hardware video decoding by the Broadcom GPU. Tested on Raspberry Pi Zero 2 W, 3 Model B+, 4 Model B, and 5.
  • Support for running on Microsoft Windows (builds with the MinGW-64 compiler in the unix-like MSYS2 environment).

Note: AirPlay2 multi-room audio streaming is not supported: use shairport-sync for that.

Packaging status (Linux and *BSD distributions)

Current Packaging status.

  • Install uxplay on Debian-based Linux systems with “sudo apt install uxplay”; on FreeBSD with “sudo pkg install uxplay”. Also available on Arch-based systems through AUR. Since v. 1.66, uxplay is now also packaged in RPM format by Fedora 38 (“sudo dnf install uxplay”).

  • For other RPM-based distributions which have not yet packaged UxPlay, a RPM “specfile” uxplay.spec is now provided with recent releases (see their “Assets”), and can also be found in the UxPlay source top directory. See the section on using this specfile for building an installable RPM package.

After installation:

  • (On Linux and *BSD): if a firewall is active on the server hosting UxPlay, make sure the default network port (UDP 5353) for mDNS/DNS-SD queries is open (see Troubleshooting below for more details); also open three UDP and three TCP ports for Uxplay, and use the “uxplay -p ” option (see “man uxplay” or “uxplay -h”).

  • Even if you install your distribution’s pre-compiled uxplay binary package, you may need to read the instructions below for running UxPlay to see which of your distribution’s GStreamer plugin packages you should also install.

  • For Audio-only mode (Apple Music, etc.) best quality is obtained with the option “uxplay -async”, but there is then a 2 second latency imposed by iOS.

  • Add any UxPlay options you want to use as defaults to a startup file ~/.uxplayrc (see “man uxplay” or “uxplay -h” for format and other possible locations). In particular, if your system uses PipeWire audio or Wayland video systems, you may wish to add “as pipewiresink” or “vs waylandsink” as defaults to the file. (Output from terminal commands “ps waux | grep pulse” or “pactl info” will contain “pipewire” if your Linux/BSD system uses it).

  • On Raspberry Pi: models using hardware h264 video decoding by the Broadcom GPU (models 4B and earlier) may require the uxplay option -bt709. If you use Ubuntu 22.10 or earlier, GStreamer must be patched to use hardware video decoding by the Broadcom GPU (also recommended but optional for Raspberry Pi OS (Bullseye): the patched GStreamer does not need option ” -bt709`“. The need for -bt709 when hardware video decoding is used seems to have reappeared starting with GStreamer-1.22.

To (easily) compile the latest UxPlay from source, see the section Getting UxPlay.

Detailed description of UxPlay

This project is a GPLv3 open source unix AirPlay2 Mirror server for Linux, macOS, and *BSD. It was initially developed by antimof using code from OpenMAX-based RPiPlay, which in turn derives from AirplayServer, shairplay, and playfair. (The antimof site is no longer involved in development, but periodically posts updates pulled from the new main UxPlay site).

UxPlay is tested on a number of systems, including (among others) Debian (10 “Buster”, 11 “Bullseye”, 12 “Bookworm”), Ubuntu (20.04 LTS, 22.04 LTS, 23.04 (also Ubuntu derivatives Linux Mint, Pop!_OS), Red Hat and clones (Fedora 38, Rocky Linux 9.2), openSUSE Leap 15.5, Mageia 9, OpenMandriva “ROME”, PCLinuxOS, Arch Linux, Manjaro, and should run on any Linux system. Also tested on macOS Catalina and Ventura (Intel) and Sonoma (M2), FreeBSD 14.0, Windows 10 and 11 (64 bit).

On Raspberry Pi 4 model B, it is tested on Raspberry Pi OS (Bullseye and Bookworm) (32- and 64-bit), Ubuntu 22.04 LTS and 23.04, Manjaro RPi4 23.02, and (without hardware video decoding) on openSUSE 15.5. Also tested on Raspberry Pi Zero 2 W, 3 model B+, and now 5.

Its main use is to act like an AppleTV for screen-mirroring (with audio) of iOS/iPadOS/macOS clients (iPhone, iPod Touch, iPad, Mac computers) on the server display of a host running Linux, macOS, or other unix (and now also Microsoft Windows). UxPlay supports Apple’s AirPlay2 protocol using “Legacy Protocol”, but some features are missing. (Details of what is publicly known about Apple’s AirPlay 2 protocol can be found here, here and here; see also pyatv which could be a resource for adding modern protocols.) While there is no guarantee that future iOS releases will keep supporting “Legacy Protocol”, iOS 17 continues support.

The UxPlay server and its client must be on the same local area network, on which a Bonjour/Zeroconf mDNS/DNS-SD server is also running (only DNS-SD “Service Discovery” service is strictly necessary, it is not necessary that the local network also be of the “.local” mDNS-based type). On Linux and BSD Unix servers, this is usually provided by Avahi, through the avahi-daemon service, and is included in most Linux distributions (this service can also be provided by macOS, iOS or Windows servers).

Connections to the UxPlay server by iOS/MacOS clients can be initiated both in AirPlay Mirror mode (which streams lossily-compressed AAC audio while mirroring the client screen, or in the alternative AirPlay Audio mode which streams Apple Lossless (ALAC) audio without screen mirroring. In Audio mode, metadata is displayed in the uxplay terminal; if UxPlay option -ca <name> is used, the accompanying cover art is also output to a periodically-updated file <name>, and can be viewed with a (reloading) graphics viewer of your choice. Switching between Mirror and Audio modes during an active connection is possible: in Mirror mode, stop mirroring (or close the mirror window) and start an Audio mode connection, switch back by initiating a Mirror mode connection; cover-art display stops/restarts as you leave/re-enter Audio mode.

  • Note that Apple video-DRM (as found in “Apple TV app” content on the client) cannot be decrypted by UxPlay, and the Apple TV app cannot be watched using UxPlay’s AirPlay Mirror mode (only the unprotected audio will be streamed, in AAC format).

  • With the new “-hls” option, UxPlay now also supports non-Mirror AirPlay video streaming (where the client controls a web server on the AirPlay server that directly receives HLS content to avoid it being decoded and re-encoded by the client). This currently only supports streaming of YouTube videos. Without the -hls option, using the icon for AirPlay video in apps such as the YouTube app will only send audio (in lossless ALAC format) without the accompanying video.

Possibility for using hardware-accelerated h264/h265 video-decoding, if available.

UxPlay uses GStreamer “plugins” for rendering audio and video. This means that video and audio are supported “out of the box”, using a choice of plugins. AirPlay streams video in h264 format: gstreamer decoding is plugin agnostic, and uses accelerated GPU hardware h264 decoders if available; if not, software decoding is used.

  • VAAPI for Intel and AMD integrated graphics, NVIDIA with “Nouveau” open-source driver

    With an Intel or AMD GPU, hardware decoding with the open-source VAAPI gstreamer plugin is preferable. The open-source “Nouveau” drivers for NVIDIA graphics are also in principle supported: see here, but this requires VAAPI to be supplemented with firmware extracted from the proprietary NVIDIA drivers.

  • NVIDIA with proprietary drivers

    The nvh264dec plugin (included in gstreamer1.0-plugins-bad since GStreamer-1.18.0) can be used for accelerated video decoding on the NVIDIA GPU after NVIDIA’s CUDA driver libcuda.so is installed. For GStreamer-1.16.3 or earlier, the plugin is called nvdec, and must be built by the user.

  • Video4Linux2 support for h264 hardware decoding on Raspberry Pi (Pi 4B and older)

    Raspberry Pi (RPi) computers (tested on Pi 4 Model B) can now run UxPlay using software video decoding, but hardware-accelerated h264/h265 decoding by firmware in the Pi’s Broadcom 2835 GPU is prefered. UxPlay accesses this using the GStreamer-1.22 Video4Linux2 (v4l2) plugin; Uses the out-of-mainline Linux kernel module bcm2835-codec maintained by Raspberry Pi, so far only included in Raspberry Pi OS, and two other distributions (Ubuntu, Manjaro) available with Raspberry Pi Imager. (For GStreamer < 1.22, see the UxPlay Wiki). Pi model 5 has no support for hardware H264 decoding, as its CPU is powerful enough for satisfactory software H264 decoding

  • Support for h265 (HEVC) hardware decoding on Raspberry Pi (Pi 4 model B and Pi 5)

    These Raspberry Pi models have a dedicated HEVC decoding block (not the GPU), with a driver “rpivid” which is not yet in the mainline Linux kernel (but is planned to be there in future). Unfortunately it produces decoded video in a non-standard pixel format (NC30 or “SAND”) which will not be supported by GStreamer until the driver is in the mainline kernel; without this support, UxPlay support for HEVC hardware decoding on Raspberry Pi will not work.

Note to packagers:

UxPlay’s GPLv3 license does not have an added “GPL exception” explicitly allowing it to be distributed in compiled form when linked to OpenSSL versions prior to v. 3.0.0 (older versions of OpenSSL have a license clause incompatible with the GPL unless OpenSSL can be regarded as a “System Library”, which it is in *BSD). Many Linux distributions treat OpenSSL as a “System Library”, but some (e.g. Debian) do not: in this case, the issue is solved by linking with OpenSSL-3.0.0 or later.

Getting UxPlay

Either download and unzip UxPlay-master.zip, or (if git is installed): “git clone https://github.com/FDH2/UxPlay”. You can also download a recent or earlier version listed in Releases.

  • A recent UxPlay can also be found on the original antimof site; that original project is inactive, but is usually kept current or almost-current with the active UxPlay github site (thank you antimof!).

Building UxPlay on Linux (or *BSD):

Debian-based systems:

(Adapt these instructions for non-Debian-based Linuxes or *BSD; for macOS, see specific instruction below). See Troubleshooting below for help with any difficulties.

You need a C/C++ compiler (e.g. g++) with the standard development libraries installed. Debian-based systems provide a package “build-essential” for use in compiling software. You also need pkg-config: if it is not found by “which pkg-config”, install pkg-config or its work-alike replacement pkgconf. Also make sure that cmake>=3.10 is installed: “sudo apt install cmake” (add build-essential and pkg-config (or pkgconf) to this if needed).

Make sure that your distribution provides OpenSSL 1.1.1 or later, and libplist 2.0 or later. (This means Debian 10 “Buster” based systems (e.g, Ubuntu 18.04) or newer; on Debian 10 systems “libplist” is an older version, you need “libplist3”.) If it does not, you may need to build and install these from source (see instructions at the end of this README).

If you have a non-standard OpenSSL installation, you may need to set the environment variable OPENSSL_ROOT_DIR (e.g. , “export OPENSSL_ROOT_DIR=/usr/local/lib64” if that is where it is installed). Similarly, for non-standard (or multiple) GStreamer installations, set the environment variable GSTREAMER_ROOT_DIR to the directory that contains the “…/gstreamer-1.0/” directory of the gstreamer installation that UxPlay should use (if this is e.g. “~/my_gstreamer/lib/gstreamer-1.0/”, set this location with “export GSTREAMER_ROOT_DIR=$HOME/my_gstreamer/lib”).

  • Most users will use the GStreamer supplied by their distribution, but a few (in particular users of Raspberry Pi OS Lite Legacy (Buster) on a Raspberry Pi model 4B who wish to stay on that unsupported Legacy OS for compatibility with other apps) should instead build a newer Gstreamer from source following these instructions . Do this before building UxPlay.

In a terminal window, change directories to the source directory of the downloaded source code (“UxPlay-*”, “*” = “master” or the release tag for zipfile downloads, “UxPlay” for “git clone” downloads), then follow the instructions below:

Note: By default UxPlay will be built with optimization for the computer it is built on; when this is not the case, as when you are packaging for a distribution, use the cmake option -DNO_MARCH_NATIVE=ON.

If you use X11 Windows on Linux or *BSD, and wish to toggle in/out of fullscreen mode with a keypress (F11 or Alt_L+Enter) UxPlay needs to be built with a dependence on X11. Starting with UxPlay-1.59, this will be done by default IF the X11 development libraries are installed and detected. Install these with “sudo apt install libx11-dev”. If GStreamer < 1.20 is detected, a fix needed by screen-sharing apps (e.g., Zoom) will also be made.

  • If X11 development libraries are present, but you wish to build UxPlay without any X11 dependence, use the cmake option -DNO_X11_DEPS=ON.
  1. sudo apt install libssl-dev libplist-dev“. (unless you need to build OpenSSL and libplist from source).
  2. sudo apt install libavahi-compat-libdnssd-dev
  3. sudo apt install libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev. (*Skip if you built Gstreamer from source)
  4. cmake . (For a cleaner build, which is useful if you modify the source, replace this bymkdir build; cd build; cmake ..”: you can then delete the contents of the build directory if needed, without affecting the source.) Also add any cmake “-D” options here as needed (e.g, -DNO_X11_DEPS=ON or -DNO_MARCH_NATIVE=ON).
  5. make
  6. sudo make install (you can afterwards uninstall with sudo make uninstall in the same directory in which this was run).

This installs the executable file “uxplay” to /usr/local/bin, (and installs a manpage to somewhere standard like /usr/local/share/man/man1 and README files to somewhere like /usr/local/share/doc/uxplay). (If “man uxplay” fails, check if $MANPATH is set: if so, the path to the manpage (usually /usr/local/share/man/) needs to be added to $MANPATH .) The uxplay executable can also be found in the build directory after the build process, if you wish to test before installing (in which case the GStreamer plugins must first be installed).

Building on non-Debian Linux and *BSD

**For those with RPM-based distributions, a RPM spec file uxplay.spec is also available: see Building an installable rpm package.

  • Red Hat, or clones like CentOS (now continued as Rocky Linux or Alma Linux): (sudo dnf install, or sudo yum install) openssl-devel libplist-devel avahi-compat-libdns_sd-devel gstreamer1-devel gstreamer1-plugins-base-devel (+libX11-devel for fullscreen X11) (some of these may be in the “CodeReady” add-on repository, called “PowerTools” by clones)

  • Mageia, PCLinuxOS, OpenMandriva: Same as Red Hat, except for name changes: (Mageia) “gstreamer1.0-devel”, “gstreamer-plugins-base1.0-devel”; (OpenMandriva) “libopenssl-devel”, “gstreamer-devel”, “libgst-plugins-base1.0-devel”. PCLinuxOS: same as Mageia, but uses synaptic (or apt) as its package manager.

  • openSUSE: (sudo zypper install) libopenssl-3-devel (formerly libopenssl-devel) libplist-2_0-devel (formerly libplist-devel) avahi-compat-mDNSResponder-devel gstreamer-devel gstreamer-plugins-base-devel (+ libX11-devel for fullscreen X11).

  • Arch Linux (Also available as a package in AUR): (sudo pacman -Syu) openssl libplist avahi gst-plugins-base.

  • FreeBSD: (sudo pkg install) libplist gstreamer1. Either avahi-libdns or mDNSResponder must also be installed to provide the dns_sd library. OpenSSL is already installed as a System Library.

Building an installable RPM package

First-time RPM builders should first install the rpm-build and rpmdevtools packages, then create the rpmbuild tree with “rpmdev-setuptree”. Then download and copy uxplay.spec into ~/rpmbuild/SPECS. In that directory, run “rpmdev-spectool -g -R uxplay.spec” to download the corresponding source file uxplay-*.tar.gz into ~/rpmbuild/SOURCES (“rpmdev-spectool” may also be just called “spectool”); then run “rpmbuild -ba uxplay.spec” (you will need to install any required dependencies this reports). This should create the uxplay RPM package in a subdirectory of ~/rpmbuild/RPMS. (uxplay.spec is tested on Fedora 38, Rocky Linux 9.2, openSUSE Leap 15.5, Mageia 9, OpenMandriva, PCLinuxOS; it can be easily modified to include dependency lists for other RPM-based distributions.)

Running UxPlay

Installing plugins (Debian-based Linux distributions, including Ubuntu and Raspberry Pi OS) (skip if you built a complete GStreamer from source)

Next install the GStreamer plugins that are needed with sudo apt install gstreamer1.0-<plugin>. Values of <plugin> required are:

  1. plugins-base
  2. libav” (for sound),
  3. plugins-good” (for v4l2 hardware h264 decoding)
  4. plugins-bad” (for h264 decoding).

Debian-based distributions split some of the plugin packages into smaller pieces: some that may also be needed include “gl” for OpenGL support (this provides the “-vs glimagesink” videosink, which can be very useful in many systems (including Raspberry Pi), and should always be used when using h264/h265 decoding by a NVIDIA GPU), “gtk3” (which provides the “-vs gtksink” videosink), and “x” for X11 support, although these may already be installed; “vaapi” is needed for hardware-accelerated h264 video decoding by Intel or AMD graphics (but not for use with NVIDIA using proprietary drivers). If sound is not working, “alsa”“,”pulseaudio”, or “pipewire” plugins may need to be installed, depending on how your audio is set up.

  • Also install “gstreamer1.0-tools” to get the utility gst-inspect-1.0 for examining the GStreamer installation.

Installing plugins (Non-Debian-based Linux or *BSD) (skip if you built a complete GStreamer from source)

In some cases, because of patent issues, the libav plugin feature avdec_aac needed for decoding AAC audio in mirror mode is not provided in the official distribution: get it from community repositories for those distributions.

  • Red Hat, or clones like CentOS (now continued as Rocky Linux or Alma Linux): Install gstreamer1-libav gstreamer1-plugins-bad-free (+ gstreamer1-vaapi for Intel/AMD graphics). In recent Fedora, gstreamer1-libav is renamed gstreamer1-plugin-libav. To get avdec_aac, install packages from rpmfusion.org: (get ffmpeg-libs from rpmfusion; on RHEL or clones, but not recent Fedora, also get gstreamer1-libav from there).

  • Mageia, PCLinuxOS, OpenMandriva: Install gstreamer1.0-libav gstreamer1.0-plugins-bad (+ gstreamer1.0-vaapi for Intel/AMD graphics). On Mageia, to get avdec_aac, install ffmpeg from the “tainted” repository, (which also provides a more complete gstreamer1.0-plugins-bad).

  • openSUSE: Install gstreamer-plugins-libav gstreamer-plugins-bad (+ gstreamer-plugins-vaapi for Intel/AMD graphics). To get avdec_aac, install libav* packages for openSUSE from Packman “Essentials”; recommendation: after adding the Packman repository, use the option in YaST Software management to switch all system packages for multimedia to Packman).

  • Arch Linux Install gst-plugins-good gst-plugins-bad gst-libav (+ gstreamer-vaapi for Intel/AMD graphics).

  • FreeBSD: Install gstreamer1-libav, gstreamer1-plugins, gstreamer1-plugins-* (* = core, good, bad, x, gtk, gl, vulkan, pulse, v4l2, …), (+ gstreamer1-vaapi for Intel/AMD graphics).

Starting and running UxPlay

Since UxPlay-1.64, UxPlay can be started with options read from a configuration file, which will be the first found of (1) a file with a path given by environment variable $UXPLAYRC, (2) ~/.uxplayrc in the user’s home directory (“~”), (3) ~/.config/uxplayrc. The format is one option per line, omitting the initial "-" of the command-line option. Lines in the configuration file beginning with "#" are treated as comments and ignored.

Run uxplay in a terminal window. On some systems, you can specify fullscreen mode with the -fs option, or toggle into and out of fullscreen mode with F11 or (held-down left Alt)+Enter keys. Use Ctrl-C (or close the window) to terminate it when done. If the UxPlay server is not seen by the iOS client’s drop-down “Screen Mirroring” panel, check that your DNS-SD server (usually avahi-daemon) is running: do this in a terminal window with systemctl status avahi-daemon. If this shows the avahi-daemon is not running, control it with sudo systemctl [start,stop,enable,disable] avahi-daemon (on non-systemd systems, such as *BSD, use sudo service avahi-daemon [status, start, stop, restart, ...]). If UxPlay is seen, but the client fails to connect when it is selected, there may be a firewall on the server that prevents UxPlay from receiving client connection requests unless some network ports are opened: if a firewall is active, also open UDP port 5353 (for mDNS queries) needed by Avahi. See Troubleshooting below for help with this or other problems.

  • Unlike an Apple TV, the UxPlay server does not by default require clients to initially “pair” with it using a pin code displayed by the server (after which the client “trusts” the server, and does not need to repeat this). Since v1.67, Uxplay offers such “pin-authentication” as an option: see “-pin” and “-reg” in Usage for details, if you wish to use it. Some clients with MDM (Mobile Device Management, often present on employer-owned devices) are required to use pin-authentication: UxPlay will provide this even when running without the pin option.

  • By default, UxPlay is locked to its current client until that client drops the connection; since UxPlay-1.58, the option -nohold modifies this behavior so that when a new client requests a connection, it removes the current client and takes over. UxPlay 1.66 introduces a mechanism ( -restrict, -allow <id>, -block <id>) to control which clients are allowed to connect, using their “deviceID” (which in Apple devices appears to be immutable).

  • In Mirror mode, GStreamer has a choice of two methods to play video with its accompanying audio: prior to UxPlay-1.64, the video and audio streams were both played as soon as possible after they arrived (the GStreamer “sync=false” method), with a GStreamer internal clock used to try to keep them synchronized. Starting with UxPlay-1.64, the other method (GStreamer’s “sync=true” mode), which uses timestamps in the audio and video streams sent by the client, is the new default. On low-decoding-power UxPlay hosts (such as Raspberry Pi Zero W or 3 B+ models) this will drop video frames that cannot be decoded in time to play with the audio, making the video jerky, but still synchronized.

The older method which does not drop late video frames worked well on more powerful systems, and is still available with the UxPlay option “-vsync no”; this method is adapted to “live streaming”, and may be better when using UxPlay as a second monitor for a Mac computer, for example, while the new default timestamp-based method is best for watching a video, to keep lip movements and voices synchronized. (Without use of timestamps, video will eventually lag behind audio if it cannot be decoded fast enough: hardware-accelerated video-decoding helped to prevent this previously when timestamps were not being used.)

  • In Audio-only mode the GStreamer “sync=false” mode (not using timestamps) is still the default, but if you want to keep the audio playing on the server synchronized with the video showing on the client, use the -async timestamp-based option. (An example might be if you want to follow the Apple Music lyrics on the client while listening to superior sound on the UxPlay server). This delays the video on the client to match audio on the server, so leads to a slight delay before a pause or track-change initiated on the client takes effect on the audio played by the server.

AirPlay volume-control attenuates volume (gain) by up to -30dB: the decibel range -30:0 can be rescaled from Low:0, or Low:High, using the option -db (“-db Low” or “-db Low:High”), Low must be negative. Rescaling is linear in decibels. Note that GStreamer’s audio format will “clip” any audio gain above +20db, so keep High below that level. The option -taper provides a “tapered” AirPlay volume-control profile some users may prefer.

The -vsync and -async options also allow an optional positive (or negative) audio-delay adjustment in milliseconds for fine-tuning : -vsync 20.5 delays audio relative to video by 0.0205 secs; a negative value advances it.)

  • you may find video is improved by the setting -fps 60 that allows some video to be played at 60 frames per second. (You can see what framerate is actually streaming by using -vs fpsdisplaysink, and/or -FPSdata.) When using this, you should use the default timestamp-based synchronization option -vsync.

  • Since UxPlay-1.54, you can display the accompanying “Cover Art” from sources like Apple Music in Audio-Only (ALAC) mode: run “uxplay -ca <name> &” in the background, then run a image viewer with an autoreload feature: an example is “feh”: run “feh -R 1 <name>” in the foreground; terminate feh and then Uxplay with “ctrl-C fg ctrl-C”.

By default, GStreamer uses an algorithm to search for the best “videosink” (GStreamer’s term for a graphics driver to display images) to use. You can overide this with the uxplay option -vs <videosink>. Which videosinks are available depends on your operating system and graphics hardware: use “gst-inspect-1.0 | grep sink | grep -e video -e Video -e image” to see what is available. Some possibilites on Linux/*BSD are:

  • glimagesink (OpenGL), waylandsink

  • xvimagesink, ximagesink (X11)

  • kmssink, fbdevsink (console graphics without X11)

  • vaapisink (for Intel/AMD hardware-accelerated graphics); for NVIDIA hardware graphics (with CUDA) use glimagesink combined with “-vd nvh264dec” (or “nvh264sldec”, a new variant which will become “nvh264dec” in GStreamer-1.24).

  • If the server is “headless” (no attached monitor, renders audio only) use -vs 0.

Note that videosink options can set using quoted arguments to -vs: e.g., -vs "xvimagesink display=:0": ximagesink and xvimagesink allow an X11 display name to be specified, and waylandsink has a similar option. Videosink options (“properties”) can be found in their GStreamer description pages,such as https://gstreamer.freedesktop.org/documentation/xvimagesink .

GStreamer also searches for the best “audiosink”; override its choice with -as <audiosink>. Choices on Linux include pulsesink, alsasink, pipewiresink, oss4sink; see what is available with gst-inspect-1.0 | grep sink | grep -e audio -e Audio.

One common problem involves GStreamer attempting to use incorrectly-configured or absent accelerated hardware h264 video decoding (e.g., VAAPI). Try “uxplay -avdec” to force software video decoding; if this works you can then try to fix accelerated hardware video decoding if you need it, or just uninstall the GStreamer vaapi plugin.

See Usage for more run-time options.

Special instructions for Raspberry Pi (tested on Raspberry Pi Zero 2 W, 3 Model B+, 4 Model B, and 5 only):

  • For Framebuffer video (for Raspberry Pi OS “Lite” and other non-X11 distributions) use the KMS videosink “-vs kmssink” (the DirectFB framebuffer videosink “dfbvideosink” is broken on the Pi, and segfaults). In this case you should explicitly use the “-vs kmssink” option, as without it, autovideosink does not find the correct videosink.

  • Raspberry Pi 5 does not provide hardware H264 decoding (and does not need it).

  • Pi Zero 2 W, 3 Model B+ and 4 Model B should use hardware H264 decoding by the Broadcom GPU, but it requires an out-of-mainstream kernel module bcm2835_codec maintained in the Raspberry Pi kernel tree; distributions that are known to supply it include Raspberry Pi OS, Ubuntu, and Manjaro-RPi4. Use software decoding (option -avdec) if this module is not available.

  • Uxplay uses the Video4Linux2 (v4l2) plugin from GStreamer-1.22 and later to access the GPU, if hardware H264 decoding is used. This should happen automatically. The option -v4l2 can be used, but it is usually best to just let GStreamer find the best video pipeline by itself.

  • On older distributions (GStreamer < 1.22), the v4l2 plugin needs a patch: see the UxPlay Wiki. Legacy Raspberry Pi OS (Bullseye) has a partially-patched GStreamer-1.18.4 which needs the uxplay option -bt709 (and don’t use -v4l2); it is still better to apply the full patch from the UxPlay Wiki in this case.

  • It appears that when hardware h264 video decoding is used, the option -bt709 became needed again in GStreamer-1.22 and later.

  • For “double-legacy” Raspberry Pi OS (Buster), there is no patch for GStreamer-1.14. Instead, first build a complete newer GStreamer-1.18.6 from source using these instructions before building UxPlay.

  • Raspberry Pi 3 Model B+ running a 32 bit OS can also access the GPU with the GStreamer OMX plugin (use option “-vd omxh264dec”), but this is broken by Pi 4 Model B firmware. OMX support was removed from Raspberry Pi OS (Bullseye), but is present in Buster.

  • H265 (4K) video is potentially supported by hardware decoding on Raspberry Pi 5 models, as well as on Raspberry Pi 4 model B, using a dedicated HEVC decoding block, but the “rpivid” kernel driver for this is not yet supported by GStreamer (this driver decodes video into a non-standard format that cannot be supported by GStreamer until the driver is in the mainline Linux kernel). Raspberry Pi provides a version of ffmpeg that can use that format, but at present UxPlay cannot use this. The best solution would be for the driver to be “upstreamed” to the kernel, allowing GStreamer support. (Software HEVC decoding works, but does not seem to give satisfactory results on the Pi).

Even with GPU video decoding, some frames may be dropped by the lower-power models to keep audio and video synchronized using timestamps. In Legacy Raspberry Pi OS (Bullseye), raspi-config “Performance Options” allows specifying how much memory to allocate to the GPU, but this setting appears to be absent in Bookworm (but it can still be set to e.g. 128MB by adding a line “gpu_mem=128” in /boot/config.txt). A Pi Zero 2 W (which has 512MB memory) worked well when tested in 32 bit Bullseye or Bookworm Lite with 128MB allocated to the GPU (default seems to be 64MB).

The basic uxplay options for R Pi are uxplay [-vs <videosink>]. The choice <videosink> = glimagesink is sometimes useful. With the Wayland video compositor, use <videosink> = waylandsink. With framebuffer video, use <videosink> = kmssink.

  • Tip: to start UxPlay on a remote host (such as a Raspberry Pi) using ssh:
   ssh user@remote_host
   export DISPLAY=:0
   nohup uxplay [options] > FILE &

Sound and video will play on the remote host; “nohup” will keep uxplay running if the ssh session is closed. Terminal output is saved to FILE (which can be /dev/null to discard it)

Building UxPlay on macOS: (Intel X86_64 and “Apple Silicon” M1/M2 Macs)

Note: A native AirPlay Server feature is included in macOS 12 Monterey, but is restricted to recent hardware. UxPlay can run on older macOS systems that will not be able to run Monterey, or can run Monterey but not AirPlay.

These instructions for macOS assume that the Xcode command-line developer tools are installed (if Xcode is installed, open the Terminal, type “sudo xcode-select –install” and accept the conditions).

It is also assumed that CMake >= 3.13 is installed: this can be done with package managers MacPorts (sudo port install cmake), Homebrew (brew install cmake), or by a download from https://cmake.org/download/. Also install git if you will use it to fetch UxPlay.

Next install libplist and openssl-3.x. Note that static versions of these libraries will be used in the macOS builds, so they can be uninstalled after building uxplay, if you wish.

  • If you use Homebrew: brew install libplist openssl@3

  • if you use MacPorts: sudo port install libplist-devel openssl3

Otherwise, build libplist and openssl from source: see instructions near the end of this README; requires development tools (autoconf, automake, libtool, etc.) to be installed.

Next get the latest macOS release of GStreamer-1.0.

Using “Official” GStreamer (Recommended for both MacPorts and Homebrew users): install the GStreamer release for macOS from https://gstreamer.freedesktop.org/download/. (This release contains its own pkg-config, so you don’t have to install one.) Install both the gstreamer-1.0 and gstreamer-1.0-devel packages. After downloading, Shift-Click on them to install (they install to /Library/FrameWorks/GStreamer.framework). Homebrew or MacPorts users should not install (or should uninstall) the GStreamer supplied by their package manager, if they use the “official” release.

  • Since GStreamer v1.22, the “Official” (gstreamer.freedesktop.org) macOS binaries require a wrapper “gst_macos_main” around the actual main program (uxplay). This should have been applied during the UxPlay compilation process, and the initial UxPlay terminal message should confirm it is being used. (UxPlay can also be built using “Official” GStreamer v.1.20.7 binaries, which work without the wrapper.)

Using Homebrew’s GStreamer: pkg-config is needed: (“brew install pkg-config gstreamer”). This causes a large number of extra packages to be installed by Homebrew as dependencies. The Homebrew gstreamer installation has recently been reworked into a single “formula” named gstreamer, which now works without needing GST_PLUGIN_PATH to be set in the enviroment. Homebrew installs gstreamer to HOMEBREW_PREFIX/lib/gstreamer-1.0 where by default HOMEBREW_PREFIX/* is /opt/homebrew/* on Apple Silicon Macs, and /usr/local/* on Intel Macs; do not put any extra non-Homebrew plugins (that you build yourself) there, and instead set GST_PLUGIN_PATH to point to their location (Homebrew does not supply a complete GStreamer, but seems to have everything needed for UxPlay). New: the UxPlay build script will now also detect Homebrew installations in non-standard locations indicated by the environment variable $HOMEBREW_PREFIX.

Using GStreamer installed from MacPorts: this is not recommended, as currently the MacPorts GStreamer is old (v1.16.2), unmaintained, and built to use X11:

(If you really wish to use the MacPorts GStreamer-1.16.2, install pkgconf (“sudo port install pkgconf”), then “sudo port install gstreamer1-gst-plugins-base gstreamer1-gst-plugins-good gstreamer1-gst-plugins-bad gstreamer1-gst-libav”. For X11 support on macOS, compile UxPlay using a special cmake option -DUSE_X11=ON, and run it from an XQuartz terminal with -vs ximagesink; older non-retina macs require a lower resolution when using X11: uxplay -s 800x600.)

After installing GStreamer, build and install uxplay: open a terminal and change into the UxPlay source directory (“UxPlay-master” for zipfile downloads, “UxPlay” for “git clone” downloads) and build/install with “cmake . ; make ; sudo make install” (same as for Linux).

  • Running UxPlay while checking for GStreamer warnings (do this with “export GST_DEBUG=2” before runnng UxPlay) reveals that with the default (since UxPlay 1.64) use of timestamps for video synchonization, many video frames are being dropped (only on macOS), perhaps due to another error (about videometa) that shows up in the GStreamer warnings. Recommendation: use the new UxPlay “no timestamp” option “-vsync no (you can add a line “vsync no” in the uxplayrc configuration file).

  • On macOS with this installation of GStreamer, the only videosinks available seem to be glimagesink (default choice made by autovideosink) and osxvideosink. The window title does not show the Airplay server name, but the window is visible to screen-sharing apps (e.g., Zoom). The only available audiosink seems to be osxaudiosink.

  • The option -nc is always used, whether or not it is selected. This is a workaround for a problem with GStreamer videosinks on macOS: if the GStreamer pipeline is destroyed while the mirror window is still open, a segfault occurs.

  • In the case of glimagesink, the resolution settings “-s wxh” do not affect the (small) initial OpenGL mirror window size, but the window can be expanded using the mouse or trackpad. In contrast, a window created with “-vs osxvideosink” is initially big, but has the wrong aspect ratio (stretched image); in this case the aspect ratio changes when the window width is changed by dragging its side; the option -vs "osxvideosink force-aspect-ratio=true" can be used to make the window have the correct aspect ratio when it first opens.

Building UxPlay on Microsoft Windows, using MSYS2 with the MinGW-64 compiler.

  • tested on Windows 10 and 11, 64-bit.
  1. Download and install Bonjour SDK for Windows v3.0. You can download the SDK without any registration at softpedia.com, or get it from the official Apple site https://developer.apple.com/download (Apple makes you register as a developer to access it from their site). This should install the Bonjour SDK as C:\Program Files\Bonjour SDK.

  2. (This is for 64-bit Windows; a build for 32-bit Windows should be possible, but is not tested.) The unix-like MSYS2 build environment will be used: download and install MSYS2 from the official site https://www.msys2.org/. Accept the default installation location C:\mysys64.

  3. MSYS2 packages are installed with a variant of the “pacman” package manager used by Arch Linux. Open a “MSYS2 MINGW64” terminal from the MSYS2 tab in the Windows Start menu, and update the new MSYS2 installation with “pacman -Syu”. Then install the MinGW-64 compiler and cmake

    pacman -S mingw-w64-x86_64-cmake mingw-w64-x86_64-gcc

    The compiler with all required dependencies will be installed in the msys64 directory, with default path C:/msys64/mingw64. Here we will simply build UxPlay from the command line in the MSYS2 environment (this uses “ninja” in place of “make” for the build system).

  4. Download the latest UxPlay from github (to use git, install it with pacman -S git, then “git clone https://github.com/FDH2/UxPlay”), then install UxPlay dependencies (openssl is already installed with MSYS2):

    pacman -S mingw-w64-x86_64-libplist mingw-w64-x86_64-gstreamer mingw-w64-x86_64-gst-plugins-base

    If you are trying a different Windows build system, MSVC versions of GStreamer for Windows are available from the official GStreamer site, but only the MinGW 64-bit build on MSYS2 has been tested.

  5. cd to the UxPlay source directory, then “mkdir build” and “cd build”. The build process assumes that the Bonjour SDK is installed at C:\Program Files\Bonjour SDK. If it is somewhere else, set the enviroment variable BONJOUR_SDK_HOME to point to its location. Then build UxPlay with

    cmake ..

    ninja

  6. Assuming no error in either of these, you will have built the uxplay executable uxplay.exe in the current (“build”) directory. The “sudo make install” and “sudo make uninstall” features offered in the other builds are not available on Windows; instead, the MSYS2 environment has /mingw64/... available, and you can install the uxplay.exe executable in C:/msys64/mingw64/bin (plus manpage and documentation in C:/msys64/mingw64/share/...) with

    cmake --install . --prefix /mingw64

    To be able to view the manpage, you need to install the manpage viewer with “pacman -S man”.

To run uxplay.exe you need to install some gstreamer plugin packages with pacman -S mingw-w64-x86_64-gst-<plugin>, where the required ones have <plugin> given by

  1. libav
  2. plugins-good
  3. plugins-bad

Other possible MSYS2 gstreamer plugin packages you might use are listed in MSYS2 packages.

You also will need to grant permission to the uxplay executable uxplay.exe to access data through the Windows firewall. You may automatically be offered the choice to do this when you first run uxplay, or you may need to do it using Windows Settings->Update and Security->Windows Security->Firewall & network protection -> allow an app through firewall. If your virus protection flags uxplay.exe as “suspicious” (but without a true malware signature) you may need to give it an exception.

Now test by running “uxplay” (in a MSYS2 terminal window). If you need to specify the audiosink, there are two main choices on Windows: the older DirectSound plugin “-as directsoundsink”, and the more modern Windows Audio Session API (wasapi) plugin “-as wasapisink”, which supports additional options such as

uxplay -as 'wasapisink device=\"<guid>\"' 

where <guid> specifies an available audio device by its GUID, which can be found using “gst-device-monitor-1.0 Audio”: <guid> has a form like \{0.0.0.00000000\}.\{98e35b2b-8eba-412e-b840-fd2c2492cf44\}. If “device” is not specified, the default audio device is used.

If you wish to specify the videosink using the -vs <videosink> option, some choices for <videosink> are d3d11videosink, d3dvideosink, glimagesink, gtksink.

  • With Direct3D 11.0 or greater, you can either always be in fullscreen mode using option -vs "d3d11videosink fullscreen-toggle-mode=property fullscreen=true", or get the ability to toggle into and out of fullscreen mode using the Alt-Enter key combination with option -vs "d3d11videosink fullscreen-toggle-mode=alt-enter". For convenience, these options will be added if just -vs d3d11videosink with or without the fullscreen option “-fs” is used. (Windows users may wish to add “vs d3d11videosink” (no initial “-”) to the UxPlay startup options file; see “man uxplay” or “uxplay -h”.)

The executable uxplay.exe can also be run without the MSYS2 environment, in the Windows Terminal, with C:\msys64\mingw64\bin\uxplay.

Usage

Options:

  • These can also be written (one option per line, without the initial “-” character) in the UxPlay startup file (either given by environment variable $UXPLAYRC, or ~/.uxplayrc or ~/.config/uxplayrc); lines begining with “#” are treated as comments, and ignored. Command line options supersede options in the startup file.

-n server_name (Default: UxPlay); server_name@_hostname_ will be the name that appears offering AirPlay services to your iPad, iPhone etc, where hostname is the name of the server running uxplay. This will also now be the name shown above the mirror display (X11) window.

-nh Do not append “@_hostname_” at the end of the AirPlay server name.

-h265 Activate “ScreenMultiCodec” support (AirPlay “Features” bit 42) for accepting h265 (4K/HEVC) video in addition to h264 video (1080p) in screen-mirror mode. When this option is used, two “video pipelines” (one for h264, one for h265) are created. If any GStreamer plugins in the pipeline are specific for h264 or h265, the correct version will be used in each pipeline. A wired Client-Server ethernet connection is preferred over Wifi for 4K video, and might be required by the client. Only recent Apple devices (M1/M2 Macs or iPads, and some iPhones) can send h265 video if a resolution “-s wxh” with h > 1080 is requested. The “-h265” option changes the default resolution (“-s” option) from 1920x1080 to 3840x2160, and leaves default maximum framerate (“-fps” option) at 30fps.

-hls Activate HTTP Live Streaming support. With this option YouTube videos can be streamed directly from YouTube servers to UxPlay (without passing through the client) by clicking on the AirPlay icon in the YouTube app.

-pin [nnnn]: (since v1.67) use Apple-style (one-time) “pin” authentication when a new client connects for the first time: a four-digit pin code is displayed on the terminal, and the client screen shows a login prompt for this to be entered. When “-pin” is used by itself, a new random pin code is chosen for each authentication; if “-pin nnnn” (e.g., “-pin 3939”) is used, this will set an unchanging fixed code. Authentication adds the server to the client’s list of “trusted servers” and the client will not need to reauthenticate provided that the client and server public keys remain unchanged. (By default since v1.68, the server public key is generated from the MAC address, which can be changed with the -m option; see the -key option for an alternative method of key generation). (Add a line “pin” in the UxPlay startup file if you wish the UxPlay server to use the pin authentication protocol).

-reg [filename]: (since v1.68). If “-pin” is used, this option maintains a register of pin-authenticated “trusted clients” in $HOME/.uxplay.register (or optionally, in filename). Without this option, returning clients that skip pin-authentication are trusted and not checked. This option may be useful if UxPlay is used in a more public environment, to record client details; the register is text, one line per client, with client’s public key (base-64 format), Device ID, and Device name; commenting out (with “#”) or deleting a line deregisters the corresponding client (see options -restrict, -block, -allow for more ways to control client access). (Add a line “reg” in the startup file if you wish to use this feature.)

-vsync [x] (In Mirror mode:) this option (now the default) uses timestamps to synchronize audio with video on the server, with an optional audio delay in (decimal) milliseconds (x = “20.5” means 0.0205 seconds delay: positive or negative delays less than a second are allowed.) It is needed on low-power systems such as Raspberry Pi without hardware video decoding.

-vsync no (In Mirror mode:) this switches off timestamp-based audio-video synchronization, restoring the default behavior prior to UxPlay-1.64. Standard desktop systems seem to work well without use of timestamps: this mode is appropriate for “live streaming” such as using UxPlay as a second monitor for a mac computer, or monitoring a webcam; with it, no video frames are dropped.

-async [x] (In Audio-Only (ALAC) mode:) this option uses timestamps to synchronize audio on the server with video on the client, with an optional audio delay in (decimal) milliseconds (x = “20.5” means 0.0205 seconds delay: positive or negative delays less than a second are allowed.) Because the client adds a video delay to account for latency, the server in -async mode adds an equivalent audio delay, which means that audio changes such as a pause or a track-change will not take effect immediately. This might in principle be mitigated by using the -al audio latency setting to change the latency (default 0.25 secs) that the server reports to the client, but at present changing this does not seem to have any effect.

-async no. This is the still the default behavior in Audio-only mode, but this option may be useful as a command-line option to switch off a -async option set in a “uxplayrc” configuration file.

-db low[:high] Rescales the AirPlay volume-control attenuation (gain) from -30dB:0dB to low:0dB or low:high. The lower limit low must be negative (attenuation); the upper limit high can be either sign. (GStreamer restricts volume-augmentation by high so that it cannot exceed +20dB). The rescaling is “flat”, so that for -db -50:10, a change in Airplay attenuation by -7dB is translated to a -7 x (60/30) = -14dB attenuation, and the maximum volume (AirPlay 0dB) is a 10dB augmentation, and Airplay -30dB would become -50dB. Note that the minimum AirPlay value (-30dB exactly) is translated to “mute”.

-taper Provides a “tapered” Airplay volume-control profile (matching the one called “dasl-tapering” in shairport-sync): each time the length of the volume slider (or the number of steps above mute, where 16 steps = full volume) is reduced by 50%, the perceived volume is halved (a 10dB attenuation). (This is modified at low volumes, to use the “untapered” volume if it is louder.)

-s wxh e.g. -s 1920x1080 (= “1080p”), the default width and height resolutions in pixels for h264 video. (The default becomes 3840x2160 (= “4K”) when the -h265 option is used.) This is just a request made to the AirPlay client, and perhaps will not be the final resolution you get. w and h are whole numbers with four digits or less. Note that the height pixel size is the controlling one used by the client for determining the streaming format; the width is dynamically adjusted to the shape of the image (portrait or landscape format, depending on how an iPad is held, for example).

-s wxh@r As above, but also informs the AirPlay client about the screen refresh rate of the display. Default is r=60 (60 Hz); r must be a whole number less than 256.

-o turns on an “overscanned” option for the display window. This reduces the image resolution by using some of the pixels requested by option -s wxh (or their default values 1920x1080) by adding an empty boundary frame of unused pixels (which would be lost in a full-screen display that overscans, and is not displayed by gstreamer). Recommendation: don’t use this option unless there is some special reason to use it.

-fs uses fullscreen mode, but only works with X11, Wayland, VAAPI, and D3D11 (Windows).

-p allows you to select the network ports used by UxPlay (these need to be opened if the server is behind a firewall). By itself, -p sets “legacy” ports TCP 7100, 7000, 7001, UDP 6000, 6001, 7011. -p n (e.g. -p 35000) sets TCP and UDP ports n, n+1, n+2. -p n1,n2,n3 (comma-separated values) sets each port separately; -p n1,n2 sets ports n1,n2,n2+1. -p tcp n or -p udp n sets just the TCP or UDP ports. Ports must be in the range [1024-65535].

If the -p option is not used, the ports are chosen dynamically (randomly), which will not work if a firewall is running.

-avdec forces use of software h264 decoding using Gstreamer element avdec_h264 (libav h264 decoder). This option should prevent autovideosink choosing a hardware-accelerated videosink plugin such as vaapisink.

-vp parser choses the GStreamer pipeline’s h264 parser element, default is h264parse. Using quotes “…” allows options to be added.

-vd decoder chooses the GStreamer pipeline’s h264 decoder element, instead of the default value “decodebin” which chooses it for you. Software decoding is done by avdec_h264; various hardware decoders include: vaapih264dec, nvdec, nvh264dec, v4l2h264dec (these require that the appropriate hardware is available). Using quotes “…” allows some parameters to be included with the decoder name.

-vc converter chooses the GStreamer pipeline’s videoconverter element, instead of the default value “videoconvert”. When using Video4Linux2 hardware-decoding by a GPU,-vc v4l2convert will also use the GPU for video conversion. Using quotes “…” allows some parameters to be included with the converter name.

-vs videosink chooses the GStreamer videosink, instead of the default value “autovideosink” which chooses it for you. Some videosink choices are: ximagesink, xvimagesink, vaapisink (for intel graphics), gtksink, glimagesink, waylandsink, osxvideosink (for macOS), kmssink (for systems without X11, like Raspberry Pi OS lite) or fpsdisplaysink (which shows the streaming framerate in fps). Using quotes “…” allows some parameters to be included with the videosink name. For example, fullscreen mode is supported by the vaapisink plugin, and is obtained using -vs "vaapisink fullscreen=true"; this also works with waylandsink. The syntax of such options is specific to a given plugin (see GStreamer documentation), and some choices of videosink might not work on your system.

-vs 0 suppresses display of streamed video. In mirror mode, the client’s screen is still mirrored at a reduced rate of 1 frame per second, but is not rendered or displayed. This option should always be used if the server is “headless” (with no attached screen to display video), and only used to render audio, which will be AAC lossily-compressed audio in mirror mode with unrendered video, and superior-quality ALAC Apple Lossless audio in Airplay audio-only mode.

-v4l2 Video settings for hardware h264 video decoding in the GPU by Video4Linux2. Equivalent to -vd v4l2h264dec -vc v4l2convert.

-bt709 A workaround for the failure of the older Video4Linux2 plugin to recognize Apple’s use of an uncommon (but permitted) “full-range color” variant of the bt709 color standard for digital TV. This is no longer needed by GStreamer-1.20.4 and backports from it.

-rpi Equivalent to “-v4l2” (Not valid for Raspberry Pi model 5, and removed in UxPlay 1.67)

-rpigl Equivalent to “-rpi -vs glimagesink”. (Removed since UxPlay 1.67)

-rpifb Equivalent to “-rpi -vs kmssink” (Removed since UxPlay 1.67)

-rpiwl Equivalent to “-rpi -vs waylandsink”. (Removed since UxPlay 1.67)

-as audiosink chooses the GStreamer audiosink, instead of letting autoaudiosink pick it for you. Some audiosink choices are: pulsesink, alsasink, pipewiresink, osssink, oss4sink, jackaudiosink, osxaudiosink (for macOS), wasapisink, directsoundsink (for Windows). Using quotes “…” might allow some optional parameters (e.g. -as "alsasink device=..." to specify a non-default output device). The syntax of such options is specific to a given plugin (see GStreamer documentation), and some choices of audiosink might not work on your system.

-as 0 (or just -a) suppresses playing of streamed audio, but displays streamed video.

-al x specifies an audio latency x in (decimal) seconds in Audio-only (ALAC), that is reported to the client. Values in the range [0.0, 10.0] seconds are allowed, and will be converted to a whole number of microseconds. Default is 0.25 sec (250000 usec). (However, the client appears to ignore this reported latency, so this option seems non-functional.)

-ca filename provides a file (where filename can include a full path) used for output of “cover art” (from Apple Music, etc.,) in audio-only ALAC mode. This file is overwritten with the latest cover art as it arrives. Cover art (jpeg format) is discarded if this option is not used. Use with a image viewer that reloads the image if it changes, or regularly (e.g. once per second.). To achieve this, run “uxplay -ca [path/to/]filename &” in the background, then run the the image viewer in the foreground. Example, using feh as the viewer: run “feh -R 1 [path/to/]filename” (in the same terminal window in which uxplay was put into the background). To quit, use ctrl-C fg ctrl-C to terminate the image viewer, bring uxplay into the foreground, and terminate it too.

-reset n sets a limit of n consecutive timeout failures of the client to respond to ntp requests from the server (these are sent every 3 seconds to check if the client is still present, and synchronize with it). After n failures, the client will be presumed to be offline, and the connection will be reset to allow a new connection. The default value of n is 5; the value n = 0 means “no limit” on timeouts.

-nofreeze closes the video window after a reset due to ntp timeout (default is to leave window open to allow a smoother reconection to the same client). This option may be useful in fullscreen mode.

-nc maintains previous UxPlay < 1.45 behavior that does not close the video window when the the client sends the “Stop Mirroring” signal. This option is currently used by default in macOS, as the window created in macOS by GStreamer does not terminate correctly (it causes a segfault) if it is still open when the GStreamer pipeline is closed.

-nohold Drops the current connection when a new client attempts to connect. Without this option, the current client maintains exclusive ownership of UxPlay until it disconnects.

-restrict Restrict clients allowed to connect to those specified by -allow <deviceID>. The deviceID has the form of a MAC address which is displayed by UxPlay when the client attempts to connect, and appears to be immutable. It has the format XX:XX:XX:XX:XX:XX, X = 0-9,A-F, and is possibly the “true” hardware MAC address of the device. Note that iOS clients generally expose different random “private Wi_Fi addresses” (“fake” MAC addresses) to different networks (for privacy reasons, to prevent tracking), which may change, and do not correpond to the deviceID.

-restrict no Remove restrictions (default). This is useful as a command-line argument to overide restrictions set in the Startup file.

-allow id Adds the deviceID = id to the list of allowed clients when client restrictions are being enforced. Usually this will be an entry in the uxplayrc startup file.

-block id Always block clients with deviceID = id, even when client restrictions are not being enforced generally. Usually this will be an entry in the uxplayrc startup file.

-FPSdata Turns on monitoring of regular reports about video streaming performance that are sent by the client. These will be displayed in the terminal window if this option is used. The data is updated by the client at 1 second intervals.

-fps n sets a maximum frame rate (in frames per second) for the AirPlay client to stream video; n must be a whole number less than 256. (The client may choose to serve video at any frame rate lower than this; default is 30 fps.) A setting of 60 fps may give you improved video but is not recommended on Raspberry Pi. A setting below 30 fps might be useful to reduce latency if you are running more than one instance of uxplay at the same time. This setting is only an advisory to the client device, so setting a high value will not force a high framerate. (You can test using “-vs fpsdisplaysink” to see what framerate is being received, or use the option -FPSdata which displays video-stream performance data continuously sent by the client during video-streaming.)

-f {H|V|I} implements “videoflip” image transforms: H = horizontal flip (right-left flip, or mirror image); V = vertical flip ; I = 180 degree rotation or inversion (which is the combination of H with V).

-r {R|L} 90 degree Right (clockwise) or Left (counter-clockwise) rotations; these image transforms are carried out after any -f transforms.

-m [mac] changes the MAC address (Device ID) used by UxPlay (default is to use the true hardware MAC address reported by the host computer’s network card). (Different server_name, MAC addresses, and network ports are needed for each running uxplay if you attempt to run more than one instance of uxplay on the same computer.) If [mac] (in form xx:xx:xx:xx:xx:xx, 6 hex octets) is not given, a random MAC address is generated. If UxPlay fails to find the true MAC address of a network card, (more specifically, the MAC address used by the first active network interface detected) a random MAC address will be used even if option -m was not specified. (Note that a random MAC address will be different each time UxPlay is started).

-key [filename]: This (more secure) option for generating and storing a persistant public key (needed for the -pin option) has been replaced by default with a (less secure) method which generates a key from the server’s “device ID” (MAC address, which can be changed with the -m option, conveniently as a startup file option). When the -key option is used, a securely generated keypair is generated and stored in $HOME/.uxplay.pem, if that file does not exist, or read from it, if it exists. (Optionally, the key can be stored in filename.) This method is more secure than the new default method, (because the Device ID is broadcast in the DNS_SD announcement) but still leaves the private key exposed to anyone who can access the pem file. This option should be set in the UxPlay startup file as a line “key” or “key filename” (no initial “-”), where filename is a full path which should be enclosed in quotes ("....") if it contains any blank spaces. Because the default method is simpler, and security of client access to uxplay is unlikely to be an important issue, the -key option is no longer recommended.

-dacp [filename]: Export current client DACP-ID and Active-Remote key to file: default is $HOME/.uxplay.dacp. (optionally can be changed to filename). Can be used by remote control applications. File is transient: only exists while client is connected.

-vdmp Dumps h264 video to file videodump.h264. -vdmp n dumps not more than n NAL units to videodump.x.h264; x= 1,2,… increases each time a SPS/PPS NAL unit arrives. To change the name videodump, use -vdmp [n] filename.

-admp Dumps audio to file audiodump.x.aac (AAC-ELD format audio), audiodump.x.alac (ALAC format audio) or audiodump.x.aud (other-format audio), where x = 1,2,3… increases each time the audio format changes. -admp n restricts the number of packets dumped to a file to n or less. To change the name audiodump, use -admp [n] filename. Note that (unlike dumped video) the dumped audio is currently only useful for debugging, as it is not containerized to make it playable with standard audio players.

-d Enable debug output. Note: this does not show GStreamer error or debug messages. To see GStreamer error and warning messages, set the environment variable GST_DEBUG with “export GST_DEBUG=2” before running uxplay. To see GStreamer information messages, set GST_DEBUG=4; for DEBUG messages, GST_DEBUG=5; increase this to see even more of the GStreamer inner workings.

Troubleshooting

Note: uxplay is run from a terminal command line, and informational messages are written to the terminal.

0. Problems in compiling UxPlay.

One user (on Ubuntu) found compilation failed with messages about linking to “usr/local/lib/libcrypto.a” and “zlib”. This was because (in addition to the standard ubuntu installation of libssl-dev), the user was unaware that a second installation with libcrypto in /usr/local was present. Solution: when more than one installation of OpenSSL is present, set the environment variable OPEN_SSL_ROOT_DIR to point to the correct one; on 64-bit Ubuntu, this is done by running export OPENSSL_ROOT_DIR=/usr/lib/X86_64-linux-gnu/ before running cmake.

1. Avahi/DNS_SD Bonjour/Zeroconf issues

The DNS_SD Service-Discovery (“Bonjour” or “Zeroconf”) service is required for UxPlay to work. On Linux, it will be usually provided by Avahi, and to troubleshoot this, you should use the tool avahi-browse. (You may need to install a separate package with a name like avahi-utils to get this.)

On Linux, make sure Avahi is installed, and start the avahi-daemon service on the system running uxplay (your distribution will document how to do this, for example: sudo systemctl <cmd> avahi-daemon or sudo service avahi-daemon <cmd>, with <cmd> one of enable, disable, start, stop, status. You might need to edit the avahi-daemon.conf file (it is typically in /etc/avahi/, find it with “sudo find /etc -name avahi-daemon.conf”): make sure that “disable-publishing” is not a selected option). Some systems may instead use the mdnsd daemon as an alternative to provide DNS-SD service. (FreeBSD offers both alternatives, but only Avahi was tested; see here.)

  • uxplay starts, but either stalls or stops after “Initialized server socket(s)” appears (without the server name showing on the client).

If UxPlay stops with the “No DNS-SD Server found” message, this means that your network does not have a running Bonjour/zeroconf DNS-SD server. Before v1.60, UxPlay used to stall silently if DNS-SD service registration failed, but now stops with an error message returned by the DNSServiceRegister function: kDNSServiceErr_Unknown if no DNS-SD server was found: (A NixOS user found that in NixOS, this error can also occur if avahi-daemon service IS running with publishing enabled, but reports “the error disappeared on NixOS by setting services.avahi.openFirewall to true”.) Other mDNS error codes are in the range FFFE FF00 (-65792) to FFFE FFFF (-65537), and are listed in the dnssd.h file. An older version of this (the one used by avahi) is found here. A few additional error codes are defined in a later version from Apple.

If UxPlay stalls without an error message and without the server name showing on the client, this is a network problem (if your UxPlay version is older than 1.60, it is also the behavior when no DNS-SD server is found.)

A useful tool for examining such network problems from the client end is the (free) Discovery DNS-SD browser available in the Apple App Store for both iOS (works on iPadOS too) and macOS.

  • Some users using dual-band (2.4GHz/5GHz) routers have reported that clients using the 5GHz band (sometimes) “fail to see UxPlay” (i.e., do not get a response to their mDNS queries), but the 2.4GHz band works. Other projects using Bonjour/mDNS have had similar reports; the issue seems to be router-specific, perhaps related to “auto” rather than fixed channel selection (5GHz has many more channels to switch between), or channel width selections; one speculation is that since mDNS uses UDP protocol (where “lost” messages are not resent), a mDNS query might get lost if channel switching occurs during the query.

If your router has this problem, a reported “fix” is to (at least on 5GHz) use fixed channel and/or fixed (not dynamic) channel width.

  • Avahi works at first, but new clients do not see UxPlay, or clients that initially saw it stop doing so after they disconnect.

This is usually because Avahi is only using the “loopback” network interface, and is not receiving mDNS queries from new clients that were not listening when UxPlay started.

To check this, after starting uxplay, use the utility avahi-browse -a -t in a different terminal window on the server to verify that the UxPlay AirTunes and AirPlay services are correctly registered (only the AirTunes service is used in the “Legacy” AirPlay Mirror mode used by UxPlay, but the AirPlay service is used for the initial contact).

The results returned by avahi-browse should show entries for uxplay like

+   eno1 IPv6 UxPlay                                        AirPlay Remote Video local
+   eno1 IPv4 UxPlay                                        AirPlay Remote Video local
+     lo IPv4 UxPlay                                        AirPlay Remote Video local
+   eno1 IPv6 863EA27598FE@UxPlay                           AirTunes Remote Audio local
+   eno1 IPv4 863EA27598FE@UxPlay                           AirTunes Remote Audio local
+     lo IPv4 863EA27598FE@UxPlay                           AirTunes Remote Audio local

If only the loopback (“lo”) entries are shown, a firewall on the UxPlay host is probably blocking full DNS-SD service, and you need to open the default UDP port 5353 for mDNS requests, as loopback-based DNS-SD service is unreliable.

If the UxPlay services are listed by avahi-browse as above, but are not seen by the client, the problem is likely to be a problem with the local network.

2. uxplay starts, but stalls after “Initialized server socket(s)” appears, with the server name showing on the client (but the client fails to connect when the UxPlay server is selected).

This shows that a DNS-SD service is working, clients hear UxPlay is available, but the UxPlay server is not receiving the response from the client. This is usually because a firewall on the server is blocking the connection request from the client. (One user who insisted that the firewall had been turned off turned out to have had two active firewalls (firewalld and ufw) both running on the server!) If possible, either turn off the firewall to see if that is the problem, or get three consecutive network ports, starting at port n, all three in the range 1024-65535, opened for both tcp and udp, and use “uxplay -p n” (or open UDP 7011,6001,6000 TCP 7100,7000,7001 and use “uxplay -p”).

If you are really sure there is no firewall, you may need to investigate your network transmissions with a tool like netstat, but almost always this is a firewall issue.

3. Problems after the client-server connection has been made:

If you do not see the message raop_rtp_mirror starting mirroring, something went wrong before the client-server negotiations were finished. For such problems, use “uxplay -d” (debug log option) to see what is happening: it will show how far the connection process gets before the failure occurs. You can compare your debug output to that from a successful start of UxPlay in the UxPlay Wiki.

If UxPlay reports that mirroring started, but you get no video or audio, the problem is probably from a GStreamer plugin that doesn’t work on your system (by default, GStreamer uses the “autovideosink” and “autoaudiosink” algorithms to guess what are the “best” plugins to use on your system). A different reason for no audio occurred when a user with a firewall only opened two udp network ports: three are required (the third one receives the audio data).

Raspberry Pi devices (Pi 4B+ and earlier: this does not apply to the Pi 5, which does not provide hardware h264 decoding, and does not need it) work best with hardware GPU h264 video decoding if the Video4Linux2 plugin in GStreamer v1.20.x or earlier has been patched (see the UxPlay Wiki for patches). This is fixed in GStreamer-1.22, and by backport patches from this in distributions such as Raspberry Pi OS (Bullseye): use option -bt709 with the GStreamer-1.18.4 from Raspberry Pi OS. This also needs the bcm2835-codec kernel module that is not in the standard Linux kernel (it is available in Raspberry Pi OS, Ubuntu and Manjaro).

  • If this kernel module is not available in your Raspberry Pi operating system, or if GStreamer < 1.22 is not patched, use option -avdec for software h264-decoding.

Sometimes “autovideosink” may select the OpenGL renderer “glimagesink” which may not work correctly on your system. Try the options “-vs ximagesink” or “-vs xvimagesink” to see if using one of these fixes the problem.

Other reported problems are connected to the GStreamer VAAPI plugin (for hardware-accelerated Intel graphics, but not NVIDIA graphics). Use the option “-avdec” to force software h264 video decoding: this should prevent autovideosink from selecting the vaapisink videosink. Alternatively, find out if the gstreamer1.0-vaapi plugin is installed, and if so, uninstall it. (If this does not fix the problem, you can reinstall it.)

There are some reports of other GStreamer problems with hardware-accelerated Intel HD graphics. One user (on Debian) solved this with “sudo apt install intel-media-va-driver-non-free”. This is a driver for 8’th (or later) generation “*-lake” Intel chips, that seems to be related to VAAPI accelerated graphics.

If you do have Intel HD graphics, and have installed the vaapi plugin, but -vs vaapisink does not work, check that vaapi is not “blacklisted” in your GStreamer installation: run gst-inspect-1.0 vaapi, if this reports 0 features, you need to export GST_VAAPI_ALL_DRIVERS=1 before running uxplay, or set this in the default environment.

You can try to fix audio or video problems by using the “-as <audiosink>” or “-vs <videosink>” options to choose the GStreamer audiosink or videosink , rather than letting GStreamer choose one for you. (See above, in Starting and running UxPlay for choices of <audiosink> or <videosink>.)

The “OpenGL renderer” window created on Linux by “-vs glimagesink” sometimes does not close properly when its “close” button is clicked. (this is a GStreamer issue). You may need to terminate uxplay with Ctrl-C to close a “zombie” OpenGl window. If similar problems happen when the client sends the “Stop Mirroring” signal, try the no-close option “-nc” that leaves the video window open.

4. GStreamer issues (missing plugins, etc.):

  • clearing the user’s GStreamer cache with rm -rf ~/.cache/gstreamer-1.0/* may be the solution to problems where gst-inspect-1.0 does not show a plugin that you believe is installed. The cache will be regenerated next time GStreamer is started. This is the solution to puzzling problems that turn out to come from corruption of the cache, and should be tried first.

If UxPlay fails to start, with a message that a required GStreamer plugin (such as “libav”) was not found, first check with the GStreamer tool gst-inspect-1.0 to see what GStreamer knows is available. (You may need to install some additional GStreamer “tools” package to get gst-inspect-1.0). For, e.g. a libav problem, check with “gst-inspect-1.0 libav”. If it is not shown as available to GStreamer, but your package manager shows the relevant package as installed (as one user found), try entirely removing and reinstalling the package. That user found that a solution to a “Required gstreamer plugin ‘libav’ not found” message that kept recurring was to clear the user’s gstreamer cache.

If it fails to start with an error like ‘no element "avdec_aac"’ this is because even though gstreamer-libav is installed. it is incomplete because some plugin features are missing: “gst-inspect-1.0 | grep avdec_aac” will show if avdec_aac is available. Unlike other GStreamer plugins, the libav plugin is a front end to FFmpeg codecs which provide avdec_*.

  • Some distributions (RedHat, SUSE, etc) provide incomplete versions of FFmpeg because of patent issues with codecs used by certain plugins. In those cases there will be some “extra package” provider like RPM fusion (RedHat), packman (SUSE) where you can get complete packages (your distribution will usually provide instructions for this, Mageia puts them in an optional “tainted” repo). The packages needed may be “ffmpeg*” or “libav*” packages: the GStreamer libav plugin package does not contain any codecs itself, it just provides a way for GStreamer to use ffmpeg/libav codec libraries which must be installed separately. For similar reasons, distributions may ship incomplete packages of GStreamer “plugins-bad”. Use user on Fedora thought they had installed from rpmfusion, but the system had not obeyed: “Adding –allowerasing to the dnf command fixed it after a restart”.

  • starting with release UxPlay-1.65.3, UxPlay will continue to function, but without audio in mirror mode, if avdec_aac is missing.

To troubleshoot GStreamer execute “export GST_DEBUG=2” to set the GStreamer debug-level environment-variable in the terminal where you will run uxplay, so that you see warning and error messages; see GStreamer debugging tools for how to see much more of what is happening inside GStreamer. Run “gst-inspect-1.0” to see which GStreamer plugins are installed on your system.

Some extra GStreamer packages for special plugins may need to be installed (or reinstalled: a user using a Wayland display system as an alternative to X11 reported that after reinstalling Lubuntu 18.4, UxPlay would not work until gstreamer1.0-x was installed, presumably for Wayland’s X11-compatibility mode). Different distributions may break up GStreamer 1.x into packages in different ways; the packages listed above in the build instructions should bring in other required GStreamer packages as dependencies, but will not install all possible plugins.

The GStreamer video pipeline, which is shown in the initial output from uxplay -d, has the default form

appsrc name=video_source ! queue ! h264parse ! decodebin ! videoconvert ! autovideosink name=video_sink sync=false

The pipeline is fully configurable: default elements “h264parse”, “decodebin”, “videoconvert”, and “autovideosink” can respectively be replaced by using uxplay options -vp, -vd, -vc, and -vs, if there is any need to modify it (entries can be given in quotes “…” to include options).

5. Mirror screen freezes (a network problem):

This can happen if the TCP video stream from the client stops arriving at the server, probably because of network problems (the UDP audio stream may continue to arrive). At 3-second intervals, UxPlay checks that the client is still connected by sending it a request for a NTP time signal. If a reply is not received from the client within a 0.3 sec time-window, an “ntp timeout” is registered. If a certain number (currently 5) of consecutive ntp timeouts occur, UxPlay assumes that the client is “dead”, and resets the connection, becoming available for connection to a new client, or reconnection to the previous one. Sometimes the connection may recover before the timeout limit is reached, and if the default limit is not right for your network, it can be modified using the option “-reset n”, where n is the desired timeout-limit value (n = 0 means “no limit”). If the connection starts to recover after ntp timeouts, a corrupt video packet from before the timeout may trigger a “connection reset by peer” error, which also causes UxPlay to reset the connection.

  • When the connection is reset, the “frozen” mirror screen of the previous connection is left in place, but does not block new connections, and will be taken over by a new client connection when it is made.

6. Protocol issues (with decryption of the encrypted audio and video streams sent by the client).

A protocol failure may trigger an unending stream of error messages, and means that the audio decryption key (also used in video decryption) was not correctly extracted from data sent by the client.

The protocol was modifed in UxPlay-1.65 after it was discovered that the client-server “pairing” step could be avoided (leading to a much quicker connection setup, without a 5 second delay) by disabling “Supports Legacy Pairing” (bit 27) in the “features” code UxPlay advertises on DNS-SD Service Discovery. Most clients will then not attempt the setup of a “shared secret key” when pairing, which is used by AppleTV for simultaneous handling of multiple clients (UxPlay only supports one client at a time). This change is now well-tested, but in case it causes any protocol failures, UxPlay can be reverted to the previous behavior by uncommenting the previous “FEATURES_1” setting (and commenting out the new one) in lib/dnssdint.h, and then rebuilding UxPlay. (“Pairing” is re-enabled when the new Apple-style one-time “pin” authentication is activated by running UxPlay with the “-pin” option introduced in UxPlay 1.67.)

Protocol failure should not happen for iOS 9.3 or later clients. However, if a client uses the same older version of the protocol that is used by the Windows-based AirPlay client emulator AirMyPC, the protocol can be switched to the older version by the setting OLD_PROTOCOL_CLIENT_USER_AGENT_LIST in UxPlay/lib/global.h. UxPlay reports the client’s “User Agent” string when it connects. If some other client also fails to decrypt all audio and video, try adding its “User Agent” string in place of “xxx” in the entry “AirMyPC/2.0;xxx” in global.h and rebuild uxplay.

Note that for DNS-SD Service Discovery, Uxplay declares itself to be an AppleTV3,2 (a 32 bit device) with a sourceVersion 220.68; this can also be changed in global.h. UxPlay also works if it declares itself as an AppleTV6,2 with sourceVersion 380.20.1 (an AppleTV 4K 1st gen, introduced 2017, running tvOS 12.2.1), so it does not seem to matter what version UxPlay claims to be.

Changelog

1.71 2024-12-13 Add support for HTTP Live Streaming (HLS), initially only for YouTube movies. Fix issue with NTP timeout on Windows.

1.70 2024-10-04 Add support for 4K (h265) video (resolution 3840 x 2160). Fix issue with GStreamer >= 1.24 when client sleeps, then wakes.

1.69 2024-08-09 Internal improvements (e.g. in -nohold option, identifying GStreamer videosink selected by autovideosink, finding X11 display) in anticipation of future HLS video support. New -nofreeze option to not leave frozen video in place when a network connection is reset. Fixes for GStreamer-1.24.x changes.

1.68 2023-12-31 New simpler (default) method for generating a persistent public key from the server MAC address (which can now be set with the -m option). (The previous method is still available with -key option). New option -reg to maintain a register of pin-authenticated clients. Corrected volume-control: now interprets AirPlay volume range -30dB:0dB as decibel gain attenuation, with new option -db low[:high] for “flat” rescaling of the dB range. Add -taper option for a “tapered” AirPlay volume-control profile.

1.67 2023-11-30 Add support for Apple-style one-time pin authentication of clients with option “-pin”: (uses SRP6a authentication protocol and public key persistence). Detection with error message of (currently) unsupported H265 video when requesting high resolution over wired ethernet. Removed rpi* options (which are not valid with new Raspberry Pi model 5, and can be replaced by combinations of other options). Added optional argument “mac” to “-m” option, to specify a replacement MAC address/Device ID. Update llhttp to v. 9.1.3. Add -dacp option for exporting current client DACP info (for remotes).

1.66 2023-09-05 Fix IPV6 support. Add option to restrict clients to those on a list of allowed deviceIDs, or to block connections from clients on a list of blocked deviceIDs. Fix for #207 from @thiccaxe (screen lag in vsync mode after client wakes from sleep).

1.65.3 2023-07-23 Add RPM spec file; add warning if required gstreamer libav feature “avdec_aac” is missing: (this occurs in RPM-based distributions that ship an incomplete FFmpeg for Patent or License reasons, and rely on users installing an externally-supplied complete FFmpeg). Mirror-mode airplay will now work without audio if avdec_aac is missing.

1.65 2023-06-03 Eliminate pair_setup part of connection protocol to allow faster connections with clients (thanks to @shuax #176 for this discovery); to revert, uncomment a line in lib/dnssdint.h. Disconnect from audio device when connection closes, to not block its use by other apps if uxplay is running but not connected. Fix for AirMyPC client (broken since 1.60), so its older non-NTP timestamp protocol works with -vsync. Corrected parsing of configuration file entries that were in quotes.

1.64 2023-04-23 Timestamp-based synchronization of audio and video is now the default in Mirror mode. (Use “-vsync no” to restore previous behavior.) A configuration file can now be used for startup options. Also some internal cleanups and a minor bugfix that fixes #192.

1.63 2023-02-12 Reworked audio-video synchronization, with new options -vsync (for Mirror mode) and -async (for Audio-Only mode, to sync with client video). Option -vsync makes software h264 decoding of streamed videos with option -avdec viable on some recent Raspberry Pi models. Internal change: all times are now processed in nanoseconds units. Removed -ao option introduced in 1.62.

1.62 2023-01-18 Added Audio-only mode time offset -ao x to allow user synchronization of ALAC audio playing on the server with video, song lyrics, etc. playing on the client. x = 5.0 appears to be optimal in many cases. Quality fixes: cleanup in volume changes, timestamps, some bugfixes.

1.61 2022-12-30 Removed -t option (workaround for an Avahi issue, correctly solved by opening network port UDP 5353 in firewall). Remove -g debug flag from CMAKE_CFLAGS. Postpend (instead of prepend) build environment CFLAGS to CMAKE_CFLAGS. Refactor parts of uxplay.cpp

1.60 2022-12-15 Added exit with error message if DNSServiceRegister fails (instead of just stalling). Test for Client’s attempt to using unsupported AirPlay 2 “REMOTE CONTROL” protocol (with no timing channel), and exit if this occurs. Reworked metadata processing to correctly parse DMAP header (previous version worked with DMAP messages currently received, but was not correct).

1.59 2022-12-12 remove “ZOOMFIX” compile option and make compilation with X11-dependence the default if X11 development libraries are detected (this now also provides fullscreen mode with a F11 or Alt+Enter key toggle); ZOOMFIX is now automatically applied for GStreamer < 1.20. New cmake option -DNO_X11_DEPS compiles uxplay without X11 dependence. Reworked internal metadata handling. Fix segfault with “-vs 0”.

1.58 2022-10-29 Add option “-nohold” that will drop existing connections when a new client connects. Update llhttp to v8.1.0.

1.57 2022-10-09 Minor fixes: (fix coredump on AUR on “stop mirroring”, occurs when compiled with AUR CFLAGS -DFORTIFY_SOURCE); graceful exit when required plugins are missing; improved support for builds on Windows. Include audioresample in GStreamer audio pipeline.

1.56 2022-09-01 Added support for building and running UxPlay-1.56 on Windows (no changes to Unix (Linux, *BSD, macOS) codebase.)

1.56 2022-07-30 Remove -bt709 from -rpi, -rpiwl, -rpifb as GStreamer is now fixed.

1.55 2022-07-04 Remove the bt709 fix from -v4l2 and create a new -bt709 option (previous “-v4l2” is now “-v4l2 -bt709”). This allows the currently-required -bt709 option to be used on its own on RPi without -v4l2 (sometimes this give better results).

1.54 2022-06-25 Add support for “Cover Art” display in Audio-only (ALAC) mode. Reverted a change that caused VAAPI to crash with AMD POLARIS graphics cards. Minor internal changes to plist code and uxplay option parsing.

1.53 2022-06-13 Internal changes to audio sync code, revised documentation, Minor bugfix (fix assertion crash when resent audio packets are empty).

1.52 2022-05-05 Cleaned up initial audio sync code, and reformatted streaming debug output (readable aligned timestamps with decimal points in seconds). Eliminate memory leaks (found by valgrind). Support for display of ALAC (audio-only) metadata (soundtrack artist names, titles etc.) in the uxplay terminal.

1.51 2022-04-24 Reworked options forVideo4Linux2 support (new option -v4l2) and short options -rpi, -rpifb, -rpiwl as synonyms for -v4l2, -v4l2 -vs kmssink, and -v4l2 -vs waylandsink. Reverted a change from 1.48 that broke reconnection after “Stop Mirroring” is sent by client.

1.50 2022-04-22 Added -fs fullscreen option (for Wayland or VAAPI plugins only), Changed -rpi to be for framebuffer (“lite”) RPi systems and added -rpigl (OpenGL) and -rpiwl (Wayland) options for RPi Desktop systems. Also modified timestamps from “DTS” to “PTS” for latency improvement, plus internal cleanups.

1.49 2022-03-28 Addded options for dumping video and/or audio to file, for debugging, etc. h264 PPS/SPS NALU’s are shown with -d. Fixed video-not-working for M1 Mac clients.

1.48 2022-03-11 Made the GStreamer video pipeline fully configurable, for use with hardware h264 decoding. Support for Raspberry Pi.

1.47 2022-02-05 Added -FPSdata option to display (in the terminal) regular reports sent by the client about video streaming performance. Internal cleanups of processing of video packets received from the client. Added -reset n option to reset the connection after n ntp timeouts (also reset after “connection reset by peer” error in video stream).

1.46 2022-01-20 Restore pre-1.44 behavior (1.44 may have broken hardware acceleration): once again use decodebin in the video pipeline; introduce new option “-avdec” to force software h264 decoding by libav h264, if needed (to prevent selection of vaapisink by autovideosink). Update llhttp to v6.0.6. UxPlay now reports itself as AppleTV3,2. Restrict connections to one client at a time (second client must now wait for first client to disconnect).

1.45 2022-01-10 New behavior: close video window when client requests “stop mirroring”. (A new “no close” option “-nc” is added for users who wish to retain previous behavior that does not close the video window).

1.44 2021-12-13 Omit hash of aeskey with ecdh_secret for an AirMyPC client; make an internal rearrangement of where this hash is done. Fully report all initial communications between client and server in -d debug mode. Replace decodebin in GStreamer video pipeline by h264-specific elements.

1.43 2021-12-07 Various internal changes, such as tests for successful decryption, uniform treatment of informational/debug messages, etc., updated README.

1.42 2021-11-20 Fix MAC detection to work with modern Linux interface naming practices, MacOS and *BSD.

1.41 2021-11-11 Further cleanups of multiple audio format support (internal changes, separated RAOP and GStreamer audio/video startup)

1.40 2021-11-09 Cleanup segfault in ALAC support, manpage location fix, show request Plists in debug mode.

1.39 2021-11-06 Added support for Apple Lossless (ALAC) audio streams.

1.38 2021-10-8 Add -as audiosink option to allow user to choose the GStreamer audiosink.

1.37 2021-09-29 Append “@hostname” to AirPlay Server name, where “hostname” is the name of the server running uxplay (reworked change in 1.36).

1.36 2021-09-29 Implemented suggestion (by @mrbesen and @PetrusZ) to use hostname of machine runing uxplay as the default server name

1.35.1 2021-09-28 Added the -vs 0 option for streaming audio, but not displaying video.

1.35 2021-09-10 now uses a GLib MainLoop, and builds on macOS (tested on Intel Mac, 10.15 ). New option -t timeout for relaunching server if no connections were active in previous timeout seconds (to renew Bonjour registration).

1.341 2021-09-04 fixed: render logger was not being destroyed by stop_server()

1.34 2021-08-27 Fixed “ZOOMFIX”: the X11 window name fix was only being made the first time the GStreamer window was created by uxplay, and not if the server was relaunched after the GStreamer window was closed, with uxplay still running. Corrected in v. 1.34

Building OpenSSL >= 1.1.1 from source.

If you need to do this, note that you may be able to use a newer version (OpenSSL-3.0.1 is known to work). You will need the standard development toolset (autoconf, automake, libtool). Download the source code from https://www.openssl.org/source/. Install the downloaded openssl by opening a terminal in your Downloads directory, and unpacking the source distribution: (“tar -xvzf openssl-3.0.1.tar.gz ; cd openssl-3.0.1”). Then build/install with “./config ; make ; sudo make install_dev”. This will typically install the needed library libcrypto.*, either in /usr/local/lib or /usr/local/lib64.

(Ignore the following for builds on MacOS:) On some systems like Debian or Ubuntu, you may also need to add a missing entry /usr/local/lib64 in /etc/ld.so.conf (or place a file containing “/usr/local/lib64/libcrypto.so” in /etc/ld.so.conf.d) and then run “sudo ldconfig”.

Building libplist >= 2.0.0 from source.

(Note: on Debian 9 “Stretch” or Ubuntu 16.04 LTS editions, you can avoid this step by installing libplist-dev and libplist3 from Debian 10 or Ubuntu 18.04.) As well as the usual build tools (autoconf, automake, libtool), you may need to also install some libpython*-dev package. Download the latest source with git from https://github.com/libimobiledevice/libplist, or get the source from the Releases section (use the *.tar.bz2 release, not the *.zip or *.tar.gz versions): download libplist-2.3.0, then unpack it (“tar -xvjf libplist-2.3.0.tar.bz2 ; cd libplist-2.3.0”), and build/install it: (“./configure ; make ; sudo make install”). This will probably install libplist-2.0.* in /usr/local/lib. The new libplist-2.3.0 release should be compatible with UxPlay; libplist-2.2.0 is also available if there are any issues.

(Ignore the following for builds on MacOS:) On some systems like Debian or Ubuntu, you may also need to add a missing entry /usr/local/lib in /etc/ld.so.conf (or place a file containing “/usr/local/lib/libplist-2.0.so” in /etc/ld.so.conf.d) and then run “sudo ldconfig”.

Disclaimer

All the resources in this repository are written using only freely available information from the internet. The code and related resources are meant for educational purposes only. It is the responsibility of the user to make sure all local laws are adhered to.

This project makes use of a third-party GPL library for handling FairPlay. The legal status of that library is unclear. Should you be a representative of Apple and have any objections against the legality of the library and its use in this project, please contact the developers and the appropriate steps will be taken.

Given the large number of third-party AirPlay receivers (mostly closed-source) available for purchase, it is our understanding that an open source implementation of the same functionality wouldn’t violate any of Apple’s rights either.

UxPlay authors

[adapted from fdraschbacher’s notes on RPiPlay antecedents]

The code in this repository accumulated from various sources over time. Here is an attempt at listing the various authors and the components they created:

UxPlay was initially created by antimof from RPiPlay, by replacing its Raspberry-Pi-adapted OpenMAX video and audio rendering system with GStreamer rendering for desktop Linux systems; the antimof work on code in renderers/ was later backported to RPiPlay, and the antimof project became dormant, but was later revived at the current GitHub site to serve a wider community of users.

The previous authors of code included in UxPlay by inheritance from RPiPlay include:

  • EstebanKubata: Created a FairPlay library called PlayFair. Located in the lib/playfair folder. License: GNU GPL
  • Juho Vähä-Herttua and contributors: Created an AirPlay audio server called ShairPlay, including support for Fairplay based on PlayFair. Most of the code in lib/ originally stems from this project. License: GNU LGPLv2.1+
  • dsafa22: Created an AirPlay 2 mirroring server AirplayServer (seems gone now), for Android based on ShairPlay. Code is preserved here, and see here for the description of the analysis of the AirPlay 2 mirror protocol that made RPiPlay possible, by the AirplayServer author. All code in lib/ concerning mirroring is dsafa22’s work. License: GNU LGPLv2.1+
  • Florian Draschbacher (FD-) and contributors: adapted dsafa22’s Android project for the Raspberry Pi, with extensive cleanups, debugging and improvements. The project RPiPlay is basically a port of dsafa22’s code to the Raspberry Pi, utilizing OpenMAX and OpenSSL for better performance on the Pi. License GPL v3. FD- has written an interesting note on the history of Airplay protocol versions, available at the RPiPlay github repository.

Independent of UxPlay, but used by it and bundled with it:

  • Fedor Indutny (of Node.js, and formerly Joyent, Inc) and contributors: Created an http parsing library called llhttp. Located at lib/llhttp/. License: MIT
UxPlay-1.71.1/README.md000066400000000000000000003074471473013662600143310ustar00rootroot00000000000000# UxPlay 1.71: AirPlay-Mirror and AirPlay-Audio server for Linux, macOS, and Unix (now also runs on Windows). ### **Now developed at the GitHub site (where ALL user issues should be posted, and latest versions can be found).** - ***NEW in v1.71**: Support for (YouTube) HLS (HTTP Live Streaming) video with the new "-hls" option.* Click on the airplay icon in the YouTube app to stream video. (You may need to wait until advertisements have finished or been skipped before clicking the YouTube airplay icon.) **Please report any issues with this new feature of UxPlay**. ## Highlights: - GPLv3, open source. - Originally supported only AirPlay Mirror protocol, now has added support for AirPlay Audio-only (Apple Lossless ALAC) streaming from current iOS/iPadOS clients. **Now with support for Airplay HLS video-streaming (currently only YouTube video).** - macOS computers (2011 or later, both Intel and "Apple Silicon" M1/M2 systems) can act either as AirPlay clients, or as the server running UxPlay. Using AirPlay, UxPlay can emulate a second display for macOS clients. - Support for older iOS clients (such as 32-bit iPad 2nd gen., iPod Touch 5th gen. and iPhone 4S, when upgraded to iOS 9.3.5, or later 64-bit devices), plus a Windows AirPlay-client emulator, AirMyPC. - Uses GStreamer plugins for audio and video rendering (with options to select different hardware-appropriate output "videosinks" and "audiosinks", and a fully-user-configurable video streaming pipeline). - Support for server behind a firewall. - Raspberry Pi support **both with and without hardware video decoding** by the Broadcom GPU. *Tested on Raspberry Pi Zero 2 W, 3 Model B+, 4 Model B, and 5.* - Support for running on Microsoft Windows (builds with the MinGW-64 compiler in the unix-like MSYS2 environment). Note: AirPlay2 multi-room audio streaming is not supported: use [shairport-sync](https://github.com/mikebrady/shairport-sync) for that. ## Packaging status (Linux and \*BSD distributions) [![Current Packaging status](https://repology.org/badge/vertical-allrepos/uxplay.svg)](https://repology.org/project/uxplay/versions). - Install uxplay on Debian-based Linux systems with "`sudo apt install uxplay`"; on FreeBSD with "`sudo pkg install uxplay`". Also available on Arch-based systems through AUR. Since v. 1.66, uxplay is now also packaged in RPM format by Fedora 38 ("`sudo dnf install uxplay`"). - For other RPM-based distributions which have not yet packaged UxPlay, a RPM "specfile" **uxplay.spec** is now provided with recent [releases](https://github.com/FDH2/UxPlay/releases) (see their "Assets"), and can also be found in the UxPlay source top directory. See the section on using this specfile for [building an installable RPM package](#building-an-installable-rpm-package). After installation: - (On Linux and \*BSD): if a firewall is active on the server hosting UxPlay, make sure the default network port (UDP 5353) for mDNS/DNS-SD queries is open (see [Troubleshooting](#troubleshooting) below for more details); also open three UDP and three TCP ports for Uxplay, and use the "uxplay -p ``{=html}" option (see "`man uxplay`" or "`uxplay -h`"). - Even if you install your distribution's pre-compiled uxplay binary package, you may need to read the instructions below for [running UxPlay](#running-uxplay) to see which of your distribution's **GStreamer plugin packages** you should also install. - For Audio-only mode (Apple Music, etc.) best quality is obtained with the option "uxplay -async", but there is then a 2 second latency imposed by iOS. - Add any UxPlay options you want to use as defaults to a startup file `~/.uxplayrc` (see "`man uxplay`" or "`uxplay -h`" for format and other possible locations). In particular, if your system uses PipeWire audio or Wayland video systems, you may wish to add "as pipewiresink" or "vs waylandsink" as defaults to the file. *(Output from terminal commands "ps waux \| grep pulse" or "pactl info" will contain "pipewire" if your Linux/BSD system uses it).* - On Raspberry Pi: models using hardware h264 video decoding by the Broadcom GPU (models 4B and earlier) may require the uxplay option -bt709. If you use Ubuntu 22.10 or earlier, GStreamer must be [patched](https://github.com/FDH2/UxPlay/wiki/Gstreamer-Video4Linux2-plugin-patches) to use hardware video decoding by the Broadcom GPU (also recommended but optional for Raspberry Pi OS (Bullseye): the patched GStreamer does not need option " -bt709`". The need for -bt709 when hardware video decoding is used seems to have reappeared starting with GStreamer-1.22. To (easily) compile the latest UxPlay from source, see the section [Getting UxPlay](#getting-uxplay). # Detailed description of UxPlay This project is a GPLv3 open source unix AirPlay2 Mirror server for Linux, macOS, and \*BSD. It was initially developed by [antimof](http://github.com/antimof/Uxplay) using code from OpenMAX-based [RPiPlay](https://github.com/FD-/RPiPlay), which in turn derives from [AirplayServer](https://github.com/KqsMea8/AirplayServer), [shairplay](https://github.com/juhovh/shairplay), and [playfair](https://github.com/EstebanKubata/playfair). (The antimof site is no longer involved in development, but periodically posts updates pulled from the new main [UxPlay site](https://github.com/FDH2/UxPlay)). UxPlay is tested on a number of systems, including (among others) Debian (10 "Buster", 11 "Bullseye", 12 "Bookworm"), Ubuntu (20.04 LTS, 22.04 LTS, 23.04 (also Ubuntu derivatives Linux Mint, Pop!\_OS), Red Hat and clones (Fedora 38, Rocky Linux 9.2), openSUSE Leap 15.5, Mageia 9, OpenMandriva "ROME", PCLinuxOS, Arch Linux, Manjaro, and should run on any Linux system. Also tested on macOS Catalina and Ventura (Intel) and Sonoma (M2), FreeBSD 14.0, Windows 10 and 11 (64 bit). On Raspberry Pi 4 model B, it is tested on Raspberry Pi OS (Bullseye and Bookworm) (32- and 64-bit), Ubuntu 22.04 LTS and 23.04, Manjaro RPi4 23.02, and (without hardware video decoding) on openSUSE 15.5. Also tested on Raspberry Pi Zero 2 W, 3 model B+, and now 5. Its main use is to act like an AppleTV for screen-mirroring (with audio) of iOS/iPadOS/macOS clients (iPhone, iPod Touch, iPad, Mac computers) on the server display of a host running Linux, macOS, or other unix (and now also Microsoft Windows). UxPlay supports Apple's AirPlay2 protocol using "Legacy Protocol", but some features are missing. (Details of what is publicly known about Apple's AirPlay 2 protocol can be found [here](https://openairplay.github.io/airplay-spec/), [here](https://github.com/SteeBono/airplayreceiver/wiki/AirPlay2-Protocol) and [here](https://emanuelecozzi.net/docs/airplay2); see also [pyatv](https://pyatv.dev/documentation/protocols) which could be a resource for adding modern protocols.) While there is no guarantee that future iOS releases will keep supporting "Legacy Protocol", iOS 17 continues support. The UxPlay server and its client must be on the same local area network, on which a **Bonjour/Zeroconf mDNS/DNS-SD server** is also running (only DNS-SD "Service Discovery" service is strictly necessary, it is not necessary that the local network also be of the ".local" mDNS-based type). On Linux and BSD Unix servers, this is usually provided by [Avahi](https://www.avahi.org), through the avahi-daemon service, and is included in most Linux distributions (this service can also be provided by macOS, iOS or Windows servers). Connections to the UxPlay server by iOS/MacOS clients can be initiated both in **AirPlay Mirror** mode (which streams lossily-compressed AAC audio while mirroring the client screen, or in the alternative **AirPlay Audio** mode which streams Apple Lossless (ALAC) audio without screen mirroring. In **Audio** mode, metadata is displayed in the uxplay terminal; if UxPlay option `-ca ` is used, the accompanying cover art is also output to a periodically-updated file ``, and can be viewed with a (reloading) graphics viewer of your choice. *Switching between* **Mirror** *and* **Audio** *modes during an active connection is possible: in* **Mirror** *mode, stop mirroring (or close the mirror window) and start an* **Audio** *mode connection, switch back by initiating a* **Mirror** *mode connection; cover-art display stops/restarts as you leave/re-enter* **Audio** *mode.* - **Note that Apple video-DRM (as found in "Apple TV app" content on the client) cannot be decrypted by UxPlay, and the Apple TV app cannot be watched using UxPlay's AirPlay Mirror mode (only the unprotected audio will be streamed, in AAC format).** - **With the new "-hls" option, UxPlay now also supports non-Mirror AirPlay video streaming (where the client controls a web server on the AirPlay server that directly receives HLS content to avoid it being decoded and re-encoded by the client). This currently only supports streaming of YouTube videos. Without the -hls option, using the icon for AirPlay video in apps such as the YouTube app will only send audio (in lossless ALAC format) without the accompanying video.** ### Possibility for using hardware-accelerated h264/h265 video-decoding, if available. UxPlay uses [GStreamer](https://gstreamer.freedesktop.org) "plugins" for rendering audio and video. This means that video and audio are supported "out of the box", using a choice of plugins. AirPlay streams video in h264 format: gstreamer decoding is plugin agnostic, and uses accelerated GPU hardware h264 decoders if available; if not, software decoding is used. - **VAAPI for Intel and AMD integrated graphics, NVIDIA with "Nouveau" open-source driver** With an Intel or AMD GPU, hardware decoding with the open-source VAAPI gstreamer plugin is preferable. The open-source "Nouveau" drivers for NVIDIA graphics are also in principle supported: see [here](https://nouveau.freedesktop.org/VideoAcceleration.html), but this requires VAAPI to be supplemented with firmware extracted from the proprietary NVIDIA drivers. - **NVIDIA with proprietary drivers** The `nvh264dec` plugin (included in gstreamer1.0-plugins-bad since GStreamer-1.18.0) can be used for accelerated video decoding on the NVIDIA GPU after NVIDIA's CUDA driver `libcuda.so` is installed. For GStreamer-1.16.3 or earlier, the plugin is called `nvdec`, and must be [built by the user](https://github.com/FDH2/UxPlay/wiki/NVIDIA-nvdec-and-nvenc-plugins). - **Video4Linux2 support for h264 hardware decoding on Raspberry Pi (Pi 4B and older)** Raspberry Pi (RPi) computers (tested on Pi 4 Model B) can now run UxPlay using software video decoding, but hardware-accelerated h264/h265 decoding by firmware in the Pi's Broadcom 2835 GPU is prefered. UxPlay accesses this using the GStreamer-1.22 Video4Linux2 (v4l2) plugin; Uses the out-of-mainline Linux kernel module bcm2835-codec maintained by Raspberry Pi, so far only included in Raspberry Pi OS, and two other distributions (Ubuntu, Manjaro) available with Raspberry Pi Imager. *(For GStreamer \< 1.22, see the [UxPlay Wiki](https://github.com/FDH2/UxPlay/wiki/Gstreamer-Video4Linux2-plugin-patches))*. Pi model 5 has no support for hardware H264 decoding, as its CPU is powerful enough for satisfactory software H264 decoding - **Support for h265 (HEVC) hardware decoding on Raspberry Pi (Pi 4 model B and Pi 5)** These Raspberry Pi models have a dedicated HEVC decoding block (not the GPU), with a driver "rpivid" which is not yet in the mainline Linux kernel (but is planned to be there in future). Unfortunately it produces decoded video in a non-standard pixel format (NC30 or "SAND") which will not be supported by GStreamer until the driver is in the mainline kernel; without this support, UxPlay support for HEVC hardware decoding on Raspberry Pi will not work. ### Note to packagers: UxPlay's GPLv3 license does not have an added "GPL exception" explicitly allowing it to be distributed in compiled form when linked to OpenSSL versions **prior to v. 3.0.0** (older versions of OpenSSL have a license clause incompatible with the GPL unless OpenSSL can be regarded as a "System Library", which it is in \*BSD). Many Linux distributions treat OpenSSL as a "System Library", but some (e.g. Debian) do not: in this case, the issue is solved by linking with OpenSSL-3.0.0 or later. # Getting UxPlay Either download and unzip [UxPlay-master.zip](https://github.com/FDH2/UxPlay/archive/refs/heads/master.zip), or (if git is installed): "git clone https://github.com/FDH2/UxPlay". You can also download a recent or earlier version listed in [Releases](https://github.com/FDH2/UxPlay/releases). - A recent UxPlay can also be found on the original [antimof site](https://github.com/antimof/UxPlay); that original project is inactive, but is usually kept current or almost-current with the [active UxPlay github site](https://github.com/FDH2/UxPlay) (thank you antimof!). ## Building UxPlay on Linux (or \*BSD): ### Debian-based systems: (Adapt these instructions for non-Debian-based Linuxes or \*BSD; for macOS, see specific instruction below). See [Troubleshooting](#troubleshooting) below for help with any difficulties. You need a C/C++ compiler (e.g. g++) with the standard development libraries installed. Debian-based systems provide a package "build-essential" for use in compiling software. You also need pkg-config: if it is not found by "`which pkg-config`", install pkg-config or its work-alike replacement pkgconf. Also make sure that cmake\>=3.10 is installed: "`sudo apt install cmake`" (add `build-essential` and `pkg-config` (or `pkgconf`) to this if needed). Make sure that your distribution provides OpenSSL 1.1.1 or later, and libplist 2.0 or later. (This means Debian 10 "Buster" based systems (e.g, Ubuntu 18.04) or newer; on Debian 10 systems "libplist" is an older version, you need "libplist3".) If it does not, you may need to build and install these from source (see instructions at the end of this README). If you have a non-standard OpenSSL installation, you may need to set the environment variable OPENSSL_ROOT_DIR (*e.g.* , "`export OPENSSL_ROOT_DIR=/usr/local/lib64`" if that is where it is installed). Similarly, for non-standard (or multiple) GStreamer installations, set the environment variable GSTREAMER_ROOT_DIR to the directory that contains the ".../gstreamer-1.0/" directory of the gstreamer installation that UxPlay should use (if this is *e.g.* "\~/my_gstreamer/lib/gstreamer-1.0/", set this location with "`export GSTREAMER_ROOT_DIR=$HOME/my_gstreamer/lib`"). - Most users will use the GStreamer supplied by their distribution, but a few (in particular users of Raspberry Pi OS Lite Legacy (Buster) on a Raspberry Pi model 4B who wish to stay on that unsupported Legacy OS for compatibility with other apps) should instead build a newer Gstreamer from source following [these instructions](https://github.com/FDH2/UxPlay/wiki/Building-latest-GStreamer-from-source-on-distributions-with-older-GStreamer-(e.g.-Raspberry-Pi-OS-).) . **Do this *before* building UxPlay**. In a terminal window, change directories to the source directory of the downloaded source code ("UxPlay-\*", "\*" = "master" or the release tag for zipfile downloads, "UxPlay" for "git clone" downloads), then follow the instructions below: **Note:** By default UxPlay will be built with optimization for the computer it is built on; when this is not the case, as when you are packaging for a distribution, use the cmake option `-DNO_MARCH_NATIVE=ON`. If you use X11 Windows on Linux or \*BSD, and wish to toggle in/out of fullscreen mode with a keypress (F11 or Alt_L+Enter) UxPlay needs to be built with a dependence on X11. Starting with UxPlay-1.59, this will be done by default **IF** the X11 development libraries are installed and detected. Install these with "`sudo apt install libx11-dev`". If GStreamer \< 1.20 is detected, a fix needed by screen-sharing apps (*e.g.*, Zoom) will also be made. - If X11 development libraries are present, but you wish to build UxPlay *without* any X11 dependence, use the cmake option `-DNO_X11_DEPS=ON`. 1. `sudo apt install libssl-dev libplist-dev`". (*unless you need to build OpenSSL and libplist from source*). 2. `sudo apt install libavahi-compat-libdnssd-dev` 3. `sudo apt install libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev`. (\**Skip if you built Gstreamer from source*) 4. `cmake .` (*For a cleaner build, which is useful if you modify the source, replace this by* "`mkdir build; cd build; cmake ..`": *you can then delete the contents of the `build` directory if needed, without affecting the source.*) Also add any cmake "`-D`" options here as needed (e.g, `-DNO_X11_DEPS=ON` or `-DNO_MARCH_NATIVE=ON`). 5. `make` 6. `sudo make install` (you can afterwards uninstall with `sudo make uninstall` in the same directory in which this was run). This installs the executable file "`uxplay`" to `/usr/local/bin`, (and installs a manpage to somewhere standard like `/usr/local/share/man/man1` and README files to somewhere like `/usr/local/share/doc/uxplay`). (If "man uxplay" fails, check if \$MANPATH is set: if so, the path to the manpage (usually /usr/local/share/man/) needs to be added to \$MANPATH .) The uxplay executable can also be found in the build directory after the build process, if you wish to test before installing (in which case the GStreamer plugins must first be installed). ### Building on non-Debian Linux and \*BSD \*\*For those with RPM-based distributions, a RPM spec file uxplay.spec is also available: see [Building an installable rpm package](#building-an-installable-rpm-package). - **Red Hat, or clones like CentOS (now continued as Rocky Linux or Alma Linux):** (sudo dnf install, or sudo yum install) openssl-devel libplist-devel avahi-compat-libdns_sd-devel gstreamer1-devel gstreamer1-plugins-base-devel (+libX11-devel for fullscreen X11) *(some of these may be in the "CodeReady" add-on repository, called "PowerTools" by clones)* - **Mageia, PCLinuxOS, OpenMandriva:** Same as Red Hat, except for name changes: (Mageia) "gstreamer1.0-devel", "gstreamer-plugins-base1.0-devel"; (OpenMandriva) "libopenssl-devel", "gstreamer-devel", "libgst-plugins-base1.0-devel". PCLinuxOS: same as Mageia, but uses synaptic (or apt) as its package manager. - **openSUSE:** (sudo zypper install) libopenssl-3-devel (formerly libopenssl-devel) libplist-2_0-devel (formerly libplist-devel) avahi-compat-mDNSResponder-devel gstreamer-devel gstreamer-plugins-base-devel (+ libX11-devel for fullscreen X11). - **Arch Linux** (*Also available as a package in AUR*): (sudo pacman -Syu) openssl libplist avahi gst-plugins-base. - **FreeBSD:** (sudo pkg install) libplist gstreamer1. Either avahi-libdns or mDNSResponder must also be installed to provide the dns_sd library. OpenSSL is already installed as a System Library. #### Building an installable RPM package First-time RPM builders should first install the rpm-build and rpmdevtools packages, then create the rpmbuild tree with "`rpmdev-setuptree`". Then download and copy uxplay.spec into `~/rpmbuild/SPECS`. In that directory, run "`rpmdev-spectool -g -R uxplay.spec`" to download the corresponding source file `uxplay-*.tar.gz` into `~/rpmbuild/SOURCES` ("rpmdev-spectool" may also be just called "spectool"); then run "`rpmbuild -ba uxplay.spec`" (you will need to install any required dependencies this reports). This should create the uxplay RPM package in a subdirectory of `~/rpmbuild/RPMS`. (**uxplay.spec** is tested on Fedora 38, Rocky Linux 9.2, openSUSE Leap 15.5, Mageia 9, OpenMandriva, PCLinuxOS; it can be easily modified to include dependency lists for other RPM-based distributions.) ## Running UxPlay ### Installing plugins (Debian-based Linux distributions, including Ubuntu and Raspberry Pi OS) (*skip if you built a complete GStreamer from source*) Next install the GStreamer plugins that are needed with `sudo apt install gstreamer1.0-`. Values of `` required are: 1. "**plugins-base**" 2. "**libav**" (for sound), 3. "**plugins-good**" (for v4l2 hardware h264 decoding) 4. "**plugins-bad**" (for h264 decoding). **Debian-based distributions split some of the plugin packages into smaller pieces:** some that may also be needed include "**gl**" for OpenGL support (this provides the "-vs glimagesink" videosink, which can be very useful in many systems (including Raspberry Pi), and should always be used when using h264/h265 decoding by a NVIDIA GPU), "**gtk3**" (which provides the "-vs gtksink" videosink), and "**x**" for X11 support, although these may already be installed; "**vaapi**" is needed for hardware-accelerated h264 video decoding by Intel or AMD graphics (but not for use with NVIDIA using proprietary drivers). If sound is not working, "**alsa**"","**pulseaudio**", or "**pipewire**" plugins may need to be installed, depending on how your audio is set up. - Also install "**gstreamer1.0-tools**" to get the utility gst-inspect-1.0 for examining the GStreamer installation. ### Installing plugins (Non-Debian-based Linux or \*BSD) (*skip if you built a complete GStreamer from source*) In some cases, because of patent issues, the libav plugin feature **avdec_aac** needed for decoding AAC audio in mirror mode is not provided in the official distribution: get it from community repositories for those distributions. - **Red Hat, or clones like CentOS (now continued as Rocky Linux or Alma Linux):** Install gstreamer1-libav gstreamer1-plugins-bad-free (+ gstreamer1-vaapi for Intel/AMD graphics). In recent Fedora, gstreamer1-libav is renamed gstreamer1-plugin-libav. **To get avdec_aac, install packages from [rpmfusion.org](https://rpmfusion.org)**: (get ffmpeg-libs from rpmfusion; on RHEL or clones, but not recent Fedora, also get gstreamer1-libav from there). - **Mageia, PCLinuxOS, OpenMandriva:** Install gstreamer1.0-libav gstreamer1.0-plugins-bad (+ gstreamer1.0-vaapi for Intel/AMD graphics). **On Mageia, to get avdec_aac, install ffmpeg from the "tainted" repository**, (which also provides a more complete gstreamer1.0-plugins-bad). - **openSUSE:** Install gstreamer-plugins-libav gstreamer-plugins-bad (+ gstreamer-plugins-vaapi for Intel/AMD graphics). **To get avdec_aac, install libav\* packages for openSUSE from [Packman](https://ftp.gwdg.de/pub/linux/misc/packman/suse/) "Essentials"**; recommendation: after adding the Packman repository, use the option in YaST Software management to switch all system packages for multimedia to Packman). - **Arch Linux** Install gst-plugins-good gst-plugins-bad gst-libav (+ gstreamer-vaapi for Intel/AMD graphics). - **FreeBSD:** Install gstreamer1-libav, gstreamer1-plugins, gstreamer1-plugins-\* (\* = core, good, bad, x, gtk, gl, vulkan, pulse, v4l2, ...), (+ gstreamer1-vaapi for Intel/AMD graphics). ### Starting and running UxPlay Since UxPlay-1.64, UxPlay can be started with options read from a configuration file, which will be the first found of (1) a file with a path given by environment variable `$UXPLAYRC`, (2) `~/.uxplayrc` in the user's home directory ("\~"), (3) `~/.config/uxplayrc`. The format is one option per line, omitting the initial `"-"` of the command-line option. Lines in the configuration file beginning with `"#"` are treated as comments and ignored. **Run uxplay in a terminal window**. On some systems, you can specify fullscreen mode with the `-fs` option, or toggle into and out of fullscreen mode with F11 or (held-down left Alt)+Enter keys. Use Ctrl-C (or close the window) to terminate it when done. If the UxPlay server is not seen by the iOS client's drop-down "Screen Mirroring" panel, check that your DNS-SD server (usually avahi-daemon) is running: do this in a terminal window with `systemctl status avahi-daemon`. If this shows the avahi-daemon is not running, control it with `sudo systemctl [start,stop,enable,disable] avahi-daemon` (on non-systemd systems, such as \*BSD, use `sudo service avahi-daemon [status, start, stop, restart, ...]`). If UxPlay is seen, but the client fails to connect when it is selected, there may be a firewall on the server that prevents UxPlay from receiving client connection requests unless some network ports are opened: **if a firewall is active, also open UDP port 5353 (for mDNS queries) needed by Avahi**. See [Troubleshooting](#troubleshooting) below for help with this or other problems. - Unlike an Apple TV, the UxPlay server does not by default require clients to initially "pair" with it using a pin code displayed by the server (after which the client "trusts" the server, and does not need to repeat this). Since v1.67, Uxplay offers such "pin-authentication" as an option: see "`-pin`" and "`-reg`" in [Usage](#usage) for details, if you wish to use it. *Some clients with MDM (Mobile Device Management, often present on employer-owned devices) are required to use pin-authentication: UxPlay will provide this even when running without the pin option.* - By default, UxPlay is locked to its current client until that client drops the connection; since UxPlay-1.58, the option `-nohold` modifies this behavior so that when a new client requests a connection, it removes the current client and takes over. UxPlay 1.66 introduces a mechanism ( `-restrict`, `-allow `, `-block `) to control which clients are allowed to connect, using their "deviceID" (which in Apple devices appears to be immutable). - In Mirror mode, GStreamer has a choice of **two** methods to play video with its accompanying audio: prior to UxPlay-1.64, the video and audio streams were both played as soon as possible after they arrived (the GStreamer "*sync=false*" method), with a GStreamer internal clock used to try to keep them synchronized. **Starting with UxPlay-1.64, the other method (GStreamer's "*sync=true*" mode), which uses timestamps in the audio and video streams sent by the client, is the new default**. On low-decoding-power UxPlay hosts (such as Raspberry Pi Zero W or 3 B+ models) this will drop video frames that cannot be decoded in time to play with the audio, making the video jerky, but still synchronized. The older method which does not drop late video frames worked well on more powerful systems, and is still available with the UxPlay option "`-vsync no`"; this method is adapted to "live streaming", and may be better when using UxPlay as a second monitor for a Mac computer, for example, while the new default timestamp-based method is best for watching a video, to keep lip movements and voices synchronized. (Without use of timestamps, video will eventually lag behind audio if it cannot be decoded fast enough: hardware-accelerated video-decoding helped to prevent this previously when timestamps were not being used.) - In Audio-only mode the GStreamer "sync=false" mode (not using timestamps) is still the default, but if you want to keep the audio playing on the server synchronized with the video showing on the client, use the `-async` timestamp-based option. (An example might be if you want to follow the Apple Music lyrics on the client while listening to superior sound on the UxPlay server). This delays the video on the client to match audio on the server, so leads to a slight delay before a pause or track-change initiated on the client takes effect on the audio played by the server. AirPlay volume-control attenuates volume (gain) by up to -30dB: the decibel range -30:0 can be rescaled from *Low*:0, or *Low*:*High*, using the option `-db` ("-db *Low*" or "-db *Low*:*High*"), *Low* must be negative. Rescaling is linear in decibels. Note that GStreamer's audio format will "clip" any audio gain above +20db, so keep *High* below that level. The option `-taper` provides a "tapered" AirPlay volume-control profile some users may prefer. The -vsync and -async options also allow an optional positive (or negative) audio-delay adjustment in *milliseconds* for fine-tuning : `-vsync 20.5` delays audio relative to video by 0.0205 secs; a negative value advances it.) - you may find video is improved by the setting -fps 60 that allows some video to be played at 60 frames per second. (You can see what framerate is actually streaming by using -vs fpsdisplaysink, and/or -FPSdata.) When using this, you should use the default timestamp-based synchronization option `-vsync`. - Since UxPlay-1.54, you can display the accompanying "Cover Art" from sources like Apple Music in Audio-Only (ALAC) mode: run "`uxplay -ca &`" in the background, then run a image viewer with an autoreload feature: an example is "feh": run "`feh -R 1 `" in the foreground; terminate feh and then Uxplay with "`ctrl-C fg ctrl-C`". By default, GStreamer uses an algorithm to search for the best "videosink" (GStreamer's term for a graphics driver to display images) to use. You can overide this with the uxplay option `-vs `. Which videosinks are available depends on your operating system and graphics hardware: use "`gst-inspect-1.0 | grep sink | grep -e video -e Video -e image`" to see what is available. Some possibilites on Linux/\*BSD are: - **glimagesink** (OpenGL), **waylandsink** - **xvimagesink**, **ximagesink** (X11) - **kmssink**, **fbdevsink** (console graphics without X11) - **vaapisink** (for Intel/AMD hardware-accelerated graphics); for NVIDIA hardware graphics (with CUDA) use **glimagesink** combined with "`-vd nvh264dec`" (or "nvh264sldec", a new variant which will become "nvh264dec" in GStreamer-1.24). - If the server is "headless" (no attached monitor, renders audio only) use `-vs 0`. Note that videosink options can set using quoted arguments to -vs: _e.g._, `-vs "xvimagesink display=:0"`: ximagesink and xvimagesink allow an X11 display name to be specified, and waylandsink has a similar option. Videosink options ("properties") can be found in their GStreamer description pages,such as https://gstreamer.freedesktop.org/documentation/xvimagesink . GStreamer also searches for the best "audiosink"; override its choice with `-as `. Choices on Linux include pulsesink, alsasink, pipewiresink, oss4sink; see what is available with `gst-inspect-1.0 | grep sink | grep -e audio -e Audio`. **One common problem involves GStreamer attempting to use incorrectly-configured or absent accelerated hardware h264 video decoding (e.g., VAAPI). Try "`uxplay -avdec`" to force software video decoding; if this works you can then try to fix accelerated hardware video decoding if you need it, or just uninstall the GStreamer vaapi plugin.** See [Usage](#usage) for more run-time options. ### **Special instructions for Raspberry Pi (tested on Raspberry Pi Zero 2 W, 3 Model B+, 4 Model B, and 5 only)**: - For Framebuffer video (for Raspberry Pi OS "Lite" and other non-X11 distributions) use the KMS videosink "-vs kmssink" (the DirectFB framebuffer videosink "dfbvideosink" is broken on the Pi, and segfaults). *In this case you should explicitly use the "-vs kmssink" option, as without it, autovideosink does not find the correct videosink.* - Raspberry Pi 5 does not provide hardware H264 decoding (and does not need it). - Pi Zero 2 W, 3 Model B+ and 4 Model B should use hardware H264 decoding by the Broadcom GPU, but it requires an out-of-mainstream kernel module bcm2835_codec maintained in the [Raspberry Pi kernel tree](https://github.com/raspberrypi/linux); distributions that are known to supply it include Raspberry Pi OS, Ubuntu, and Manjaro-RPi4. Use software decoding (option -avdec) if this module is not available. - Uxplay uses the Video4Linux2 (v4l2) plugin from GStreamer-1.22 and later to access the GPU, if hardware H264 decoding is used. This should happen automatically. The option -v4l2 can be used, but it is usually best to just let GStreamer find the best video pipeline by itself. - On older distributions (GStreamer \< 1.22), the v4l2 plugin needs a patch: see the [UxPlay Wiki](https://github.com/FDH2/UxPlay/wiki/Gstreamer-Video4Linux2-plugin-patches). Legacy Raspberry Pi OS (Bullseye) has a partially-patched GStreamer-1.18.4 which needs the uxplay option -bt709 (and don't use -v4l2); it is still better to apply the full patch from the UxPlay Wiki in this case. - **It appears that when hardware h264 video decoding is used, the option -bt709 became needed again in GStreamer-1.22 and later.** - For "double-legacy" Raspberry Pi OS (Buster), there is no patch for GStreamer-1.14. Instead, first build a complete newer GStreamer-1.18.6 from source using [these instructions](https://github.com/FDH2/UxPlay/wiki/Building-latest-GStreamer-from-source-on-distributions-with-older-GStreamer-(e.g.-Raspberry-Pi-OS-).) before building UxPlay. - Raspberry Pi 3 Model B+ running a 32 bit OS can also access the GPU with the GStreamer OMX plugin (use option "`-vd omxh264dec`"), but this is broken by Pi 4 Model B firmware. OMX support was removed from Raspberry Pi OS (Bullseye), but is present in Buster. - **H265 (4K)** video is potentially supported by hardware decoding on Raspberry Pi 5 models, as well as on Raspberry Pi 4 model B, using a dedicated HEVC decoding block, but the "rpivid" kernel driver for this is not yet supported by GStreamer (this driver decodes video into a non-standard format that cannot be supported by GStreamer until the driver is in the mainline Linux kernel). Raspberry Pi provides a version of ffmpeg that can use that format, but at present UxPlay cannot use this. The best solution would be for the driver to be "upstreamed" to the kernel, allowing GStreamer support. (Software HEVC decoding works, but does not seem to give satisfactory results on the Pi). Even with GPU video decoding, some frames may be dropped by the lower-power models to keep audio and video synchronized using timestamps. In Legacy Raspberry Pi OS (Bullseye), raspi-config "Performance Options" allows specifying how much memory to allocate to the GPU, but this setting appears to be absent in Bookworm (but it can still be set to e.g. 128MB by adding a line "gpu_mem=128" in /boot/config.txt). A Pi Zero 2 W (which has 512MB memory) worked well when tested in 32 bit Bullseye or Bookworm Lite with 128MB allocated to the GPU (default seems to be 64MB). The basic uxplay options for R Pi are `uxplay [-vs ]`. The choice `` = `glimagesink` is sometimes useful. With the Wayland video compositor, use `` = `waylandsink`. With framebuffer video, use `` = `kmssink`. - Tip: to start UxPlay on a remote host (such as a Raspberry Pi) using ssh: ```{=html} ``` ssh user@remote_host export DISPLAY=:0 nohup uxplay [options] > FILE & Sound and video will play on the remote host; "nohup" will keep uxplay running if the ssh session is closed. Terminal output is saved to FILE (which can be /dev/null to discard it) ## Building UxPlay on macOS: **(Intel X86_64 and "Apple Silicon" M1/M2 Macs)** *Note: A native AirPlay Server feature is included in macOS 12 Monterey, but is restricted to recent hardware. UxPlay can run on older macOS systems that will not be able to run Monterey, or can run Monterey but not AirPlay.* These instructions for macOS assume that the Xcode command-line developer tools are installed (if Xcode is installed, open the Terminal, type "sudo xcode-select --install" and accept the conditions). It is also assumed that CMake \>= 3.13 is installed: this can be done with package managers [MacPorts](http://www.macports.org) (`sudo port install cmake`), [Homebrew](http://brew.sh) (`brew install cmake`), or by a download from . Also install `git` if you will use it to fetch UxPlay. Next install libplist and openssl-3.x. Note that static versions of these libraries will be used in the macOS builds, so they can be uninstalled after building uxplay, if you wish. - If you use Homebrew: `brew install libplist openssl@3` - if you use MacPorts: `sudo port install libplist-devel openssl3` Otherwise, build libplist and openssl from source: see instructions near the end of this README; requires development tools (autoconf, automake, libtool, *etc.*) to be installed. Next get the latest macOS release of GStreamer-1.0. **Using "Official" GStreamer (Recommended for both MacPorts and Homebrew users)**: install the GStreamer release for macOS from . (This release contains its own pkg-config, so you don't have to install one.) Install both the gstreamer-1.0 and gstreamer-1.0-devel packages. After downloading, Shift-Click on them to install (they install to /Library/FrameWorks/GStreamer.framework). Homebrew or MacPorts users should **not** install (or should uninstall) the GStreamer supplied by their package manager, if they use the "official" release. - Since GStreamer v1.22, the "Official" (gstreamer.freedesktop.org) macOS binaries require a wrapper "gst_macos_main" around the actual main program (uxplay). This should have been applied during the UxPlay compilation process, and the initial UxPlay terminal message should confirm it is being used. (UxPlay can also be built using "Official" GStreamer v.1.20.7 binaries, which work without the wrapper.) **Using Homebrew's GStreamer**: pkg-config is needed: ("brew install pkg-config gstreamer"). This causes a large number of extra packages to be installed by Homebrew as dependencies. The [Homebrew gstreamer installation](https://formulae.brew.sh/formula/gstreamer#default) has recently been reworked into a single "formula" named `gstreamer`, which now works without needing GST_PLUGIN_PATH to be set in the enviroment. Homebrew installs gstreamer to `HOMEBREW_PREFIX/lib/gstreamer-1.0` where by default `HOMEBREW_PREFIX/*` is `/opt/homebrew/*` on Apple Silicon Macs, and `/usr/local/*` on Intel Macs; do not put any extra non-Homebrew plugins (that you build yourself) there, and instead set GST_PLUGIN_PATH to point to their location (Homebrew does not supply a complete GStreamer, but seems to have everything needed for UxPlay). **New: the UxPlay build script will now also detect Homebrew installations in non-standard locations indicated by the environment variable `$HOMEBREW_PREFIX`.** **Using GStreamer installed from MacPorts**: this is **not** recommended, as currently the MacPorts GStreamer is old (v1.16.2), unmaintained, and built to use X11: - Instead [build gstreamer yourself](https://github.com/FDH2/UxPlay/wiki/Building-GStreamer-from-Source-on-macOS-with-MacPorts) if you use MacPorts and do not want to use the "Official" Gstreamer binaries. *(If you really wish to use the MacPorts GStreamer-1.16.2, install pkgconf ("sudo port install pkgconf"), then "sudo port install gstreamer1-gst-plugins-base gstreamer1-gst-plugins-good gstreamer1-gst-plugins-bad gstreamer1-gst-libav". For X11 support on macOS, compile UxPlay using a special cmake option `-DUSE_X11=ON`, and run it from an XQuartz terminal with -vs ximagesink; older non-retina macs require a lower resolution when using X11: `uxplay -s 800x600`.)* After installing GStreamer, build and install uxplay: open a terminal and change into the UxPlay source directory ("UxPlay-master" for zipfile downloads, "UxPlay" for "git clone" downloads) and build/install with "cmake . ; make ; sudo make install" (same as for Linux). - Running UxPlay while checking for GStreamer warnings (do this with "export GST_DEBUG=2" before runnng UxPlay) reveals that with the default (since UxPlay 1.64) use of timestamps for video synchonization, many video frames are being dropped (only on macOS), perhaps due to another error (about videometa) that shows up in the GStreamer warnings. **Recommendation: use the new UxPlay "no timestamp" option "`-vsync no`"** (you can add a line "vsync no" in the uxplayrc configuration file). - On macOS with this installation of GStreamer, the only videosinks available seem to be glimagesink (default choice made by autovideosink) and osxvideosink. The window title does not show the Airplay server name, but the window is visible to screen-sharing apps (e.g., Zoom). The only available audiosink seems to be osxaudiosink. - The option -nc is always used, whether or not it is selected. This is a workaround for a problem with GStreamer videosinks on macOS: if the GStreamer pipeline is destroyed while the mirror window is still open, a segfault occurs. - In the case of glimagesink, the resolution settings "-s wxh" do not affect the (small) initial OpenGL mirror window size, but the window can be expanded using the mouse or trackpad. In contrast, a window created with "-vs osxvideosink" is initially big, but has the wrong aspect ratio (stretched image); in this case the aspect ratio changes when the window width is changed by dragging its side; the option `-vs "osxvideosink force-aspect-ratio=true"` can be used to make the window have the correct aspect ratio when it first opens. ## Building UxPlay on Microsoft Windows, using MSYS2 with the MinGW-64 compiler. - tested on Windows 10 and 11, 64-bit. 1. Download and install **Bonjour SDK for Windows v3.0**. You can download the SDK without any registration at [softpedia.com](https://www.softpedia.com/get/Programming/SDK-DDK/Bonjour-SDK.shtml), or get it from the official Apple site [https://developer.apple.com/download](https://developer.apple.com/download/all/?q=Bonjour%20SDK%20for%20Windows) (Apple makes you register as a developer to access it from their site). This should install the Bonjour SDK as `C:\Program Files\Bonjour SDK`. 2. (This is for 64-bit Windows; a build for 32-bit Windows should be possible, but is not tested.) The unix-like MSYS2 build environment will be used: download and install MSYS2 from the official site [https://www.msys2.org/](https://www.msys2.org). Accept the default installation location `C:\mysys64`. 3. [MSYS2 packages](https://packages.msys2.org/package/) are installed with a variant of the "pacman" package manager used by Arch Linux. Open a "MSYS2 MINGW64" terminal from the MSYS2 tab in the Windows Start menu, and update the new MSYS2 installation with "pacman -Syu". Then install the **MinGW-64** compiler and **cmake** pacman -S mingw-w64-x86_64-cmake mingw-w64-x86_64-gcc The compiler with all required dependencies will be installed in the msys64 directory, with default path `C:/msys64/mingw64`. Here we will simply build UxPlay from the command line in the MSYS2 environment (this uses "`ninja`" in place of "`make`" for the build system). 4. Download the latest UxPlay from github **(to use `git`, install it with `pacman -S git`, then "`git clone https://github.com/FDH2/UxPlay`")**, then install UxPlay dependencies (openssl is already installed with MSYS2): `pacman -S mingw-w64-x86_64-libplist mingw-w64-x86_64-gstreamer mingw-w64-x86_64-gst-plugins-base` If you are trying a different Windows build system, MSVC versions of GStreamer for Windows are available from the [official GStreamer site](https://gstreamer.freedesktop.org/download/), but only the MinGW 64-bit build on MSYS2 has been tested. 5. cd to the UxPlay source directory, then "`mkdir build`" and "`cd build`". The build process assumes that the Bonjour SDK is installed at `C:\Program Files\Bonjour SDK`. If it is somewhere else, set the enviroment variable BONJOUR_SDK_HOME to point to its location. Then build UxPlay with `cmake ..` `ninja` 6. Assuming no error in either of these, you will have built the uxplay executable **uxplay.exe** in the current ("build") directory. The "sudo make install" and "sudo make uninstall" features offered in the other builds are not available on Windows; instead, the MSYS2 environment has `/mingw64/...` available, and you can install the uxplay.exe executable in `C:/msys64/mingw64/bin` (plus manpage and documentation in `C:/msys64/mingw64/share/...`) with `cmake --install . --prefix /mingw64` To be able to view the manpage, you need to install the manpage viewer with "`pacman -S man`". To run **uxplay.exe** you need to install some gstreamer plugin packages with `pacman -S mingw-w64-x86_64-gst-`, where the required ones have `` given by 1. **libav** 2. **plugins-good** 3. **plugins-bad** Other possible MSYS2 gstreamer plugin packages you might use are listed in [MSYS2 packages](https://packages.msys2.org/package/). You also will need to grant permission to the uxplay executable uxplay.exe to access data through the Windows firewall. You may automatically be offered the choice to do this when you first run uxplay, or you may need to do it using **Windows Settings-\>Update and Security-\>Windows Security-\>Firewall & network protection -\> allow an app through firewall**. If your virus protection flags uxplay.exe as "suspicious" (but without a true malware signature) you may need to give it an exception. Now test by running "`uxplay`" (in a MSYS2 terminal window). If you need to specify the audiosink, there are two main choices on Windows: the older DirectSound plugin "`-as directsoundsink`", and the more modern Windows Audio Session API (wasapi) plugin "`-as wasapisink`", which supports [additional options](https://gstreamer.freedesktop.org/documentation/wasapi/wasapisink.html) such as uxplay -as 'wasapisink device=\"\"' where `` specifies an available audio device by its GUID, which can be found using "`gst-device-monitor-1.0 Audio`": `` has a form like `\{0.0.0.00000000\}.\{98e35b2b-8eba-412e-b840-fd2c2492cf44\}`. If "`device`" is not specified, the default audio device is used. If you wish to specify the videosink using the `-vs ` option, some choices for `` are `d3d11videosink`, `d3dvideosink`, `glimagesink`, `gtksink`. - With Direct3D 11.0 or greater, you can either always be in fullscreen mode using option `-vs "d3d11videosink fullscreen-toggle-mode=property fullscreen=true"`, or get the ability to toggle into and out of fullscreen mode using the Alt-Enter key combination with option `-vs "d3d11videosink fullscreen-toggle-mode=alt-enter"`. For convenience, these options will be added if just `-vs d3d11videosink` with or without the fullscreen option "-fs" is used. *(Windows users may wish to add "`vs d3d11videosink`" (no initial "`-`") to the UxPlay startup options file; see "man uxplay" or "uxplay -h".)* The executable uxplay.exe can also be run without the MSYS2 environment, in the Windows Terminal, with `C:\msys64\mingw64\bin\uxplay`. # Usage Options: - These can also be written (one option per line, without the initial "`-`" character) in the UxPlay startup file (either given by environment variable `$UXPLAYRC`, or `~/.uxplayrc` or `~/.config/uxplayrc`); lines begining with "`#`" are treated as comments, and ignored. Command line options supersede options in the startup file. **-n server_name** (Default: UxPlay); server_name@\_hostname\_ will be the name that appears offering AirPlay services to your iPad, iPhone etc, where *hostname* is the name of the server running uxplay. This will also now be the name shown above the mirror display (X11) window. **-nh** Do not append "@_hostname_" at the end of the AirPlay server name. **-h265** Activate "ScreenMultiCodec" support (AirPlay "Features" bit 42) for accepting h265 (4K/HEVC) video in addition to h264 video (1080p) in screen-mirror mode. When this option is used, two "video pipelines" (one for h264, one for h265) are created. If any GStreamer plugins in the pipeline are specific for h264 or h265, the correct version will be used in each pipeline. A wired Client-Server ethernet connection is preferred over Wifi for 4K video, and might be required by the client. Only recent Apple devices (M1/M2 Macs or iPads, and some iPhones) can send h265 video if a resolution "-s wxh" with h \> 1080 is requested. The "-h265" option changes the default resolution ("-s" option) from 1920x1080 to 3840x2160, and leaves default maximum framerate ("-fps" option) at 30fps. **-hls** Activate HTTP Live Streaming support. With this option YouTube videos can be streamed directly from YouTube servers to UxPlay (without passing through the client) by clicking on the AirPlay icon in the YouTube app. **-pin \[nnnn\]**: (since v1.67) use Apple-style (one-time) "pin" authentication when a new client connects for the first time: a four-digit pin code is displayed on the terminal, and the client screen shows a login prompt for this to be entered. When "-pin" is used by itself, a new random pin code is chosen for each authentication; if "-pin nnnn" (e.g., "-pin 3939") is used, this will set an unchanging fixed code. Authentication adds the server to the client's list of "trusted servers" and the client will not need to reauthenticate provided that the client and server public keys remain unchanged. (By default since v1.68, the server public key is generated from the MAC address, which can be changed with the -m option; see the -key option for an alternative method of key generation). *(Add a line "pin" in the UxPlay startup file if you wish the UxPlay server to use the pin authentication protocol).* **-reg \[*filename*\]**: (since v1.68). If "-pin" is used, this option maintains a register of pin-authenticated "trusted clients" in \$HOME/.uxplay.register (or optionally, in *filename*). Without this option, returning clients that skip pin-authentication are trusted and not checked. This option may be useful if UxPlay is used in a more public environment, to record client details; the register is text, one line per client, with client's public key (base-64 format), Device ID, and Device name; commenting out (with "\#") or deleting a line deregisters the corresponding client (see options -restrict, -block, -allow for more ways to control client access). *(Add a line "reg" in the startup file if you wish to use this feature.)* **-vsync \[x\]** (In Mirror mode:) this option (**now the default**) uses timestamps to synchronize audio with video on the server, with an optional audio delay in (decimal) milliseconds (*x* = "20.5" means 0.0205 seconds delay: positive or negative delays less than a second are allowed.) It is needed on low-power systems such as Raspberry Pi without hardware video decoding. **-vsync no** (In Mirror mode:) this switches off timestamp-based audio-video synchronization, restoring the default behavior prior to UxPlay-1.64. Standard desktop systems seem to work well without use of timestamps: this mode is appropriate for "live streaming" such as using UxPlay as a second monitor for a mac computer, or monitoring a webcam; with it, no video frames are dropped. **-async \[x\]** (In Audio-Only (ALAC) mode:) this option uses timestamps to synchronize audio on the server with video on the client, with an optional audio delay in (decimal) milliseconds (*x* = "20.5" means 0.0205 seconds delay: positive or negative delays less than a second are allowed.) Because the client adds a video delay to account for latency, the server in -async mode adds an equivalent audio delay, which means that audio changes such as a pause or a track-change will not take effect immediately. *This might in principle be mitigated by using the `-al` audio latency setting to change the latency (default 0.25 secs) that the server reports to the client, but at present changing this does not seem to have any effect*. **-async no**. This is the still the default behavior in Audio-only mode, but this option may be useful as a command-line option to switch off a `-async` option set in a "uxplayrc" configuration file. **-db *low*\[:*high*\]** Rescales the AirPlay volume-control attenuation (gain) from -30dB:0dB to *low*:0dB or *low*:*high*. The lower limit *low* must be negative (attenuation); the upper limit *high* can be either sign. (GStreamer restricts volume-augmentation by *high* so that it cannot exceed +20dB). The rescaling is "flat", so that for -db -50:10, a change in Airplay attenuation by -7dB is translated to a -7 x (60/30) = -14dB attenuation, and the maximum volume (AirPlay 0dB) is a 10dB augmentation, and Airplay -30dB would become -50dB. Note that the minimum AirPlay value (-30dB exactly) is translated to "mute". **-taper** Provides a "tapered" Airplay volume-control profile (matching the one called "dasl-tapering" in [shairport-sync](https://github.com/mikebrady/shairport-sync)): each time the length of the volume slider (or the number of steps above mute, where 16 steps = full volume) is reduced by 50%, the perceived volume is halved (a 10dB attenuation). (This is modified at low volumes, to use the "untapered" volume if it is louder.) **-s wxh** e.g. -s 1920x1080 (= "1080p"), the default width and height resolutions in pixels for h264 video. (The default becomes 3840x2160 (= "4K") when the -h265 option is used.) This is just a request made to the AirPlay client, and perhaps will not be the final resolution you get. w and h are whole numbers with four digits or less. Note that the **height** pixel size is the controlling one used by the client for determining the streaming format; the width is dynamically adjusted to the shape of the image (portrait or landscape format, depending on how an iPad is held, for example). **-s wxh@r** As above, but also informs the AirPlay client about the screen refresh rate of the display. Default is r=60 (60 Hz); r must be a whole number less than 256. **-o** turns on an "overscanned" option for the display window. This reduces the image resolution by using some of the pixels requested by option -s wxh (or their default values 1920x1080) by adding an empty boundary frame of unused pixels (which would be lost in a full-screen display that overscans, and is not displayed by gstreamer). Recommendation: **don't use this option** unless there is some special reason to use it. **-fs** uses fullscreen mode, but only works with X11, Wayland, VAAPI, and D3D11 (Windows). **-p** allows you to select the network ports used by UxPlay (these need to be opened if the server is behind a firewall). By itself, -p sets "legacy" ports TCP 7100, 7000, 7001, UDP 6000, 6001, 7011. -p n (e.g. -p 35000) sets TCP and UDP ports n, n+1, n+2. -p n1,n2,n3 (comma-separated values) sets each port separately; -p n1,n2 sets ports n1,n2,n2+1. -p tcp n or -p udp n sets just the TCP or UDP ports. Ports must be in the range \[1024-65535\]. If the -p option is not used, the ports are chosen dynamically (randomly), which will not work if a firewall is running. **-avdec** forces use of software h264 decoding using Gstreamer element avdec_h264 (libav h264 decoder). This option should prevent autovideosink choosing a hardware-accelerated videosink plugin such as vaapisink. **-vp *parser*** choses the GStreamer pipeline's h264 parser element, default is h264parse. Using quotes "..." allows options to be added. **-vd *decoder*** chooses the GStreamer pipeline's h264 decoder element, instead of the default value "decodebin" which chooses it for you. Software decoding is done by avdec_h264; various hardware decoders include: vaapih264dec, nvdec, nvh264dec, v4l2h264dec (these require that the appropriate hardware is available). Using quotes "..." allows some parameters to be included with the decoder name. **-vc *converter*** chooses the GStreamer pipeline's videoconverter element, instead of the default value "videoconvert". When using Video4Linux2 hardware-decoding by a GPU,`-vc v4l2convert` will also use the GPU for video conversion. Using quotes "..." allows some parameters to be included with the converter name. **-vs *videosink*** chooses the GStreamer videosink, instead of the default value "autovideosink" which chooses it for you. Some videosink choices are: ximagesink, xvimagesink, vaapisink (for intel graphics), gtksink, glimagesink, waylandsink, osxvideosink (for macOS), kmssink (for systems without X11, like Raspberry Pi OS lite) or fpsdisplaysink (which shows the streaming framerate in fps). Using quotes "..." allows some parameters to be included with the videosink name. For example, **fullscreen** mode is supported by the vaapisink plugin, and is obtained using `-vs "vaapisink fullscreen=true"`; this also works with `waylandsink`. The syntax of such options is specific to a given plugin (see GStreamer documentation), and some choices of videosink might not work on your system. **-vs 0** suppresses display of streamed video. In mirror mode, the client's screen is still mirrored at a reduced rate of 1 frame per second, but is not rendered or displayed. This option should always be used if the server is "headless" (with no attached screen to display video), and only used to render audio, which will be AAC lossily-compressed audio in mirror mode with unrendered video, and superior-quality ALAC Apple Lossless audio in Airplay audio-only mode. **-v4l2** Video settings for hardware h264 video decoding in the GPU by Video4Linux2. Equivalent to `-vd v4l2h264dec -vc v4l2convert`. **-bt709** A workaround for the failure of the older Video4Linux2 plugin to recognize Apple's use of an uncommon (but permitted) "full-range color" variant of the bt709 color standard for digital TV. This is no longer needed by GStreamer-1.20.4 and backports from it. **-rpi** Equivalent to "-v4l2" (Not valid for Raspberry Pi model 5, and removed in UxPlay 1.67) **-rpigl** Equivalent to "-rpi -vs glimagesink". (Removed since UxPlay 1.67) **-rpifb** Equivalent to "-rpi -vs kmssink" (Removed since UxPlay 1.67) **-rpiwl** Equivalent to "-rpi -vs waylandsink". (Removed since UxPlay 1.67) **-as *audiosink*** chooses the GStreamer audiosink, instead of letting autoaudiosink pick it for you. Some audiosink choices are: pulsesink, alsasink, pipewiresink, osssink, oss4sink, jackaudiosink, osxaudiosink (for macOS), wasapisink, directsoundsink (for Windows). Using quotes "..." might allow some optional parameters (e.g. `-as "alsasink device=..."` to specify a non-default output device). The syntax of such options is specific to a given plugin (see GStreamer documentation), and some choices of audiosink might not work on your system. **-as 0** (or just **-a**) suppresses playing of streamed audio, but displays streamed video. **-al *x*** specifies an audio latency *x* in (decimal) seconds in Audio-only (ALAC), that is reported to the client. Values in the range \[0.0, 10.0\] seconds are allowed, and will be converted to a whole number of microseconds. Default is 0.25 sec (250000 usec). *(However, the client appears to ignore this reported latency, so this option seems non-functional.)* **-ca *filename*** provides a file (where *filename* can include a full path) used for output of "cover art" (from Apple Music, *etc.*,) in audio-only ALAC mode. This file is overwritten with the latest cover art as it arrives. Cover art (jpeg format) is discarded if this option is not used. Use with a image viewer that reloads the image if it changes, or regularly (*e.g.* once per second.). To achieve this, run "`uxplay -ca [path/to/]filename &`" in the background, then run the the image viewer in the foreground. Example, using `feh` as the viewer: run "`feh -R 1 [path/to/]filename`" (in the same terminal window in which uxplay was put into the background). To quit, use `ctrl-C fg ctrl-C` to terminate the image viewer, bring `uxplay` into the foreground, and terminate it too. **-reset n** sets a limit of *n* consecutive timeout failures of the client to respond to ntp requests from the server (these are sent every 3 seconds to check if the client is still present, and synchronize with it). After *n* failures, the client will be presumed to be offline, and the connection will be reset to allow a new connection. The default value of *n* is 5; the value *n* = 0 means "no limit" on timeouts. **-nofreeze** closes the video window after a reset due to ntp timeout (default is to leave window open to allow a smoother reconection to the same client). This option may be useful in fullscreen mode. **-nc** maintains previous UxPlay \< 1.45 behavior that does **not close** the video window when the the client sends the "Stop Mirroring" signal. *This option is currently used by default in macOS, as the window created in macOS by GStreamer does not terminate correctly (it causes a segfault) if it is still open when the GStreamer pipeline is closed.* **-nohold** Drops the current connection when a new client attempts to connect. Without this option, the current client maintains exclusive ownership of UxPlay until it disconnects. **-restrict** Restrict clients allowed to connect to those specified by `-allow `. The deviceID has the form of a MAC address which is displayed by UxPlay when the client attempts to connect, and appears to be immutable. It has the format `XX:XX:XX:XX:XX:XX`, X = 0-9,A-F, and is possibly the "true" hardware MAC address of the device. Note that iOS clients generally expose different random "private Wi_Fi addresses" ("fake" MAC addresses) to different networks (for privacy reasons, to prevent tracking), which may change, and do not correpond to the deviceID. **-restrict no** Remove restrictions (default). This is useful as a command-line argument to overide restrictions set in the Startup file. **-allow *id*** Adds the deviceID = *id* to the list of allowed clients when client restrictions are being enforced. Usually this will be an entry in the uxplayrc startup file. **-block *id*** Always block clients with deviceID = *id*, even when client restrictions are not being enforced generally. Usually this will be an entry in the uxplayrc startup file. **-FPSdata** Turns on monitoring of regular reports about video streaming performance that are sent by the client. These will be displayed in the terminal window if this option is used. The data is updated by the client at 1 second intervals. **-fps n** sets a maximum frame rate (in frames per second) for the AirPlay client to stream video; n must be a whole number less than 256. (The client may choose to serve video at any frame rate lower than this; default is 30 fps.) A setting of 60 fps may give you improved video but is not recommended on Raspberry Pi. A setting below 30 fps might be useful to reduce latency if you are running more than one instance of uxplay at the same time. *This setting is only an advisory to the client device, so setting a high value will not force a high framerate.* (You can test using "-vs fpsdisplaysink" to see what framerate is being received, or use the option -FPSdata which displays video-stream performance data continuously sent by the client during video-streaming.) **-f {H\|V\|I}** implements "videoflip" image transforms: H = horizontal flip (right-left flip, or mirror image); V = vertical flip ; I = 180 degree rotation or inversion (which is the combination of H with V). **-r {R\|L}** 90 degree Right (clockwise) or Left (counter-clockwise) rotations; these image transforms are carried out after any **-f** transforms. **-m \[mac\]** changes the MAC address (Device ID) used by UxPlay (default is to use the true hardware MAC address reported by the host computer's network card). (Different server_name, MAC addresses, and network ports are needed for each running uxplay if you attempt to run more than one instance of uxplay on the same computer.) If \[mac\] (in form xx:xx:xx:xx:xx:xx, 6 hex octets) is not given, a random MAC address is generated. If UxPlay fails to find the true MAC address of a network card, (more specifically, the MAC address used by the first active network interface detected) a random MAC address will be used even if option **-m** was not specified. (Note that a random MAC address will be different each time UxPlay is started). **-key \[*filename*\]**: This (more secure) option for generating and storing a persistant public key (needed for the -pin option) has been replaced by default with a (less secure) method which generates a key from the server's "device ID" (MAC address, which can be changed with the -m option, conveniently as a startup file option). When the -key option is used, a securely generated keypair is generated and stored in `$HOME/.uxplay.pem`, if that file does not exist, or read from it, if it exists. (Optionally, the key can be stored in *filename*.) This method is more secure than the new default method, (because the Device ID is broadcast in the DNS_SD announcement) but still leaves the private key exposed to anyone who can access the pem file. This option should be set in the UxPlay startup file as a line "key" or "key *filename*" (no initial "-"), where *filename* is a full path which should be enclosed in quotes (`"...."`) if it contains any blank spaces. **Because the default method is simpler, and security of client access to uxplay is unlikely to be an important issue, the -key option is no longer recommended**. **-dacp \[*filename*\]**: Export current client DACP-ID and Active-Remote key to file: default is \$HOME/.uxplay.dacp. (optionally can be changed to *filename*). Can be used by remote control applications. File is transient: only exists while client is connected. **-vdmp** Dumps h264 video to file videodump.h264. -vdmp n dumps not more than n NAL units to videodump.x.h264; x= 1,2,... increases each time a SPS/PPS NAL unit arrives. To change the name *videodump*, use -vdmp \[n\] *filename*. **-admp** Dumps audio to file audiodump.x.aac (AAC-ELD format audio), audiodump.x.alac (ALAC format audio) or audiodump.x.aud (other-format audio), where x = 1,2,3... increases each time the audio format changes. -admp *n* restricts the number of packets dumped to a file to *n* or less. To change the name *audiodump*, use -admp \[n\] *filename*. *Note that (unlike dumped video) the dumped audio is currently only useful for debugging, as it is not containerized to make it playable with standard audio players.* **-d** Enable debug output. Note: this does not show GStreamer error or debug messages. To see GStreamer error and warning messages, set the environment variable GST_DEBUG with "export GST_DEBUG=2" before running uxplay. To see GStreamer information messages, set GST_DEBUG=4; for DEBUG messages, GST_DEBUG=5; increase this to see even more of the GStreamer inner workings. # Troubleshooting Note: `uxplay` is run from a terminal command line, and informational messages are written to the terminal. ### 0. Problems in compiling UxPlay. One user (on Ubuntu) found compilation failed with messages about linking to "usr/local/lib/libcrypto.a" and "zlib". This was because (in addition to the standard ubuntu installation of libssl-dev), the user was unaware that a second installation with libcrypto in /usr/local was present. Solution: when more than one installation of OpenSSL is present, set the environment variable OPEN_SSL_ROOT_DIR to point to the correct one; on 64-bit Ubuntu, this is done by running `export OPENSSL_ROOT_DIR=/usr/lib/X86_64-linux-gnu/` before running cmake. ### 1. **Avahi/DNS_SD Bonjour/Zeroconf issues** The DNS_SD Service-Discovery ("Bonjour" or "Zeroconf") service is required for UxPlay to work. On Linux, it will be usually provided by Avahi, and to troubleshoot this, you should use the tool `avahi-browse`. (You may need to install a separate package with a name like `avahi-utils` to get this.) On Linux, make sure Avahi is installed, and start the avahi-daemon service on the system running uxplay (your distribution will document how to do this, for example: `sudo systemctl avahi-daemon` or `sudo service avahi-daemon `, with `` one of enable, disable, start, stop, status. You might need to edit the avahi-daemon.conf file (it is typically in /etc/avahi/, find it with "`sudo find /etc -name avahi-daemon.conf`"): make sure that "disable-publishing" is **not** a selected option). Some systems may instead use the mdnsd daemon as an alternative to provide DNS-SD service. (FreeBSD offers both alternatives, but only Avahi was tested; see [here](https://gist.github.com/reidransom/6033227).) - **uxplay starts, but either stalls or stops after "Initialized server socket(s)" appears (*without the server name showing on the client*)**. If UxPlay stops with the "No DNS-SD Server found" message, this means that your network **does not have a running Bonjour/zeroconf DNS-SD server.** Before v1.60, UxPlay used to stall silently if DNS-SD service registration failed, but now stops with an error message returned by the DNSServiceRegister function: kDNSServiceErr_Unknown if no DNS-SD server was found: *(A NixOS user found that in NixOS, this error can also occur if avahi-daemon service IS running with publishing enabled, but reports "the error disappeared on NixOS by setting services.avahi.openFirewall to true".)* Other mDNS error codes are in the range FFFE FF00 (-65792) to FFFE FFFF (-65537), and are listed in the dnssd.h file. An older version of this (the one used by avahi) is found [here](https://github.com/lathiat/avahi/blob/master/avahi-compat-libdns_sd/dns_sd.h). A few additional error codes are defined in a later version from [Apple](https://opensource.apple.com/source/mDNSResponder/mDNSResponder-544/mDNSShared/dns_sd.h.auto.html). If UxPlay stalls *without an error message* and *without the server name showing on the client*, **this is a network problem** (if your UxPlay version is older than 1.60, it is also the behavior when no DNS-SD server is found.) A useful tool for examining such network problems from the client end is the (free) Discovery DNS-SD browser [available in the Apple App Store](https://apps.apple.com/us/developer/lily-ballard/id305441020) for both iOS (works on iPadOS too) and macOS. - Some users using dual-band (2.4GHz/5GHz) routers have reported that clients using the 5GHz band (sometimes) "fail to see UxPlay" (i.e., do not get a response to their mDNS queries), but the 2.4GHz band works. Other projects using Bonjour/mDNS have had similar reports; the issue seems to be router-specific, perhaps related to "auto" rather than fixed channel selection (5GHz has many more channels to switch between), or channel width selections; one speculation is that since mDNS uses UDP protocol (where "lost" messages are not resent), a mDNS query might get lost if channel switching occurs during the query. If your router has this problem, a reported "fix" is to (at least on 5GHz) use fixed channel and/or fixed (not dynamic) channel width. - **Avahi works at first, but new clients do not see UxPlay, or clients that initially saw it stop doing so after they disconnect**. This is usually because Avahi is only using the "loopback" network interface, and is not receiving mDNS queries from new clients that were not listening when UxPlay started. To check this, after starting uxplay, use the utility `avahi-browse -a -t` **in a different terminal window** on the server to verify that the UxPlay AirTunes and AirPlay services are correctly registered (only the AirTunes service is used in the "Legacy" AirPlay Mirror mode used by UxPlay, but the AirPlay service is used for the initial contact). The results returned by avahi-browse should show entries for uxplay like + eno1 IPv6 UxPlay AirPlay Remote Video local + eno1 IPv4 UxPlay AirPlay Remote Video local + lo IPv4 UxPlay AirPlay Remote Video local + eno1 IPv6 863EA27598FE@UxPlay AirTunes Remote Audio local + eno1 IPv4 863EA27598FE@UxPlay AirTunes Remote Audio local + lo IPv4 863EA27598FE@UxPlay AirTunes Remote Audio local If only the loopback ("lo") entries are shown, a firewall on the UxPlay host is probably blocking full DNS-SD service, and you need to open the default UDP port 5353 for mDNS requests, as loopback-based DNS-SD service is unreliable. If the UxPlay services are listed by avahi-browse as above, but are not seen by the client, the problem is likely to be a problem with the local network. ### 2. uxplay starts, but stalls after "Initialized server socket(s)" appears, *with the server name showing on the client* (but the client fails to connect when the UxPlay server is selected). This shows that a *DNS-SD* service is working, clients hear UxPlay is available, but the UxPlay server is not receiving the response from the client. This is usually because a firewall on the server is blocking the connection request from the client. (One user who insisted that the firewall had been turned off turned out to have had *two* active firewalls (*firewalld* and *ufw*) *both* running on the server!) If possible, either turn off the firewall to see if that is the problem, or get three consecutive network ports, starting at port n, all three in the range 1024-65535, opened for both tcp and udp, and use "uxplay -p n" (or open UDP 7011,6001,6000 TCP 7100,7000,7001 and use "uxplay -p"). If you are *really* sure there is no firewall, you may need to investigate your network transmissions with a tool like netstat, but almost always this is a firewall issue. ### 3. Problems *after* the client-server connection has been made: If you do *not* see the message `raop_rtp_mirror starting mirroring`, something went wrong before the client-server negotiations were finished. For such problems, use "uxplay -d" (debug log option) to see what is happening: it will show how far the connection process gets before the failure occurs. You can compare your debug output to that from a successful start of UxPlay in the [UxPlay Wiki](https://github.com/FDH2/UxPlay/wiki). **If UxPlay reports that mirroring started, but you get no video or audio, the problem is probably from a GStreamer plugin that doesn't work on your system** (by default, GStreamer uses the "autovideosink" and "autoaudiosink" algorithms to guess what are the "best" plugins to use on your system). A different reason for no audio occurred when a user with a firewall only opened two udp network ports: **three** are required (the third one receives the audio data). **Raspberry Pi** devices (*Pi 4B+ and earlier: this does not apply to the Pi 5, which does not provide hardware h264 decoding, and does not need it*) work best with hardware GPU h264 video decoding if the Video4Linux2 plugin in GStreamer v1.20.x or earlier has been patched (see the UxPlay [Wiki](https://github.com/FDH2/UxPlay/wiki/Gstreamer-Video4Linux2-plugin-patches) for patches). This is fixed in GStreamer-1.22, and by backport patches from this in distributions such as Raspberry Pi OS (Bullseye): **use option `-bt709` with the GStreamer-1.18.4 from Raspberry Pi OS**. This also needs the bcm2835-codec kernel module that is not in the standard Linux kernel (it is available in Raspberry Pi OS, Ubuntu and Manjaro). - **If this kernel module is not available in your Raspberry Pi operating system, or if GStreamer \< 1.22 is not patched, use option `-avdec` for software h264-decoding.** Sometimes "autovideosink" may select the OpenGL renderer "glimagesink" which may not work correctly on your system. Try the options "-vs ximagesink" or "-vs xvimagesink" to see if using one of these fixes the problem. Other reported problems are connected to the GStreamer VAAPI plugin (for hardware-accelerated Intel graphics, but not NVIDIA graphics). Use the option "-avdec" to force software h264 video decoding: this should prevent autovideosink from selecting the vaapisink videosink. Alternatively, find out if the gstreamer1.0-vaapi plugin is installed, and if so, uninstall it. (If this does not fix the problem, you can reinstall it.) There are some reports of other GStreamer problems with hardware-accelerated Intel HD graphics. One user (on Debian) solved this with "sudo apt install intel-media-va-driver-non-free". This is a driver for 8'th (or later) generation "\*-lake" Intel chips, that seems to be related to VAAPI accelerated graphics. If you *do* have Intel HD graphics, and have installed the vaapi plugin, but `-vs vaapisink` does not work, check that vaapi is not "blacklisted" in your GStreamer installation: run `gst-inspect-1.0 vaapi`, if this reports `0 features`, you need to `export GST_VAAPI_ALL_DRIVERS=1` before running uxplay, or set this in the default environment. You can try to fix audio or video problems by using the "`-as `" or "`-vs `" options to choose the GStreamer audiosink or videosink , rather than letting GStreamer choose one for you. (See above, in [Starting and running UxPlay](#starting-and-running-uxplay) for choices of `` or ``.) The "OpenGL renderer" window created on Linux by "-vs glimagesink" sometimes does not close properly when its "close" button is clicked. (this is a GStreamer issue). You may need to terminate uxplay with Ctrl-C to close a "zombie" OpenGl window. If similar problems happen when the client sends the "Stop Mirroring" signal, try the no-close option "-nc" that leaves the video window open. ### 4. GStreamer issues (missing plugins, etc.): - clearing the user's GStreamer cache with `rm -rf ~/.cache/gstreamer-1.0/*` may be the solution to problems where gst-inspect-1.0 does not show a plugin that you believe is installed. The cache will be regenerated next time GStreamer is started. **This is the solution to puzzling problems that turn out to come from corruption of the cache, and should be tried first.** If UxPlay fails to start, with a message that a required GStreamer plugin (such as "libav") was not found, first check with the GStreamer tool gst-inspect-1.0 to see what GStreamer knows is available. (You may need to install some additional GStreamer "tools" package to get gst-inspect-1.0). For, *e.g.* a libav problem, check with "`gst-inspect-1.0 libav`". If it is not shown as available to GStreamer, but your package manager shows the relevant package as installed (as one user found), try entirely removing and reinstalling the package. That user found that a solution to a "**Required gstreamer plugin 'libav' not found**" message that kept recurring was to clear the user's gstreamer cache. If it fails to start with an error like '`no element "avdec_aac"`' this is because even though gstreamer-libav is installed. it is incomplete because some plugin features are missing: "`gst-inspect-1.0 | grep avdec_aac`" will show if avdec_aac is available. Unlike other GStreamer plugins, the libav plugin is a front end to FFmpeg codecs which provide avdec\_\*. - Some distributions (RedHat, SUSE, etc) provide incomplete versions of FFmpeg because of patent issues with codecs used by certain plugins. In those cases there will be some "extra package" provider like [RPM fusion](https://rpmfusion.org) (RedHat), [packman](http://packman.links2linux.org/) (SUSE) where you can get complete packages (your distribution will usually provide instructions for this, Mageia puts them in an optional "tainted" repo). The packages needed may be "ffmpeg\*" or "libav\*" packages: the GStreamer libav plugin package does not contain any codecs itself, it just provides a way for GStreamer to use ffmpeg/libav codec libraries which must be installed separately. For similar reasons, distributions may ship incomplete packages of GStreamer "plugins-bad". Use user on Fedora thought they had installed from rpmfusion, but the system had not obeyed: *"Adding --allowerasing to the dnf command fixed it after a restart"*. - starting with release UxPlay-1.65.3, UxPlay will continue to function, but without audio in mirror mode, if avdec_aac is missing. To troubleshoot GStreamer execute "export GST_DEBUG=2" to set the GStreamer debug-level environment-variable in the terminal where you will run uxplay, so that you see warning and error messages; see [GStreamer debugging tools](https://gstreamer.freedesktop.org/documentation/tutorials/basic/debugging-tools.html) for how to see much more of what is happening inside GStreamer. Run "gst-inspect-1.0" to see which GStreamer plugins are installed on your system. Some extra GStreamer packages for special plugins may need to be installed (or reinstalled: a user using a Wayland display system as an alternative to X11 reported that after reinstalling Lubuntu 18.4, UxPlay would not work until gstreamer1.0-x was installed, presumably for Wayland's X11-compatibility mode). Different distributions may break up GStreamer 1.x into packages in different ways; the packages listed above in the build instructions should bring in other required GStreamer packages as dependencies, but will not install all possible plugins. The GStreamer video pipeline, which is shown in the initial output from `uxplay -d`, has the default form appsrc name=video_source ! queue ! h264parse ! decodebin ! videoconvert ! autovideosink name=video_sink sync=false The pipeline is fully configurable: default elements "h264parse", "decodebin", "videoconvert", and "autovideosink" can respectively be replaced by using uxplay options `-vp`, `-vd`, `-vc`, and `-vs`, if there is any need to modify it (entries can be given in quotes "..." to include options). ### 5. Mirror screen freezes (a network problem): This can happen if the TCP video stream from the client stops arriving at the server, probably because of network problems (the UDP audio stream may continue to arrive). At 3-second intervals, UxPlay checks that the client is still connected by sending it a request for a NTP time signal. If a reply is not received from the client within a 0.3 sec time-window, an "ntp timeout" is registered. If a certain number (currently 5) of consecutive ntp timeouts occur, UxPlay assumes that the client is "dead", and resets the connection, becoming available for connection to a new client, or reconnection to the previous one. Sometimes the connection may recover before the timeout limit is reached, and if the default limit is not right for your network, it can be modified using the option "-reset *n*", where *n* is the desired timeout-limit value (*n* = 0 means "no limit"). If the connection starts to recover after ntp timeouts, a corrupt video packet from before the timeout may trigger a "connection reset by peer" error, which also causes UxPlay to reset the connection. - When the connection is reset, the "frozen" mirror screen of the previous connection is left in place, but does **not** block new connections, and will be taken over by a new client connection when it is made. ### 6. Protocol issues (with decryption of the encrypted audio and video streams sent by the client). A protocol failure may trigger an unending stream of error messages, and means that the audio decryption key (also used in video decryption) was not correctly extracted from data sent by the client. The protocol was modifed in UxPlay-1.65 after it was discovered that the client-server "pairing" step could be avoided (leading to a much quicker connection setup, without a 5 second delay) by disabling "Supports Legacy Pairing" (bit 27) in the "features" code UxPlay advertises on DNS-SD Service Discovery. Most clients will then not attempt the setup of a "shared secret key" when pairing, which is used by AppleTV for simultaneous handling of multiple clients (UxPlay only supports one client at a time). **This change is now well-tested, but in case it causes any protocol failures, UxPlay can be reverted to the previous behavior by uncommenting the previous "FEATURES_1" setting (and commenting out the new one) in lib/dnssdint.h, and then rebuilding UxPlay.** ("Pairing" is re-enabled when the new Apple-style one-time "pin" authentication is activated by running UxPlay with the "-pin" option introduced in UxPlay 1.67.) Protocol failure should not happen for iOS 9.3 or later clients. However, if a client uses the same older version of the protocol that is used by the Windows-based AirPlay client emulator *AirMyPC*, the protocol can be switched to the older version by the setting `OLD_PROTOCOL_CLIENT_USER_AGENT_LIST` in `UxPlay/lib/global.h`. UxPlay reports the client's "User Agent" string when it connects. If some other client also fails to decrypt all audio and video, try adding its "User Agent" string in place of "xxx" in the entry "AirMyPC/2.0;xxx" in global.h and rebuild uxplay. Note that for DNS-SD Service Discovery, Uxplay declares itself to be an AppleTV3,2 (a 32 bit device) with a sourceVersion 220.68; this can also be changed in global.h. UxPlay also works if it declares itself as an AppleTV6,2 with sourceVersion 380.20.1 (an AppleTV 4K 1st gen, introduced 2017, running tvOS 12.2.1), so it does not seem to matter what version UxPlay claims to be. # Changelog 1.71 2024-12-13 Add support for HTTP Live Streaming (HLS), initially only for YouTube movies. Fix issue with NTP timeout on Windows. 1.70 2024-10-04 Add support for 4K (h265) video (resolution 3840 x 2160). Fix issue with GStreamer \>= 1.24 when client sleeps, then wakes. 1.69 2024-08-09 Internal improvements (e.g. in -nohold option, identifying GStreamer videosink selected by autovideosink, finding X11 display) in anticipation of future HLS video support. New -nofreeze option to not leave frozen video in place when a network connection is reset. Fixes for GStreamer-1.24.x changes. 1.68 2023-12-31 New simpler (default) method for generating a persistent public key from the server MAC address (which can now be set with the -m option). (The previous method is still available with -key option). New option -reg to maintain a register of pin-authenticated clients. Corrected volume-control: now interprets AirPlay volume range -30dB:0dB as decibel gain attenuation, with new option -db low\[:high\] for "flat" rescaling of the dB range. Add -taper option for a "tapered" AirPlay volume-control profile. 1.67 2023-11-30 Add support for Apple-style one-time pin authentication of clients with option "-pin": (uses SRP6a authentication protocol and public key persistence). Detection with error message of (currently) unsupported H265 video when requesting high resolution over wired ethernet. Removed rpi\* options (which are not valid with new Raspberry Pi model 5, and can be replaced by combinations of other options). Added optional argument "mac" to "-m" option, to specify a replacement MAC address/Device ID. Update llhttp to v. 9.1.3. Add -dacp option for exporting current client DACP info (for remotes). 1.66 2023-09-05 Fix IPV6 support. Add option to restrict clients to those on a list of allowed deviceIDs, or to block connections from clients on a list of blocked deviceIDs. Fix for #207 from @thiccaxe (screen lag in vsync mode after client wakes from sleep). 1.65.3 2023-07-23 Add RPM spec file; add warning if required gstreamer libav feature "avdec_aac" is missing: (this occurs in RPM-based distributions that ship an incomplete FFmpeg for Patent or License reasons, and rely on users installing an externally-supplied complete FFmpeg). Mirror-mode airplay will now work without audio if avdec_aac is missing. 1.65 2023-06-03 Eliminate pair_setup part of connection protocol to allow faster connections with clients (thanks to @shuax #176 for this discovery); to revert, uncomment a line in lib/dnssdint.h. Disconnect from audio device when connection closes, to not block its use by other apps if uxplay is running but not connected. Fix for AirMyPC client (broken since 1.60), so its older non-NTP timestamp protocol works with -vsync. Corrected parsing of configuration file entries that were in quotes. 1.64 2023-04-23 Timestamp-based synchronization of audio and video is now the default in Mirror mode. (Use "-vsync no" to restore previous behavior.) A configuration file can now be used for startup options. Also some internal cleanups and a minor bugfix that fixes #192. 1.63 2023-02-12 Reworked audio-video synchronization, with new options -vsync (for Mirror mode) and -async (for Audio-Only mode, to sync with client video). Option -vsync makes software h264 decoding of streamed videos with option -avdec viable on some recent Raspberry Pi models. Internal change: all times are now processed in nanoseconds units. Removed -ao option introduced in 1.62. 1.62 2023-01-18 Added Audio-only mode time offset -ao x to allow user synchronization of ALAC audio playing on the server with video, song lyrics, etc. playing on the client. x = 5.0 appears to be optimal in many cases. Quality fixes: cleanup in volume changes, timestamps, some bugfixes. 1.61 2022-12-30 Removed -t option (workaround for an Avahi issue, correctly solved by opening network port UDP 5353 in firewall). Remove -g debug flag from CMAKE_CFLAGS. Postpend (instead of prepend) build environment CFLAGS to CMAKE_CFLAGS. Refactor parts of uxplay.cpp 1.60 2022-12-15 Added exit with error message if DNSServiceRegister fails (instead of just stalling). Test for Client's attempt to using unsupported AirPlay 2 "REMOTE CONTROL" protocol (with no timing channel), and exit if this occurs. Reworked metadata processing to correctly parse DMAP header (previous version worked with DMAP messages currently received, but was not correct). 1.59 2022-12-12 remove "ZOOMFIX" compile option and make compilation with X11-dependence the default if X11 development libraries are detected (this now also provides fullscreen mode with a F11 or Alt+Enter key toggle); ZOOMFIX is now automatically applied for GStreamer \< 1.20. New cmake option -DNO_X11_DEPS compiles uxplay without X11 dependence. Reworked internal metadata handling. Fix segfault with "-vs 0". 1.58 2022-10-29 Add option "-nohold" that will drop existing connections when a new client connects. Update llhttp to v8.1.0. 1.57 2022-10-09 Minor fixes: (fix coredump on AUR on "stop mirroring", occurs when compiled with AUR CFLAGS -DFORTIFY_SOURCE); graceful exit when required plugins are missing; improved support for builds on Windows. Include audioresample in GStreamer audio pipeline. 1.56 2022-09-01 Added support for building and running UxPlay-1.56 on Windows (no changes to Unix (Linux, \*BSD, macOS) codebase.) 1.56 2022-07-30 Remove -bt709 from -rpi, -rpiwl, -rpifb as GStreamer is now fixed. 1.55 2022-07-04 Remove the bt709 fix from -v4l2 and create a new -bt709 option (previous "-v4l2" is now "-v4l2 -bt709"). This allows the currently-required -bt709 option to be used on its own on RPi without -v4l2 (sometimes this give better results). 1.54 2022-06-25 Add support for "Cover Art" display in Audio-only (ALAC) mode. Reverted a change that caused VAAPI to crash with AMD POLARIS graphics cards. Minor internal changes to plist code and uxplay option parsing. 1.53 2022-06-13 Internal changes to audio sync code, revised documentation, Minor bugfix (fix assertion crash when resent audio packets are empty). 1.52 2022-05-05 Cleaned up initial audio sync code, and reformatted streaming debug output (readable aligned timestamps with decimal points in seconds). Eliminate memory leaks (found by valgrind). Support for display of ALAC (audio-only) metadata (soundtrack artist names, titles etc.) in the uxplay terminal. 1.51 2022-04-24 Reworked options forVideo4Linux2 support (new option -v4l2) and short options -rpi, -rpifb, -rpiwl as synonyms for -v4l2, -v4l2 -vs kmssink, and -v4l2 -vs waylandsink. Reverted a change from 1.48 that broke reconnection after "Stop Mirroring" is sent by client. 1.50 2022-04-22 Added -fs fullscreen option (for Wayland or VAAPI plugins only), Changed -rpi to be for framebuffer ("lite") RPi systems and added -rpigl (OpenGL) and -rpiwl (Wayland) options for RPi Desktop systems. Also modified timestamps from "DTS" to "PTS" for latency improvement, plus internal cleanups. 1.49 2022-03-28 Addded options for dumping video and/or audio to file, for debugging, etc. h264 PPS/SPS NALU's are shown with -d. Fixed video-not-working for M1 Mac clients. 1.48 2022-03-11 Made the GStreamer video pipeline fully configurable, for use with hardware h264 decoding. Support for Raspberry Pi. 1.47 2022-02-05 Added -FPSdata option to display (in the terminal) regular reports sent by the client about video streaming performance. Internal cleanups of processing of video packets received from the client. Added -reset n option to reset the connection after n ntp timeouts (also reset after "connection reset by peer" error in video stream). 1.46 2022-01-20 Restore pre-1.44 behavior (1.44 may have broken hardware acceleration): once again use decodebin in the video pipeline; introduce new option "-avdec" to force software h264 decoding by libav h264, if needed (to prevent selection of vaapisink by autovideosink). Update llhttp to v6.0.6. UxPlay now reports itself as AppleTV3,2. Restrict connections to one client at a time (second client must now wait for first client to disconnect). 1.45 2022-01-10 New behavior: close video window when client requests "stop mirroring". (A new "no close" option "-nc" is added for users who wish to retain previous behavior that does not close the video window). 1.44 2021-12-13 Omit hash of aeskey with ecdh_secret for an AirMyPC client; make an internal rearrangement of where this hash is done. Fully report all initial communications between client and server in -d debug mode. Replace decodebin in GStreamer video pipeline by h264-specific elements. 1.43 2021-12-07 Various internal changes, such as tests for successful decryption, uniform treatment of informational/debug messages, etc., updated README. 1.42 2021-11-20 Fix MAC detection to work with modern Linux interface naming practices, MacOS and \*BSD. 1.41 2021-11-11 Further cleanups of multiple audio format support (internal changes, separated RAOP and GStreamer audio/video startup) 1.40 2021-11-09 Cleanup segfault in ALAC support, manpage location fix, show request Plists in debug mode. 1.39 2021-11-06 Added support for Apple Lossless (ALAC) audio streams. 1.38 2021-10-8 Add -as *audiosink* option to allow user to choose the GStreamer audiosink. 1.37 2021-09-29 Append "@hostname" to AirPlay Server name, where "hostname" is the name of the server running uxplay (reworked change in 1.36). 1.36 2021-09-29 Implemented suggestion (by @mrbesen and @PetrusZ) to use hostname of machine runing uxplay as the default server name 1.35.1 2021-09-28 Added the -vs 0 option for streaming audio, but not displaying video. 1.35 2021-09-10 now uses a GLib MainLoop, and builds on macOS (tested on Intel Mac, 10.15 ). New option -t *timeout* for relaunching server if no connections were active in previous *timeout* seconds (to renew Bonjour registration). 1.341 2021-09-04 fixed: render logger was not being destroyed by stop_server() 1.34 2021-08-27 Fixed "ZOOMFIX": the X11 window name fix was only being made the first time the GStreamer window was created by uxplay, and not if the server was relaunched after the GStreamer window was closed, with uxplay still running. Corrected in v. 1.34 ### Building OpenSSL \>= 1.1.1 from source. If you need to do this, note that you may be able to use a newer version (OpenSSL-3.0.1 is known to work). You will need the standard development toolset (autoconf, automake, libtool). Download the source code from . Install the downloaded openssl by opening a terminal in your Downloads directory, and unpacking the source distribution: ("tar -xvzf openssl-3.0.1.tar.gz ; cd openssl-3.0.1"). Then build/install with "./config ; make ; sudo make install_dev". This will typically install the needed library `libcrypto.*`, either in /usr/local/lib or /usr/local/lib64. *(Ignore the following for builds on MacOS:)* On some systems like Debian or Ubuntu, you may also need to add a missing entry `/usr/local/lib64` in /etc/ld.so.conf (or place a file containing "/usr/local/lib64/libcrypto.so" in /etc/ld.so.conf.d) and then run "sudo ldconfig". ### Building libplist \>= 2.0.0 from source. *(Note: on Debian 9 "Stretch" or Ubuntu 16.04 LTS editions, you can avoid this step by installing libplist-dev and libplist3 from Debian 10 or Ubuntu 18.04.)* As well as the usual build tools (autoconf, automake, libtool), you may need to also install some libpython\*-dev package. Download the latest source with git from , or get the source from the Releases section (use the \*.tar.bz2 release, **not** the \*.zip or \*.tar.gz versions): download [libplist-2.3.0](https://github.com/libimobiledevice/libplist/releases/download/2.3.0/libplist-2.3.0.tar.bz2), then unpack it ("tar -xvjf libplist-2.3.0.tar.bz2 ; cd libplist-2.3.0"), and build/install it: ("./configure ; make ; sudo make install"). This will probably install libplist-2.0.\* in /usr/local/lib. The new libplist-2.3.0 release should be compatible with UxPlay; [libplist-2.2.0](https://github.com/libimobiledevice/libplist/releases/download/2.2.0/libplist-2.2.0.tar.bz2) is also available if there are any issues. *(Ignore the following for builds on MacOS:)* On some systems like Debian or Ubuntu, you may also need to add a missing entry `/usr/local/lib` in /etc/ld.so.conf (or place a file containing "/usr/local/lib/libplist-2.0.so" in /etc/ld.so.conf.d) and then run "sudo ldconfig". # Disclaimer All the resources in this repository are written using only freely available information from the internet. The code and related resources are meant for educational purposes only. It is the responsibility of the user to make sure all local laws are adhered to. This project makes use of a third-party GPL library for handling FairPlay. The legal status of that library is unclear. Should you be a representative of Apple and have any objections against the legality of the library and its use in this project, please contact the developers and the appropriate steps will be taken. Given the large number of third-party AirPlay receivers (mostly closed-source) available for purchase, it is our understanding that an open source implementation of the same functionality wouldn't violate any of Apple's rights either. # UxPlay authors *\[adapted from fdraschbacher's notes on RPiPlay antecedents\]* The code in this repository accumulated from various sources over time. Here is an attempt at listing the various authors and the components they created: UxPlay was initially created by **antimof** from RPiPlay, by replacing its Raspberry-Pi-adapted OpenMAX video and audio rendering system with GStreamer rendering for desktop Linux systems; the antimof work on code in `renderers/` was later backported to RPiPlay, and the antimof project became dormant, but was later revived at the [current GitHub site](http://github.com/FDH2/UxPlay) to serve a wider community of users. The previous authors of code included in UxPlay by inheritance from RPiPlay include: - **EstebanKubata**: Created a FairPlay library called [PlayFair](https://github.com/EstebanKubata/playfair). Located in the `lib/playfair` folder. License: GNU GPL - **Juho Vähä-Herttua** and contributors: Created an AirPlay audio server called [ShairPlay](https://github.com/juhovh/shairplay), including support for Fairplay based on PlayFair. Most of the code in `lib/` originally stems from this project. License: GNU LGPLv2.1+ - **dsafa22**: Created an AirPlay 2 mirroring server [AirplayServer](https://github.com/dsafa22/AirplayServer) (seems gone now), for Android based on ShairPlay. Code is preserved [here](https://github.com/jiangban/AirplayServer), and [see here](https://github.com/FDH2/UxPlay/wiki/AirPlay2) for the description of the analysis of the AirPlay 2 mirror protocol that made RPiPlay possible, by the AirplayServer author. All code in `lib/` concerning mirroring is dsafa22's work. License: GNU LGPLv2.1+ - **Florian Draschbacher** (FD-) and contributors: adapted dsafa22's Android project for the Raspberry Pi, with extensive cleanups, debugging and improvements. The project [RPiPlay](https://github.com/FD-/RPiPlay) is basically a port of dsafa22's code to the Raspberry Pi, utilizing OpenMAX and OpenSSL for better performance on the Pi. License GPL v3. FD- has written an interesting note on the history of [Airplay protocol versions](http://github.com/FD-/RPiPlay#airplay-protocol-versions), available at the RPiPlay github repository. Independent of UxPlay, but used by it and bundled with it: - **Fedor Indutny** (of Node.js, and formerly Joyent, Inc) and contributors: Created an http parsing library called [llhttp](https://github.com/nodejs/llhttp). Located at `lib/llhttp/`. License: MIT UxPlay-1.71.1/README.txt000066400000000000000000003074471473013662600145500ustar00rootroot00000000000000# UxPlay 1.71: AirPlay-Mirror and AirPlay-Audio server for Linux, macOS, and Unix (now also runs on Windows). ### **Now developed at the GitHub site (where ALL user issues should be posted, and latest versions can be found).** - ***NEW in v1.71**: Support for (YouTube) HLS (HTTP Live Streaming) video with the new "-hls" option.* Click on the airplay icon in the YouTube app to stream video. (You may need to wait until advertisements have finished or been skipped before clicking the YouTube airplay icon.) **Please report any issues with this new feature of UxPlay**. ## Highlights: - GPLv3, open source. - Originally supported only AirPlay Mirror protocol, now has added support for AirPlay Audio-only (Apple Lossless ALAC) streaming from current iOS/iPadOS clients. **Now with support for Airplay HLS video-streaming (currently only YouTube video).** - macOS computers (2011 or later, both Intel and "Apple Silicon" M1/M2 systems) can act either as AirPlay clients, or as the server running UxPlay. Using AirPlay, UxPlay can emulate a second display for macOS clients. - Support for older iOS clients (such as 32-bit iPad 2nd gen., iPod Touch 5th gen. and iPhone 4S, when upgraded to iOS 9.3.5, or later 64-bit devices), plus a Windows AirPlay-client emulator, AirMyPC. - Uses GStreamer plugins for audio and video rendering (with options to select different hardware-appropriate output "videosinks" and "audiosinks", and a fully-user-configurable video streaming pipeline). - Support for server behind a firewall. - Raspberry Pi support **both with and without hardware video decoding** by the Broadcom GPU. *Tested on Raspberry Pi Zero 2 W, 3 Model B+, 4 Model B, and 5.* - Support for running on Microsoft Windows (builds with the MinGW-64 compiler in the unix-like MSYS2 environment). Note: AirPlay2 multi-room audio streaming is not supported: use [shairport-sync](https://github.com/mikebrady/shairport-sync) for that. ## Packaging status (Linux and \*BSD distributions) [![Current Packaging status](https://repology.org/badge/vertical-allrepos/uxplay.svg)](https://repology.org/project/uxplay/versions). - Install uxplay on Debian-based Linux systems with "`sudo apt install uxplay`"; on FreeBSD with "`sudo pkg install uxplay`". Also available on Arch-based systems through AUR. Since v. 1.66, uxplay is now also packaged in RPM format by Fedora 38 ("`sudo dnf install uxplay`"). - For other RPM-based distributions which have not yet packaged UxPlay, a RPM "specfile" **uxplay.spec** is now provided with recent [releases](https://github.com/FDH2/UxPlay/releases) (see their "Assets"), and can also be found in the UxPlay source top directory. See the section on using this specfile for [building an installable RPM package](#building-an-installable-rpm-package). After installation: - (On Linux and \*BSD): if a firewall is active on the server hosting UxPlay, make sure the default network port (UDP 5353) for mDNS/DNS-SD queries is open (see [Troubleshooting](#troubleshooting) below for more details); also open three UDP and three TCP ports for Uxplay, and use the "uxplay -p ``{=html}" option (see "`man uxplay`" or "`uxplay -h`"). - Even if you install your distribution's pre-compiled uxplay binary package, you may need to read the instructions below for [running UxPlay](#running-uxplay) to see which of your distribution's **GStreamer plugin packages** you should also install. - For Audio-only mode (Apple Music, etc.) best quality is obtained with the option "uxplay -async", but there is then a 2 second latency imposed by iOS. - Add any UxPlay options you want to use as defaults to a startup file `~/.uxplayrc` (see "`man uxplay`" or "`uxplay -h`" for format and other possible locations). In particular, if your system uses PipeWire audio or Wayland video systems, you may wish to add "as pipewiresink" or "vs waylandsink" as defaults to the file. *(Output from terminal commands "ps waux \| grep pulse" or "pactl info" will contain "pipewire" if your Linux/BSD system uses it).* - On Raspberry Pi: models using hardware h264 video decoding by the Broadcom GPU (models 4B and earlier) may require the uxplay option -bt709. If you use Ubuntu 22.10 or earlier, GStreamer must be [patched](https://github.com/FDH2/UxPlay/wiki/Gstreamer-Video4Linux2-plugin-patches) to use hardware video decoding by the Broadcom GPU (also recommended but optional for Raspberry Pi OS (Bullseye): the patched GStreamer does not need option " -bt709\`". The need for -bt709 when hardware video decoding is used seems to have reappeared starting with GStreamer-1.22. To (easily) compile the latest UxPlay from source, see the section [Getting UxPlay](#getting-uxplay). # Detailed description of UxPlay This project is a GPLv3 open source unix AirPlay2 Mirror server for Linux, macOS, and \*BSD. It was initially developed by [antimof](http://github.com/antimof/Uxplay) using code from OpenMAX-based [RPiPlay](https://github.com/FD-/RPiPlay), which in turn derives from [AirplayServer](https://github.com/KqsMea8/AirplayServer), [shairplay](https://github.com/juhovh/shairplay), and [playfair](https://github.com/EstebanKubata/playfair). (The antimof site is no longer involved in development, but periodically posts updates pulled from the new main [UxPlay site](https://github.com/FDH2/UxPlay)). UxPlay is tested on a number of systems, including (among others) Debian (10 "Buster", 11 "Bullseye", 12 "Bookworm"), Ubuntu (20.04 LTS, 22.04 LTS, 23.04 (also Ubuntu derivatives Linux Mint, Pop!\_OS), Red Hat and clones (Fedora 38, Rocky Linux 9.2), openSUSE Leap 15.5, Mageia 9, OpenMandriva "ROME", PCLinuxOS, Arch Linux, Manjaro, and should run on any Linux system. Also tested on macOS Catalina and Ventura (Intel) and Sonoma (M2), FreeBSD 14.0, Windows 10 and 11 (64 bit). On Raspberry Pi 4 model B, it is tested on Raspberry Pi OS (Bullseye and Bookworm) (32- and 64-bit), Ubuntu 22.04 LTS and 23.04, Manjaro RPi4 23.02, and (without hardware video decoding) on openSUSE 15.5. Also tested on Raspberry Pi Zero 2 W, 3 model B+, and now 5. Its main use is to act like an AppleTV for screen-mirroring (with audio) of iOS/iPadOS/macOS clients (iPhone, iPod Touch, iPad, Mac computers) on the server display of a host running Linux, macOS, or other unix (and now also Microsoft Windows). UxPlay supports Apple's AirPlay2 protocol using "Legacy Protocol", but some features are missing. (Details of what is publicly known about Apple's AirPlay 2 protocol can be found [here](https://openairplay.github.io/airplay-spec/), [here](https://github.com/SteeBono/airplayreceiver/wiki/AirPlay2-Protocol) and [here](https://emanuelecozzi.net/docs/airplay2); see also [pyatv](https://pyatv.dev/documentation/protocols) which could be a resource for adding modern protocols.) While there is no guarantee that future iOS releases will keep supporting "Legacy Protocol", iOS 17 continues support. The UxPlay server and its client must be on the same local area network, on which a **Bonjour/Zeroconf mDNS/DNS-SD server** is also running (only DNS-SD "Service Discovery" service is strictly necessary, it is not necessary that the local network also be of the ".local" mDNS-based type). On Linux and BSD Unix servers, this is usually provided by [Avahi](https://www.avahi.org), through the avahi-daemon service, and is included in most Linux distributions (this service can also be provided by macOS, iOS or Windows servers). Connections to the UxPlay server by iOS/MacOS clients can be initiated both in **AirPlay Mirror** mode (which streams lossily-compressed AAC audio while mirroring the client screen, or in the alternative **AirPlay Audio** mode which streams Apple Lossless (ALAC) audio without screen mirroring. In **Audio** mode, metadata is displayed in the uxplay terminal; if UxPlay option `-ca ` is used, the accompanying cover art is also output to a periodically-updated file ``, and can be viewed with a (reloading) graphics viewer of your choice. *Switching between* **Mirror** *and* **Audio** *modes during an active connection is possible: in* **Mirror** *mode, stop mirroring (or close the mirror window) and start an* **Audio** *mode connection, switch back by initiating a* **Mirror** *mode connection; cover-art display stops/restarts as you leave/re-enter* **Audio** *mode.* - **Note that Apple video-DRM (as found in "Apple TV app" content on the client) cannot be decrypted by UxPlay, and the Apple TV app cannot be watched using UxPlay's AirPlay Mirror mode (only the unprotected audio will be streamed, in AAC format).** - **With the new "-hls" option, UxPlay now also supports non-Mirror AirPlay video streaming (where the client controls a web server on the AirPlay server that directly receives HLS content to avoid it being decoded and re-encoded by the client). This currently only supports streaming of YouTube videos. Without the -hls option, using the icon for AirPlay video in apps such as the YouTube app will only send audio (in lossless ALAC format) without the accompanying video.** ### Possibility for using hardware-accelerated h264/h265 video-decoding, if available. UxPlay uses [GStreamer](https://gstreamer.freedesktop.org) "plugins" for rendering audio and video. This means that video and audio are supported "out of the box", using a choice of plugins. AirPlay streams video in h264 format: gstreamer decoding is plugin agnostic, and uses accelerated GPU hardware h264 decoders if available; if not, software decoding is used. - **VAAPI for Intel and AMD integrated graphics, NVIDIA with "Nouveau" open-source driver** With an Intel or AMD GPU, hardware decoding with the open-source VAAPI gstreamer plugin is preferable. The open-source "Nouveau" drivers for NVIDIA graphics are also in principle supported: see [here](https://nouveau.freedesktop.org/VideoAcceleration.html), but this requires VAAPI to be supplemented with firmware extracted from the proprietary NVIDIA drivers. - **NVIDIA with proprietary drivers** The `nvh264dec` plugin (included in gstreamer1.0-plugins-bad since GStreamer-1.18.0) can be used for accelerated video decoding on the NVIDIA GPU after NVIDIA's CUDA driver `libcuda.so` is installed. For GStreamer-1.16.3 or earlier, the plugin is called `nvdec`, and must be [built by the user](https://github.com/FDH2/UxPlay/wiki/NVIDIA-nvdec-and-nvenc-plugins). - **Video4Linux2 support for h264 hardware decoding on Raspberry Pi (Pi 4B and older)** Raspberry Pi (RPi) computers (tested on Pi 4 Model B) can now run UxPlay using software video decoding, but hardware-accelerated h264/h265 decoding by firmware in the Pi's Broadcom 2835 GPU is prefered. UxPlay accesses this using the GStreamer-1.22 Video4Linux2 (v4l2) plugin; Uses the out-of-mainline Linux kernel module bcm2835-codec maintained by Raspberry Pi, so far only included in Raspberry Pi OS, and two other distributions (Ubuntu, Manjaro) available with Raspberry Pi Imager. *(For GStreamer \< 1.22, see the [UxPlay Wiki](https://github.com/FDH2/UxPlay/wiki/Gstreamer-Video4Linux2-plugin-patches))*. Pi model 5 has no support for hardware H264 decoding, as its CPU is powerful enough for satisfactory software H264 decoding - **Support for h265 (HEVC) hardware decoding on Raspberry Pi (Pi 4 model B and Pi 5)** These Raspberry Pi models have a dedicated HEVC decoding block (not the GPU), with a driver "rpivid" which is not yet in the mainline Linux kernel (but is planned to be there in future). Unfortunately it produces decoded video in a non-standard pixel format (NC30 or "SAND") which will not be supported by GStreamer until the driver is in the mainline kernel; without this support, UxPlay support for HEVC hardware decoding on Raspberry Pi will not work. ### Note to packagers: UxPlay's GPLv3 license does not have an added "GPL exception" explicitly allowing it to be distributed in compiled form when linked to OpenSSL versions **prior to v. 3.0.0** (older versions of OpenSSL have a license clause incompatible with the GPL unless OpenSSL can be regarded as a "System Library", which it is in \*BSD). Many Linux distributions treat OpenSSL as a "System Library", but some (e.g. Debian) do not: in this case, the issue is solved by linking with OpenSSL-3.0.0 or later. # Getting UxPlay Either download and unzip [UxPlay-master.zip](https://github.com/FDH2/UxPlay/archive/refs/heads/master.zip), or (if git is installed): "git clone https://github.com/FDH2/UxPlay". You can also download a recent or earlier version listed in [Releases](https://github.com/FDH2/UxPlay/releases). - A recent UxPlay can also be found on the original [antimof site](https://github.com/antimof/UxPlay); that original project is inactive, but is usually kept current or almost-current with the [active UxPlay github site](https://github.com/FDH2/UxPlay) (thank you antimof!). ## Building UxPlay on Linux (or \*BSD): ### Debian-based systems: (Adapt these instructions for non-Debian-based Linuxes or \*BSD; for macOS, see specific instruction below). See [Troubleshooting](#troubleshooting) below for help with any difficulties. You need a C/C++ compiler (e.g. g++) with the standard development libraries installed. Debian-based systems provide a package "build-essential" for use in compiling software. You also need pkg-config: if it is not found by "`which pkg-config`", install pkg-config or its work-alike replacement pkgconf. Also make sure that cmake\>=3.10 is installed: "`sudo apt install cmake`" (add `build-essential` and `pkg-config` (or `pkgconf`) to this if needed). Make sure that your distribution provides OpenSSL 1.1.1 or later, and libplist 2.0 or later. (This means Debian 10 "Buster" based systems (e.g, Ubuntu 18.04) or newer; on Debian 10 systems "libplist" is an older version, you need "libplist3".) If it does not, you may need to build and install these from source (see instructions at the end of this README). If you have a non-standard OpenSSL installation, you may need to set the environment variable OPENSSL_ROOT_DIR (*e.g.* , "`export OPENSSL_ROOT_DIR=/usr/local/lib64`" if that is where it is installed). Similarly, for non-standard (or multiple) GStreamer installations, set the environment variable GSTREAMER_ROOT_DIR to the directory that contains the ".../gstreamer-1.0/" directory of the gstreamer installation that UxPlay should use (if this is *e.g.* "\~/my_gstreamer/lib/gstreamer-1.0/", set this location with "`export GSTREAMER_ROOT_DIR=$HOME/my_gstreamer/lib`"). - Most users will use the GStreamer supplied by their distribution, but a few (in particular users of Raspberry Pi OS Lite Legacy (Buster) on a Raspberry Pi model 4B who wish to stay on that unsupported Legacy OS for compatibility with other apps) should instead build a newer Gstreamer from source following [these instructions](https://github.com/FDH2/UxPlay/wiki/Building-latest-GStreamer-from-source-on-distributions-with-older-GStreamer-(e.g.-Raspberry-Pi-OS-).) . **Do this *before* building UxPlay**. In a terminal window, change directories to the source directory of the downloaded source code ("UxPlay-\*", "\*" = "master" or the release tag for zipfile downloads, "UxPlay" for "git clone" downloads), then follow the instructions below: **Note:** By default UxPlay will be built with optimization for the computer it is built on; when this is not the case, as when you are packaging for a distribution, use the cmake option `-DNO_MARCH_NATIVE=ON`. If you use X11 Windows on Linux or \*BSD, and wish to toggle in/out of fullscreen mode with a keypress (F11 or Alt_L+Enter) UxPlay needs to be built with a dependence on X11. Starting with UxPlay-1.59, this will be done by default **IF** the X11 development libraries are installed and detected. Install these with "`sudo apt install libx11-dev`". If GStreamer \< 1.20 is detected, a fix needed by screen-sharing apps (*e.g.*, Zoom) will also be made. - If X11 development libraries are present, but you wish to build UxPlay *without* any X11 dependence, use the cmake option `-DNO_X11_DEPS=ON`. 1. `sudo apt install libssl-dev libplist-dev`". (*unless you need to build OpenSSL and libplist from source*). 2. `sudo apt install libavahi-compat-libdnssd-dev` 3. `sudo apt install libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev`. (\**Skip if you built Gstreamer from source*) 4. `cmake .` (*For a cleaner build, which is useful if you modify the source, replace this by* "`mkdir build; cd build; cmake ..`": *you can then delete the contents of the `build` directory if needed, without affecting the source.*) Also add any cmake "`-D`" options here as needed (e.g, `-DNO_X11_DEPS=ON` or `-DNO_MARCH_NATIVE=ON`). 5. `make` 6. `sudo make install` (you can afterwards uninstall with `sudo make uninstall` in the same directory in which this was run). This installs the executable file "`uxplay`" to `/usr/local/bin`, (and installs a manpage to somewhere standard like `/usr/local/share/man/man1` and README files to somewhere like `/usr/local/share/doc/uxplay`). (If "man uxplay" fails, check if \$MANPATH is set: if so, the path to the manpage (usually /usr/local/share/man/) needs to be added to \$MANPATH .) The uxplay executable can also be found in the build directory after the build process, if you wish to test before installing (in which case the GStreamer plugins must first be installed). ### Building on non-Debian Linux and \*BSD \*\*For those with RPM-based distributions, a RPM spec file uxplay.spec is also available: see [Building an installable rpm package](#building-an-installable-rpm-package). - **Red Hat, or clones like CentOS (now continued as Rocky Linux or Alma Linux):** (sudo dnf install, or sudo yum install) openssl-devel libplist-devel avahi-compat-libdns_sd-devel gstreamer1-devel gstreamer1-plugins-base-devel (+libX11-devel for fullscreen X11) *(some of these may be in the "CodeReady" add-on repository, called "PowerTools" by clones)* - **Mageia, PCLinuxOS, OpenMandriva:** Same as Red Hat, except for name changes: (Mageia) "gstreamer1.0-devel", "gstreamer-plugins-base1.0-devel"; (OpenMandriva) "libopenssl-devel", "gstreamer-devel", "libgst-plugins-base1.0-devel". PCLinuxOS: same as Mageia, but uses synaptic (or apt) as its package manager. - **openSUSE:** (sudo zypper install) libopenssl-3-devel (formerly libopenssl-devel) libplist-2_0-devel (formerly libplist-devel) avahi-compat-mDNSResponder-devel gstreamer-devel gstreamer-plugins-base-devel (+ libX11-devel for fullscreen X11). - **Arch Linux** (*Also available as a package in AUR*): (sudo pacman -Syu) openssl libplist avahi gst-plugins-base. - **FreeBSD:** (sudo pkg install) libplist gstreamer1. Either avahi-libdns or mDNSResponder must also be installed to provide the dns_sd library. OpenSSL is already installed as a System Library. #### Building an installable RPM package First-time RPM builders should first install the rpm-build and rpmdevtools packages, then create the rpmbuild tree with "`rpmdev-setuptree`". Then download and copy uxplay.spec into `~/rpmbuild/SPECS`. In that directory, run "`rpmdev-spectool -g -R uxplay.spec`" to download the corresponding source file `uxplay-*.tar.gz` into `~/rpmbuild/SOURCES` ("rpmdev-spectool" may also be just called "spectool"); then run "`rpmbuild -ba uxplay.spec`" (you will need to install any required dependencies this reports). This should create the uxplay RPM package in a subdirectory of `~/rpmbuild/RPMS`. (**uxplay.spec** is tested on Fedora 38, Rocky Linux 9.2, openSUSE Leap 15.5, Mageia 9, OpenMandriva, PCLinuxOS; it can be easily modified to include dependency lists for other RPM-based distributions.) ## Running UxPlay ### Installing plugins (Debian-based Linux distributions, including Ubuntu and Raspberry Pi OS) (*skip if you built a complete GStreamer from source*) Next install the GStreamer plugins that are needed with `sudo apt install gstreamer1.0-`. Values of `` required are: 1. "**plugins-base**" 2. "**libav**" (for sound), 3. "**plugins-good**" (for v4l2 hardware h264 decoding) 4. "**plugins-bad**" (for h264 decoding). **Debian-based distributions split some of the plugin packages into smaller pieces:** some that may also be needed include "**gl**" for OpenGL support (this provides the "-vs glimagesink" videosink, which can be very useful in many systems (including Raspberry Pi), and should always be used when using h264/h265 decoding by a NVIDIA GPU), "**gtk3**" (which provides the "-vs gtksink" videosink), and "**x**" for X11 support, although these may already be installed; "**vaapi**" is needed for hardware-accelerated h264 video decoding by Intel or AMD graphics (but not for use with NVIDIA using proprietary drivers). If sound is not working, "**alsa**"","**pulseaudio**", or "**pipewire**" plugins may need to be installed, depending on how your audio is set up. - Also install "**gstreamer1.0-tools**" to get the utility gst-inspect-1.0 for examining the GStreamer installation. ### Installing plugins (Non-Debian-based Linux or \*BSD) (*skip if you built a complete GStreamer from source*) In some cases, because of patent issues, the libav plugin feature **avdec_aac** needed for decoding AAC audio in mirror mode is not provided in the official distribution: get it from community repositories for those distributions. - **Red Hat, or clones like CentOS (now continued as Rocky Linux or Alma Linux):** Install gstreamer1-libav gstreamer1-plugins-bad-free (+ gstreamer1-vaapi for Intel/AMD graphics). In recent Fedora, gstreamer1-libav is renamed gstreamer1-plugin-libav. **To get avdec_aac, install packages from [rpmfusion.org](https://rpmfusion.org)**: (get ffmpeg-libs from rpmfusion; on RHEL or clones, but not recent Fedora, also get gstreamer1-libav from there). - **Mageia, PCLinuxOS, OpenMandriva:** Install gstreamer1.0-libav gstreamer1.0-plugins-bad (+ gstreamer1.0-vaapi for Intel/AMD graphics). **On Mageia, to get avdec_aac, install ffmpeg from the "tainted" repository**, (which also provides a more complete gstreamer1.0-plugins-bad). - **openSUSE:** Install gstreamer-plugins-libav gstreamer-plugins-bad (+ gstreamer-plugins-vaapi for Intel/AMD graphics). **To get avdec_aac, install libav\* packages for openSUSE from [Packman](https://ftp.gwdg.de/pub/linux/misc/packman/suse/) "Essentials"**; recommendation: after adding the Packman repository, use the option in YaST Software management to switch all system packages for multimedia to Packman). - **Arch Linux** Install gst-plugins-good gst-plugins-bad gst-libav (+ gstreamer-vaapi for Intel/AMD graphics). - **FreeBSD:** Install gstreamer1-libav, gstreamer1-plugins, gstreamer1-plugins-\* (\* = core, good, bad, x, gtk, gl, vulkan, pulse, v4l2, ...), (+ gstreamer1-vaapi for Intel/AMD graphics). ### Starting and running UxPlay Since UxPlay-1.64, UxPlay can be started with options read from a configuration file, which will be the first found of (1) a file with a path given by environment variable `$UXPLAYRC`, (2) `~/.uxplayrc` in the user's home directory ("\~"), (3) `~/.config/uxplayrc`. The format is one option per line, omitting the initial `"-"` of the command-line option. Lines in the configuration file beginning with `"#"` are treated as comments and ignored. **Run uxplay in a terminal window**. On some systems, you can specify fullscreen mode with the `-fs` option, or toggle into and out of fullscreen mode with F11 or (held-down left Alt)+Enter keys. Use Ctrl-C (or close the window) to terminate it when done. If the UxPlay server is not seen by the iOS client's drop-down "Screen Mirroring" panel, check that your DNS-SD server (usually avahi-daemon) is running: do this in a terminal window with `systemctl status avahi-daemon`. If this shows the avahi-daemon is not running, control it with `sudo systemctl [start,stop,enable,disable] avahi-daemon` (on non-systemd systems, such as \*BSD, use `sudo service avahi-daemon [status, start, stop, restart, ...]`). If UxPlay is seen, but the client fails to connect when it is selected, there may be a firewall on the server that prevents UxPlay from receiving client connection requests unless some network ports are opened: **if a firewall is active, also open UDP port 5353 (for mDNS queries) needed by Avahi**. See [Troubleshooting](#troubleshooting) below for help with this or other problems. - Unlike an Apple TV, the UxPlay server does not by default require clients to initially "pair" with it using a pin code displayed by the server (after which the client "trusts" the server, and does not need to repeat this). Since v1.67, Uxplay offers such "pin-authentication" as an option: see "`-pin`" and "`-reg`" in [Usage](#usage) for details, if you wish to use it. *Some clients with MDM (Mobile Device Management, often present on employer-owned devices) are required to use pin-authentication: UxPlay will provide this even when running without the pin option.* - By default, UxPlay is locked to its current client until that client drops the connection; since UxPlay-1.58, the option `-nohold` modifies this behavior so that when a new client requests a connection, it removes the current client and takes over. UxPlay 1.66 introduces a mechanism ( `-restrict`, `-allow `, `-block `) to control which clients are allowed to connect, using their "deviceID" (which in Apple devices appears to be immutable). - In Mirror mode, GStreamer has a choice of **two** methods to play video with its accompanying audio: prior to UxPlay-1.64, the video and audio streams were both played as soon as possible after they arrived (the GStreamer "*sync=false*" method), with a GStreamer internal clock used to try to keep them synchronized. **Starting with UxPlay-1.64, the other method (GStreamer's "*sync=true*" mode), which uses timestamps in the audio and video streams sent by the client, is the new default**. On low-decoding-power UxPlay hosts (such as Raspberry Pi Zero W or 3 B+ models) this will drop video frames that cannot be decoded in time to play with the audio, making the video jerky, but still synchronized. The older method which does not drop late video frames worked well on more powerful systems, and is still available with the UxPlay option "`-vsync no`"; this method is adapted to "live streaming", and may be better when using UxPlay as a second monitor for a Mac computer, for example, while the new default timestamp-based method is best for watching a video, to keep lip movements and voices synchronized. (Without use of timestamps, video will eventually lag behind audio if it cannot be decoded fast enough: hardware-accelerated video-decoding helped to prevent this previously when timestamps were not being used.) - In Audio-only mode the GStreamer "sync=false" mode (not using timestamps) is still the default, but if you want to keep the audio playing on the server synchronized with the video showing on the client, use the `-async` timestamp-based option. (An example might be if you want to follow the Apple Music lyrics on the client while listening to superior sound on the UxPlay server). This delays the video on the client to match audio on the server, so leads to a slight delay before a pause or track-change initiated on the client takes effect on the audio played by the server. AirPlay volume-control attenuates volume (gain) by up to -30dB: the decibel range -30:0 can be rescaled from *Low*:0, or *Low*:*High*, using the option `-db` ("-db *Low*" or "-db *Low*:*High*"), *Low* must be negative. Rescaling is linear in decibels. Note that GStreamer's audio format will "clip" any audio gain above +20db, so keep *High* below that level. The option `-taper` provides a "tapered" AirPlay volume-control profile some users may prefer. The -vsync and -async options also allow an optional positive (or negative) audio-delay adjustment in *milliseconds* for fine-tuning : `-vsync 20.5` delays audio relative to video by 0.0205 secs; a negative value advances it.) - you may find video is improved by the setting -fps 60 that allows some video to be played at 60 frames per second. (You can see what framerate is actually streaming by using -vs fpsdisplaysink, and/or -FPSdata.) When using this, you should use the default timestamp-based synchronization option `-vsync`. - Since UxPlay-1.54, you can display the accompanying "Cover Art" from sources like Apple Music in Audio-Only (ALAC) mode: run "`uxplay -ca &`" in the background, then run a image viewer with an autoreload feature: an example is "feh": run "`feh -R 1 `" in the foreground; terminate feh and then Uxplay with "`ctrl-C fg ctrl-C`". By default, GStreamer uses an algorithm to search for the best "videosink" (GStreamer's term for a graphics driver to display images) to use. You can overide this with the uxplay option `-vs `. Which videosinks are available depends on your operating system and graphics hardware: use "`gst-inspect-1.0 | grep sink | grep -e video -e Video -e image`" to see what is available. Some possibilites on Linux/\*BSD are: - **glimagesink** (OpenGL), **waylandsink** - **xvimagesink**, **ximagesink** (X11) - **kmssink**, **fbdevsink** (console graphics without X11) - **vaapisink** (for Intel/AMD hardware-accelerated graphics); for NVIDIA hardware graphics (with CUDA) use **glimagesink** combined with "`-vd nvh264dec`" (or "nvh264sldec", a new variant which will become "nvh264dec" in GStreamer-1.24). - If the server is "headless" (no attached monitor, renders audio only) use `-vs 0`. Note that videosink options can set using quoted arguments to -vs: *e.g.*, `-vs "xvimagesink display=:0"`: ximagesink and xvimagesink allow an X11 display name to be specified, and waylandsink has a similar option. Videosink options ("properties") can be found in their GStreamer description pages,such as https://gstreamer.freedesktop.org/documentation/xvimagesink . GStreamer also searches for the best "audiosink"; override its choice with `-as `. Choices on Linux include pulsesink, alsasink, pipewiresink, oss4sink; see what is available with `gst-inspect-1.0 | grep sink | grep -e audio -e Audio`. **One common problem involves GStreamer attempting to use incorrectly-configured or absent accelerated hardware h264 video decoding (e.g., VAAPI). Try "`uxplay -avdec`" to force software video decoding; if this works you can then try to fix accelerated hardware video decoding if you need it, or just uninstall the GStreamer vaapi plugin.** See [Usage](#usage) for more run-time options. ### **Special instructions for Raspberry Pi (tested on Raspberry Pi Zero 2 W, 3 Model B+, 4 Model B, and 5 only)**: - For Framebuffer video (for Raspberry Pi OS "Lite" and other non-X11 distributions) use the KMS videosink "-vs kmssink" (the DirectFB framebuffer videosink "dfbvideosink" is broken on the Pi, and segfaults). *In this case you should explicitly use the "-vs kmssink" option, as without it, autovideosink does not find the correct videosink.* - Raspberry Pi 5 does not provide hardware H264 decoding (and does not need it). - Pi Zero 2 W, 3 Model B+ and 4 Model B should use hardware H264 decoding by the Broadcom GPU, but it requires an out-of-mainstream kernel module bcm2835_codec maintained in the [Raspberry Pi kernel tree](https://github.com/raspberrypi/linux); distributions that are known to supply it include Raspberry Pi OS, Ubuntu, and Manjaro-RPi4. Use software decoding (option -avdec) if this module is not available. - Uxplay uses the Video4Linux2 (v4l2) plugin from GStreamer-1.22 and later to access the GPU, if hardware H264 decoding is used. This should happen automatically. The option -v4l2 can be used, but it is usually best to just let GStreamer find the best video pipeline by itself. - On older distributions (GStreamer \< 1.22), the v4l2 plugin needs a patch: see the [UxPlay Wiki](https://github.com/FDH2/UxPlay/wiki/Gstreamer-Video4Linux2-plugin-patches). Legacy Raspberry Pi OS (Bullseye) has a partially-patched GStreamer-1.18.4 which needs the uxplay option -bt709 (and don't use -v4l2); it is still better to apply the full patch from the UxPlay Wiki in this case. - **It appears that when hardware h264 video decoding is used, the option -bt709 became needed again in GStreamer-1.22 and later.** - For "double-legacy" Raspberry Pi OS (Buster), there is no patch for GStreamer-1.14. Instead, first build a complete newer GStreamer-1.18.6 from source using [these instructions](https://github.com/FDH2/UxPlay/wiki/Building-latest-GStreamer-from-source-on-distributions-with-older-GStreamer-(e.g.-Raspberry-Pi-OS-).) before building UxPlay. - Raspberry Pi 3 Model B+ running a 32 bit OS can also access the GPU with the GStreamer OMX plugin (use option "`-vd omxh264dec`"), but this is broken by Pi 4 Model B firmware. OMX support was removed from Raspberry Pi OS (Bullseye), but is present in Buster. - **H265 (4K)** video is potentially supported by hardware decoding on Raspberry Pi 5 models, as well as on Raspberry Pi 4 model B, using a dedicated HEVC decoding block, but the "rpivid" kernel driver for this is not yet supported by GStreamer (this driver decodes video into a non-standard format that cannot be supported by GStreamer until the driver is in the mainline Linux kernel). Raspberry Pi provides a version of ffmpeg that can use that format, but at present UxPlay cannot use this. The best solution would be for the driver to be "upstreamed" to the kernel, allowing GStreamer support. (Software HEVC decoding works, but does not seem to give satisfactory results on the Pi). Even with GPU video decoding, some frames may be dropped by the lower-power models to keep audio and video synchronized using timestamps. In Legacy Raspberry Pi OS (Bullseye), raspi-config "Performance Options" allows specifying how much memory to allocate to the GPU, but this setting appears to be absent in Bookworm (but it can still be set to e.g. 128MB by adding a line "gpu_mem=128" in /boot/config.txt). A Pi Zero 2 W (which has 512MB memory) worked well when tested in 32 bit Bullseye or Bookworm Lite with 128MB allocated to the GPU (default seems to be 64MB). The basic uxplay options for R Pi are `uxplay [-vs ]`. The choice `` = `glimagesink` is sometimes useful. With the Wayland video compositor, use `` = `waylandsink`. With framebuffer video, use `` = `kmssink`. - Tip: to start UxPlay on a remote host (such as a Raspberry Pi) using ssh: ```{=html} ``` ssh user@remote_host export DISPLAY=:0 nohup uxplay [options] > FILE & Sound and video will play on the remote host; "nohup" will keep uxplay running if the ssh session is closed. Terminal output is saved to FILE (which can be /dev/null to discard it) ## Building UxPlay on macOS: **(Intel X86_64 and "Apple Silicon" M1/M2 Macs)** *Note: A native AirPlay Server feature is included in macOS 12 Monterey, but is restricted to recent hardware. UxPlay can run on older macOS systems that will not be able to run Monterey, or can run Monterey but not AirPlay.* These instructions for macOS assume that the Xcode command-line developer tools are installed (if Xcode is installed, open the Terminal, type "sudo xcode-select --install" and accept the conditions). It is also assumed that CMake \>= 3.13 is installed: this can be done with package managers [MacPorts](http://www.macports.org) (`sudo port install cmake`), [Homebrew](http://brew.sh) (`brew install cmake`), or by a download from . Also install `git` if you will use it to fetch UxPlay. Next install libplist and openssl-3.x. Note that static versions of these libraries will be used in the macOS builds, so they can be uninstalled after building uxplay, if you wish. - If you use Homebrew: `brew install libplist openssl@3` - if you use MacPorts: `sudo port install libplist-devel openssl3` Otherwise, build libplist and openssl from source: see instructions near the end of this README; requires development tools (autoconf, automake, libtool, *etc.*) to be installed. Next get the latest macOS release of GStreamer-1.0. **Using "Official" GStreamer (Recommended for both MacPorts and Homebrew users)**: install the GStreamer release for macOS from . (This release contains its own pkg-config, so you don't have to install one.) Install both the gstreamer-1.0 and gstreamer-1.0-devel packages. After downloading, Shift-Click on them to install (they install to /Library/FrameWorks/GStreamer.framework). Homebrew or MacPorts users should **not** install (or should uninstall) the GStreamer supplied by their package manager, if they use the "official" release. - Since GStreamer v1.22, the "Official" (gstreamer.freedesktop.org) macOS binaries require a wrapper "gst_macos_main" around the actual main program (uxplay). This should have been applied during the UxPlay compilation process, and the initial UxPlay terminal message should confirm it is being used. (UxPlay can also be built using "Official" GStreamer v.1.20.7 binaries, which work without the wrapper.) **Using Homebrew's GStreamer**: pkg-config is needed: ("brew install pkg-config gstreamer"). This causes a large number of extra packages to be installed by Homebrew as dependencies. The [Homebrew gstreamer installation](https://formulae.brew.sh/formula/gstreamer#default) has recently been reworked into a single "formula" named `gstreamer`, which now works without needing GST_PLUGIN_PATH to be set in the enviroment. Homebrew installs gstreamer to `HOMEBREW_PREFIX/lib/gstreamer-1.0` where by default `HOMEBREW_PREFIX/*` is `/opt/homebrew/*` on Apple Silicon Macs, and `/usr/local/*` on Intel Macs; do not put any extra non-Homebrew plugins (that you build yourself) there, and instead set GST_PLUGIN_PATH to point to their location (Homebrew does not supply a complete GStreamer, but seems to have everything needed for UxPlay). **New: the UxPlay build script will now also detect Homebrew installations in non-standard locations indicated by the environment variable `$HOMEBREW_PREFIX`.** **Using GStreamer installed from MacPorts**: this is **not** recommended, as currently the MacPorts GStreamer is old (v1.16.2), unmaintained, and built to use X11: - Instead [build gstreamer yourself](https://github.com/FDH2/UxPlay/wiki/Building-GStreamer-from-Source-on-macOS-with-MacPorts) if you use MacPorts and do not want to use the "Official" Gstreamer binaries. *(If you really wish to use the MacPorts GStreamer-1.16.2, install pkgconf ("sudo port install pkgconf"), then "sudo port install gstreamer1-gst-plugins-base gstreamer1-gst-plugins-good gstreamer1-gst-plugins-bad gstreamer1-gst-libav". For X11 support on macOS, compile UxPlay using a special cmake option `-DUSE_X11=ON`, and run it from an XQuartz terminal with -vs ximagesink; older non-retina macs require a lower resolution when using X11: `uxplay -s 800x600`.)* After installing GStreamer, build and install uxplay: open a terminal and change into the UxPlay source directory ("UxPlay-master" for zipfile downloads, "UxPlay" for "git clone" downloads) and build/install with "cmake . ; make ; sudo make install" (same as for Linux). - Running UxPlay while checking for GStreamer warnings (do this with "export GST_DEBUG=2" before runnng UxPlay) reveals that with the default (since UxPlay 1.64) use of timestamps for video synchonization, many video frames are being dropped (only on macOS), perhaps due to another error (about videometa) that shows up in the GStreamer warnings. **Recommendation: use the new UxPlay "no timestamp" option "`-vsync no`"** (you can add a line "vsync no" in the uxplayrc configuration file). - On macOS with this installation of GStreamer, the only videosinks available seem to be glimagesink (default choice made by autovideosink) and osxvideosink. The window title does not show the Airplay server name, but the window is visible to screen-sharing apps (e.g., Zoom). The only available audiosink seems to be osxaudiosink. - The option -nc is always used, whether or not it is selected. This is a workaround for a problem with GStreamer videosinks on macOS: if the GStreamer pipeline is destroyed while the mirror window is still open, a segfault occurs. - In the case of glimagesink, the resolution settings "-s wxh" do not affect the (small) initial OpenGL mirror window size, but the window can be expanded using the mouse or trackpad. In contrast, a window created with "-vs osxvideosink" is initially big, but has the wrong aspect ratio (stretched image); in this case the aspect ratio changes when the window width is changed by dragging its side; the option `-vs "osxvideosink force-aspect-ratio=true"` can be used to make the window have the correct aspect ratio when it first opens. ## Building UxPlay on Microsoft Windows, using MSYS2 with the MinGW-64 compiler. - tested on Windows 10 and 11, 64-bit. 1. Download and install **Bonjour SDK for Windows v3.0**. You can download the SDK without any registration at [softpedia.com](https://www.softpedia.com/get/Programming/SDK-DDK/Bonjour-SDK.shtml), or get it from the official Apple site [https://developer.apple.com/download](https://developer.apple.com/download/all/?q=Bonjour%20SDK%20for%20Windows) (Apple makes you register as a developer to access it from their site). This should install the Bonjour SDK as `C:\Program Files\Bonjour SDK`. 2. (This is for 64-bit Windows; a build for 32-bit Windows should be possible, but is not tested.) The unix-like MSYS2 build environment will be used: download and install MSYS2 from the official site [https://www.msys2.org/](https://www.msys2.org). Accept the default installation location `C:\mysys64`. 3. [MSYS2 packages](https://packages.msys2.org/package/) are installed with a variant of the "pacman" package manager used by Arch Linux. Open a "MSYS2 MINGW64" terminal from the MSYS2 tab in the Windows Start menu, and update the new MSYS2 installation with "pacman -Syu". Then install the **MinGW-64** compiler and **cmake** pacman -S mingw-w64-x86_64-cmake mingw-w64-x86_64-gcc The compiler with all required dependencies will be installed in the msys64 directory, with default path `C:/msys64/mingw64`. Here we will simply build UxPlay from the command line in the MSYS2 environment (this uses "`ninja`" in place of "`make`" for the build system). 4. Download the latest UxPlay from github **(to use `git`, install it with `pacman -S git`, then "`git clone https://github.com/FDH2/UxPlay`")**, then install UxPlay dependencies (openssl is already installed with MSYS2): `pacman -S mingw-w64-x86_64-libplist mingw-w64-x86_64-gstreamer mingw-w64-x86_64-gst-plugins-base` If you are trying a different Windows build system, MSVC versions of GStreamer for Windows are available from the [official GStreamer site](https://gstreamer.freedesktop.org/download/), but only the MinGW 64-bit build on MSYS2 has been tested. 5. cd to the UxPlay source directory, then "`mkdir build`" and "`cd build`". The build process assumes that the Bonjour SDK is installed at `C:\Program Files\Bonjour SDK`. If it is somewhere else, set the enviroment variable BONJOUR_SDK_HOME to point to its location. Then build UxPlay with `cmake ..` `ninja` 6. Assuming no error in either of these, you will have built the uxplay executable **uxplay.exe** in the current ("build") directory. The "sudo make install" and "sudo make uninstall" features offered in the other builds are not available on Windows; instead, the MSYS2 environment has `/mingw64/...` available, and you can install the uxplay.exe executable in `C:/msys64/mingw64/bin` (plus manpage and documentation in `C:/msys64/mingw64/share/...`) with `cmake --install . --prefix /mingw64` To be able to view the manpage, you need to install the manpage viewer with "`pacman -S man`". To run **uxplay.exe** you need to install some gstreamer plugin packages with `pacman -S mingw-w64-x86_64-gst-`, where the required ones have `` given by 1. **libav** 2. **plugins-good** 3. **plugins-bad** Other possible MSYS2 gstreamer plugin packages you might use are listed in [MSYS2 packages](https://packages.msys2.org/package/). You also will need to grant permission to the uxplay executable uxplay.exe to access data through the Windows firewall. You may automatically be offered the choice to do this when you first run uxplay, or you may need to do it using **Windows Settings-\>Update and Security-\>Windows Security-\>Firewall & network protection -\> allow an app through firewall**. If your virus protection flags uxplay.exe as "suspicious" (but without a true malware signature) you may need to give it an exception. Now test by running "`uxplay`" (in a MSYS2 terminal window). If you need to specify the audiosink, there are two main choices on Windows: the older DirectSound plugin "`-as directsoundsink`", and the more modern Windows Audio Session API (wasapi) plugin "`-as wasapisink`", which supports [additional options](https://gstreamer.freedesktop.org/documentation/wasapi/wasapisink.html) such as uxplay -as 'wasapisink device=\"\"' where `` specifies an available audio device by its GUID, which can be found using "`gst-device-monitor-1.0 Audio`": `` has a form like `\{0.0.0.00000000\}.\{98e35b2b-8eba-412e-b840-fd2c2492cf44\}`. If "`device`" is not specified, the default audio device is used. If you wish to specify the videosink using the `-vs ` option, some choices for `` are `d3d11videosink`, `d3dvideosink`, `glimagesink`, `gtksink`. - With Direct3D 11.0 or greater, you can either always be in fullscreen mode using option `-vs "d3d11videosink fullscreen-toggle-mode=property fullscreen=true"`, or get the ability to toggle into and out of fullscreen mode using the Alt-Enter key combination with option `-vs "d3d11videosink fullscreen-toggle-mode=alt-enter"`. For convenience, these options will be added if just `-vs d3d11videosink` with or without the fullscreen option "-fs" is used. *(Windows users may wish to add "`vs d3d11videosink`" (no initial "`-`") to the UxPlay startup options file; see "man uxplay" or "uxplay -h".)* The executable uxplay.exe can also be run without the MSYS2 environment, in the Windows Terminal, with `C:\msys64\mingw64\bin\uxplay`. # Usage Options: - These can also be written (one option per line, without the initial "`-`" character) in the UxPlay startup file (either given by environment variable `$UXPLAYRC`, or `~/.uxplayrc` or `~/.config/uxplayrc`); lines begining with "`#`" are treated as comments, and ignored. Command line options supersede options in the startup file. **-n server_name** (Default: UxPlay); server_name@\_hostname\_ will be the name that appears offering AirPlay services to your iPad, iPhone etc, where *hostname* is the name of the server running uxplay. This will also now be the name shown above the mirror display (X11) window. **-nh** Do not append "@_hostname_" at the end of the AirPlay server name. **-h265** Activate "ScreenMultiCodec" support (AirPlay "Features" bit 42) for accepting h265 (4K/HEVC) video in addition to h264 video (1080p) in screen-mirror mode. When this option is used, two "video pipelines" (one for h264, one for h265) are created. If any GStreamer plugins in the pipeline are specific for h264 or h265, the correct version will be used in each pipeline. A wired Client-Server ethernet connection is preferred over Wifi for 4K video, and might be required by the client. Only recent Apple devices (M1/M2 Macs or iPads, and some iPhones) can send h265 video if a resolution "-s wxh" with h \> 1080 is requested. The "-h265" option changes the default resolution ("-s" option) from 1920x1080 to 3840x2160, and leaves default maximum framerate ("-fps" option) at 30fps. **-hls** Activate HTTP Live Streaming support. With this option YouTube videos can be streamed directly from YouTube servers to UxPlay (without passing through the client) by clicking on the AirPlay icon in the YouTube app. **-pin \[nnnn\]**: (since v1.67) use Apple-style (one-time) "pin" authentication when a new client connects for the first time: a four-digit pin code is displayed on the terminal, and the client screen shows a login prompt for this to be entered. When "-pin" is used by itself, a new random pin code is chosen for each authentication; if "-pin nnnn" (e.g., "-pin 3939") is used, this will set an unchanging fixed code. Authentication adds the server to the client's list of "trusted servers" and the client will not need to reauthenticate provided that the client and server public keys remain unchanged. (By default since v1.68, the server public key is generated from the MAC address, which can be changed with the -m option; see the -key option for an alternative method of key generation). *(Add a line "pin" in the UxPlay startup file if you wish the UxPlay server to use the pin authentication protocol).* **-reg \[*filename*\]**: (since v1.68). If "-pin" is used, this option maintains a register of pin-authenticated "trusted clients" in \$HOME/.uxplay.register (or optionally, in *filename*). Without this option, returning clients that skip pin-authentication are trusted and not checked. This option may be useful if UxPlay is used in a more public environment, to record client details; the register is text, one line per client, with client's public key (base-64 format), Device ID, and Device name; commenting out (with "\#") or deleting a line deregisters the corresponding client (see options -restrict, -block, -allow for more ways to control client access). *(Add a line "reg" in the startup file if you wish to use this feature.)* **-vsync \[x\]** (In Mirror mode:) this option (**now the default**) uses timestamps to synchronize audio with video on the server, with an optional audio delay in (decimal) milliseconds (*x* = "20.5" means 0.0205 seconds delay: positive or negative delays less than a second are allowed.) It is needed on low-power systems such as Raspberry Pi without hardware video decoding. **-vsync no** (In Mirror mode:) this switches off timestamp-based audio-video synchronization, restoring the default behavior prior to UxPlay-1.64. Standard desktop systems seem to work well without use of timestamps: this mode is appropriate for "live streaming" such as using UxPlay as a second monitor for a mac computer, or monitoring a webcam; with it, no video frames are dropped. **-async \[x\]** (In Audio-Only (ALAC) mode:) this option uses timestamps to synchronize audio on the server with video on the client, with an optional audio delay in (decimal) milliseconds (*x* = "20.5" means 0.0205 seconds delay: positive or negative delays less than a second are allowed.) Because the client adds a video delay to account for latency, the server in -async mode adds an equivalent audio delay, which means that audio changes such as a pause or a track-change will not take effect immediately. *This might in principle be mitigated by using the `-al` audio latency setting to change the latency (default 0.25 secs) that the server reports to the client, but at present changing this does not seem to have any effect*. **-async no**. This is the still the default behavior in Audio-only mode, but this option may be useful as a command-line option to switch off a `-async` option set in a "uxplayrc" configuration file. **-db *low*\[:*high*\]** Rescales the AirPlay volume-control attenuation (gain) from -30dB:0dB to *low*:0dB or *low*:*high*. The lower limit *low* must be negative (attenuation); the upper limit *high* can be either sign. (GStreamer restricts volume-augmentation by *high* so that it cannot exceed +20dB). The rescaling is "flat", so that for -db -50:10, a change in Airplay attenuation by -7dB is translated to a -7 x (60/30) = -14dB attenuation, and the maximum volume (AirPlay 0dB) is a 10dB augmentation, and Airplay -30dB would become -50dB. Note that the minimum AirPlay value (-30dB exactly) is translated to "mute". **-taper** Provides a "tapered" Airplay volume-control profile (matching the one called "dasl-tapering" in [shairport-sync](https://github.com/mikebrady/shairport-sync)): each time the length of the volume slider (or the number of steps above mute, where 16 steps = full volume) is reduced by 50%, the perceived volume is halved (a 10dB attenuation). (This is modified at low volumes, to use the "untapered" volume if it is louder.) **-s wxh** e.g. -s 1920x1080 (= "1080p"), the default width and height resolutions in pixels for h264 video. (The default becomes 3840x2160 (= "4K") when the -h265 option is used.) This is just a request made to the AirPlay client, and perhaps will not be the final resolution you get. w and h are whole numbers with four digits or less. Note that the **height** pixel size is the controlling one used by the client for determining the streaming format; the width is dynamically adjusted to the shape of the image (portrait or landscape format, depending on how an iPad is held, for example). **-s wxh@r** As above, but also informs the AirPlay client about the screen refresh rate of the display. Default is r=60 (60 Hz); r must be a whole number less than 256. **-o** turns on an "overscanned" option for the display window. This reduces the image resolution by using some of the pixels requested by option -s wxh (or their default values 1920x1080) by adding an empty boundary frame of unused pixels (which would be lost in a full-screen display that overscans, and is not displayed by gstreamer). Recommendation: **don't use this option** unless there is some special reason to use it. **-fs** uses fullscreen mode, but only works with X11, Wayland, VAAPI, and D3D11 (Windows). **-p** allows you to select the network ports used by UxPlay (these need to be opened if the server is behind a firewall). By itself, -p sets "legacy" ports TCP 7100, 7000, 7001, UDP 6000, 6001, 7011. -p n (e.g. -p 35000) sets TCP and UDP ports n, n+1, n+2. -p n1,n2,n3 (comma-separated values) sets each port separately; -p n1,n2 sets ports n1,n2,n2+1. -p tcp n or -p udp n sets just the TCP or UDP ports. Ports must be in the range \[1024-65535\]. If the -p option is not used, the ports are chosen dynamically (randomly), which will not work if a firewall is running. **-avdec** forces use of software h264 decoding using Gstreamer element avdec_h264 (libav h264 decoder). This option should prevent autovideosink choosing a hardware-accelerated videosink plugin such as vaapisink. **-vp *parser*** choses the GStreamer pipeline's h264 parser element, default is h264parse. Using quotes "..." allows options to be added. **-vd *decoder*** chooses the GStreamer pipeline's h264 decoder element, instead of the default value "decodebin" which chooses it for you. Software decoding is done by avdec_h264; various hardware decoders include: vaapih264dec, nvdec, nvh264dec, v4l2h264dec (these require that the appropriate hardware is available). Using quotes "..." allows some parameters to be included with the decoder name. **-vc *converter*** chooses the GStreamer pipeline's videoconverter element, instead of the default value "videoconvert". When using Video4Linux2 hardware-decoding by a GPU,`-vc v4l2convert` will also use the GPU for video conversion. Using quotes "..." allows some parameters to be included with the converter name. **-vs *videosink*** chooses the GStreamer videosink, instead of the default value "autovideosink" which chooses it for you. Some videosink choices are: ximagesink, xvimagesink, vaapisink (for intel graphics), gtksink, glimagesink, waylandsink, osxvideosink (for macOS), kmssink (for systems without X11, like Raspberry Pi OS lite) or fpsdisplaysink (which shows the streaming framerate in fps). Using quotes "..." allows some parameters to be included with the videosink name. For example, **fullscreen** mode is supported by the vaapisink plugin, and is obtained using `-vs "vaapisink fullscreen=true"`; this also works with `waylandsink`. The syntax of such options is specific to a given plugin (see GStreamer documentation), and some choices of videosink might not work on your system. **-vs 0** suppresses display of streamed video. In mirror mode, the client's screen is still mirrored at a reduced rate of 1 frame per second, but is not rendered or displayed. This option should always be used if the server is "headless" (with no attached screen to display video), and only used to render audio, which will be AAC lossily-compressed audio in mirror mode with unrendered video, and superior-quality ALAC Apple Lossless audio in Airplay audio-only mode. **-v4l2** Video settings for hardware h264 video decoding in the GPU by Video4Linux2. Equivalent to `-vd v4l2h264dec -vc v4l2convert`. **-bt709** A workaround for the failure of the older Video4Linux2 plugin to recognize Apple's use of an uncommon (but permitted) "full-range color" variant of the bt709 color standard for digital TV. This is no longer needed by GStreamer-1.20.4 and backports from it. **-rpi** Equivalent to "-v4l2" (Not valid for Raspberry Pi model 5, and removed in UxPlay 1.67) **-rpigl** Equivalent to "-rpi -vs glimagesink". (Removed since UxPlay 1.67) **-rpifb** Equivalent to "-rpi -vs kmssink" (Removed since UxPlay 1.67) **-rpiwl** Equivalent to "-rpi -vs waylandsink". (Removed since UxPlay 1.67) **-as *audiosink*** chooses the GStreamer audiosink, instead of letting autoaudiosink pick it for you. Some audiosink choices are: pulsesink, alsasink, pipewiresink, osssink, oss4sink, jackaudiosink, osxaudiosink (for macOS), wasapisink, directsoundsink (for Windows). Using quotes "..." might allow some optional parameters (e.g. `-as "alsasink device=..."` to specify a non-default output device). The syntax of such options is specific to a given plugin (see GStreamer documentation), and some choices of audiosink might not work on your system. **-as 0** (or just **-a**) suppresses playing of streamed audio, but displays streamed video. **-al *x*** specifies an audio latency *x* in (decimal) seconds in Audio-only (ALAC), that is reported to the client. Values in the range \[0.0, 10.0\] seconds are allowed, and will be converted to a whole number of microseconds. Default is 0.25 sec (250000 usec). *(However, the client appears to ignore this reported latency, so this option seems non-functional.)* **-ca *filename*** provides a file (where *filename* can include a full path) used for output of "cover art" (from Apple Music, *etc.*,) in audio-only ALAC mode. This file is overwritten with the latest cover art as it arrives. Cover art (jpeg format) is discarded if this option is not used. Use with a image viewer that reloads the image if it changes, or regularly (*e.g.* once per second.). To achieve this, run "`uxplay -ca [path/to/]filename &`" in the background, then run the the image viewer in the foreground. Example, using `feh` as the viewer: run "`feh -R 1 [path/to/]filename`" (in the same terminal window in which uxplay was put into the background). To quit, use `ctrl-C fg ctrl-C` to terminate the image viewer, bring `uxplay` into the foreground, and terminate it too. **-reset n** sets a limit of *n* consecutive timeout failures of the client to respond to ntp requests from the server (these are sent every 3 seconds to check if the client is still present, and synchronize with it). After *n* failures, the client will be presumed to be offline, and the connection will be reset to allow a new connection. The default value of *n* is 5; the value *n* = 0 means "no limit" on timeouts. **-nofreeze** closes the video window after a reset due to ntp timeout (default is to leave window open to allow a smoother reconection to the same client). This option may be useful in fullscreen mode. **-nc** maintains previous UxPlay \< 1.45 behavior that does **not close** the video window when the the client sends the "Stop Mirroring" signal. *This option is currently used by default in macOS, as the window created in macOS by GStreamer does not terminate correctly (it causes a segfault) if it is still open when the GStreamer pipeline is closed.* **-nohold** Drops the current connection when a new client attempts to connect. Without this option, the current client maintains exclusive ownership of UxPlay until it disconnects. **-restrict** Restrict clients allowed to connect to those specified by `-allow `. The deviceID has the form of a MAC address which is displayed by UxPlay when the client attempts to connect, and appears to be immutable. It has the format `XX:XX:XX:XX:XX:XX`, X = 0-9,A-F, and is possibly the "true" hardware MAC address of the device. Note that iOS clients generally expose different random "private Wi_Fi addresses" ("fake" MAC addresses) to different networks (for privacy reasons, to prevent tracking), which may change, and do not correpond to the deviceID. **-restrict no** Remove restrictions (default). This is useful as a command-line argument to overide restrictions set in the Startup file. **-allow *id*** Adds the deviceID = *id* to the list of allowed clients when client restrictions are being enforced. Usually this will be an entry in the uxplayrc startup file. **-block *id*** Always block clients with deviceID = *id*, even when client restrictions are not being enforced generally. Usually this will be an entry in the uxplayrc startup file. **-FPSdata** Turns on monitoring of regular reports about video streaming performance that are sent by the client. These will be displayed in the terminal window if this option is used. The data is updated by the client at 1 second intervals. **-fps n** sets a maximum frame rate (in frames per second) for the AirPlay client to stream video; n must be a whole number less than 256. (The client may choose to serve video at any frame rate lower than this; default is 30 fps.) A setting of 60 fps may give you improved video but is not recommended on Raspberry Pi. A setting below 30 fps might be useful to reduce latency if you are running more than one instance of uxplay at the same time. *This setting is only an advisory to the client device, so setting a high value will not force a high framerate.* (You can test using "-vs fpsdisplaysink" to see what framerate is being received, or use the option -FPSdata which displays video-stream performance data continuously sent by the client during video-streaming.) **-f {H\|V\|I}** implements "videoflip" image transforms: H = horizontal flip (right-left flip, or mirror image); V = vertical flip ; I = 180 degree rotation or inversion (which is the combination of H with V). **-r {R\|L}** 90 degree Right (clockwise) or Left (counter-clockwise) rotations; these image transforms are carried out after any **-f** transforms. **-m \[mac\]** changes the MAC address (Device ID) used by UxPlay (default is to use the true hardware MAC address reported by the host computer's network card). (Different server_name, MAC addresses, and network ports are needed for each running uxplay if you attempt to run more than one instance of uxplay on the same computer.) If \[mac\] (in form xx:xx:xx:xx:xx:xx, 6 hex octets) is not given, a random MAC address is generated. If UxPlay fails to find the true MAC address of a network card, (more specifically, the MAC address used by the first active network interface detected) a random MAC address will be used even if option **-m** was not specified. (Note that a random MAC address will be different each time UxPlay is started). **-key \[*filename*\]**: This (more secure) option for generating and storing a persistant public key (needed for the -pin option) has been replaced by default with a (less secure) method which generates a key from the server's "device ID" (MAC address, which can be changed with the -m option, conveniently as a startup file option). When the -key option is used, a securely generated keypair is generated and stored in `$HOME/.uxplay.pem`, if that file does not exist, or read from it, if it exists. (Optionally, the key can be stored in *filename*.) This method is more secure than the new default method, (because the Device ID is broadcast in the DNS_SD announcement) but still leaves the private key exposed to anyone who can access the pem file. This option should be set in the UxPlay startup file as a line "key" or "key *filename*" (no initial "-"), where *filename* is a full path which should be enclosed in quotes (`"...."`) if it contains any blank spaces. **Because the default method is simpler, and security of client access to uxplay is unlikely to be an important issue, the -key option is no longer recommended**. **-dacp \[*filename*\]**: Export current client DACP-ID and Active-Remote key to file: default is \$HOME/.uxplay.dacp. (optionally can be changed to *filename*). Can be used by remote control applications. File is transient: only exists while client is connected. **-vdmp** Dumps h264 video to file videodump.h264. -vdmp n dumps not more than n NAL units to videodump.x.h264; x= 1,2,... increases each time a SPS/PPS NAL unit arrives. To change the name *videodump*, use -vdmp \[n\] *filename*. **-admp** Dumps audio to file audiodump.x.aac (AAC-ELD format audio), audiodump.x.alac (ALAC format audio) or audiodump.x.aud (other-format audio), where x = 1,2,3... increases each time the audio format changes. -admp *n* restricts the number of packets dumped to a file to *n* or less. To change the name *audiodump*, use -admp \[n\] *filename*. *Note that (unlike dumped video) the dumped audio is currently only useful for debugging, as it is not containerized to make it playable with standard audio players.* **-d** Enable debug output. Note: this does not show GStreamer error or debug messages. To see GStreamer error and warning messages, set the environment variable GST_DEBUG with "export GST_DEBUG=2" before running uxplay. To see GStreamer information messages, set GST_DEBUG=4; for DEBUG messages, GST_DEBUG=5; increase this to see even more of the GStreamer inner workings. # Troubleshooting Note: `uxplay` is run from a terminal command line, and informational messages are written to the terminal. ### 0. Problems in compiling UxPlay. One user (on Ubuntu) found compilation failed with messages about linking to "usr/local/lib/libcrypto.a" and "zlib". This was because (in addition to the standard ubuntu installation of libssl-dev), the user was unaware that a second installation with libcrypto in /usr/local was present. Solution: when more than one installation of OpenSSL is present, set the environment variable OPEN_SSL_ROOT_DIR to point to the correct one; on 64-bit Ubuntu, this is done by running `export OPENSSL_ROOT_DIR=/usr/lib/X86_64-linux-gnu/` before running cmake. ### 1. **Avahi/DNS_SD Bonjour/Zeroconf issues** The DNS_SD Service-Discovery ("Bonjour" or "Zeroconf") service is required for UxPlay to work. On Linux, it will be usually provided by Avahi, and to troubleshoot this, you should use the tool `avahi-browse`. (You may need to install a separate package with a name like `avahi-utils` to get this.) On Linux, make sure Avahi is installed, and start the avahi-daemon service on the system running uxplay (your distribution will document how to do this, for example: `sudo systemctl avahi-daemon` or `sudo service avahi-daemon `, with `` one of enable, disable, start, stop, status. You might need to edit the avahi-daemon.conf file (it is typically in /etc/avahi/, find it with "`sudo find /etc -name avahi-daemon.conf`"): make sure that "disable-publishing" is **not** a selected option). Some systems may instead use the mdnsd daemon as an alternative to provide DNS-SD service. (FreeBSD offers both alternatives, but only Avahi was tested; see [here](https://gist.github.com/reidransom/6033227).) - **uxplay starts, but either stalls or stops after "Initialized server socket(s)" appears (*without the server name showing on the client*)**. If UxPlay stops with the "No DNS-SD Server found" message, this means that your network **does not have a running Bonjour/zeroconf DNS-SD server.** Before v1.60, UxPlay used to stall silently if DNS-SD service registration failed, but now stops with an error message returned by the DNSServiceRegister function: kDNSServiceErr_Unknown if no DNS-SD server was found: *(A NixOS user found that in NixOS, this error can also occur if avahi-daemon service IS running with publishing enabled, but reports "the error disappeared on NixOS by setting services.avahi.openFirewall to true".)* Other mDNS error codes are in the range FFFE FF00 (-65792) to FFFE FFFF (-65537), and are listed in the dnssd.h file. An older version of this (the one used by avahi) is found [here](https://github.com/lathiat/avahi/blob/master/avahi-compat-libdns_sd/dns_sd.h). A few additional error codes are defined in a later version from [Apple](https://opensource.apple.com/source/mDNSResponder/mDNSResponder-544/mDNSShared/dns_sd.h.auto.html). If UxPlay stalls *without an error message* and *without the server name showing on the client*, **this is a network problem** (if your UxPlay version is older than 1.60, it is also the behavior when no DNS-SD server is found.) A useful tool for examining such network problems from the client end is the (free) Discovery DNS-SD browser [available in the Apple App Store](https://apps.apple.com/us/developer/lily-ballard/id305441020) for both iOS (works on iPadOS too) and macOS. - Some users using dual-band (2.4GHz/5GHz) routers have reported that clients using the 5GHz band (sometimes) "fail to see UxPlay" (i.e., do not get a response to their mDNS queries), but the 2.4GHz band works. Other projects using Bonjour/mDNS have had similar reports; the issue seems to be router-specific, perhaps related to "auto" rather than fixed channel selection (5GHz has many more channels to switch between), or channel width selections; one speculation is that since mDNS uses UDP protocol (where "lost" messages are not resent), a mDNS query might get lost if channel switching occurs during the query. If your router has this problem, a reported "fix" is to (at least on 5GHz) use fixed channel and/or fixed (not dynamic) channel width. - **Avahi works at first, but new clients do not see UxPlay, or clients that initially saw it stop doing so after they disconnect**. This is usually because Avahi is only using the "loopback" network interface, and is not receiving mDNS queries from new clients that were not listening when UxPlay started. To check this, after starting uxplay, use the utility `avahi-browse -a -t` **in a different terminal window** on the server to verify that the UxPlay AirTunes and AirPlay services are correctly registered (only the AirTunes service is used in the "Legacy" AirPlay Mirror mode used by UxPlay, but the AirPlay service is used for the initial contact). The results returned by avahi-browse should show entries for uxplay like + eno1 IPv6 UxPlay AirPlay Remote Video local + eno1 IPv4 UxPlay AirPlay Remote Video local + lo IPv4 UxPlay AirPlay Remote Video local + eno1 IPv6 863EA27598FE@UxPlay AirTunes Remote Audio local + eno1 IPv4 863EA27598FE@UxPlay AirTunes Remote Audio local + lo IPv4 863EA27598FE@UxPlay AirTunes Remote Audio local If only the loopback ("lo") entries are shown, a firewall on the UxPlay host is probably blocking full DNS-SD service, and you need to open the default UDP port 5353 for mDNS requests, as loopback-based DNS-SD service is unreliable. If the UxPlay services are listed by avahi-browse as above, but are not seen by the client, the problem is likely to be a problem with the local network. ### 2. uxplay starts, but stalls after "Initialized server socket(s)" appears, *with the server name showing on the client* (but the client fails to connect when the UxPlay server is selected). This shows that a *DNS-SD* service is working, clients hear UxPlay is available, but the UxPlay server is not receiving the response from the client. This is usually because a firewall on the server is blocking the connection request from the client. (One user who insisted that the firewall had been turned off turned out to have had *two* active firewalls (*firewalld* and *ufw*) *both* running on the server!) If possible, either turn off the firewall to see if that is the problem, or get three consecutive network ports, starting at port n, all three in the range 1024-65535, opened for both tcp and udp, and use "uxplay -p n" (or open UDP 7011,6001,6000 TCP 7100,7000,7001 and use "uxplay -p"). If you are *really* sure there is no firewall, you may need to investigate your network transmissions with a tool like netstat, but almost always this is a firewall issue. ### 3. Problems *after* the client-server connection has been made: If you do *not* see the message `raop_rtp_mirror starting mirroring`, something went wrong before the client-server negotiations were finished. For such problems, use "uxplay -d" (debug log option) to see what is happening: it will show how far the connection process gets before the failure occurs. You can compare your debug output to that from a successful start of UxPlay in the [UxPlay Wiki](https://github.com/FDH2/UxPlay/wiki). **If UxPlay reports that mirroring started, but you get no video or audio, the problem is probably from a GStreamer plugin that doesn't work on your system** (by default, GStreamer uses the "autovideosink" and "autoaudiosink" algorithms to guess what are the "best" plugins to use on your system). A different reason for no audio occurred when a user with a firewall only opened two udp network ports: **three** are required (the third one receives the audio data). **Raspberry Pi** devices (*Pi 4B+ and earlier: this does not apply to the Pi 5, which does not provide hardware h264 decoding, and does not need it*) work best with hardware GPU h264 video decoding if the Video4Linux2 plugin in GStreamer v1.20.x or earlier has been patched (see the UxPlay [Wiki](https://github.com/FDH2/UxPlay/wiki/Gstreamer-Video4Linux2-plugin-patches) for patches). This is fixed in GStreamer-1.22, and by backport patches from this in distributions such as Raspberry Pi OS (Bullseye): **use option `-bt709` with the GStreamer-1.18.4 from Raspberry Pi OS**. This also needs the bcm2835-codec kernel module that is not in the standard Linux kernel (it is available in Raspberry Pi OS, Ubuntu and Manjaro). - **If this kernel module is not available in your Raspberry Pi operating system, or if GStreamer \< 1.22 is not patched, use option `-avdec` for software h264-decoding.** Sometimes "autovideosink" may select the OpenGL renderer "glimagesink" which may not work correctly on your system. Try the options "-vs ximagesink" or "-vs xvimagesink" to see if using one of these fixes the problem. Other reported problems are connected to the GStreamer VAAPI plugin (for hardware-accelerated Intel graphics, but not NVIDIA graphics). Use the option "-avdec" to force software h264 video decoding: this should prevent autovideosink from selecting the vaapisink videosink. Alternatively, find out if the gstreamer1.0-vaapi plugin is installed, and if so, uninstall it. (If this does not fix the problem, you can reinstall it.) There are some reports of other GStreamer problems with hardware-accelerated Intel HD graphics. One user (on Debian) solved this with "sudo apt install intel-media-va-driver-non-free". This is a driver for 8'th (or later) generation "\*-lake" Intel chips, that seems to be related to VAAPI accelerated graphics. If you *do* have Intel HD graphics, and have installed the vaapi plugin, but `-vs vaapisink` does not work, check that vaapi is not "blacklisted" in your GStreamer installation: run `gst-inspect-1.0 vaapi`, if this reports `0 features`, you need to `export GST_VAAPI_ALL_DRIVERS=1` before running uxplay, or set this in the default environment. You can try to fix audio or video problems by using the "`-as `" or "`-vs `" options to choose the GStreamer audiosink or videosink , rather than letting GStreamer choose one for you. (See above, in [Starting and running UxPlay](#starting-and-running-uxplay) for choices of `` or ``.) The "OpenGL renderer" window created on Linux by "-vs glimagesink" sometimes does not close properly when its "close" button is clicked. (this is a GStreamer issue). You may need to terminate uxplay with Ctrl-C to close a "zombie" OpenGl window. If similar problems happen when the client sends the "Stop Mirroring" signal, try the no-close option "-nc" that leaves the video window open. ### 4. GStreamer issues (missing plugins, etc.): - clearing the user's GStreamer cache with `rm -rf ~/.cache/gstreamer-1.0/*` may be the solution to problems where gst-inspect-1.0 does not show a plugin that you believe is installed. The cache will be regenerated next time GStreamer is started. **This is the solution to puzzling problems that turn out to come from corruption of the cache, and should be tried first.** If UxPlay fails to start, with a message that a required GStreamer plugin (such as "libav") was not found, first check with the GStreamer tool gst-inspect-1.0 to see what GStreamer knows is available. (You may need to install some additional GStreamer "tools" package to get gst-inspect-1.0). For, *e.g.* a libav problem, check with "`gst-inspect-1.0 libav`". If it is not shown as available to GStreamer, but your package manager shows the relevant package as installed (as one user found), try entirely removing and reinstalling the package. That user found that a solution to a "**Required gstreamer plugin 'libav' not found**" message that kept recurring was to clear the user's gstreamer cache. If it fails to start with an error like '`no element "avdec_aac"`' this is because even though gstreamer-libav is installed. it is incomplete because some plugin features are missing: "`gst-inspect-1.0 | grep avdec_aac`" will show if avdec_aac is available. Unlike other GStreamer plugins, the libav plugin is a front end to FFmpeg codecs which provide avdec\_\*. - Some distributions (RedHat, SUSE, etc) provide incomplete versions of FFmpeg because of patent issues with codecs used by certain plugins. In those cases there will be some "extra package" provider like [RPM fusion](https://rpmfusion.org) (RedHat), [packman](http://packman.links2linux.org/) (SUSE) where you can get complete packages (your distribution will usually provide instructions for this, Mageia puts them in an optional "tainted" repo). The packages needed may be "ffmpeg\*" or "libav\*" packages: the GStreamer libav plugin package does not contain any codecs itself, it just provides a way for GStreamer to use ffmpeg/libav codec libraries which must be installed separately. For similar reasons, distributions may ship incomplete packages of GStreamer "plugins-bad". Use user on Fedora thought they had installed from rpmfusion, but the system had not obeyed: *"Adding --allowerasing to the dnf command fixed it after a restart"*. - starting with release UxPlay-1.65.3, UxPlay will continue to function, but without audio in mirror mode, if avdec_aac is missing. To troubleshoot GStreamer execute "export GST_DEBUG=2" to set the GStreamer debug-level environment-variable in the terminal where you will run uxplay, so that you see warning and error messages; see [GStreamer debugging tools](https://gstreamer.freedesktop.org/documentation/tutorials/basic/debugging-tools.html) for how to see much more of what is happening inside GStreamer. Run "gst-inspect-1.0" to see which GStreamer plugins are installed on your system. Some extra GStreamer packages for special plugins may need to be installed (or reinstalled: a user using a Wayland display system as an alternative to X11 reported that after reinstalling Lubuntu 18.4, UxPlay would not work until gstreamer1.0-x was installed, presumably for Wayland's X11-compatibility mode). Different distributions may break up GStreamer 1.x into packages in different ways; the packages listed above in the build instructions should bring in other required GStreamer packages as dependencies, but will not install all possible plugins. The GStreamer video pipeline, which is shown in the initial output from `uxplay -d`, has the default form appsrc name=video_source ! queue ! h264parse ! decodebin ! videoconvert ! autovideosink name=video_sink sync=false The pipeline is fully configurable: default elements "h264parse", "decodebin", "videoconvert", and "autovideosink" can respectively be replaced by using uxplay options `-vp`, `-vd`, `-vc`, and `-vs`, if there is any need to modify it (entries can be given in quotes "..." to include options). ### 5. Mirror screen freezes (a network problem): This can happen if the TCP video stream from the client stops arriving at the server, probably because of network problems (the UDP audio stream may continue to arrive). At 3-second intervals, UxPlay checks that the client is still connected by sending it a request for a NTP time signal. If a reply is not received from the client within a 0.3 sec time-window, an "ntp timeout" is registered. If a certain number (currently 5) of consecutive ntp timeouts occur, UxPlay assumes that the client is "dead", and resets the connection, becoming available for connection to a new client, or reconnection to the previous one. Sometimes the connection may recover before the timeout limit is reached, and if the default limit is not right for your network, it can be modified using the option "-reset *n*", where *n* is the desired timeout-limit value (*n* = 0 means "no limit"). If the connection starts to recover after ntp timeouts, a corrupt video packet from before the timeout may trigger a "connection reset by peer" error, which also causes UxPlay to reset the connection. - When the connection is reset, the "frozen" mirror screen of the previous connection is left in place, but does **not** block new connections, and will be taken over by a new client connection when it is made. ### 6. Protocol issues (with decryption of the encrypted audio and video streams sent by the client). A protocol failure may trigger an unending stream of error messages, and means that the audio decryption key (also used in video decryption) was not correctly extracted from data sent by the client. The protocol was modifed in UxPlay-1.65 after it was discovered that the client-server "pairing" step could be avoided (leading to a much quicker connection setup, without a 5 second delay) by disabling "Supports Legacy Pairing" (bit 27) in the "features" code UxPlay advertises on DNS-SD Service Discovery. Most clients will then not attempt the setup of a "shared secret key" when pairing, which is used by AppleTV for simultaneous handling of multiple clients (UxPlay only supports one client at a time). **This change is now well-tested, but in case it causes any protocol failures, UxPlay can be reverted to the previous behavior by uncommenting the previous "FEATURES_1" setting (and commenting out the new one) in lib/dnssdint.h, and then rebuilding UxPlay.** ("Pairing" is re-enabled when the new Apple-style one-time "pin" authentication is activated by running UxPlay with the "-pin" option introduced in UxPlay 1.67.) Protocol failure should not happen for iOS 9.3 or later clients. However, if a client uses the same older version of the protocol that is used by the Windows-based AirPlay client emulator *AirMyPC*, the protocol can be switched to the older version by the setting `OLD_PROTOCOL_CLIENT_USER_AGENT_LIST` in `UxPlay/lib/global.h`. UxPlay reports the client's "User Agent" string when it connects. If some other client also fails to decrypt all audio and video, try adding its "User Agent" string in place of "xxx" in the entry "AirMyPC/2.0;xxx" in global.h and rebuild uxplay. Note that for DNS-SD Service Discovery, Uxplay declares itself to be an AppleTV3,2 (a 32 bit device) with a sourceVersion 220.68; this can also be changed in global.h. UxPlay also works if it declares itself as an AppleTV6,2 with sourceVersion 380.20.1 (an AppleTV 4K 1st gen, introduced 2017, running tvOS 12.2.1), so it does not seem to matter what version UxPlay claims to be. # Changelog 1.71 2024-12-13 Add support for HTTP Live Streaming (HLS), initially only for YouTube movies. Fix issue with NTP timeout on Windows. 1.70 2024-10-04 Add support for 4K (h265) video (resolution 3840 x 2160). Fix issue with GStreamer \>= 1.24 when client sleeps, then wakes. 1.69 2024-08-09 Internal improvements (e.g. in -nohold option, identifying GStreamer videosink selected by autovideosink, finding X11 display) in anticipation of future HLS video support. New -nofreeze option to not leave frozen video in place when a network connection is reset. Fixes for GStreamer-1.24.x changes. 1.68 2023-12-31 New simpler (default) method for generating a persistent public key from the server MAC address (which can now be set with the -m option). (The previous method is still available with -key option). New option -reg to maintain a register of pin-authenticated clients. Corrected volume-control: now interprets AirPlay volume range -30dB:0dB as decibel gain attenuation, with new option -db low\[:high\] for "flat" rescaling of the dB range. Add -taper option for a "tapered" AirPlay volume-control profile. 1.67 2023-11-30 Add support for Apple-style one-time pin authentication of clients with option "-pin": (uses SRP6a authentication protocol and public key persistence). Detection with error message of (currently) unsupported H265 video when requesting high resolution over wired ethernet. Removed rpi\* options (which are not valid with new Raspberry Pi model 5, and can be replaced by combinations of other options). Added optional argument "mac" to "-m" option, to specify a replacement MAC address/Device ID. Update llhttp to v. 9.1.3. Add -dacp option for exporting current client DACP info (for remotes). 1.66 2023-09-05 Fix IPV6 support. Add option to restrict clients to those on a list of allowed deviceIDs, or to block connections from clients on a list of blocked deviceIDs. Fix for #207 from @thiccaxe (screen lag in vsync mode after client wakes from sleep). 1.65.3 2023-07-23 Add RPM spec file; add warning if required gstreamer libav feature "avdec_aac" is missing: (this occurs in RPM-based distributions that ship an incomplete FFmpeg for Patent or License reasons, and rely on users installing an externally-supplied complete FFmpeg). Mirror-mode airplay will now work without audio if avdec_aac is missing. 1.65 2023-06-03 Eliminate pair_setup part of connection protocol to allow faster connections with clients (thanks to @shuax #176 for this discovery); to revert, uncomment a line in lib/dnssdint.h. Disconnect from audio device when connection closes, to not block its use by other apps if uxplay is running but not connected. Fix for AirMyPC client (broken since 1.60), so its older non-NTP timestamp protocol works with -vsync. Corrected parsing of configuration file entries that were in quotes. 1.64 2023-04-23 Timestamp-based synchronization of audio and video is now the default in Mirror mode. (Use "-vsync no" to restore previous behavior.) A configuration file can now be used for startup options. Also some internal cleanups and a minor bugfix that fixes #192. 1.63 2023-02-12 Reworked audio-video synchronization, with new options -vsync (for Mirror mode) and -async (for Audio-Only mode, to sync with client video). Option -vsync makes software h264 decoding of streamed videos with option -avdec viable on some recent Raspberry Pi models. Internal change: all times are now processed in nanoseconds units. Removed -ao option introduced in 1.62. 1.62 2023-01-18 Added Audio-only mode time offset -ao x to allow user synchronization of ALAC audio playing on the server with video, song lyrics, etc. playing on the client. x = 5.0 appears to be optimal in many cases. Quality fixes: cleanup in volume changes, timestamps, some bugfixes. 1.61 2022-12-30 Removed -t option (workaround for an Avahi issue, correctly solved by opening network port UDP 5353 in firewall). Remove -g debug flag from CMAKE_CFLAGS. Postpend (instead of prepend) build environment CFLAGS to CMAKE_CFLAGS. Refactor parts of uxplay.cpp 1.60 2022-12-15 Added exit with error message if DNSServiceRegister fails (instead of just stalling). Test for Client's attempt to using unsupported AirPlay 2 "REMOTE CONTROL" protocol (with no timing channel), and exit if this occurs. Reworked metadata processing to correctly parse DMAP header (previous version worked with DMAP messages currently received, but was not correct). 1.59 2022-12-12 remove "ZOOMFIX" compile option and make compilation with X11-dependence the default if X11 development libraries are detected (this now also provides fullscreen mode with a F11 or Alt+Enter key toggle); ZOOMFIX is now automatically applied for GStreamer \< 1.20. New cmake option -DNO_X11_DEPS compiles uxplay without X11 dependence. Reworked internal metadata handling. Fix segfault with "-vs 0". 1.58 2022-10-29 Add option "-nohold" that will drop existing connections when a new client connects. Update llhttp to v8.1.0. 1.57 2022-10-09 Minor fixes: (fix coredump on AUR on "stop mirroring", occurs when compiled with AUR CFLAGS -DFORTIFY_SOURCE); graceful exit when required plugins are missing; improved support for builds on Windows. Include audioresample in GStreamer audio pipeline. 1.56 2022-09-01 Added support for building and running UxPlay-1.56 on Windows (no changes to Unix (Linux, \*BSD, macOS) codebase.) 1.56 2022-07-30 Remove -bt709 from -rpi, -rpiwl, -rpifb as GStreamer is now fixed. 1.55 2022-07-04 Remove the bt709 fix from -v4l2 and create a new -bt709 option (previous "-v4l2" is now "-v4l2 -bt709"). This allows the currently-required -bt709 option to be used on its own on RPi without -v4l2 (sometimes this give better results). 1.54 2022-06-25 Add support for "Cover Art" display in Audio-only (ALAC) mode. Reverted a change that caused VAAPI to crash with AMD POLARIS graphics cards. Minor internal changes to plist code and uxplay option parsing. 1.53 2022-06-13 Internal changes to audio sync code, revised documentation, Minor bugfix (fix assertion crash when resent audio packets are empty). 1.52 2022-05-05 Cleaned up initial audio sync code, and reformatted streaming debug output (readable aligned timestamps with decimal points in seconds). Eliminate memory leaks (found by valgrind). Support for display of ALAC (audio-only) metadata (soundtrack artist names, titles etc.) in the uxplay terminal. 1.51 2022-04-24 Reworked options forVideo4Linux2 support (new option -v4l2) and short options -rpi, -rpifb, -rpiwl as synonyms for -v4l2, -v4l2 -vs kmssink, and -v4l2 -vs waylandsink. Reverted a change from 1.48 that broke reconnection after "Stop Mirroring" is sent by client. 1.50 2022-04-22 Added -fs fullscreen option (for Wayland or VAAPI plugins only), Changed -rpi to be for framebuffer ("lite") RPi systems and added -rpigl (OpenGL) and -rpiwl (Wayland) options for RPi Desktop systems. Also modified timestamps from "DTS" to "PTS" for latency improvement, plus internal cleanups. 1.49 2022-03-28 Addded options for dumping video and/or audio to file, for debugging, etc. h264 PPS/SPS NALU's are shown with -d. Fixed video-not-working for M1 Mac clients. 1.48 2022-03-11 Made the GStreamer video pipeline fully configurable, for use with hardware h264 decoding. Support for Raspberry Pi. 1.47 2022-02-05 Added -FPSdata option to display (in the terminal) regular reports sent by the client about video streaming performance. Internal cleanups of processing of video packets received from the client. Added -reset n option to reset the connection after n ntp timeouts (also reset after "connection reset by peer" error in video stream). 1.46 2022-01-20 Restore pre-1.44 behavior (1.44 may have broken hardware acceleration): once again use decodebin in the video pipeline; introduce new option "-avdec" to force software h264 decoding by libav h264, if needed (to prevent selection of vaapisink by autovideosink). Update llhttp to v6.0.6. UxPlay now reports itself as AppleTV3,2. Restrict connections to one client at a time (second client must now wait for first client to disconnect). 1.45 2022-01-10 New behavior: close video window when client requests "stop mirroring". (A new "no close" option "-nc" is added for users who wish to retain previous behavior that does not close the video window). 1.44 2021-12-13 Omit hash of aeskey with ecdh_secret for an AirMyPC client; make an internal rearrangement of where this hash is done. Fully report all initial communications between client and server in -d debug mode. Replace decodebin in GStreamer video pipeline by h264-specific elements. 1.43 2021-12-07 Various internal changes, such as tests for successful decryption, uniform treatment of informational/debug messages, etc., updated README. 1.42 2021-11-20 Fix MAC detection to work with modern Linux interface naming practices, MacOS and \*BSD. 1.41 2021-11-11 Further cleanups of multiple audio format support (internal changes, separated RAOP and GStreamer audio/video startup) 1.40 2021-11-09 Cleanup segfault in ALAC support, manpage location fix, show request Plists in debug mode. 1.39 2021-11-06 Added support for Apple Lossless (ALAC) audio streams. 1.38 2021-10-8 Add -as *audiosink* option to allow user to choose the GStreamer audiosink. 1.37 2021-09-29 Append "@hostname" to AirPlay Server name, where "hostname" is the name of the server running uxplay (reworked change in 1.36). 1.36 2021-09-29 Implemented suggestion (by @mrbesen and @PetrusZ) to use hostname of machine runing uxplay as the default server name 1.35.1 2021-09-28 Added the -vs 0 option for streaming audio, but not displaying video. 1.35 2021-09-10 now uses a GLib MainLoop, and builds on macOS (tested on Intel Mac, 10.15 ). New option -t *timeout* for relaunching server if no connections were active in previous *timeout* seconds (to renew Bonjour registration). 1.341 2021-09-04 fixed: render logger was not being destroyed by stop_server() 1.34 2021-08-27 Fixed "ZOOMFIX": the X11 window name fix was only being made the first time the GStreamer window was created by uxplay, and not if the server was relaunched after the GStreamer window was closed, with uxplay still running. Corrected in v. 1.34 ### Building OpenSSL \>= 1.1.1 from source. If you need to do this, note that you may be able to use a newer version (OpenSSL-3.0.1 is known to work). You will need the standard development toolset (autoconf, automake, libtool). Download the source code from . Install the downloaded openssl by opening a terminal in your Downloads directory, and unpacking the source distribution: ("tar -xvzf openssl-3.0.1.tar.gz ; cd openssl-3.0.1"). Then build/install with "./config ; make ; sudo make install_dev". This will typically install the needed library `libcrypto.*`, either in /usr/local/lib or /usr/local/lib64. *(Ignore the following for builds on MacOS:)* On some systems like Debian or Ubuntu, you may also need to add a missing entry `/usr/local/lib64` in /etc/ld.so.conf (or place a file containing "/usr/local/lib64/libcrypto.so" in /etc/ld.so.conf.d) and then run "sudo ldconfig". ### Building libplist \>= 2.0.0 from source. *(Note: on Debian 9 "Stretch" or Ubuntu 16.04 LTS editions, you can avoid this step by installing libplist-dev and libplist3 from Debian 10 or Ubuntu 18.04.)* As well as the usual build tools (autoconf, automake, libtool), you may need to also install some libpython\*-dev package. Download the latest source with git from , or get the source from the Releases section (use the \*.tar.bz2 release, **not** the \*.zip or \*.tar.gz versions): download [libplist-2.3.0](https://github.com/libimobiledevice/libplist/releases/download/2.3.0/libplist-2.3.0.tar.bz2), then unpack it ("tar -xvjf libplist-2.3.0.tar.bz2 ; cd libplist-2.3.0"), and build/install it: ("./configure ; make ; sudo make install"). This will probably install libplist-2.0.\* in /usr/local/lib. The new libplist-2.3.0 release should be compatible with UxPlay; [libplist-2.2.0](https://github.com/libimobiledevice/libplist/releases/download/2.2.0/libplist-2.2.0.tar.bz2) is also available if there are any issues. *(Ignore the following for builds on MacOS:)* On some systems like Debian or Ubuntu, you may also need to add a missing entry `/usr/local/lib` in /etc/ld.so.conf (or place a file containing "/usr/local/lib/libplist-2.0.so" in /etc/ld.so.conf.d) and then run "sudo ldconfig". # Disclaimer All the resources in this repository are written using only freely available information from the internet. The code and related resources are meant for educational purposes only. It is the responsibility of the user to make sure all local laws are adhered to. This project makes use of a third-party GPL library for handling FairPlay. The legal status of that library is unclear. Should you be a representative of Apple and have any objections against the legality of the library and its use in this project, please contact the developers and the appropriate steps will be taken. Given the large number of third-party AirPlay receivers (mostly closed-source) available for purchase, it is our understanding that an open source implementation of the same functionality wouldn't violate any of Apple's rights either. # UxPlay authors *\[adapted from fdraschbacher's notes on RPiPlay antecedents\]* The code in this repository accumulated from various sources over time. Here is an attempt at listing the various authors and the components they created: UxPlay was initially created by **antimof** from RPiPlay, by replacing its Raspberry-Pi-adapted OpenMAX video and audio rendering system with GStreamer rendering for desktop Linux systems; the antimof work on code in `renderers/` was later backported to RPiPlay, and the antimof project became dormant, but was later revived at the [current GitHub site](http://github.com/FDH2/UxPlay) to serve a wider community of users. The previous authors of code included in UxPlay by inheritance from RPiPlay include: - **EstebanKubata**: Created a FairPlay library called [PlayFair](https://github.com/EstebanKubata/playfair). Located in the `lib/playfair` folder. License: GNU GPL - **Juho Vähä-Herttua** and contributors: Created an AirPlay audio server called [ShairPlay](https://github.com/juhovh/shairplay), including support for Fairplay based on PlayFair. Most of the code in `lib/` originally stems from this project. License: GNU LGPLv2.1+ - **dsafa22**: Created an AirPlay 2 mirroring server [AirplayServer](https://github.com/dsafa22/AirplayServer) (seems gone now), for Android based on ShairPlay. Code is preserved [here](https://github.com/jiangban/AirplayServer), and [see here](https://github.com/FDH2/UxPlay/wiki/AirPlay2) for the description of the analysis of the AirPlay 2 mirror protocol that made RPiPlay possible, by the AirplayServer author. All code in `lib/` concerning mirroring is dsafa22's work. License: GNU LGPLv2.1+ - **Florian Draschbacher** (FD-) and contributors: adapted dsafa22's Android project for the Raspberry Pi, with extensive cleanups, debugging and improvements. The project [RPiPlay](https://github.com/FD-/RPiPlay) is basically a port of dsafa22's code to the Raspberry Pi, utilizing OpenMAX and OpenSSL for better performance on the Pi. License GPL v3. FD- has written an interesting note on the history of [Airplay protocol versions](http://github.com/FD-/RPiPlay#airplay-protocol-versions), available at the RPiPlay github repository. Independent of UxPlay, but used by it and bundled with it: - **Fedor Indutny** (of Node.js, and formerly Joyent, Inc) and contributors: Created an http parsing library called [llhttp](https://github.com/nodejs/llhttp). Located at `lib/llhttp/`. License: MIT UxPlay-1.71.1/cmake_uninstall.cmake.in000066400000000000000000000015311473013662600176130ustar00rootroot00000000000000if(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt") message(FATAL_ERROR "Cannot find install manifest: @CMAKE_BINARY_DIR@/install_manifest.txt") endif() file(READ "@CMAKE_BINARY_DIR@/install_manifest.txt" files) string(REGEX REPLACE "\n" ";" files "${files}") foreach(file ${files}) message(STATUS "Uninstalling $ENV{DESTDIR}${file}") if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") execute_process( COMMAND "@CMAKE_COMMAND@" -E remove "$ENV{DESTDIR}${file}" OUTPUT_VARIABLE rm_out RESULT_VARIABLE rm_retval ) if(NOT "${rm_retval}" STREQUAL 0) message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") endif() else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") message(STATUS "File $ENV{DESTDIR}${file} does not exist.") endif() endforeach() UxPlay-1.71.1/lib/000077500000000000000000000000001473013662600136015ustar00rootroot00000000000000UxPlay-1.71.1/lib/CMakeLists.txt000066400000000000000000000156701473013662600163520ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.5) include_directories( playfair llhttp ) message( STATUS "*** CFLAGS \"" ${CMAKE_C_FLAGS} "\" from build environment will be postpended to CMAKE_CFLAGS" ) # Common x86/x86_64 cflags if( NOT NO_MARCH_NATIVE AND CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)" ) set( CMAKE_C_FLAGS "-Ofast -march=native ${CMAKE_C_FLAGS}" ) message( STATUS "Using CFLAGS with -march=native" ) message( STATUS "*** ONLY USE THIS WHEN COMPILING ON THE MACHINE THAT WILL RUN UXPLAY" ) message( STATUS " run \"cmake -DNO_MARCH_NATIVE=ON\" to switch off this compiler option" ) else() message( STATUS "Not using -march=native" ) set( CMAKE_C_FLAGS "-O2 ${CMAKE_C_FLAGS}" ) endif() # Common Linux cflags if ( UNIX AND NOT APPLE ) set( CMAKE_C_FLAGS "-DSTANDALONE -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS -DTARGET_POSIX -D_LINUX -fPIC -DPIC -D_REENTRANT -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Wall ${CMAKE_C_FLAGS}" ) endif() if ( WIN32 ) message( STATUS "Building for Windows " ) set( CMAKE_C_FLAGS "-DSTANDALONE -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS -DTARGET_POSIX -D_WIN32 -fPIC -DPIC -D_REENTRANT -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Wall ${CMAKE_C_FLAGS}" ) endif() message( STATUS "using CMAKE_CFLAGS: " ${CMAKE_C_FLAGS} ) #activate the NOHOLD feature to drop existing connections if a third connection is made add_definitions( -DNOHOLD ) INCLUDE (CheckIncludeFiles) if( WIN32 ) CHECK_INCLUDE_FILES ("winsock2.h" WINSOCK2 ) else() # for BSD Unix (e.g. FreeBSD) CHECK_INCLUDE_FILES ("sys/endian.h" BSD ) if ( BSD ) add_definitions( -DSYS_ENDIAN_H ) endif ( BSD ) endif() if( APPLE ) set( ENV{PKG_CONFIG_PATH} "/usr/local/lib/pkgconfig" ) # standard location, and Brew set( ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:/opt/homebrew/lib/pkgconfig" ) # Brew for M1 macs set( ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:$ENV{HOMEBREW_PREFIX}/lib/pkgconfig" ) # Brew using prefix set( ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:/opt/local/lib/pkgconfig/" ) # MacPorts set( ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:/usr/local/opt/openssl@3/lib/pkgconfig" ) # Brew openssl set( ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:/opt/homebrew/opt/openssl@3/lib/pkgconfig" ) # Brew M1 openssl set( ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:$ENV{HOMEBREW_PREFIX}/opt/openssl@3/lib/pkgconfig" ) # Brew using prefix openssl message( "PKG_CONFIG_PATH (Apple, lib) = " $ENV{PKG_CONFIG_PATH} ) find_program( PKG_CONFIG_EXECUTABLE pkg-config PATHS /Library/FrameWorks/GStreamer.framework/Commands ) message( "PKG_CONFIG_EXECUTABLE " ${PKG_CONFIG_EXECUTABLE} ) endif() find_package(PkgConfig REQUIRED) aux_source_directory(. play_src) set(DIR_SRCS ${play_src}) add_library( airplay STATIC ${DIR_SRCS} ) if ( APPLE ) target_link_libraries( airplay pthread playfair llhttp ) elseif( WIN32 ) target_link_libraries( airplay pthread playfair llhttp wsock32 iphlpapi ws2_32 ) else() target_link_libraries( airplay PUBLIC pthread playfair llhttp ) endif() # libplist if( APPLE ) # use static linking pkg_search_module(PLIST REQUIRED libplist-2.0) find_library( LIBPLIST libplist-2.0.a REQUIRED ) message( STATUS "(Static linking) LIBPLIST " ${LIBPLIST} ) target_link_libraries ( airplay ${LIBPLIST} ) elseif( WIN32) pkg_search_module(PLIST REQUIRED libplist-2.0) find_library( LIBPLIST ${PLIST_LIBRARIES} PATH ${PLIST_LIBDIR} ) target_link_libraries ( airplay ${LIBPLIST} ) else () pkg_search_module(PLIST libplist>=2.0) if(NOT PLIST_FOUND) pkg_search_module(PLIST REQUIRED libplist-2.0) endif() find_library( LIBPLIST ${PLIST_LIBRARIES} PATH ${PLIST_LIBDIR} ) target_link_libraries ( airplay PUBLIC ${LIBPLIST} ) endif() if ( PLIST_FOUND ) message( STATUS "found libplist-${PLIST_VERSION}" ) endif() target_include_directories( airplay PRIVATE ${PLIST_INCLUDE_DIRS} ) #libcrypto if( APPLE ) # use static linking # can either compile Openssl 1.1.1 or 3.0.0 from source (install_dev to /usr/local) or use Macports or Brew # MacPorts needs zlib with it. Brew has a "keg-only" installation in /usr/local/opt/openssl@3 # Brew on M1 macs puts this in /opt/homebrew/opt/openssl@3 pkg_check_modules( OPENSSL REQUIRED openssl>=1.1.1) message( "OPENSSL_LIBRARY_DIRS " ${OPENSSL_LIBRARY_DIRS} ) message( "OPENSSL_INCLUDE_DIRS " ${OPENSSL_INCLUDE_DIRS} ) find_library( LIBCRYPTO libcrypto.a PATHS ${OPENSSL_LIBRARY_DIRS} REQUIRED ) message( "(Static linking) LIBCRYPTO " ${LIBCRYPTO} ) target_link_libraries( airplay ${LIBCRYPTO} ) if( LIBCRYPTO MATCHES "/opt/local/lib/libcrypto.a" ) #MacPorts openssl find_library( LIBZ libz.a) # needed by MacPorts openssl message("(MacPorts) LIBZ= " ${LIBZ} ) target_link_libraries( airplay ${LIBZ} ) endif() target_include_directories( airplay PRIVATE ${OPENSSL_INCLUDE_DIRS} ) elseif( WIN32 ) find_package(OpenSSL 1.1.1 REQUIRED) target_compile_definitions( airplay PUBLIC OPENSSL_API_COMPAT=0x10101000L ) target_link_libraries( airplay OpenSSL::Crypto ) else() find_package(OpenSSL 1.1.1 REQUIRED) target_compile_definitions( airplay PUBLIC OPENSSL_API_COMPAT=0x10101000L ) target_link_libraries( airplay PUBLIC OpenSSL::Crypto ) endif() #dns_sd if ( NOT APPLE ) pkg_search_module(AVAHI_DNSSD avahi-compat-libdns_sd) if (AVAHI_DNSSD_FOUND) target_include_directories( airplay PRIVATE ${AVAHI_DNSSD_INCLUDE_DIRS} ) find_library( DNSSD ${AVAHI_DNSSD_LIBRARIES} PATH ${AVAHI_DNSSD_LIBDIR}) target_link_libraries(airplay PUBLIC ${DNSSD} ) else() # can also build if mDNSResponder or another implementation of dns_sd is present instead of Avahi if ( WIN32 ) if (DEFINED ENV{BONJOUR_SDK_HOME}) set(BONJOUR_SDK "$ENV{BONJOUR_SDK_HOME}" ) else() set(BONJOUR_SDK "C:\\Program Files\\Bonjour SDK") endif() message( STATUS "BONJOUR_SDK_HOME " ${BONJOUR_SDK} ) set(DNSSD "${BONJOUR_SDK}/Lib/x64/dnssd.lib") target_link_libraries(airplay ${DNSSD} ) message( STATUS "dns_sd: using " ${DNSSD} ) find_path(DNSSD_INCLUDE_DIR dns_sd.h HINTS ${BONJOUR_SDK}/Include ) else() find_library( DNSSD dns_sd ) if( NOT DNSSD ) message( FATAL_ERROR "libdns_sd missing; can be provided by avahi_compat-libdns_sd or mDNSResponder." ) else() message( STATUS "dns_sd: found" ${DNSSD} ) endif() target_link_libraries(airplay PUBLIC ${DNSSD} ) find_path(DNSSD_INCLUDE_DIR dns_sd.h HINTS ${CMAKE_INSTALL_INCLUDEDIR} ) endif() if ( NOT DNSSD_INCLUDE_DIR ) message( FATAL_ERROR " dns_sd.h not found ") else() message( STATUS "found dns_sd.h in " ${DNSSD_INCLUDE_DIR} ) endif() target_include_directories( airplay PRIVATE ${DNSSD_INCLUDE_DIR} ) endif() endif() UxPlay-1.71.1/lib/airplay_video.c000066400000000000000000000226141473013662600166010ustar00rootroot00000000000000/** * Copyright (c) 2024 fduncanh * All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * */ // it should only start and stop the media_data_store that handles all HLS transactions, without // otherwise participating in them. #include #include #include #include #include #include "raop.h" #include "airplay_video.h" struct media_item_s { char *uri; char *playlist; int access; }; struct airplay_video_s { raop_t *raop; char apple_session_id[37]; char playback_uuid[37]; char *uri_prefix; char local_uri_prefix[23]; int next_uri; int FCUP_RequestID; float start_position_seconds; playback_info_t *playback_info; // The local port of the airplay server on the AirPlay server unsigned short airplay_port; char *master_uri; char *master_playlist; media_item_t *media_data_store; int num_uri; }; // initialize airplay_video service. int airplay_video_service_init(raop_t *raop, unsigned short http_port, const char *session_id) { char uri[] = "http://localhost:xxxxx"; assert(raop); airplay_video_t *airplay_video = deregister_airplay_video(raop); if (airplay_video) { airplay_video_service_destroy(airplay_video); } airplay_video = (airplay_video_t *) calloc(1, sizeof(airplay_video_t)); if (!airplay_video) { return -1; } /* create local_uri_prefix string */ strncpy(airplay_video->local_uri_prefix, uri, sizeof(airplay_video->local_uri_prefix)); char *ptr = strstr(airplay_video->local_uri_prefix, "xxxxx"); snprintf(ptr, 6, "%-5u", http_port); ptr = strstr(airplay_video->local_uri_prefix, " "); if (ptr) { *ptr = '\0'; } if (!register_airplay_video(raop, airplay_video)) { return -2; } //printf(" %p %p\n", airplay_video, get_airplay_video(raop)); airplay_video->raop = raop; airplay_video->FCUP_RequestID = 0; size_t len = strlen(session_id); assert(len == 36); strncpy(airplay_video->apple_session_id, session_id, len); (airplay_video->apple_session_id)[len] = '\0'; airplay_video->start_position_seconds = 0.0f; airplay_video->master_uri = NULL; airplay_video->media_data_store = NULL; airplay_video->master_playlist = NULL; airplay_video->num_uri = 0; airplay_video->next_uri = 0; return 0; } // destroy the airplay_video service void airplay_video_service_destroy(airplay_video_t *airplay_video) { if (airplay_video->uri_prefix) { free(airplay_video->uri_prefix); } if (airplay_video->master_uri) { free (airplay_video->master_uri); } if (airplay_video->media_data_store) { destroy_media_data_store(airplay_video); } if (airplay_video->master_playlist) { free (airplay_video->master_playlist); } free (airplay_video); } const char *get_apple_session_id(airplay_video_t *airplay_video) { return airplay_video->apple_session_id; } float get_start_position_seconds(airplay_video_t *airplay_video) { return airplay_video->start_position_seconds; } void set_start_position_seconds(airplay_video_t *airplay_video, float start_position_seconds) { airplay_video->start_position_seconds = start_position_seconds; } void set_playback_uuid(airplay_video_t *airplay_video, const char *playback_uuid) { size_t len = strlen(playback_uuid); assert(len == 36); memcpy(airplay_video->playback_uuid, playback_uuid, len); (airplay_video->playback_uuid)[len] = '\0'; } void set_uri_prefix(airplay_video_t *airplay_video, char *uri_prefix, int uri_prefix_len) { if (airplay_video->uri_prefix) { free (airplay_video->uri_prefix); } airplay_video->uri_prefix = (char *) calloc(uri_prefix_len + 1, sizeof(char)); memcpy(airplay_video->uri_prefix, uri_prefix, uri_prefix_len); } char *get_uri_prefix(airplay_video_t *airplay_video) { return airplay_video->uri_prefix; } char *get_uri_local_prefix(airplay_video_t *airplay_video) { return airplay_video->local_uri_prefix; } char *get_master_uri(airplay_video_t *airplay_video) { return airplay_video->master_uri; } int get_next_FCUP_RequestID(airplay_video_t *airplay_video) { return ++(airplay_video->FCUP_RequestID); } void set_next_media_uri_id(airplay_video_t *airplay_video, int num) { airplay_video->next_uri = num; } int get_next_media_uri_id(airplay_video_t *airplay_video) { return airplay_video->next_uri; } /* master playlist */ void store_master_playlist(airplay_video_t *airplay_video, char *master_playlist) { if (airplay_video->master_playlist) { free (airplay_video->master_playlist); } airplay_video->master_playlist = master_playlist; } char *get_master_playlist(airplay_video_t *airplay_video) { return airplay_video->master_playlist; } /* media_data_store */ int get_num_media_uri(airplay_video_t *airplay_video) { return airplay_video->num_uri; } void destroy_media_data_store(airplay_video_t *airplay_video) { media_item_t *media_data_store = airplay_video->media_data_store; if (media_data_store) { for (int i = 0; i < airplay_video->num_uri ; i ++ ) { if (media_data_store[i].uri) { free (media_data_store[i].uri); } if (media_data_store[i].playlist) { free (media_data_store[i].playlist); } } } free (media_data_store); airplay_video->num_uri = 0; } void create_media_data_store(airplay_video_t * airplay_video, char ** uri_list, int num_uri) { destroy_media_data_store(airplay_video); media_item_t *media_data_store = calloc(num_uri, sizeof(media_item_t)); for (int i = 0; i < num_uri; i++) { media_data_store[i].uri = uri_list[i]; media_data_store[i].playlist = NULL; media_data_store[i].access = 0; } airplay_video->media_data_store = media_data_store; airplay_video->num_uri = num_uri; } int store_media_data_playlist_by_num(airplay_video_t *airplay_video, char * media_playlist, int num) { media_item_t *media_data_store = airplay_video->media_data_store; if ( num < 0 || num >= airplay_video->num_uri) { return -1; } else if (media_data_store[num].playlist) { return -2; } media_data_store[num].playlist = media_playlist; return 0; } char * get_media_playlist_by_num(airplay_video_t *airplay_video, int num) { media_item_t *media_data_store = airplay_video->media_data_store; if (media_data_store == NULL) { return NULL; } if (num >= 0 && num num_uri) { return media_data_store[num].playlist; } return NULL; } int get_media_playlist_by_uri(airplay_video_t *airplay_video, const char *uri) { /* Problem: there can be more than one StreamInf playlist with the same uri: * they differ by choice of partner Media (audio, subtitles) playlists * If the same uri is requested again, one of the other ones will be returned * (the least-previously-requested one will be served up) */ // modified to return the position of the media playlist in the master playlist media_item_t *media_data_store = airplay_video->media_data_store; if (media_data_store == NULL) { return -2; } int found = 0;; int num = -1; int access = -1; for (int i = 0; i < airplay_video->num_uri; i++) { if (strstr(media_data_store[i].uri, uri)) { if (!found) { found = 1; num = i; access = media_data_store[i].access; } else { /* change > below to >= to reverse the order of choice */ if (access > media_data_store[i].access) { access = media_data_store[i].access; num = i; } } } } if (found) { //printf("found %s\n", media_data_store[num].uri); ++media_data_store[num].access; return num; } return -1; } char * get_media_uri_by_num(airplay_video_t *airplay_video, int num) { media_item_t * media_data_store = airplay_video->media_data_store; if (media_data_store == NULL) { return NULL; } if (num >= 0 && num < airplay_video->num_uri) { return media_data_store[num].uri; } return NULL; } int get_media_uri_num(airplay_video_t *airplay_video, char * uri) { media_item_t *media_data_store = airplay_video->media_data_store; for (int i = 0; i < airplay_video->num_uri ; i++) { if (strstr(media_data_store[i].uri, uri)) { return i; } } return -1; } int analyze_media_playlist(char *playlist, float *duration) { float next; int count = 0; char *ptr = strstr(playlist, "#EXTINF:"); *duration = 0.0f; while (ptr != NULL) { char *end; ptr += strlen("#EXTINF:"); next = strtof(ptr, &end); *duration += next; count++; ptr = strstr(end, "#EXTINF:"); } return count; } UxPlay-1.71.1/lib/airplay_video.h000066400000000000000000000064111473013662600166030ustar00rootroot00000000000000/* * Copyright (c) 2024 fduncanh, All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * *================================================================= */ #ifndef AIRPLAY_VIDEO_H #define AIRPLAY_VIDEO_H #include #include #include "raop.h" #include "logger.h" typedef struct airplay_video_s airplay_video_t; typedef struct media_item_s media_item_t; const char *get_apple_session_id(airplay_video_t *airplay_video); void set_start_position_seconds(airplay_video_t *airplay_video, float start_position_seconds); float get_start_position_seconds(airplay_video_t *airplay_video); void set_playback_uuid(airplay_video_t *airplay_video, const char *playback_uuid); void set_uri_prefix(airplay_video_t *airplay_video, char *uri_prefix, int uri_prefix_len); char *get_uri_prefix(airplay_video_t *airplay_video); char *get_uri_local_prefix(airplay_video_t *airplay_video); int get_next_FCUP_RequestID(airplay_video_t *airplay_video); void set_next_media_uri_id(airplay_video_t *airplay_video, int id); int get_next_media_uri_id(airplay_video_t *airplay_video); int get_media_playlist_by_uri(airplay_video_t *airplay_video, const char *uri); void store_master_playlist(airplay_video_t *airplay_video, char *master_playlist); char *get_master_playlist(airplay_video_t *airplay_video); int get_num_media_uri(airplay_video_t *airplay_video); void destroy_media_data_store(airplay_video_t *airplay_video); void create_media_data_store(airplay_video_t * airplay_video, char ** media_data_store, int num_uri); int store_media_data_playlist_by_num(airplay_video_t *airplay_video, char * media_playlist, int num); char *get_media_playlist_by_num(airplay_video_t *airplay_video, int num); char *get_media_uri_by_num(airplay_video_t *airplay_video, int num); int get_media_uri_num(airplay_video_t *airplay_video, char * uri); int analyze_media_playlist(char *playlist, float *duration); void airplay_video_service_destroy(airplay_video_t *airplay_video); // C wrappers for c++ class MediaDataStore //create the media_data_store, return a pointer to it. void* media_data_store_create(void *conn_opaque, uint16_t port); //delete the media_data_store void media_data_store_destroy(void *media_data_store); // called by the POST /action handler: char *process_media_data(void *media_data_store, const char *url, const char *data, int datalen); //called by the POST /play handler bool request_media_data(void *media_data_store, const char *primary_url, const char * session_id); //called by airplay_video_media_http_connection::get_handler: &path = req.uri) char *query_media_data(void *media_data_store, const char *url, int *len); //called by the post_stop_handler: void media_data_store_reset(void *media_data_store); const char *adjust_primary_uri(void *media_data_store, const char *url); #endif //AIRPLAY_VIDEO_H UxPlay-1.71.1/lib/byteutils.c000066400000000000000000000073631473013662600160020ustar00rootroot00000000000000/* * Copyright (c) 2019 dsafa22, All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * *================================================================= * modified by fduncanh 2021-23 */ #define SECOND_IN_NSECS 1000000000UL #include #ifdef _WIN32 # include #else # include #endif #include "byteutils.h" #ifdef _WIN32 # ifndef ntonll # define ntohll(x) ((1==ntohl(1)) ? (x) : (((uint64_t)ntohl((x) & 0xFFFFFFFFUL)) << 32) | ntohl((uint32_t)((x) >> 32))) # endif #else # ifndef htonll # ifdef SYS_ENDIAN_H # include # else # include # endif # define htonll(x) htobe64(x) # define ntohll(x) be64toh(x) # endif #endif // The functions in this file assume a little endian cpu architecture! /** * Reads a little endian unsigned 16 bit integer from the buffer at position offset */ uint16_t byteutils_get_short(unsigned char* b, int offset) { return *((uint16_t*)(b + offset)); } /** * Reads a little endian unsigned 32 bit integer from the buffer at position offset */ uint32_t byteutils_get_int(unsigned char* b, int offset) { return *((uint32_t*)(b + offset)); } /** * Reads a little endian unsigned 64 bit integer from the buffer at position offset */ uint64_t byteutils_get_long(unsigned char* b, int offset) { return *((uint64_t*)(b + offset)); } /** * Reads a big endian unsigned 16 bit integer from the buffer at position offset */ uint16_t byteutils_get_short_be(unsigned char* b, int offset) { return ntohs(byteutils_get_short(b, offset)); } /** * Reads a big endian unsigned 32 bit integer from the buffer at position offset */ uint32_t byteutils_get_int_be(unsigned char* b, int offset) { return ntohl(byteutils_get_int(b, offset)); } /** * Reads a big endian unsigned 64 bit integer from the buffer at position offset */ uint64_t byteutils_get_long_be(unsigned char* b, int offset) { return ntohll(byteutils_get_long(b, offset)); } /** * Reads a float from the buffer at position offset */ float byteutils_get_float(unsigned char* b, int offset) { return *((float*)(b + offset)); } /** * Writes a little endian unsigned 32 bit integer to the buffer at position offset */ void byteutils_put_int(unsigned char* b, int offset, uint32_t value) { *((uint32_t*)(b + offset)) = value; } /** * Reads an ntp timestamp and returns it as nano seconds since the Unix epoch */ uint64_t byteutils_get_ntp_timestamp(unsigned char *b, int offset) { uint64_t seconds = ntohl(((unsigned int) byteutils_get_int(b, offset))) - SECONDS_FROM_1900_TO_1970; uint64_t fraction = ntohl((unsigned int) byteutils_get_int(b, offset + 4)); return (seconds * SECOND_IN_NSECS) + ((fraction * SECOND_IN_NSECS) >> 32); } /** * Writes a time given as nano seconds since the Unix time epoch as an ntp timestamp * into the buffer at position offset */ void byteutils_put_ntp_timestamp(unsigned char *b, int offset, uint64_t ns_since_1970) { uint64_t seconds = ns_since_1970 / SECOND_IN_NSECS; uint64_t nanoseconds = ns_since_1970 % SECOND_IN_NSECS; seconds += SECONDS_FROM_1900_TO_1970; uint64_t fraction = (nanoseconds << 32) / SECOND_IN_NSECS; // Write in big endian! byteutils_put_int(b, offset, htonl(seconds)); byteutils_put_int(b, offset + 4, htonl(fraction)); } UxPlay-1.71.1/lib/byteutils.h000066400000000000000000000024631473013662600160030ustar00rootroot00000000000000/* * Copyright (c) 2019 dsafa22, All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. */ #ifndef AIRPLAYSERVER_BYTEUTILS_H #define AIRPLAYSERVER_BYTEUTILS_H #include uint16_t byteutils_get_short(unsigned char* b, int offset); uint32_t byteutils_get_int(unsigned char* b, int offset); uint64_t byteutils_get_long(unsigned char* b, int offset); uint16_t byteutils_get_short_be(unsigned char* b, int offset); uint32_t byteutils_get_int_be(unsigned char* b, int offset); uint64_t byteutils_get_long_be(unsigned char* b, int offset); float byteutils_get_float(unsigned char* b, int offset); #define SECONDS_FROM_1900_TO_1970 2208988800ULL uint64_t byteutils_get_ntp_timestamp(unsigned char *b, int offset); void byteutils_put_ntp_timestamp(unsigned char *b, int offset, uint64_t us_since_1970); #endif //AIRPLAYSERVER_BYTEUTILS_H UxPlay-1.71.1/lib/compat.c000066400000000000000000000023141473013662600152300ustar00rootroot00000000000000 /* * Copyright (c) 2024 F. Duncanh, All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * *================================================================== */ #ifdef _WIN32 #include #include #include "compat.h" #define MAX_SOCKET_ERROR_MESSAGE_LENGTH 256 /* Windows (winsock2) socket error message text */ char *wsa_strerror(int errnum) { static char message[MAX_SOCKET_ERROR_MESSAGE_LENGTH] = { 0 }; FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, 0, errnum, 0, message, sizeof(message), 0); char *nl = strchr(message, '\n'); if (nl) { *nl = 0; /* remove any trailing newline, or truncate to one line */ } return message; } #endif UxPlay-1.71.1/lib/compat.h000066400000000000000000000017701473013662600152420ustar00rootroot00000000000000/** * Copyright (C) 2011-2012 Juho Vähä-Herttua * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. */ #ifndef COMPAT_H #define COMPAT_H #if defined(WIN32) #include #include #ifndef snprintf #define snprintf _snprintf #endif #else #include #include #include #include #include #include #include #include #include #include #endif #include "sockets.h" #include "threads.h" #endif UxPlay-1.71.1/lib/crypto.c000066400000000000000000000363311473013662600152730ustar00rootroot00000000000000/** * RPiPlay - An open-source AirPlay mirroring server for Raspberry Pi * Copyright (C) 2019 Florian Draschbacher * Copyright (C) 2020 Jaslo Ziska * * 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, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * *=================================================================== * modified by fduncanh 2021-2022 */ #include "crypto.h" #include #include #include #include #include #include #include #include #include "utils.h" #define SALT_PK "UxPlay-Persistent-Not-Secure-Public-Key" struct aes_ctx_s { EVP_CIPHER_CTX *cipher_ctx; uint8_t key[AES_128_BLOCK_SIZE]; uint8_t iv[AES_128_BLOCK_SIZE]; aes_direction_t direction; uint8_t block_offset; }; uint8_t waste[AES_128_BLOCK_SIZE]; // Common AES utilities void handle_error(const char* location) { long error = ERR_get_error(); const char* error_str = ERR_error_string(error, NULL); fprintf(stderr, "Crypto error at %s: %s\n", location, error_str); exit(EXIT_FAILURE); } aes_ctx_t *aes_init(const uint8_t *key, const uint8_t *iv, const EVP_CIPHER *type, aes_direction_t direction) { aes_ctx_t *ctx = malloc(sizeof(aes_ctx_t)); assert(ctx != NULL); ctx->cipher_ctx = EVP_CIPHER_CTX_new(); assert(ctx->cipher_ctx != NULL); ctx->block_offset = 0; ctx->direction = direction; if (direction == AES_ENCRYPT) { if (!EVP_EncryptInit_ex(ctx->cipher_ctx, type, NULL, key, iv)) { handle_error(__func__); } } else { if (!EVP_DecryptInit_ex(ctx->cipher_ctx, type, NULL, key, iv)) { handle_error(__func__); } } memcpy(ctx->key, key, AES_128_BLOCK_SIZE); memcpy(ctx->iv, iv, AES_128_BLOCK_SIZE); EVP_CIPHER_CTX_set_padding(ctx->cipher_ctx, 0); return ctx; } void aes_encrypt(aes_ctx_t *ctx, const uint8_t *in, uint8_t *out, int in_len) { int out_len_e = 0; if (!EVP_EncryptUpdate(ctx->cipher_ctx, out, &out_len_e, in, in_len)) { handle_error(__func__); } int out_len_f = in_len - out_len_e; if (!EVP_EncryptFinal_ex(ctx->cipher_ctx, out + out_len_e, &out_len_f)) { handle_error(__func__); } assert(out_len_e + out_len_f <= in_len); } void aes_decrypt(aes_ctx_t *ctx, const uint8_t *in, uint8_t *out, int in_len) { int out_len_d = 0; if (!EVP_DecryptUpdate(ctx->cipher_ctx, out, &out_len_d, in, in_len)) { handle_error(__func__); } int out_len_f = in_len - out_len_d; if (!EVP_DecryptFinal_ex(ctx->cipher_ctx, out + out_len_d, &out_len_f)) { handle_error(__func__); } assert(out_len_f + out_len_d <= in_len); } void aes_destroy(aes_ctx_t *ctx) { if (ctx) { EVP_CIPHER_CTX_free(ctx->cipher_ctx); free(ctx); } } void aes_reset(aes_ctx_t *ctx, const EVP_CIPHER *type, aes_direction_t direction) { uint8_t key[AES_128_BLOCK_SIZE], iv[AES_128_BLOCK_SIZE]; memcpy(key, ctx->key, AES_128_BLOCK_SIZE); memcpy(iv, ctx->iv, AES_128_BLOCK_SIZE); if (!EVP_CIPHER_CTX_reset(ctx->cipher_ctx)) { handle_error(__func__); } if (direction == AES_ENCRYPT) { if (!EVP_EncryptInit_ex(ctx->cipher_ctx, type, NULL, key, iv)) { handle_error(__func__); } } else { if (!EVP_DecryptInit_ex(ctx->cipher_ctx, type, NULL, key, iv)) { handle_error(__func__); } } memcpy(ctx->key, key, AES_128_BLOCK_SIZE); memcpy(ctx->iv, iv, AES_128_BLOCK_SIZE); EVP_CIPHER_CTX_set_padding(ctx->cipher_ctx, 0); } // AES CTR aes_ctx_t *aes_ctr_init(const uint8_t *key, const uint8_t *iv) { return aes_init(key, iv, EVP_aes_128_ctr(), AES_ENCRYPT); } void aes_ctr_encrypt(aes_ctx_t *ctx, const uint8_t *in, uint8_t *out, int len) { aes_encrypt(ctx, in, out, len); ctx->block_offset = (ctx->block_offset + len) % AES_128_BLOCK_SIZE; } void aes_ctr_start_fresh_block(aes_ctx_t *ctx) { // Is there a better way to do this? if (ctx->block_offset == 0) return; aes_ctr_encrypt(ctx, waste, waste, AES_128_BLOCK_SIZE - ctx->block_offset); } void aes_ctr_decrypt(aes_ctx_t *ctx, const uint8_t *in, uint8_t *out, int len) { aes_encrypt(ctx, in, out, len); } void aes_ctr_reset(aes_ctx_t *ctx) { aes_reset(ctx, EVP_aes_128_ctr(), AES_ENCRYPT); } void aes_ctr_destroy(aes_ctx_t *ctx) { aes_destroy(ctx); } // AES CBC aes_ctx_t *aes_cbc_init(const uint8_t *key, const uint8_t *iv, aes_direction_t direction) { return aes_init(key, iv, EVP_aes_128_cbc(), direction); } void aes_cbc_encrypt(aes_ctx_t *ctx, const uint8_t *in, uint8_t *out, int len) { assert(ctx->direction == AES_ENCRYPT); aes_encrypt(ctx, in, out, len); } void aes_cbc_decrypt(aes_ctx_t *ctx, const uint8_t *in, uint8_t *out, int len) { assert(ctx->direction == AES_DECRYPT); aes_decrypt(ctx, in, out, len); } void aes_cbc_reset(aes_ctx_t *ctx) { aes_reset(ctx, EVP_aes_128_cbc(), ctx->direction); } void aes_cbc_destroy(aes_ctx_t *ctx) { aes_destroy(ctx); } // X25519 struct x25519_key_s { EVP_PKEY *pkey; }; x25519_key_t *x25519_key_generate(void) { x25519_key_t *key; EVP_PKEY_CTX *pctx; key = calloc(1, sizeof(x25519_key_t)); assert(key); pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_X25519, NULL); if (!pctx) { handle_error(__func__); } if (!EVP_PKEY_keygen_init(pctx)) { handle_error(__func__); } if (!EVP_PKEY_keygen(pctx, &key->pkey)) { handle_error(__func__); } EVP_PKEY_CTX_free(pctx); return key; } x25519_key_t *x25519_key_from_raw(const unsigned char data[X25519_KEY_SIZE]) { x25519_key_t *key; key = malloc(sizeof(x25519_key_t)); assert(key); key->pkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_X25519, NULL, data, X25519_KEY_SIZE); if (!key->pkey) { handle_error(__func__); } return key; } void x25519_key_get_raw(unsigned char data[X25519_KEY_SIZE], const x25519_key_t *key) { assert(key); if (!EVP_PKEY_get_raw_public_key(key->pkey, data, &(size_t) {X25519_KEY_SIZE})) { handle_error(__func__); } } void x25519_key_destroy(x25519_key_t *key) { if (key) { EVP_PKEY_free(key->pkey); free(key); } } void x25519_derive_secret(unsigned char secret[X25519_KEY_SIZE], const x25519_key_t *ours, const x25519_key_t *theirs) { EVP_PKEY_CTX *pctx; assert(ours); assert(theirs); pctx = EVP_PKEY_CTX_new(ours->pkey, NULL); if (!pctx) { handle_error(__func__); } if (!EVP_PKEY_derive_init(pctx)) { handle_error(__func__); } if (!EVP_PKEY_derive_set_peer(pctx, theirs->pkey)) { handle_error(__func__); } if (!EVP_PKEY_derive(pctx, secret, &(size_t) {X25519_KEY_SIZE})) { handle_error(__func__); } EVP_PKEY_CTX_free(pctx); } // GCM AES 128 int gcm_encrypt(const unsigned char *plaintext, int plaintext_len, unsigned char *ciphertext, unsigned char *key, unsigned char *iv, unsigned char *tag) { EVP_CIPHER_CTX *ctx; int len; int ciphertext_len; if(!(ctx = EVP_CIPHER_CTX_new())) handle_error(__func__); if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL)) handle_error(__func__); if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 16, NULL)) handle_error(__func__); if(1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv)) handle_error(__func__); if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len)) handle_error(__func__); ciphertext_len = len; if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) handle_error(__func__); ciphertext_len += len; if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag)) handle_error(__func__); EVP_CIPHER_CTX_free(ctx); return ciphertext_len; } int gcm_decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *plaintext, unsigned char *key, unsigned char *iv, unsigned char *tag) { EVP_CIPHER_CTX *ctx; int len; int plaintext_len; int ret; if(!(ctx = EVP_CIPHER_CTX_new())) handle_error(__func__); if(!EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL)) handle_error(__func__); if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 16, NULL)) handle_error(__func__); if(!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv)) handle_error(__func__); if(!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len)) handle_error(__func__); plaintext_len = len; if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag)) handle_error(__func__); ret = EVP_DecryptFinal_ex(ctx, plaintext + len, &len); EVP_CIPHER_CTX_free(ctx); if(ret > 0) { /* Success */ plaintext_len += len; return plaintext_len; } else { /* Verify failed */ return -1; } } // ED25519 struct ed25519_key_s { EVP_PKEY *pkey; }; ed25519_key_t *ed25519_key_generate(const char *device_id, const char *keyfile, int *result) { ed25519_key_t *key; EVP_PKEY_CTX *pctx; BIO *bp; FILE *file; bool new_pk = false; bool use_keyfile = strlen(keyfile); *result = 0; key = calloc(1, sizeof(ed25519_key_t)); assert(key); if (use_keyfile) { file = fopen(keyfile, "r"); if (file) { bp = BIO_new_fp(file, BIO_NOCLOSE); key->pkey = PEM_read_PrivateKey(file, NULL, NULL, NULL); BIO_free(bp); fclose(file); if (!key->pkey) { new_pk = true; } } else { new_pk = true; } } else { /* generate (insecure) persistent keypair using device_id */ unsigned char hash[SHA512_DIGEST_LENGTH]; char salt[] = SALT_PK; sha_ctx_t *ctx = sha_init(); sha_update(ctx, (const unsigned char *) salt, (unsigned int) strlen(salt)); sha_update(ctx, (const unsigned char *) device_id, (unsigned int) strlen(device_id)); sha_final(ctx, hash, NULL); sha_destroy(ctx); key->pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, NULL, (const unsigned char *) hash, ED25519_KEY_SIZE); } if (new_pk) { pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_ED25519, NULL); if (!pctx) { handle_error(__func__); } if (!EVP_PKEY_keygen_init(pctx)) { handle_error(__func__); } if (!EVP_PKEY_keygen(pctx, &key->pkey)) { handle_error(__func__); } EVP_PKEY_CTX_free(pctx); if (use_keyfile) { file = fopen(keyfile, "w"); if (file) { bp = BIO_new_fp(file, BIO_NOCLOSE); PEM_write_bio_PrivateKey(bp, key->pkey, NULL, NULL, 0, NULL, NULL); BIO_free(bp); fclose(file); *result = 1; } } } return key; } ed25519_key_t *ed25519_key_from_raw(const unsigned char data[ED25519_KEY_SIZE]) { ed25519_key_t *key; key = malloc(sizeof(ed25519_key_t)); assert(key); key->pkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL, data, ED25519_KEY_SIZE); if (!key->pkey) { handle_error(__func__); } return key; } void ed25519_key_get_raw(unsigned char data[ED25519_KEY_SIZE], const ed25519_key_t *key) { assert(key); if (!EVP_PKEY_get_raw_public_key(key->pkey, data, &(size_t) {ED25519_KEY_SIZE})) { handle_error(__func__); } } ed25519_key_t *ed25519_key_copy(const ed25519_key_t *key) { ed25519_key_t *new_key; assert(key); new_key = malloc(sizeof(ed25519_key_t)); assert(new_key); new_key->pkey = key->pkey; if (!EVP_PKEY_up_ref(key->pkey)) { handle_error(__func__); } return new_key; } void ed25519_sign(unsigned char *signature, size_t signature_len, const unsigned char *data, size_t data_len, const ed25519_key_t *key) { EVP_MD_CTX *mctx; mctx = EVP_MD_CTX_new(); if (!mctx) { handle_error(__func__); } if (!EVP_DigestSignInit(mctx, NULL, NULL, NULL, key->pkey)) { handle_error(__func__); } if (!EVP_DigestSign(mctx, signature, &signature_len, data, data_len)) { handle_error(__func__); } EVP_MD_CTX_free(mctx); } int ed25519_verify(const unsigned char *signature, size_t signature_len, const unsigned char *data, size_t data_len, const ed25519_key_t *key) { EVP_MD_CTX *mctx; mctx = EVP_MD_CTX_new(); if (!mctx) { handle_error(__func__); } if (!EVP_DigestVerifyInit(mctx, NULL, NULL, NULL, key->pkey)) { handle_error(__func__); } int ret = EVP_DigestVerify(mctx, signature, signature_len, data, data_len); if (ret < 0) { handle_error(__func__); } EVP_MD_CTX_free(mctx); return ret; } void ed25519_key_destroy(ed25519_key_t *key) { if (key) { EVP_PKEY_free(key->pkey); free(key); } } // SHA 512 struct sha_ctx_s { EVP_MD_CTX *digest_ctx; }; sha_ctx_t *sha_init() { sha_ctx_t *ctx = malloc(sizeof(sha_ctx_t)); assert(ctx != NULL); ctx->digest_ctx = EVP_MD_CTX_new(); assert(ctx->digest_ctx != NULL); if (!EVP_DigestInit_ex(ctx->digest_ctx, EVP_sha512(), NULL)) { handle_error(__func__); } return ctx; } void sha_update(sha_ctx_t *ctx, const uint8_t *in, int len) { if (!EVP_DigestUpdate(ctx->digest_ctx, in, len)) { handle_error(__func__); } } void sha_final(sha_ctx_t *ctx, uint8_t *out, unsigned int *len) { if (!EVP_DigestFinal_ex(ctx->digest_ctx, out, len)) { handle_error(__func__); } } void sha_reset(sha_ctx_t *ctx) { if (!EVP_MD_CTX_reset(ctx->digest_ctx) || !EVP_DigestInit_ex(ctx->digest_ctx, EVP_sha512(), NULL)) { handle_error(__func__); } } void sha_destroy(sha_ctx_t *ctx) { if (ctx) { EVP_MD_CTX_free(ctx->digest_ctx); free(ctx); } } int get_random_bytes(unsigned char *buf, int num) { return RAND_bytes(buf, num); } #include void pk_to_base64(const unsigned char *pk, int pk_len, char *pk_base64, int len) { memset(pk_base64, 0, len); int len64 = (4 * (pk_len /3)) + (pk_len % 3 ? 4 : 0); assert (len > len64); BIO *b64 = BIO_new(BIO_f_base64()); BIO *bio = BIO_new(BIO_s_mem()); BUF_MEM *bufferPtr; bio = BIO_push(b64, bio); BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); BIO_write(bio, pk, pk_len); BIO_flush(bio); BIO_get_mem_ptr(bio, &bufferPtr); BIO_set_close(bio, BIO_NOCLOSE); BIO_free_all(bio); memcpy(pk_base64,(*bufferPtr).data, len64); } UxPlay-1.71.1/lib/crypto.h000066400000000000000000000102231473013662600152700ustar00rootroot00000000000000/** * RPiPlay - An open-source AirPlay mirroring server for Raspberry Pi * Copyright (C) 2019 Florian Draschbacher * Copyright (C) 2020 Jaslo Ziska * * 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, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * modified by fduncanh 2023 */ /* * Helper methods for various crypto operations. * Uses OpenSSL behind the scenes. */ #ifndef CRYPTO_H #define CRYPTO_H #include #include #ifdef __cplusplus extern "C" { #endif // 128bit AES in CTR mode #define AES_128_BLOCK_SIZE 16 typedef enum aes_direction_e { AES_DECRYPT, AES_ENCRYPT } aes_direction_t; typedef struct aes_ctx_s aes_ctx_t; aes_ctx_t *aes_ctr_init(const uint8_t *key, const uint8_t *iv); void aes_ctr_reset(aes_ctx_t *ctx); void aes_ctr_encrypt(aes_ctx_t *ctx, const uint8_t *in, uint8_t *out, int len); void aes_ctr_decrypt(aes_ctx_t *ctx, const uint8_t *in, uint8_t *out, int len); void aes_ctr_start_fresh_block(aes_ctx_t *ctx); void aes_ctr_destroy(aes_ctx_t *ctx); aes_ctx_t *aes_cbc_init(const uint8_t *key, const uint8_t *iv, aes_direction_t direction); void aes_cbc_reset(aes_ctx_t *ctx); void aes_cbc_encrypt(aes_ctx_t *ctx, const uint8_t *in, uint8_t *out, int len); void aes_cbc_decrypt(aes_ctx_t *ctx, const uint8_t *in, uint8_t *out, int len); void aes_cbc_destroy(aes_ctx_t *ctx); // X25519 #define X25519_KEY_SIZE 32 typedef struct x25519_key_s x25519_key_t; x25519_key_t *x25519_key_generate(void); x25519_key_t *x25519_key_from_raw(const unsigned char data[X25519_KEY_SIZE]); void x25519_key_get_raw(unsigned char data[X25519_KEY_SIZE], const x25519_key_t *key); void x25519_key_destroy(x25519_key_t *key); int get_random_bytes(unsigned char *buf, int num); void pk_to_base64(const unsigned char *pk, int pk_len, char *pk_base64, int len); void x25519_derive_secret(unsigned char secret[X25519_KEY_SIZE], const x25519_key_t *ours, const x25519_key_t *theirs); // GCM AES 128 int gcm_encrypt(const unsigned char *plaintext, int plaintext_len, unsigned char *ciphertext, unsigned char *key, unsigned char *iv, unsigned char *tag); int gcm_decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *plaintext, unsigned char *key, unsigned char *iv, unsigned char *tag); // ED25519 #define ED25519_KEY_SIZE 32 typedef struct ed25519_key_s ed25519_key_t; ed25519_key_t *ed25519_key_generate(const char *device_id, const char * keyfile, int * result); ed25519_key_t *ed25519_key_from_raw(const unsigned char data[ED25519_KEY_SIZE]); void ed25519_key_get_raw(unsigned char data[ED25519_KEY_SIZE], const ed25519_key_t *key); /* * Note that this function does *not copy* the OpenSSL key but only the wrapper. The internal OpenSSL key is still the * same. Only the reference count is increased so destroying both the original and the copy is allowed. */ ed25519_key_t *ed25519_key_copy(const ed25519_key_t *key); void ed25519_key_destroy(ed25519_key_t *key); void ed25519_sign(unsigned char *signature, size_t signature_len, const unsigned char *data, size_t data_len, const ed25519_key_t *key); int ed25519_verify(const unsigned char *signature, size_t signature_len, const unsigned char *data, size_t data_len, const ed25519_key_t *key); // SHA512 typedef struct sha_ctx_s sha_ctx_t; sha_ctx_t *sha_init(); void sha_update(sha_ctx_t *ctx, const uint8_t *in, int len); void sha_final(sha_ctx_t *ctx, uint8_t *out, unsigned int *len); void sha_reset(sha_ctx_t *ctx); void sha_destroy(sha_ctx_t *ctx); #ifdef __cplusplus } #endif #endif UxPlay-1.71.1/lib/dnssd.c000066400000000000000000000376301473013662600150710ustar00rootroot00000000000000/** * Copyright (C) 2011-2012 Juho Vähä-Herttua * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * *================================================================= * modified by fduncanh 2022 */ /* These defines allow us to compile on iOS */ #ifndef __has_feature # define __has_feature(x) 0 #endif #ifndef __has_extension # define __has_extension __has_feature #endif #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "dnssdint.h" #include "dnssd.h" #include "global.h" #include "compat.h" #include "utils.h" #include #define MAX_DEVICEID 18 #define MAX_SERVNAME 256 #if defined(HAVE_LIBDL) && !defined(__APPLE__) # define USE_LIBDL 1 #else # define USE_LIBDL 0 #endif #if defined(_WIN32) || USE_LIBDL # ifdef _WIN32 # include # if !defined(EFI32) && !defined(EFI64) # define DNSSD_STDCALL __stdcall # else # define DNSSD_STDCALL # endif # else # include # define DNSSD_STDCALL # endif typedef struct _DNSServiceRef_t *DNSServiceRef; #ifndef _WIN32 typedef union _TXTRecordRef_t { char PrivateData[16]; char *ForceNaturalAlignment; } TXTRecordRef; #endif typedef uint32_t DNSServiceFlags; typedef int32_t DNSServiceErrorType; typedef void (DNSSD_STDCALL *DNSServiceRegisterReply) ( DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode, const char *name, const char *regtype, const char *domain, void *context ); #else //# include # define DNSSD_STDCALL #endif typedef DNSServiceErrorType (DNSSD_STDCALL *DNSServiceRegister_t) ( DNSServiceRef *sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, const char *name, const char *regtype, const char *domain, const char *host, uint16_t port, uint16_t txtLen, const void *txtRecord, DNSServiceRegisterReply callBack, void *context ); typedef void (DNSSD_STDCALL *DNSServiceRefDeallocate_t)(DNSServiceRef sdRef); typedef void (DNSSD_STDCALL *TXTRecordCreate_t) ( TXTRecordRef *txtRecord, uint16_t bufferLen, void *buffer ); typedef void (DNSSD_STDCALL *TXTRecordDeallocate_t)(TXTRecordRef *txtRecord); typedef DNSServiceErrorType (DNSSD_STDCALL *TXTRecordSetValue_t) ( TXTRecordRef *txtRecord, const char *key, uint8_t valueSize, const void *value ); typedef uint16_t (DNSSD_STDCALL *TXTRecordGetLength_t)(const TXTRecordRef *txtRecord); typedef const void * (DNSSD_STDCALL *TXTRecordGetBytesPtr_t)(const TXTRecordRef *txtRecord); struct dnssd_s { #ifdef WIN32 HMODULE module; #elif USE_LIBDL void *module; #endif DNSServiceRegister_t DNSServiceRegister; DNSServiceRefDeallocate_t DNSServiceRefDeallocate; TXTRecordCreate_t TXTRecordCreate; TXTRecordSetValue_t TXTRecordSetValue; TXTRecordGetLength_t TXTRecordGetLength; TXTRecordGetBytesPtr_t TXTRecordGetBytesPtr; TXTRecordDeallocate_t TXTRecordDeallocate; TXTRecordRef raop_record; TXTRecordRef airplay_record; DNSServiceRef raop_service; DNSServiceRef airplay_service; char *name; int name_len; char *hw_addr; int hw_addr_len; char *pk; uint32_t features1; uint32_t features2; unsigned char require_pw; }; dnssd_t * dnssd_init(const char* name, int name_len, const char* hw_addr, int hw_addr_len, int *error, int require_pw) { dnssd_t *dnssd; char *end; unsigned long features; if (error) *error = DNSSD_ERROR_NOERROR; dnssd = calloc(1, sizeof(dnssd_t)); if (!dnssd) { if (error) *error = DNSSD_ERROR_OUTOFMEM; return NULL; } dnssd->require_pw = (unsigned char) require_pw; features = strtoul(FEATURES_1, &end, 16); if (!end || (features & 0xFFFFFFFF) != features) { free (dnssd); if (error) *error = DNSSD_ERROR_BADFEATURES; return NULL; } dnssd->features1 = (uint32_t) features; features = strtoul(FEATURES_2, &end, 16); if (!end || (features & 0xFFFFFFFF) != features) { free (dnssd); if (error) *error = DNSSD_ERROR_BADFEATURES; return NULL; } dnssd->features2 = (uint32_t) features; #ifdef WIN32 dnssd->module = LoadLibraryA("dnssd.dll"); if (!dnssd->module) { if (error) *error = DNSSD_ERROR_LIBNOTFOUND; free(dnssd); return NULL; } dnssd->DNSServiceRegister = (DNSServiceRegister_t)GetProcAddress(dnssd->module, "DNSServiceRegister"); dnssd->DNSServiceRefDeallocate = (DNSServiceRefDeallocate_t)GetProcAddress(dnssd->module, "DNSServiceRefDeallocate"); dnssd->TXTRecordCreate = (TXTRecordCreate_t)GetProcAddress(dnssd->module, "TXTRecordCreate"); dnssd->TXTRecordSetValue = (TXTRecordSetValue_t)GetProcAddress(dnssd->module, "TXTRecordSetValue"); dnssd->TXTRecordGetLength = (TXTRecordGetLength_t)GetProcAddress(dnssd->module, "TXTRecordGetLength"); dnssd->TXTRecordGetBytesPtr = (TXTRecordGetBytesPtr_t)GetProcAddress(dnssd->module, "TXTRecordGetBytesPtr"); dnssd->TXTRecordDeallocate = (TXTRecordDeallocate_t)GetProcAddress(dnssd->module, "TXTRecordDeallocate"); if (!dnssd->DNSServiceRegister || !dnssd->DNSServiceRefDeallocate || !dnssd->TXTRecordCreate || !dnssd->TXTRecordSetValue || !dnssd->TXTRecordGetLength || !dnssd->TXTRecordGetBytesPtr || !dnssd->TXTRecordDeallocate) { if (error) *error = DNSSD_ERROR_PROCNOTFOUND; FreeLibrary(dnssd->module); free(dnssd); return NULL; } #elif USE_LIBDL dnssd->module = dlopen("libdns_sd.so", RTLD_LAZY); if (!dnssd->module) { if (error) *error = DNSSD_ERROR_LIBNOTFOUND; free(dnssd); return NULL; } dnssd->DNSServiceRegister = (DNSServiceRegister_t)dlsym(dnssd->module, "DNSServiceRegister"); dnssd->DNSServiceRefDeallocate = (DNSServiceRefDeallocate_t)dlsym(dnssd->module, "DNSServiceRefDeallocate"); dnssd->TXTRecordCreate = (TXTRecordCreate_t)dlsym(dnssd->module, "TXTRecordCreate"); dnssd->TXTRecordSetValue = (TXTRecordSetValue_t)dlsym(dnssd->module, "TXTRecordSetValue"); dnssd->TXTRecordGetLength = (TXTRecordGetLength_t)dlsym(dnssd->module, "TXTRecordGetLength"); dnssd->TXTRecordGetBytesPtr = (TXTRecordGetBytesPtr_t)dlsym(dnssd->module, "TXTRecordGetBytesPtr"); dnssd->TXTRecordDeallocate = (TXTRecordDeallocate_t)dlsym(dnssd->module, "TXTRecordDeallocate"); if (!dnssd->DNSServiceRegister || !dnssd->DNSServiceRefDeallocate || !dnssd->TXTRecordCreate || !dnssd->TXTRecordSetValue || !dnssd->TXTRecordGetLength || !dnssd->TXTRecordGetBytesPtr || !dnssd->TXTRecordDeallocate) { if (error) *error = DNSSD_ERROR_PROCNOTFOUND; dlclose(dnssd->module); free(dnssd); return NULL; } #else dnssd->DNSServiceRegister = &DNSServiceRegister; dnssd->DNSServiceRefDeallocate = &DNSServiceRefDeallocate; dnssd->TXTRecordCreate = &TXTRecordCreate; dnssd->TXTRecordSetValue = &TXTRecordSetValue; dnssd->TXTRecordGetLength = &TXTRecordGetLength; dnssd->TXTRecordGetBytesPtr = &TXTRecordGetBytesPtr; dnssd->TXTRecordDeallocate = &TXTRecordDeallocate; #endif dnssd->name_len = name_len; dnssd->name = calloc(1, name_len + 1); if (!dnssd->name) { free(dnssd); if (error) *error = DNSSD_ERROR_OUTOFMEM; return NULL; } memcpy(dnssd->name, name, name_len); dnssd->hw_addr_len = hw_addr_len; dnssd->hw_addr = calloc(1, dnssd->hw_addr_len); if (!dnssd->hw_addr) { free(dnssd->name); free(dnssd); if (error) *error = DNSSD_ERROR_OUTOFMEM; return NULL; } memcpy(dnssd->hw_addr, hw_addr, hw_addr_len); return dnssd; } void dnssd_destroy(dnssd_t *dnssd) { if (dnssd) { #ifdef WIN32 FreeLibrary(dnssd->module); #elif USE_LIBDL dlclose(dnssd->module); #endif free(dnssd); } } int dnssd_register_raop(dnssd_t *dnssd, unsigned short port) { char servname[MAX_SERVNAME]; DNSServiceErrorType retval; char features[22]; assert(dnssd); snprintf(features, sizeof(features), "0x%X,0x%X", dnssd->features1, dnssd->features2); dnssd->TXTRecordCreate(&dnssd->raop_record, 0, NULL); dnssd->TXTRecordSetValue(&dnssd->raop_record, "ch", strlen(RAOP_CH), RAOP_CH); dnssd->TXTRecordSetValue(&dnssd->raop_record, "cn", strlen(RAOP_CN), RAOP_CN); dnssd->TXTRecordSetValue(&dnssd->raop_record, "da", strlen(RAOP_DA), RAOP_DA); dnssd->TXTRecordSetValue(&dnssd->raop_record, "et", strlen(RAOP_ET), RAOP_ET); dnssd->TXTRecordSetValue(&dnssd->raop_record, "vv", strlen(RAOP_VV), RAOP_VV); dnssd->TXTRecordSetValue(&dnssd->raop_record, "ft", strlen(features), features); dnssd->TXTRecordSetValue(&dnssd->raop_record, "am", strlen(GLOBAL_MODEL), GLOBAL_MODEL); dnssd->TXTRecordSetValue(&dnssd->raop_record, "md", strlen(RAOP_MD), RAOP_MD); dnssd->TXTRecordSetValue(&dnssd->raop_record, "rhd", strlen(RAOP_RHD), RAOP_RHD); if (dnssd->require_pw) { dnssd->TXTRecordSetValue(&dnssd->raop_record, "pw", strlen("true"), "true"); } else { dnssd->TXTRecordSetValue(&dnssd->raop_record, "pw", strlen("false"), "false"); } dnssd->TXTRecordSetValue(&dnssd->raop_record, "sr", strlen(RAOP_SR), RAOP_SR); dnssd->TXTRecordSetValue(&dnssd->raop_record, "ss", strlen(RAOP_SS), RAOP_SS); dnssd->TXTRecordSetValue(&dnssd->raop_record, "sv", strlen(RAOP_SV), RAOP_SV); dnssd->TXTRecordSetValue(&dnssd->raop_record, "tp", strlen(RAOP_TP), RAOP_TP); dnssd->TXTRecordSetValue(&dnssd->raop_record, "txtvers", strlen(RAOP_TXTVERS), RAOP_TXTVERS); dnssd->TXTRecordSetValue(&dnssd->raop_record, "sf", strlen(RAOP_SF), RAOP_SF); dnssd->TXTRecordSetValue(&dnssd->raop_record, "vs", strlen(RAOP_VS), RAOP_VS); dnssd->TXTRecordSetValue(&dnssd->raop_record, "vn", strlen(RAOP_VN), RAOP_VN); dnssd->TXTRecordSetValue(&dnssd->raop_record, "pk", strlen(dnssd->pk), dnssd->pk); /* Convert hardware address to string */ if (utils_hwaddr_raop(servname, sizeof(servname), dnssd->hw_addr, dnssd->hw_addr_len) < 0) { /* FIXME: handle better */ return -1; } /* Check that we have bytes for 'hw@name' format */ if (sizeof(servname) < strlen(servname) + 1 + dnssd->name_len + 1) { /* FIXME: handle better */ return -2; } strncat(servname, "@", sizeof(servname)-strlen(servname)-1); strncat(servname, dnssd->name, sizeof(servname)-strlen(servname)-1); /* Register the service */ retval = dnssd->DNSServiceRegister(&dnssd->raop_service, 0, 0, servname, "_raop._tcp", NULL, NULL, htons(port), dnssd->TXTRecordGetLength(&dnssd->raop_record), dnssd->TXTRecordGetBytesPtr(&dnssd->raop_record), NULL, NULL); return (int) retval; /* error codes are listed in Apple's dns_sd.h */ } int dnssd_register_airplay(dnssd_t *dnssd, unsigned short port) { char device_id[3 * MAX_HWADDR_LEN]; DNSServiceErrorType retval; char features[22]; assert(dnssd); snprintf(features, sizeof(features), "0x%X,0x%X", dnssd->features1, dnssd->features2); /* Convert hardware address to string */ if (utils_hwaddr_airplay(device_id, sizeof(device_id), dnssd->hw_addr, dnssd->hw_addr_len) < 0) { /* FIXME: handle better */ return -1; } dnssd->TXTRecordCreate(&dnssd->airplay_record, 0, NULL); dnssd->TXTRecordSetValue(&dnssd->airplay_record, "deviceid", strlen(device_id), device_id); dnssd->TXTRecordSetValue(&dnssd->airplay_record, "features", strlen(features), features); dnssd->TXTRecordSetValue(&dnssd->airplay_record, "flags", strlen(AIRPLAY_FLAGS), AIRPLAY_FLAGS); dnssd->TXTRecordSetValue(&dnssd->airplay_record, "model", strlen(GLOBAL_MODEL), GLOBAL_MODEL); dnssd->TXTRecordSetValue(&dnssd->airplay_record, "pk", strlen(dnssd->pk), dnssd->pk); if (dnssd->require_pw) { dnssd->TXTRecordSetValue(&dnssd->airplay_record, "pw", strlen("true"), "true"); } else { dnssd->TXTRecordSetValue(&dnssd->airplay_record, "pw", strlen("false"), "false"); } dnssd->TXTRecordSetValue(&dnssd->airplay_record, "pi", strlen(AIRPLAY_PI), AIRPLAY_PI); dnssd->TXTRecordSetValue(&dnssd->airplay_record, "srcvers", strlen(AIRPLAY_SRCVERS), AIRPLAY_SRCVERS); dnssd->TXTRecordSetValue(&dnssd->airplay_record, "vv", strlen(AIRPLAY_VV), AIRPLAY_VV); /* Register the service */ retval = dnssd->DNSServiceRegister(&dnssd->airplay_service, 0, 0, dnssd->name, "_airplay._tcp", NULL, NULL, htons(port), dnssd->TXTRecordGetLength(&dnssd->airplay_record), dnssd->TXTRecordGetBytesPtr(&dnssd->airplay_record), NULL, NULL); return (int) retval; /* error codes are listed in Apple's dns_sd.h */ } const char * dnssd_get_airplay_txt(dnssd_t *dnssd, int *length) { *length = dnssd->TXTRecordGetLength(&dnssd->airplay_record); return dnssd->TXTRecordGetBytesPtr(&dnssd->airplay_record); } const char * dnssd_get_name(dnssd_t *dnssd, int *length) { *length = dnssd->name_len; return dnssd->name; } const char * dnssd_get_hw_addr(dnssd_t *dnssd, int *length) { *length = dnssd->hw_addr_len; return dnssd->hw_addr; } void dnssd_unregister_raop(dnssd_t *dnssd) { assert(dnssd); if (!dnssd->raop_service) { return; } /* Deallocate TXT record */ dnssd->TXTRecordDeallocate(&dnssd->raop_record); dnssd->DNSServiceRefDeallocate(dnssd->raop_service); dnssd->raop_service = NULL; if (dnssd->airplay_service == NULL) { free(dnssd->name); free(dnssd->hw_addr); } } void dnssd_unregister_airplay(dnssd_t *dnssd) { assert(dnssd); if (!dnssd->airplay_service) { return; } /* Deallocate TXT record */ dnssd->TXTRecordDeallocate(&dnssd->airplay_record); dnssd->DNSServiceRefDeallocate(dnssd->airplay_service); dnssd->airplay_service = NULL; if (dnssd->raop_service == NULL) { free(dnssd->name); free(dnssd->hw_addr); } } uint64_t dnssd_get_airplay_features(dnssd_t *dnssd) { uint64_t features = ((uint64_t) dnssd->features2) << 32; features += (uint64_t) dnssd->features1; return features; } void dnssd_set_pk(dnssd_t *dnssd, char * pk_str) { dnssd->pk = pk_str; } void dnssd_set_airplay_features(dnssd_t *dnssd, int bit, int val) { uint32_t mask; uint32_t *features; if (bit < 0 || bit > 63) return; if (val < 0 || val > 1) return; if (bit >= 32) { mask = 0x1 << (bit - 32); features = &(dnssd->features2); } else { mask = 0x1 << bit; features = &(dnssd->features1); } if (val) { *features = *features | mask; } else { *features = *features & ~mask; } } UxPlay-1.71.1/lib/dnssd.h000066400000000000000000000036061473013662600150720ustar00rootroot00000000000000/** * Copyright (C) 2012 Juho Vähä-Herttua * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. */ #ifndef DNSSD_H #define DNSSD_H #include #if defined(WIN32) && defined(DLL_EXPORT) # define DNSSD_API __declspec(dllexport) #else # define DNSSD_API #endif #ifdef __cplusplus extern "C" { #endif #define DNSSD_ERROR_NOERROR 0 #define DNSSD_ERROR_HWADDRLEN 1 #define DNSSD_ERROR_OUTOFMEM 2 #define DNSSD_ERROR_LIBNOTFOUND 3 #define DNSSD_ERROR_PROCNOTFOUND 4 #define DNSSD_ERROR_BADFEATURES 5 typedef struct dnssd_s dnssd_t; DNSSD_API dnssd_t *dnssd_init(const char *name, int name_len, const char *hw_addr, int hw_addr_len, int *error, int require_pw); DNSSD_API int dnssd_register_raop(dnssd_t *dnssd, unsigned short port); DNSSD_API int dnssd_register_airplay(dnssd_t *dnssd, unsigned short port); DNSSD_API void dnssd_unregister_raop(dnssd_t *dnssd); DNSSD_API void dnssd_unregister_airplay(dnssd_t *dnssd); DNSSD_API const char *dnssd_get_airplay_txt(dnssd_t *dnssd, int *length); DNSSD_API const char *dnssd_get_name(dnssd_t *dnssd, int *length); DNSSD_API const char *dnssd_get_hw_addr(dnssd_t *dnssd, int *length); DNSSD_API void dnssd_set_airplay_features(dnssd_t *dnssd, int bit, int val); DNSSD_API uint64_t dnssd_get_airplay_features(dnssd_t *dnssd); DNSSD_API void dnssd_set_pk(dnssd_t *dnssd, char * pk_str); DNSSD_API void dnssd_destroy(dnssd_t *dnssd); #ifdef __cplusplus } #endif #endif UxPlay-1.71.1/lib/dnssdint.h000066400000000000000000000041371473013662600156050ustar00rootroot00000000000000/** * Copyright (C) 2012 Juho Vähä-Herttua * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * *================================================================== * modified by fduncanh 2022 */ #ifndef DNSSDINT_H #define DNSSDINT_H #include "global.h" /* the previous behavior of announcing UxPlay with a fixed public key PK * can be restored by uncommenting the following line */ //#define PK "b07727d6f6cd6e08b58ede525ec3cdeaa252ad9f683feb212ef8a205246554e7" #define RAOP_TXTVERS "1" #define RAOP_CH "2" /* Audio channels: 2 */ #define RAOP_CN "0,1,2,3" /* Audio codec: PCM, ALAC, AAC, AAC ELD */ #define RAOP_ET "0,3,5" /* Encryption type: None, FairPlay, FairPlay SAPv2.5 */ #define RAOP_VV "2" #define FEATURES_1 "0x5A7FFEE6" /* first 32 bits of features, with bit 27 ("supports legacy pairing") ON */ //#define FEATURES_1 "0x527FFEE6" /* first 32 bits of features, with bit 27 ("supports legacy pairing") OFF */ #define FEATURES_2 "0x0" /* second 32 bits of features */ #define RAOP_RHD "5.6.0.0" #define RAOP_SF "0x4" #define RAOP_SV "false" #define RAOP_DA "true" #define RAOP_SR "44100" /* Sample rate: 44100 */ #define RAOP_SS "16" /* Sample size: 16 */ #define RAOP_VS GLOBAL_VERSION /* defined in global.h */ #define RAOP_TP "UDP" /* Transport protocol. Possible values: UDP or TCP or TCP,UDP */ #define RAOP_MD "0,1,2" /* Metadata: text, artwork, progress */ #define RAOP_VN "65537" #define AIRPLAY_SRCVERS GLOBAL_VERSION /*defined in global.h */ #define AIRPLAY_FLAGS "0x4" #define AIRPLAY_VV "2" #define AIRPLAY_PI "2e388006-13ba-4041-9a67-25dd4a43d536" #endif UxPlay-1.71.1/lib/fairplay.h000066400000000000000000000020311473013662600155550ustar00rootroot00000000000000/** * Copyright (C) 2018 Juho Vähä-Herttua * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. */ #ifndef FAIRPLAY_H #define FAIRPLAY_H #include "logger.h" typedef struct fairplay_s fairplay_t; fairplay_t *fairplay_init(logger_t *logger); int fairplay_setup(fairplay_t *fp, const unsigned char req[16], unsigned char res[142]); int fairplay_handshake(fairplay_t *fp, const unsigned char req[164], unsigned char res[32]); int fairplay_decrypt(fairplay_t *fp, const unsigned char input[72], unsigned char output[16]); void fairplay_destroy(fairplay_t *fp); #endif UxPlay-1.71.1/lib/fairplay_playfair.c000066400000000000000000000116461473013662600174530ustar00rootroot00000000000000/** * Copyright (C) 2018 Juho Vähä-Herttua * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. */ #include #include #include #include "fairplay.h" #include "playfair/playfair.h" char reply_message[4][142] = {{0x46,0x50,0x4c,0x59,0x03,0x01,0x02,0x00,0x00,0x00,0x00,0x82,0x02,0x00,0x0f,0x9f,0x3f,0x9e,0x0a,0x25,0x21,0xdb,0xdf,0x31,0x2a,0xb2,0xbf,0xb2,0x9e,0x8d,0x23,0x2b,0x63,0x76,0xa8,0xc8,0x18,0x70,0x1d,0x22,0xae,0x93,0xd8,0x27,0x37,0xfe,0xaf,0x9d,0xb4,0xfd,0xf4,0x1c,0x2d,0xba,0x9d,0x1f,0x49,0xca,0xaa,0xbf,0x65,0x91,0xac,0x1f,0x7b,0xc6,0xf7,0xe0,0x66,0x3d,0x21,0xaf,0xe0,0x15,0x65,0x95,0x3e,0xab,0x81,0xf4,0x18,0xce,0xed,0x09,0x5a,0xdb,0x7c,0x3d,0x0e,0x25,0x49,0x09,0xa7,0x98,0x31,0xd4,0x9c,0x39,0x82,0x97,0x34,0x34,0xfa,0xcb,0x42,0xc6,0x3a,0x1c,0xd9,0x11,0xa6,0xfe,0x94,0x1a,0x8a,0x6d,0x4a,0x74,0x3b,0x46,0xc3,0xa7,0x64,0x9e,0x44,0xc7,0x89,0x55,0xe4,0x9d,0x81,0x55,0x00,0x95,0x49,0xc4,0xe2,0xf7,0xa3,0xf6,0xd5,0xba}, {0x46,0x50,0x4c,0x59,0x03,0x01,0x02,0x00,0x00,0x00,0x00,0x82,0x02,0x01,0xcf,0x32,0xa2,0x57,0x14,0xb2,0x52,0x4f,0x8a,0xa0,0xad,0x7a,0xf1,0x64,0xe3,0x7b,0xcf,0x44,0x24,0xe2,0x00,0x04,0x7e,0xfc,0x0a,0xd6,0x7a,0xfc,0xd9,0x5d,0xed,0x1c,0x27,0x30,0xbb,0x59,0x1b,0x96,0x2e,0xd6,0x3a,0x9c,0x4d,0xed,0x88,0xba,0x8f,0xc7,0x8d,0xe6,0x4d,0x91,0xcc,0xfd,0x5c,0x7b,0x56,0xda,0x88,0xe3,0x1f,0x5c,0xce,0xaf,0xc7,0x43,0x19,0x95,0xa0,0x16,0x65,0xa5,0x4e,0x19,0x39,0xd2,0x5b,0x94,0xdb,0x64,0xb9,0xe4,0x5d,0x8d,0x06,0x3e,0x1e,0x6a,0xf0,0x7e,0x96,0x56,0x16,0x2b,0x0e,0xfa,0x40,0x42,0x75,0xea,0x5a,0x44,0xd9,0x59,0x1c,0x72,0x56,0xb9,0xfb,0xe6,0x51,0x38,0x98,0xb8,0x02,0x27,0x72,0x19,0x88,0x57,0x16,0x50,0x94,0x2a,0xd9,0x46,0x68,0x8a}, {0x46,0x50,0x4c,0x59,0x03,0x01,0x02,0x00,0x00,0x00,0x00,0x82,0x02,0x02,0xc1,0x69,0xa3,0x52,0xee,0xed,0x35,0xb1,0x8c,0xdd,0x9c,0x58,0xd6,0x4f,0x16,0xc1,0x51,0x9a,0x89,0xeb,0x53,0x17,0xbd,0x0d,0x43,0x36,0xcd,0x68,0xf6,0x38,0xff,0x9d,0x01,0x6a,0x5b,0x52,0xb7,0xfa,0x92,0x16,0xb2,0xb6,0x54,0x82,0xc7,0x84,0x44,0x11,0x81,0x21,0xa2,0xc7,0xfe,0xd8,0x3d,0xb7,0x11,0x9e,0x91,0x82,0xaa,0xd7,0xd1,0x8c,0x70,0x63,0xe2,0xa4,0x57,0x55,0x59,0x10,0xaf,0x9e,0x0e,0xfc,0x76,0x34,0x7d,0x16,0x40,0x43,0x80,0x7f,0x58,0x1e,0xe4,0xfb,0xe4,0x2c,0xa9,0xde,0xdc,0x1b,0x5e,0xb2,0xa3,0xaa,0x3d,0x2e,0xcd,0x59,0xe7,0xee,0xe7,0x0b,0x36,0x29,0xf2,0x2a,0xfd,0x16,0x1d,0x87,0x73,0x53,0xdd,0xb9,0x9a,0xdc,0x8e,0x07,0x00,0x6e,0x56,0xf8,0x50,0xce}, {0x46,0x50,0x4c,0x59,0x03,0x01,0x02,0x00,0x00,0x00,0x00,0x82,0x02,0x03,0x90,0x01,0xe1,0x72,0x7e,0x0f,0x57,0xf9,0xf5,0x88,0x0d,0xb1,0x04,0xa6,0x25,0x7a,0x23,0xf5,0xcf,0xff,0x1a,0xbb,0xe1,0xe9,0x30,0x45,0x25,0x1a,0xfb,0x97,0xeb,0x9f,0xc0,0x01,0x1e,0xbe,0x0f,0x3a,0x81,0xdf,0x5b,0x69,0x1d,0x76,0xac,0xb2,0xf7,0xa5,0xc7,0x08,0xe3,0xd3,0x28,0xf5,0x6b,0xb3,0x9d,0xbd,0xe5,0xf2,0x9c,0x8a,0x17,0xf4,0x81,0x48,0x7e,0x3a,0xe8,0x63,0xc6,0x78,0x32,0x54,0x22,0xe6,0xf7,0x8e,0x16,0x6d,0x18,0xaa,0x7f,0xd6,0x36,0x25,0x8b,0xce,0x28,0x72,0x6f,0x66,0x1f,0x73,0x88,0x93,0xce,0x44,0x31,0x1e,0x4b,0xe6,0xc0,0x53,0x51,0x93,0xe5,0xef,0x72,0xe8,0x68,0x62,0x33,0x72,0x9c,0x22,0x7d,0x82,0x0c,0x99,0x94,0x45,0xd8,0x92,0x46,0xc8,0xc3,0x59}}; char fp_header[] = {0x46, 0x50, 0x4c, 0x59, 0x03, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x14}; struct fairplay_s { logger_t *logger; unsigned char keymsg[164]; unsigned int keymsglen; }; fairplay_t * fairplay_init(logger_t *logger) { fairplay_t *fp; fp = calloc(1, sizeof(fairplay_t)); if (!fp) { return NULL; } fp->logger = logger; return fp; } int fairplay_setup(fairplay_t *fp, const unsigned char req[16], unsigned char res[142]) { int mode; assert(fp); if (req[4] != 0x03) { /* Unsupported fairplay version */ return -1; } mode = req[14]; memcpy(res, reply_message[mode], 142); fp->keymsglen = 0; return 0; } int fairplay_handshake(fairplay_t *fp, const unsigned char req[164], unsigned char res[32]) { assert(fp); if (req[4] != 0x03) { /* Unsupported fairplay version */ return -1; } memcpy(fp->keymsg, req, 164); fp->keymsglen = 164; memcpy(res, fp_header, 12); memcpy(res + 12, req + 144, 20); return 0; } int fairplay_decrypt(fairplay_t *fp, const unsigned char input[72], unsigned char output[16]) { if (fp->keymsglen != 164) { return -1; } playfair_decrypt(fp->keymsg, (unsigned char *) input, output); return 0; } void fairplay_destroy(fairplay_t *fp) { free(fp); } UxPlay-1.71.1/lib/fcup_request.h000066400000000000000000000116761473013662600164720ustar00rootroot00000000000000/* * Copyright (c) 2022 fduncanh * All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * */ /* this file is part of raop.c via http_handlers.h and should not be included in any other file */ //produces the fcup request plist in xml format as a null-terminated string char *create_fcup_request(const char *url, int request_id, const char *client_session_id, int *datalen) { char *plist_xml = NULL; /* values taken from apsdk-public; */ /* these seem to be arbitrary choices */ const int sessionID = 1; const int FCUP_Response_ClientInfo = 1; const int FCUP_Response_ClientRef = 40030004; /* taken from a working AppleTV? */ const char User_Agent[] = "AppleCoreMedia/1.0.0.11B554a (Apple TV; U; CPU OS 7_0_4 like Mac OS X; en_us"; plist_t req_root_node = plist_new_dict(); plist_t session_id_node = plist_new_uint((int64_t) sessionID); plist_dict_set_item(req_root_node, "sessionID", session_id_node); plist_t type_node = plist_new_string("unhandledURLRequest"); plist_dict_set_item(req_root_node, "type", type_node); plist_t fcup_request_node = plist_new_dict(); plist_t client_info_node = plist_new_uint(FCUP_Response_ClientInfo); plist_dict_set_item(fcup_request_node, "FCUP_Response_ClientInfo", client_info_node); plist_t client_ref_node = plist_new_uint((int64_t) FCUP_Response_ClientRef); plist_dict_set_item(fcup_request_node, "FCUP_Response_ClientRef", client_ref_node); plist_t request_id_node = plist_new_uint((int64_t) request_id); plist_dict_set_item(fcup_request_node, "FCUP_Response_RequestID", request_id_node); plist_t url_node = plist_new_string(url); plist_dict_set_item(fcup_request_node, "FCUP_Response_URL", url_node); plist_t session_id1_node = plist_new_uint((int64_t) sessionID); plist_dict_set_item(fcup_request_node, "sessionID", session_id1_node); plist_t fcup_response_header_node = plist_new_dict(); plist_t playback_session_id_node = plist_new_string(client_session_id); plist_dict_set_item(fcup_response_header_node, "X-Playback-Session-Id", playback_session_id_node); plist_t user_agent_node = plist_new_string(User_Agent); plist_dict_set_item(fcup_response_header_node, "User-Agent", user_agent_node); plist_dict_set_item(fcup_request_node, "FCUP_Response_Headers", fcup_response_header_node); plist_dict_set_item(req_root_node, "request", fcup_request_node); uint32_t uint_val; plist_to_xml(req_root_node, &plist_xml, &uint_val); *datalen = (int) uint_val; plist_free(req_root_node); assert(plist_xml[*datalen] == '\0'); return plist_xml; //needs to be freed after use } int fcup_request(void *conn_opaque, const char *media_url, const char *client_session_id, int request_id) { raop_conn_t *conn = (raop_conn_t *) conn_opaque; int datalen = 0; int requestlen; int socket_fd = httpd_get_connection_socket_by_type(conn->raop->httpd, CONNECTION_TYPE_PTTH, 1); logger_log(conn->raop->logger, LOGGER_DEBUG, "fcup_request send socket = %d", socket_fd); /* create xml plist request data */ char *plist_xml = create_fcup_request(media_url, request_id, client_session_id, &datalen); /* use http_response tools for creating the reverse http request */ http_response_t *request = http_response_create(); http_response_reverse_request_init(request, "POST", "/event", "HTTP/1.1"); http_response_add_header(request, "X-Apple-Session-ID", client_session_id); http_response_add_header(request, "Content-Type", "text/x-apple-plist+xml"); http_response_finish(request, plist_xml, datalen); free(plist_xml); const char *http_request = http_response_get_data(request, &requestlen); int send_len = send(socket_fd, http_request, requestlen, 0); if (send_len < 0) { int sock_err = SOCKET_GET_ERROR(); logger_log(conn->raop->logger, LOGGER_ERR, "fcup_request: send error %d:%s\n", sock_err, strerror(sock_err)); http_response_destroy(request); /* shut down connection? */ return -1; } if (logger_get_level(conn->raop->logger) >= LOGGER_DEBUG) { char *request_str = utils_data_to_text(http_request, requestlen); logger_log(conn->raop->logger, LOGGER_DEBUG, "\n%s", request_str); free (request_str); } http_response_destroy(request); logger_log(conn->raop->logger, LOGGER_DEBUG,"fcup_request: send sent Request of %d bytes from socket %d\n", send_len, socket_fd); return 0; } UxPlay-1.71.1/lib/global.h000066400000000000000000000021451473013662600152140ustar00rootroot00000000000000/** * Copyright (C) 2012 Juho Vähä-Herttua * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * *================================================================== * modified by fduncanh 2021-2022 */ #ifndef GLOBAL_H #define GLOBAL_H #define GLOBAL_MODEL "AppleTV3,2" #define GLOBAL_VERSION "220.68" /* use old protocol for audio AES key if client's User-Agent string is contained in these strings */ /* replace xxx by any new User-Agent string as needed */ #define OLD_PROTOCOL_CLIENT_USER_AGENT_LIST "AirMyPC/2.0;xxx" #define DECRYPTION_TEST 0 /* set to 1 or 2 to examine audio decryption */ #define MAX_HWADDR_LEN 6 #endif UxPlay-1.71.1/lib/http_handlers.h000066400000000000000000001153161473013662600166200ustar00rootroot00000000000000/** * Copyright (c) 2024 fduncanh * All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * */ /* this file is part of raop.c and should not be included in any other file */ #include "airplay_video.h" #include "fcup_request.h" static void http_handler_server_info(raop_conn_t *conn, http_request_t *request, http_response_t *response, char **response_data, int *response_datalen) { assert(conn->raop->dnssd); int hw_addr_raw_len = 0; const char *hw_addr_raw = dnssd_get_hw_addr(conn->raop->dnssd, &hw_addr_raw_len); char *hw_addr = calloc(1, 3 * hw_addr_raw_len); //int hw_addr_len = utils_hwaddr_airplay(hw_addr, 3 * hw_addr_raw_len, hw_addr_raw, hw_addr_raw_len); plist_t r_node = plist_new_dict(); /* first 12 AirPlay features bits (R to L): 0x27F = 0010 0111 1111 * Only bits 0-6 and bit 9 are set: * 0. video supported * 1. photo supported * 2. video protected wirh FairPlay DRM * 3. volume control supported for video * 4. HLS supported * 5. slideshow supported * 6. (unknown) * 9. audio supported. */ plist_t features_node = plist_new_uint(0x27F); plist_dict_set_item(r_node, "features", features_node); plist_t mac_address_node = plist_new_string(hw_addr); plist_dict_set_item(r_node, "macAddress", mac_address_node); plist_t model_node = plist_new_string(GLOBAL_MODEL); plist_dict_set_item(r_node, "model", model_node); plist_t os_build_node = plist_new_string("12B435"); plist_dict_set_item(r_node, "osBuildVersion", os_build_node); plist_t protovers_node = plist_new_string("1.0"); plist_dict_set_item(r_node, "protovers", protovers_node); plist_t source_version_node = plist_new_string(GLOBAL_VERSION); plist_dict_set_item(r_node, "srcvers", source_version_node); plist_t vv_node = plist_new_uint(strtol(AIRPLAY_VV, NULL, 10)); plist_dict_set_item(r_node, "vv", vv_node); plist_t device_id_node = plist_new_string(hw_addr); plist_dict_set_item(r_node, "deviceid", device_id_node); plist_to_xml(r_node, response_data, (uint32_t *) response_datalen); //assert(*response_datalen == strlen(*response_data)); /* last character (at *response_data[response_datalen - 1]) is 0x0a = '\n' * (*response_data[response_datalen] is '\0'). * apsdk removes the last "\n" by overwriting it with '\0', and reducing response_datalen by 1. * TODO: check if this is necessary */ plist_free(r_node); http_response_add_header(response, "Content-Type", "text/x-apple-plist+xml"); free(hw_addr); /* initialize the airplay video service */ const char *session_id = http_request_get_header(request, "X-Apple-Session-ID"); airplay_video_service_init(conn->raop, conn->raop->port, session_id); } static void http_handler_scrub(raop_conn_t *conn, http_request_t *request, http_response_t *response, char **response_data, int *response_datalen) { const char *url = http_request_get_url(request); const char *data = strstr(url, "?"); float scrub_position = 0.0f; if (data) { data++; const char *position = strstr(data, "=") + 1; char *end; double value = strtod(position, &end); if (end && end != position) { scrub_position = (float) value; logger_log(conn->raop->logger, LOGGER_DEBUG, "http_handler_scrub: got position = %.6f", scrub_position); } } logger_log(conn->raop->logger, LOGGER_DEBUG, "**********************SCRUB %f ***********************",scrub_position); conn->raop->callbacks.on_video_scrub(conn->raop->callbacks.cls, scrub_position); } static void http_handler_rate(raop_conn_t *conn, http_request_t *request, http_response_t *response, char **response_data, int *response_datalen) { const char *url = http_request_get_url(request); const char *data = strstr(url, "?"); float rate_value = 0.0f; if (data) { data++; const char *rate = strstr(data, "=") + 1; char *end; float value = strtof(rate, &end); if (end && end != rate) { rate_value = value; logger_log(conn->raop->logger, LOGGER_DEBUG, "http_handler_rate: got rate = %.6f", rate_value); } } conn->raop->callbacks.on_video_rate(conn->raop->callbacks.cls, rate_value); } static void http_handler_stop(raop_conn_t *conn, http_request_t *request, http_response_t *response, char **response_data, int *response_datalen) { logger_log(conn->raop->logger, LOGGER_INFO, "client HTTP request POST stop"); conn->raop->callbacks.on_video_stop(conn->raop->callbacks.cls); } /* handles PUT /setProperty http requests from Client to Server */ static void http_handler_set_property(raop_conn_t *conn, http_request_t *request, http_response_t *response, char **response_data, int *response_datalen) { const char *url = http_request_get_url(request); const char *property = url + strlen("/setProperty?"); logger_log(conn->raop->logger, LOGGER_DEBUG, "http_handler_set_property: %s", property); /* actionAtItemEnd: values: 0: advance (advance to next item, if there is one) 1: pause (pause playing) 2: none (do nothing) reverseEndTime (only used when rate < 0) time at which reverse playback ends forwardEndTime (only used when rate > 0) time at which reverse playback ends */ if (!strcmp(property, "reverseEndTime") || !strcmp(property, "forwardEndTime") || !strcmp(property, "actionAtItemEnd")) { logger_log(conn->raop->logger, LOGGER_DEBUG, "property %s is known but unhandled", property); plist_t errResponse = plist_new_dict(); plist_t errCode = plist_new_uint(0); plist_dict_set_item(errResponse, "errorCode", errCode); plist_to_xml(errResponse, response_data, (uint32_t *) response_datalen); plist_free(errResponse); http_response_add_header(response, "Content-Type", "text/x-apple-plist+xml"); } else { logger_log(conn->raop->logger, LOGGER_DEBUG, "property %s is unknown, unhandled", property); http_response_add_header(response, "Content-Length", "0"); } } /* handles GET /getProperty http requests from Client to Server. (not implemented) */ static void http_handler_get_property(raop_conn_t *conn, http_request_t *request, http_response_t *response, char **response_data, int *response_datalen) { const char *url = http_request_get_url(request); const char *property = url + strlen("getProperty?"); logger_log(conn->raop->logger, LOGGER_DEBUG, "http_handler_get_property: %s (unhandled)", property); } /* this request (for a variant FairPlay decryption) cannot be handled by UxPlay */ static void http_handler_fpsetup2(raop_conn_t *conn, http_request_t *request, http_response_t *response, char **response_data, int *response_datalen) { logger_log(conn->raop->logger, LOGGER_WARNING, "client HTTP request POST fp-setup2 is unhandled"); http_response_add_header(response, "Content-Type", "application/x-apple-binary-plist"); int req_datalen; const unsigned char *req_data = (unsigned char *) http_request_get_data(request, &req_datalen); logger_log(conn->raop->logger, LOGGER_ERR, "only FairPlay version 0x03 is implemented, version is 0x%2.2x", req_data[4]); http_response_init(response, "HTTP/1.1", 421, "Misdirected Request"); } // called by http_handler_playback_info while preparing response to a GET /playback_info request from the client. typedef struct time_range_s { double start; double duration; } time_range_t; void time_range_to_plist(void *time_ranges, const int n_time_ranges, plist_t time_ranges_node) { time_range_t *tr = (time_range_t *) time_ranges; for (int i = 0 ; i < n_time_ranges; i++) { plist_t time_range_node = plist_new_dict(); plist_t duration_node = plist_new_real(tr[i].duration); plist_dict_set_item(time_range_node, "duration", duration_node); plist_t start_node = plist_new_real(tr[i].start); plist_dict_set_item(time_range_node, "start", start_node); plist_array_append_item(time_ranges_node, time_range_node); } } // called by http_handler_playback_info while preparing response to a GET /playback_info request from the client. int create_playback_info_plist_xml(playback_info_t *playback_info, char **plist_xml) { plist_t res_root_node = plist_new_dict(); plist_t duration_node = plist_new_real(playback_info->duration); plist_dict_set_item(res_root_node, "duration", duration_node); plist_t position_node = plist_new_real(playback_info->position); plist_dict_set_item(res_root_node, "position", position_node); plist_t rate_node = plist_new_real(playback_info->rate); plist_dict_set_item(res_root_node, "rate", rate_node); /* should these be int or bool? */ plist_t ready_to_play_node = plist_new_uint(playback_info->ready_to_play); plist_dict_set_item(res_root_node, "readyToPlay", ready_to_play_node); plist_t playback_buffer_empty_node = plist_new_uint(playback_info->playback_buffer_empty); plist_dict_set_item(res_root_node, "playbackBufferEmpty", playback_buffer_empty_node); plist_t playback_buffer_full_node = plist_new_uint(playback_info->playback_buffer_full); plist_dict_set_item(res_root_node, "playbackBufferFull", playback_buffer_full_node); plist_t playback_likely_to_keep_up_node = plist_new_uint(playback_info->playback_likely_to_keep_up); plist_dict_set_item(res_root_node, "playbackLikelyToKeepUp", playback_likely_to_keep_up_node); plist_t loaded_time_ranges_node = plist_new_array(); time_range_to_plist(playback_info->loadedTimeRanges, playback_info->num_loaded_time_ranges, loaded_time_ranges_node); plist_dict_set_item(res_root_node, "loadedTimeRanges", loaded_time_ranges_node); plist_t seekable_time_ranges_node = plist_new_array(); time_range_to_plist(playback_info->seekableTimeRanges, playback_info->num_seekable_time_ranges, seekable_time_ranges_node); plist_dict_set_item(res_root_node, "seekableTimeRanges", seekable_time_ranges_node); int len; plist_to_xml(res_root_node, plist_xml, (uint32_t *) &len); /* plist_xml is null-terminated, last character is '/n' */ plist_free(res_root_node); return len; } /* this handles requests from the Client for "Playback information" while the Media is playing on the Media Player. (The Server gets this information by monitoring the Media Player). The Client could use the information to e.g. update the slider it shows with progress to the player (0%-100%). It does not affect playing of the Media*/ static void http_handler_playback_info(raop_conn_t *conn, http_request_t *request, http_response_t *response, char **response_data, int *response_datalen) { logger_log(conn->raop->logger, LOGGER_DEBUG, "http_handler_playback_info"); //const char *session_id = http_request_get_header(request, "X-Apple-Session-ID"); playback_info_t playback_info; playback_info.stallcount = 0; playback_info.ready_to_play = true; // ???; playback_info.playback_buffer_empty = false; // maybe need to get this from playbin playback_info.playback_buffer_full = true; playback_info.playback_likely_to_keep_up = true; conn->raop->callbacks.on_video_acquire_playback_info(conn->raop->callbacks.cls, &playback_info); if (playback_info.duration == -1.0) { /* video has finished, reset */ logger_log(conn->raop->logger, LOGGER_DEBUG, "playback_info not available (finishing)"); //httpd_remove_known_connections(conn->raop->httpd); http_response_set_disconnect(response,1); conn->raop->callbacks.video_reset(conn->raop->callbacks.cls); return; } else if (playback_info.position == -1.0) { logger_log(conn->raop->logger, LOGGER_DEBUG, "playback_info not available"); return; } playback_info.num_loaded_time_ranges = 1; time_range_t time_ranges_loaded[1]; time_ranges_loaded[0].start = playback_info.position; time_ranges_loaded[0].duration = playback_info.duration - playback_info.position; playback_info.loadedTimeRanges = (void *) &time_ranges_loaded; playback_info.num_seekable_time_ranges = 1; time_range_t time_ranges_seekable[1]; time_ranges_seekable[0].start = 0.0; time_ranges_seekable[0].duration = playback_info.position; playback_info.seekableTimeRanges = (void *) &time_ranges_seekable; *response_datalen = create_playback_info_plist_xml(&playback_info, response_data); http_response_add_header(response, "Content-Type", "text/x-apple-plist+xml"); } /* this handles the POST /reverse request from Client to Server on a AirPlay http channel to "Upgrade" to "PTTH/1.0" Reverse HTTP protocol proposed in 2009 Internet-Draft https://datatracker.ietf.org/doc/id/draft-lentczner-rhttp-00.txt . After the Upgrade the channel becomes a reverse http "AirPlay (reversed)" channel for http requests from Server to Client. */ static void http_handler_reverse(raop_conn_t *conn, http_request_t *request, http_response_t *response, char **response_data, int *response_datalen) { /* get http socket for send */ int socket_fd = httpd_get_connection_socket (conn->raop->httpd, (void *) conn); if (socket_fd < 0) { logger_log(conn->raop->logger, LOGGER_ERR, "fcup_request failed to retrieve socket_fd from httpd"); /* shut down connection? */ } const char *purpose = http_request_get_header(request, "X-Apple-Purpose"); const char *connection = http_request_get_header(request, "Connection"); const char *upgrade = http_request_get_header(request, "Upgrade"); logger_log(conn->raop->logger, LOGGER_INFO, "client requested reverse connection: %s; purpose: %s \"%s\"", connection, upgrade, purpose); httpd_set_connection_type(conn->raop->httpd, (void *) conn, CONNECTION_TYPE_PTTH); int type_PTTH = httpd_count_connection_type(conn->raop->httpd, CONNECTION_TYPE_PTTH); if (type_PTTH == 1) { logger_log(conn->raop->logger, LOGGER_DEBUG, "will use socket %d for %s connections", socket_fd, purpose); http_response_init(response, "HTTP/1.1", 101, "Switching Protocols"); http_response_add_header(response, "Connection", "Upgrade"); http_response_add_header(response, "Upgrade", "PTTH/1.0"); } else { logger_log(conn->raop->logger, LOGGER_ERR, "multiple TPPH connections (%d) are forbidden", type_PTTH ); } } /* this copies a Media Playlist into a null-terminated string. If it has the "#YT-EXT-CONDENSED-URI" header, it is also expanded into the full Media Playlist format */ char *adjust_yt_condensed_playlist(const char *media_playlist) { /* expands a YT-EXT_CONDENSED-URL media playlist into a full media playlist * returns a pointer to the expanded playlist, WHICH MUST BE FREED AFTER USE */ const char *base_uri_begin; const char *params_begin; const char *prefix_begin; size_t base_uri_len; size_t params_len; size_t prefix_len; const char* ptr = strstr(media_playlist, "#EXTM3U\n"); ptr += strlen("#EXTM3U\n"); assert(ptr); if (strncmp(ptr, "#YT-EXT-CONDENSED-URL", strlen("#YT-EXT-CONDENSED-URL"))) { size_t len = strlen(media_playlist); char * playlist_copy = (char *) malloc(len + 1); memcpy(playlist_copy, media_playlist, len); playlist_copy[len] = '\0'; return playlist_copy; } ptr = strstr(ptr, "BASE-URI="); base_uri_begin = strchr(ptr, '"'); base_uri_begin++; ptr = strchr(base_uri_begin, '"'); base_uri_len = ptr - base_uri_begin; char *base_uri = (char *) calloc(base_uri_len + 1, sizeof(char)); assert(base_uri); memcpy(base_uri, base_uri_begin, base_uri_len); //must free ptr = strstr(ptr, "PARAMS="); params_begin = strchr(ptr, '"'); params_begin++; ptr = strchr(params_begin,'"'); params_len = ptr - params_begin; char *params = (char *) calloc(params_len + 1, sizeof(char)); assert(params); memcpy(params, params_begin, params_len); //must free ptr = strstr(ptr, "PREFIX="); prefix_begin = strchr(ptr, '"'); prefix_begin++; ptr = strchr(prefix_begin,'"'); prefix_len = ptr - prefix_begin; char *prefix = (char *) calloc(prefix_len + 1, sizeof(char)); assert(prefix); memcpy(prefix, prefix_begin, prefix_len); //must free /* expand params */ int nparams = 0; int *params_size = NULL; const char **params_start = NULL; if (strlen(params)) { nparams = 1; char * comma = strchr(params, ','); while (comma) { nparams++; comma++; comma = strchr(comma, ','); } params_start = (const char **) calloc(nparams, sizeof(char *)); //must free params_size = (int *) calloc(nparams, sizeof(int)); //must free ptr = params; for (int i = 0; i < nparams; i++) { comma = strchr(ptr, ','); params_start[i] = ptr; if (comma) { params_size[i] = (int) (comma - ptr); ptr = comma; ptr++; } else { params_size[i] = (int) (params + params_len - ptr); break; } } } int count = 0; ptr = strstr(media_playlist, "#EXTINF"); while (ptr) { count++; ptr = strstr(++ptr, "#EXTINF"); } size_t old_size = strlen(media_playlist); size_t new_size = old_size; new_size += count * (base_uri_len + params_len); char * new_playlist = (char *) calloc( new_size + 100, sizeof(char)); const char *old_pos = media_playlist; char *new_pos = new_playlist; ptr = old_pos; ptr = strstr(old_pos, "#EXTINF:"); size_t len = ptr - old_pos; /* copy header section before chunks */ memcpy(new_pos, old_pos, len); old_pos += len; new_pos += len; int counter = 0; while (ptr) { counter++; /* for each chunk */ const char *end = NULL; char *start = strstr(ptr, prefix); len = start - ptr; /* copy first line of chunk entry */ memcpy(new_pos, old_pos, len); old_pos += len; new_pos += len; /* copy base uri to replace prefix*/ memcpy(new_pos, base_uri, base_uri_len); new_pos += base_uri_len; old_pos += prefix_len; ptr = strstr(old_pos, "#EXTINF:"); /* insert the PARAMS separators on the slices line */ end = old_pos; int last = nparams - 1; for (int i = 0; i < nparams; i++) { if (i != last) { end = strchr(end, '/'); } else { end = strstr(end, "#EXT"); /* the next line starts with either #EXTINF (usually) or #EXT-X-ENDLIST (at last chunk)*/ } *new_pos = '/'; new_pos++; memcpy(new_pos, params_start[i], params_size[i]); new_pos += params_size[i]; *new_pos = '/'; new_pos++; len = end - old_pos; end++; memcpy (new_pos, old_pos, len); new_pos += len; old_pos += len; if (i != last) { old_pos++; /* last entry is not followed by "/" separator */ } } } /* copy tail */ len = media_playlist + strlen(media_playlist) - old_pos; memcpy(new_pos, old_pos, len); new_pos += len; old_pos += len; new_playlist[new_size] = '\0'; free (prefix); free (base_uri); free (params); if (params_size) { free (params_size); } if (params_start) { free (params_start); } return new_playlist; } /* this adjusts the uri prefixes in the Master Playlist, for sending to the Media Player running on the Server Host */ char *adjust_master_playlist (char *fcup_response_data, int fcup_response_datalen, char *uri_prefix, char *uri_local_prefix) { size_t uri_prefix_len = strlen(uri_prefix); size_t uri_local_prefix_len = strlen(uri_local_prefix); int counter = 0; char *ptr = strstr(fcup_response_data, uri_prefix); while (ptr != NULL) { counter++; ptr++; ptr = strstr(ptr, uri_prefix); } size_t len = uri_local_prefix_len - uri_prefix_len; len *= counter; len += fcup_response_datalen; char *new_master = (char *) malloc(len + 1); *(new_master + len) = '\0'; char *first = fcup_response_data; char *new = new_master; char *last = strstr(first, uri_prefix); counter = 0; while (last != NULL) { counter++; len = last - first; memcpy(new, first, len); first = last + uri_prefix_len; new += len; memcpy(new, uri_local_prefix, uri_local_prefix_len); new += uri_local_prefix_len; last = strstr(last + uri_prefix_len, uri_prefix); if (last == NULL) { len = fcup_response_data + fcup_response_datalen - first; memcpy(new, first, len); break; } } return new_master; } /* this parses the Master Playlist to make a table of the Media Playlist uri's that it lists */ int create_media_uri_table(const char *url_prefix, const char *master_playlist_data, int datalen, char ***media_uri_table, int *num_uri) { char *ptr = strstr(master_playlist_data, url_prefix); char ** table = NULL; if (ptr == NULL) { return -1; } int count = 0; while (ptr != NULL) { char *end = strstr(ptr, "m3u8"); if (end == NULL) { return 1; } end += sizeof("m3u8"); count++; ptr = strstr(end, url_prefix); } table = (char **) calloc(count, sizeof(char *)); if (!table) { return -1; } for (int i = 0; i < count; i++) { table[i] = NULL; } ptr = strstr(master_playlist_data, url_prefix); count = 0; while (ptr != NULL) { char *end = strstr(ptr, "m3u8"); char *uri; if (end == NULL) { return 0; } end += sizeof("m3u8"); size_t len = end - ptr - 1; uri = (char *) calloc(len + 1, sizeof(char)); memcpy(uri , ptr, len); table[count] = uri; uri = NULL; count ++; ptr = strstr(end, url_prefix); } *num_uri = count; *media_uri_table = table; return 0; } /* the POST /action request from Client to Server on the AirPlay http channel follows a POST /event "FCUP Request" from Server to Client on the reverse http channel, for a HLS playlist (first the Master Playlist, then the Media Playlists listed in the Master Playlist. The POST /action request contains the playlist requested by the Server in the preceding "FCUP Request". The FCUP Request sequence continues until all Media Playlists have been obtained by the Server */ static void http_handler_action(raop_conn_t *conn, http_request_t *request, http_response_t *response, char **response_data, int *response_datalen) { bool data_is_plist = false; plist_t req_root_node = NULL; uint64_t uint_val; int request_id = 0; int fcup_response_statuscode = 0; bool logger_debug = (logger_get_level(conn->raop->logger) >= LOGGER_DEBUG); const char* session_id = http_request_get_header(request, "X-Apple-Session-ID"); if (!session_id) { logger_log(conn->raop->logger, LOGGER_ERR, "Play request had no X-Apple-Session-ID"); goto post_action_error; } const char *apple_session_id = get_apple_session_id(conn->raop->airplay_video); if (strcmp(session_id, apple_session_id)){ logger_log(conn->raop->logger, LOGGER_ERR, "X-Apple-Session-ID has changed:\n was:\"%s\"\n now:\"%s\"", apple_session_id, session_id); goto post_action_error; } /* verify that this request contains a binary plist*/ char *header_str = NULL; http_request_get_header_string(request, &header_str); logger_log(conn->raop->logger, LOGGER_DEBUG, "request header: %s", header_str); data_is_plist = (strstr(header_str,"apple-binary-plist") != NULL); free(header_str); if (!data_is_plist) { logger_log(conn->raop->logger, LOGGER_INFO, "POST /action: did not receive expected plist from client"); goto post_action_error; } /* extract the root_node plist */ int request_datalen = 0; const char *request_data = http_request_get_data(request, &request_datalen); if (request_datalen == 0) { logger_log(conn->raop->logger, LOGGER_INFO, "POST /action: did not receive expected plist from client"); goto post_action_error; } plist_from_bin(request_data, request_datalen, &req_root_node); /* determine type of data */ plist_t req_type_node = plist_dict_get_item(req_root_node, "type"); if (!PLIST_IS_STRING(req_type_node)) { goto post_action_error; } /* three possible types are known */ char *type = NULL; int action_type = 0; plist_get_string_val(req_type_node, &type); logger_log(conn->raop->logger, LOGGER_DEBUG, "action type is %s", type); if (strstr(type, "unhandledURLResponse")) { action_type = 1; } else if (strstr(type, "playlistInsert")) { action_type = 2; } else if (strstr(type, "playlistRemove")) { action_type = 3; } free (type); plist_t req_params_node = NULL; switch (action_type) { case 1: goto unhandledURLResponse; case 2: logger_log(conn->raop->logger, LOGGER_INFO, "unhandled action type playlistInsert (add new playback)"); goto finish; case 3: logger_log(conn->raop->logger, LOGGER_INFO, "unhandled action type playlistRemove (stop playback)"); goto finish; default: logger_log(conn->raop->logger, LOGGER_INFO, "unknown action type (unhandled)"); goto finish; } unhandledURLResponse:; req_params_node = plist_dict_get_item(req_root_node, "params"); if (!PLIST_IS_DICT (req_params_node)) { goto post_action_error; } /* handling type "unhandledURLResponse" (case 1)*/ uint_val = 0; int fcup_response_datalen = 0; if (logger_debug) { plist_t plist_fcup_response_statuscode_node = plist_dict_get_item(req_params_node, "FCUP_Response_StatusCode"); if (plist_fcup_response_statuscode_node) { plist_get_uint_val(plist_fcup_response_statuscode_node, &uint_val); fcup_response_statuscode = (int) uint_val; uint_val = 0; logger_log(conn->raop->logger, LOGGER_DEBUG, "FCUP_Response_StatusCode = %d", fcup_response_statuscode); } plist_t plist_fcup_response_requestid_node = plist_dict_get_item(req_params_node, "FCUP_Response_RequestID"); if (plist_fcup_response_requestid_node) { plist_get_uint_val(plist_fcup_response_requestid_node, &uint_val); request_id = (int) uint_val; uint_val = 0; logger_log(conn->raop->logger, LOGGER_DEBUG, "FCUP_Response_RequestID = %d", request_id); } } plist_t plist_fcup_response_url_node = plist_dict_get_item(req_params_node, "FCUP_Response_URL"); if (!PLIST_IS_STRING(plist_fcup_response_url_node)) { goto post_action_error; } char *fcup_response_url = NULL; plist_get_string_val(plist_fcup_response_url_node, &fcup_response_url); if (!fcup_response_url) { goto post_action_error; } logger_log(conn->raop->logger, LOGGER_DEBUG, "FCUP_Response_URL = %s", fcup_response_url); plist_t plist_fcup_response_data_node = plist_dict_get_item(req_params_node, "FCUP_Response_Data"); if (!PLIST_IS_DATA(plist_fcup_response_data_node)){ goto post_action_error; } uint_val = 0; char *fcup_response_data = NULL; plist_get_data_val(plist_fcup_response_data_node, &fcup_response_data, &uint_val); fcup_response_datalen = (int) uint_val; if (!fcup_response_data) { free (fcup_response_url); goto post_action_error; } if (logger_debug) { logger_log(conn->raop->logger, LOGGER_DEBUG, "FCUP_Response datalen = %d", fcup_response_datalen); char *data = malloc(fcup_response_datalen + 1); memcpy(data, fcup_response_data, fcup_response_datalen); data[fcup_response_datalen] = '\0'; logger_log(conn->raop->logger, LOGGER_DEBUG, "begin FCUP Response data:\n%s\nend FCUP Response data",data); free (data); } char *ptr = strstr(fcup_response_url, "/master.m3u8"); if (ptr) { /* this is a master playlist */ char *uri_prefix = get_uri_prefix(conn->raop->airplay_video); char ** media_data_store = NULL; int num_uri = 0; char *uri_local_prefix = get_uri_local_prefix(conn->raop->airplay_video); char *new_master = adjust_master_playlist (fcup_response_data, fcup_response_datalen, uri_prefix, uri_local_prefix); store_master_playlist(conn->raop->airplay_video, new_master); create_media_uri_table(uri_prefix, fcup_response_data, fcup_response_datalen, &media_data_store, &num_uri); create_media_data_store(conn->raop->airplay_video, media_data_store, num_uri); num_uri = get_num_media_uri(conn->raop->airplay_video); set_next_media_uri_id(conn->raop->airplay_video, 0); } else { /* this is a media playlist */ assert(fcup_response_data); char *playlist = (char *) calloc(fcup_response_datalen + 1, sizeof(char)); memcpy(playlist, fcup_response_data, fcup_response_datalen); int uri_num = get_next_media_uri_id(conn->raop->airplay_video); --uri_num; // (next num is current num + 1) store_media_data_playlist_by_num(conn->raop->airplay_video, playlist, uri_num); float duration = 0.0f; int count = analyze_media_playlist(playlist, &duration); if (count) { logger_log(conn->raop->logger, LOGGER_DEBUG, "\n%s:\nreceived media playlist has %5d chunks, total duration %9.3f secs\n", fcup_response_url, count, duration); } } if (fcup_response_data) { free (fcup_response_data); } if (fcup_response_url) { free (fcup_response_url); } int num_uri = get_num_media_uri(conn->raop->airplay_video); int uri_num = get_next_media_uri_id(conn->raop->airplay_video); if (uri_num < num_uri) { fcup_request((void *) conn, get_media_uri_by_num(conn->raop->airplay_video, uri_num), apple_session_id, get_next_FCUP_RequestID(conn->raop->airplay_video)); set_next_media_uri_id(conn->raop->airplay_video, ++uri_num); } else { char * uri_local_prefix = get_uri_local_prefix(conn->raop->airplay_video); conn->raop->callbacks.on_video_play(conn->raop->callbacks.cls, strcat(uri_local_prefix, "/master.m3u8"), get_start_position_seconds(conn->raop->airplay_video)); } finish: plist_free(req_root_node); return; post_action_error:; http_response_init(response, "HTTP/1.1", 400, "Bad Request"); if (req_root_node) { plist_free(req_root_node); } } /* The POST /play request from the Client to Server on the AirPlay http channel contains (among other information) the "Content Location" that specifies the HLS Playlists for the video to be streamed, as well as the video "start position in seconds". Once this request is received by the Sever, the Server sends a POST /event "FCUP Request" request to the Client on the reverse http channel, to request the HLS Master Playlist */ static void http_handler_play(raop_conn_t *conn, http_request_t *request, http_response_t *response, char **response_data, int *response_datalen) { char* playback_location = NULL; plist_t req_root_node = NULL; float start_position_seconds = 0.0f; bool data_is_binary_plist = false; bool data_is_text = false; bool data_is_octet = false; logger_log(conn->raop->logger, LOGGER_DEBUG, "http_handler_play"); const char* session_id = http_request_get_header(request, "X-Apple-Session-ID"); if (!session_id) { logger_log(conn->raop->logger, LOGGER_ERR, "Play request had no X-Apple-Session-ID"); goto play_error; } const char *apple_session_id = get_apple_session_id(conn->raop->airplay_video); if (strcmp(session_id, apple_session_id)){ logger_log(conn->raop->logger, LOGGER_ERR, "X-Apple-Session-ID has changed:\n was:\"%s\"\n now:\"%s\"", apple_session_id, session_id); goto play_error; } int request_datalen = -1; const char *request_data = http_request_get_data(request, &request_datalen); if (request_datalen > 0) { char *header_str = NULL; http_request_get_header_string(request, &header_str); logger_log(conn->raop->logger, LOGGER_DEBUG, "request header:\n%s", header_str); data_is_binary_plist = (strstr(header_str, "x-apple-binary-plist") != NULL); data_is_text = (strstr(header_str, "text/parameters") != NULL); data_is_octet = (strstr(header_str, "octet-stream") != NULL); free (header_str); } if (!data_is_text && !data_is_octet && !data_is_binary_plist) { goto play_error; } if (data_is_text) { logger_log(conn->raop->logger, LOGGER_ERR, "Play request Content is text (unsupported)"); goto play_error; } if (data_is_octet) { logger_log(conn->raop->logger, LOGGER_ERR, "Play request Content is octet-stream (unsupported)"); goto play_error; } if (data_is_binary_plist) { plist_from_bin(request_data, request_datalen, &req_root_node); plist_t req_uuid_node = plist_dict_get_item(req_root_node, "uuid"); if (!req_uuid_node) { goto play_error; } else { char* playback_uuid = NULL; plist_get_string_val(req_uuid_node, &playback_uuid); set_playback_uuid(conn->raop->airplay_video, playback_uuid); free (playback_uuid); } plist_t req_content_location_node = plist_dict_get_item(req_root_node, "Content-Location"); if (!req_content_location_node) { goto play_error; } else { plist_get_string_val(req_content_location_node, &playback_location); } plist_t req_start_position_seconds_node = plist_dict_get_item(req_root_node, "Start-Position-Seconds"); if (!req_start_position_seconds_node) { logger_log(conn->raop->logger, LOGGER_INFO, "No Start-Position-Seconds in Play request"); } else { double start_position = 0.0; plist_get_real_val(req_start_position_seconds_node, &start_position); start_position_seconds = (float) start_position; } set_start_position_seconds(conn->raop->airplay_video, (float) start_position_seconds); } char *ptr = strstr(playback_location, "/master.m3u8"); int prefix_len = (int) (ptr - playback_location); set_uri_prefix(conn->raop->airplay_video, playback_location, prefix_len); set_next_media_uri_id(conn->raop->airplay_video, 0); fcup_request((void *) conn, playback_location, apple_session_id, get_next_FCUP_RequestID(conn->raop->airplay_video)); if (playback_location) { free (playback_location); } if (req_root_node) { plist_free(req_root_node); } return; play_error:; if (req_root_node) { plist_free(req_root_node); } logger_log(conn->raop->logger, LOGGER_ERR, "Could not find valid Plist Data for /play, Unhandled"); http_response_init(response, "HTTP/1.1", 400, "Bad Request"); } /* the HLS handler handles http requests GET /[uri] on the HLS channel from the media player to the Server, asking for (adjusted) copies of Playlists: first the Master Playlist (adjusted to change the uri prefix to "http://localhost:[port]/.......m3u8"), then the Media Playlists that the media player wishes to use. If the client supplied Media playlists with the "YT-EXT-CONDENSED-URI" header, these must be adjusted into the standard uncondensed form before sending with the response. The uri in the request is the uri for the Media Playlist, taken from the Master Playlist, with the uri prefix removed. */ static void http_handler_hls(raop_conn_t *conn, http_request_t *request, http_response_t *response, char **response_data, int *response_datalen) { const char *method = http_request_get_method(request); assert (!strcmp(method, "GET")); const char *url = http_request_get_url(request); const char* upgrade = http_request_get_header(request, "Upgrade"); if (upgrade) { //don't accept Upgrade: h2c request ? return; } if (!strcmp(url, "/master.m3u8")){ char * master_playlist = get_master_playlist(conn->raop->airplay_video); size_t len = strlen(master_playlist); char * data = (char *) malloc(len + 1); memcpy(data, master_playlist, len); data[len] = '\0'; *response_data = data; *response_datalen = (int ) len; } else { int num = get_media_playlist_by_uri(conn->raop->airplay_video, url); if (num < 0) { logger_log(conn->raop->logger, LOGGER_ERR,"Requested playlist %s not found", url); assert(0); } else { char *media_playlist = get_media_playlist_by_num(conn->raop->airplay_video, num); assert(media_playlist); char *data = adjust_yt_condensed_playlist(media_playlist); *response_data = data; *response_datalen = strlen(data); float duration = 0.0f; int chunks = analyze_media_playlist(data, &duration); logger_log(conn->raop->logger, LOGGER_INFO, "Requested media_playlist %s has %5d chunks, total duration %9.3f secs", url, chunks, duration); } } http_response_add_header(response, "Access-Control-Allow-Headers", "Content-type"); http_response_add_header(response, "Access-Control-Allow-Origin", "*"); const char *date; date = gmt_time_string(); http_response_add_header(response, "Date", date); if (*response_datalen > 0) { http_response_add_header(response, "Content-Type", "application/x-mpegURL; charset=utf-8"); } else if (*response_datalen == 0) { http_response_init(response, "HTTP/1.1", 404, "Not Found"); } } UxPlay-1.71.1/lib/http_request.c000066400000000000000000000203501473013662600164740ustar00rootroot00000000000000/** * Copyright (C) 2011-2012 Juho Vähä-Herttua * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * *================================================================== * modified by fduncanh 2021 */ #include #include #include #include #include "http_request.h" #include "llhttp/llhttp.h" struct http_request_s { llhttp_t parser; llhttp_settings_t parser_settings; bool is_reverse; // if true, this is a reverse-response from client const char *method; char *url; char protocol[9]; char **headers; int headers_size; int headers_index; char *data; int datalen; int complete; }; static int on_url(llhttp_t *parser, const char *at, size_t length) { http_request_t *request = parser->data; int urllen = request->url ? strlen(request->url) : 0; request->url = realloc(request->url, urllen+length+1); assert(request->url); request->url[urllen] = '\0'; strncat(request->url, at, length); strncpy(request->protocol, at + length + 1, 8); return 0; } static int on_header_field(llhttp_t *parser, const char *at, size_t length) { http_request_t *request = parser->data; /* Check if our index is a value */ if (request->headers_index%2 == 1) { request->headers_index++; } /* Allocate space for new field-value pair */ if (request->headers_index == request->headers_size) { request->headers_size += 2; request->headers = realloc(request->headers, request->headers_size*sizeof(char*)); assert(request->headers); request->headers[request->headers_index] = NULL; request->headers[request->headers_index+1] = NULL; } /* Allocate space in the current header string */ if (request->headers[request->headers_index] == NULL) { request->headers[request->headers_index] = calloc(1, length+1); } else { request->headers[request->headers_index] = realloc( request->headers[request->headers_index], strlen(request->headers[request->headers_index])+length+1 ); } assert(request->headers[request->headers_index]); strncat(request->headers[request->headers_index], at, length); return 0; } static int on_header_value(llhttp_t *parser, const char *at, size_t length) { http_request_t *request = parser->data; /* Check if our index is a field */ if (request->headers_index%2 == 0) { request->headers_index++; } /* Allocate space in the current header string */ if (request->headers[request->headers_index] == NULL) { request->headers[request->headers_index] = calloc(1, length+1); } else { request->headers[request->headers_index] = realloc( request->headers[request->headers_index], strlen(request->headers[request->headers_index])+length+1 ); } assert(request->headers[request->headers_index]); strncat(request->headers[request->headers_index], at, length); return 0; } static int on_body(llhttp_t *parser, const char *at, size_t length) { http_request_t *request = parser->data; request->data = realloc(request->data, request->datalen+length); assert(request->data); memcpy(request->data+request->datalen, at, length); request->datalen += length; return 0; } static int on_message_complete(llhttp_t *parser) { http_request_t *request = parser->data; request->method = llhttp_method_name(request->parser.method); request->complete = 1; return 0; } http_request_t * http_request_init(void) { http_request_t *request; request = calloc(1, sizeof(http_request_t)); if (!request) { return NULL; } llhttp_settings_init(&request->parser_settings); request->parser_settings.on_url = &on_url; request->parser_settings.on_header_field = &on_header_field; request->parser_settings.on_header_value = &on_header_value; request->parser_settings.on_body = &on_body; request->parser_settings.on_message_complete = &on_message_complete; llhttp_init(&request->parser, HTTP_REQUEST, &request->parser_settings); request->parser.data = request; request->is_reverse = false; return request; } void http_request_destroy(http_request_t *request) { int i; if (request) { free(request->url); for (i=0; iheaders_size; i++) { free(request->headers[i]); } free(request->headers); free(request->data); free(request); } } int http_request_add_data(http_request_t *request, const char *data, int datalen) { int ret; assert(request); ret = llhttp_execute(&request->parser, data, datalen); /* support for "Upgrade" to reverse http ("PTTH/1.0") protocol */ llhttp_resume_after_upgrade(&request->parser); return ret; } int http_request_is_complete(http_request_t *request) { assert(request); return request->complete; } int http_request_has_error(http_request_t *request) { assert(request); if (request->is_reverse) { return 0; } return (llhttp_get_errno(&request->parser) != HPE_OK); } const char * http_request_get_error_name(http_request_t *request) { assert(request); if (request->is_reverse) { return NULL; } return llhttp_errno_name(llhttp_get_errno(&request->parser)); } const char * http_request_get_error_description(http_request_t *request) { assert(request); if (request->is_reverse) { return NULL; } return llhttp_get_error_reason(&request->parser); } const char * http_request_get_method(http_request_t *request) { assert(request); if (request->is_reverse) { return NULL; } return request->method; } const char * http_request_get_url(http_request_t *request) { assert(request); if (request->is_reverse) { return NULL; } return request->url; } const char * http_request_get_protocol(http_request_t *request) { assert(request); if (request->is_reverse) { return NULL; } return request->protocol; } const char * http_request_get_header(http_request_t *request, const char *name) { int i; assert(request); if (request->is_reverse) { return NULL; } for (i=0; iheaders_size; i+=2) { if (!strcmp(request->headers[i], name)) { return request->headers[i+1]; } } return NULL; } const char * http_request_get_data(http_request_t *request, int *datalen) { assert(request); if (datalen) { *datalen = request->datalen; } return request->data; } int http_request_get_header_string(http_request_t *request, char **header_str) { if(!request || request->headers_size == 0) { *header_str = NULL; return 0; } if (request->is_reverse) { *header_str = NULL; return 0; } int len = 0; for (int i = 0; i < request->headers_size; i++) { len += strlen(request->headers[i]); if (i%2 == 0) { len += 2; } else { len++; } } char *str = calloc(len+1, sizeof(char)); assert(str); *header_str = str; char *p = str; int n = len + 1; for (int i = 0; i < request->headers_size; i++) { int hlen = strlen(request->headers[i]); snprintf(p, n, "%s", request->headers[i]); n -= hlen; p += hlen; if (i%2 == 0) { snprintf(p, n, ": "); n -= 2; p += 2; } else { snprintf(p, n, "\n"); n--; p++; } } assert(p == &(str[len])); return len; } bool http_request_is_reverse(http_request_t *request) { return request->is_reverse; } void http_request_set_reverse(http_request_t *request) { request->is_reverse = true; } UxPlay-1.71.1/lib/http_request.h000066400000000000000000000032021473013662600164760ustar00rootroot00000000000000/** * Copyright (C) 2011-2012 Juho Vähä-Herttua * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. */ #ifndef HTTP_REQUEST_H #define HTTP_REQUEST_H #include typedef struct http_request_s http_request_t; http_request_t *http_request_init(void); int http_request_add_data(http_request_t *request, const char *data, int datalen); int http_request_is_complete(http_request_t *request); int http_request_has_error(http_request_t *request); const char *http_request_get_error_name(http_request_t *request); const char *http_request_get_error_description(http_request_t *request); const char *http_request_get_method(http_request_t *request); const char *http_request_get_url(http_request_t *request); const char *http_request_get_protocol(http_request_t *request); const char *http_request_get_header(http_request_t *request, const char *name); const char *http_request_get_data(http_request_t *request, int *datalen); int http_request_get_header_string(http_request_t *request, char **header_str); bool http_request_is_reverse(http_request_t *request); void http_request_set_reverse(http_request_t *request); void http_request_destroy(http_request_t *request); #endif UxPlay-1.71.1/lib/http_response.c000066400000000000000000000132421473013662600166440ustar00rootroot00000000000000/** * Copyright (C) 2011-2012 Juho Vähä-Herttua * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. */ #include #include #include #include #include "http_response.h" #include "compat.h" struct http_response_s { int complete; int disconnect; char *data; int data_size; int data_length; }; static void http_response_add_data(http_response_t *response, const char *data, int datalen) { int newdatasize; assert(response); assert(data); assert(datalen > 0); newdatasize = response->data_size; while (response->data_size+datalen > newdatasize) { newdatasize *= 2; } if (newdatasize != response->data_size) { response->data = realloc(response->data, newdatasize); assert(response->data); } memcpy(response->data+response->data_length, data, datalen); response->data_length += datalen; } http_response_t * http_response_create() { http_response_t *response = (http_response_t *) calloc(1, sizeof(http_response_t)); if (!response) { return NULL; } /* Allocate response data */ response->data_size = 1024; response->data = (char *) malloc(response->data_size); if (!response->data) { free(response); return NULL; } return response; } void http_response_init(http_response_t *response, const char *protocol, int code, const char *message) { assert(response); response->data_length = 0; /* can be used to reinitialize a previously-initialized response */ char codestr[4]; assert(code >= 100 && code < 1000); /* Convert code into string */ memset(codestr, 0, sizeof(codestr)); snprintf(codestr, sizeof(codestr), "%u", code); /* Add first line of response to the data array */ http_response_add_data(response, protocol, strlen(protocol)); http_response_add_data(response, " ", 1); http_response_add_data(response, codestr, strlen(codestr)); http_response_add_data(response, " ", 1); http_response_add_data(response, message, strlen(message)); http_response_add_data(response, "\r\n", 2); } void http_response_reverse_request_init(http_response_t *request, const char *method, const char *url, const char *protocol) { assert(request); request->data_length = 0; /* reinitialize a previously-initialized response as a reverse-HTTP (PTTH/1.0) request */ /* Add first line of response to the data array */ http_response_add_data(request, method, strlen(method)); http_response_add_data(request, " ", 1); http_response_add_data(request, url, strlen(url)); http_response_add_data(request, " ", 1); http_response_add_data(request, protocol, strlen(protocol)); http_response_add_data(request, "\r\n", 2); } void http_response_destroy(http_response_t *response) { if (response) { free(response->data); free(response); } } void http_response_add_header(http_response_t *response, const char *name, const char *value) { assert(response); assert(name); assert(value); http_response_add_data(response, name, strlen(name)); http_response_add_data(response, ": ", 2); http_response_add_data(response, value, strlen(value)); http_response_add_data(response, "\r\n", 2); } void http_response_finish(http_response_t *response, const char *data, int datalen) { assert(response); assert(datalen==0 || (data && datalen > 0)); if (data && datalen > 0) { const char *hdrname = "Content-Length"; char hdrvalue[16]; memset(hdrvalue, 0, sizeof(hdrvalue)); snprintf(hdrvalue, sizeof(hdrvalue)-1, "%d", datalen); /* Add Content-Length header first */ http_response_add_data(response, hdrname, strlen(hdrname)); http_response_add_data(response, ": ", 2); http_response_add_data(response, hdrvalue, strlen(hdrvalue)); http_response_add_data(response, "\r\n\r\n", 4); /* Add data to the end of response */ http_response_add_data(response, data, datalen); } else { /* check for "Content-Type" header, with datalen = 0 */ const char *item = "Content-Type"; int item_len = strlen(item); const char *part = response->data; int end = response->data_length - item_len; for (int i = 0; i < end; i++) { if (memcmp (part, item, item_len) == 0) { const char *hdrname = "Content-Length: 0"; http_response_add_data(response, hdrname, strlen(hdrname)); http_response_add_data(response, "\r\n", 2); break; } part++; } /* Add extra end of line after headers */ http_response_add_data(response, "\r\n", 2); } response->complete = 1; } void http_response_set_disconnect(http_response_t *response, int disconnect) { assert(response); response->disconnect = !!disconnect; } int http_response_get_disconnect(http_response_t *response) { assert(response); return response->disconnect; } const char * http_response_get_data(http_response_t *response, int *datalen) { assert(response); assert(datalen); assert(response->complete); *datalen = response->data_length; return response->data; } UxPlay-1.71.1/lib/http_response.h000066400000000000000000000030221473013662600166440ustar00rootroot00000000000000/** * Copyright (C) 2011-2012 Juho Vähä-Herttua * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * *============================================================== * modified fduncanh 2024 */ #ifndef HTTP_RESPONSE_H #define HTTP_RESPONSE_H typedef struct http_response_s http_response_t; http_response_t *http_response_create(); void http_response_init(http_response_t *response, const char *protocol, int code, const char *message); void http_response_reverse_request_init(http_response_t *request, const char *method, const char *url, const char *protocol); void http_response_add_header(http_response_t *response, const char *name, const char *value); void http_response_finish(http_response_t *response, const char *data, int datalen); void http_response_set_disconnect(http_response_t *response, int disconnect); int http_response_get_disconnect(http_response_t *response); const char *http_response_get_data(http_response_t *response, int *datalen); void http_response_destroy(http_response_t *response); #endif UxPlay-1.71.1/lib/httpd.c000066400000000000000000000526421473013662600151010ustar00rootroot00000000000000/** * Copyright (C) 2011-2012 Juho Vähä-Herttua * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * *=================================================================== * modified by fduncanh 2022 */ #include #include #include #include #include #include #include "httpd.h" #include "netutils.h" #include "http_request.h" #include "compat.h" #include "logger.h" #include "utils.h" static const char *typename[] = { [CONNECTION_TYPE_UNKNOWN] = "Unknown", [CONNECTION_TYPE_RAOP] = "RAOP", [CONNECTION_TYPE_AIRPLAY] = "AirPlay", [CONNECTION_TYPE_PTTH] = "AirPlay (reversed)", [CONNECTION_TYPE_HLS] = "HLS" }; struct http_connection_s { int connected; int socket_fd; void *user_data; connection_type_t type; http_request_t *request; }; typedef struct http_connection_s http_connection_t; struct httpd_s { logger_t *logger; httpd_callbacks_t callbacks; int max_connections; int open_connections; http_connection_t *connections; char nohold; /* These variables only edited mutex locked */ int running; int joined; thread_handle_t thread; mutex_handle_t run_mutex; /* Server fds for accepting connections */ int server_fd4; int server_fd6; }; const char * httpd_get_connection_typename (connection_type_t type) { return typename[type]; } int httpd_get_connection_socket (httpd_t *httpd, void *user_data) { for (int i = 0; i < httpd->max_connections; i++) { http_connection_t *connection = &httpd->connections[i]; if (!connection->connected) { continue; } if (connection->user_data == user_data) { return connection->socket_fd; } } return -1; } int httpd_set_connection_type (httpd_t *httpd, void *user_data, connection_type_t type) { for (int i = 0; i < httpd->max_connections; i++) { http_connection_t *connection = &httpd->connections[i]; if (!connection->connected) { continue; } if (connection->user_data == user_data) { connection->type = type; return i; } } return -1; } int httpd_count_connection_type (httpd_t *httpd, connection_type_t type) { int count = 0; for (int i = 0; i < httpd->max_connections; i++) { http_connection_t *connection = &httpd->connections[i]; if (!connection->connected) { continue; } if (connection->type == type) { count++; } } return count; } int httpd_get_connection_socket_by_type (httpd_t *httpd, connection_type_t type, int instance){ int count = 0; for (int i = 0; i < httpd->max_connections; i++) { http_connection_t *connection = &httpd->connections[i]; if (!connection->connected) { continue; } if (connection->type == type) { count++; if (count == instance) { return connection->socket_fd; } } } return 0; } void * httpd_get_connection_by_type (httpd_t *httpd, connection_type_t type, int instance){ int count = 0; for (int i = 0; i < httpd->max_connections; i++) { http_connection_t *connection = &httpd->connections[i]; if (!connection->connected) { continue; } if (connection->type == type) { count++; if (count == instance) { return connection->user_data; } } } return NULL; } #define MAX_CONNECTIONS 12 /* value used in AppleTV 3*/ httpd_t * httpd_init(logger_t *logger, httpd_callbacks_t *callbacks, int nohold) { httpd_t *httpd; assert(logger); assert(callbacks); /* Allocate the httpd_t structure */ httpd = calloc(1, sizeof(httpd_t)); if (!httpd) { return NULL; } httpd->nohold = (nohold ? 1 : 0); httpd->max_connections = MAX_CONNECTIONS; httpd->connections = calloc(httpd->max_connections, sizeof(http_connection_t)); if (!httpd->connections) { free(httpd); return NULL; } /* Use the logger provided */ httpd->logger = logger; /* Save callback pointers */ memcpy(&httpd->callbacks, callbacks, sizeof(httpd_callbacks_t)); /* Initial status joined */ httpd->running = 0; httpd->joined = 1; return httpd; } void httpd_destroy(httpd_t *httpd) { if (httpd) { httpd_stop(httpd); free(httpd->connections); free(httpd); } } static void httpd_remove_connection(httpd_t *httpd, http_connection_t *connection) { if (connection->request) { http_request_destroy(connection->request); connection->request = NULL; } httpd->callbacks.conn_destroy(connection->user_data); shutdown(connection->socket_fd, SHUT_WR); closesocket(connection->socket_fd); connection->connected = 0; connection->user_data = NULL; connection->type = CONNECTION_TYPE_UNKNOWN; httpd->open_connections--; } static int httpd_add_connection(httpd_t *httpd, int fd, unsigned char *local, int local_len, unsigned char *remote, int remote_len, unsigned int zone_id) { void *user_data; int i; for (i=0; imax_connections; i++) { if (!httpd->connections[i].connected) { break; } } if (i == httpd->max_connections) { /* This code should never be reached, we do not select server_fds when full */ logger_log(httpd->logger, LOGGER_INFO, "Max connections reached"); return -1; } user_data = httpd->callbacks.conn_init(httpd->callbacks.opaque, local, local_len, remote, remote_len, zone_id); if (!user_data) { logger_log(httpd->logger, LOGGER_ERR, "Error initializing HTTP request handler"); return -1; } httpd->open_connections++; httpd->connections[i].socket_fd = fd; httpd->connections[i].connected = 1; httpd->connections[i].user_data = user_data; httpd->connections[i].type = CONNECTION_TYPE_UNKNOWN; //should not be necessary ... return 0; } static int httpd_accept_connection(httpd_t *httpd, int server_fd, int is_ipv6) { struct sockaddr_storage remote_saddr; socklen_t remote_saddrlen; struct sockaddr_storage local_saddr; socklen_t local_saddrlen; unsigned char *local, *remote; unsigned int local_zone_id, remote_zone_id; int local_len, remote_len; int ret, fd; remote_saddrlen = sizeof(remote_saddr); fd = accept(server_fd, (struct sockaddr *)&remote_saddr, &remote_saddrlen); if (fd == -1) { /* FIXME: Error happened */ return -1; } local_saddrlen = sizeof(local_saddr); ret = getsockname(fd, (struct sockaddr *)&local_saddr, &local_saddrlen); if (ret == -1) { shutdown(fd, SHUT_RDWR); closesocket(fd); return 0; } logger_log(httpd->logger, LOGGER_INFO, "Accepted %s client on socket %d", (is_ipv6 ? "IPv6" : "IPv4"), fd); local = netutils_get_address(&local_saddr, &local_len, &local_zone_id); remote = netutils_get_address(&remote_saddr, &remote_len, &remote_zone_id); assert (local_zone_id == remote_zone_id); ret = httpd_add_connection(httpd, fd, local, local_len, remote, remote_len, local_zone_id); if (ret == -1) { shutdown(fd, SHUT_RDWR); closesocket(fd); return 0; } return 1; } bool httpd_nohold(httpd_t *httpd) { return (httpd->nohold ? true: false); } void httpd_remove_known_connections(httpd_t *httpd) { for (int i = 0; i < httpd->max_connections; i++) { http_connection_t *connection = &httpd->connections[i]; if (!connection->connected || connection->type == CONNECTION_TYPE_UNKNOWN) { continue; } httpd_remove_connection(httpd, connection); } } static THREAD_RETVAL httpd_thread(void *arg) { httpd_t *httpd = arg; char http[] = "HTTP/1.1"; char buffer[1024]; int i; bool logger_debug = (logger_get_level(httpd->logger) >= LOGGER_DEBUG); assert(httpd); while (1) { fd_set rfds; struct timeval tv; int nfds=0; int ret; int new_request; MUTEX_LOCK(httpd->run_mutex); if (!httpd->running) { MUTEX_UNLOCK(httpd->run_mutex); break; } MUTEX_UNLOCK(httpd->run_mutex); /* Set timeout value to 5ms */ tv.tv_sec = 1; tv.tv_usec = 5000; /* Get the correct nfds value and set rfds */ FD_ZERO(&rfds); if (httpd->open_connections < httpd->max_connections) { if (httpd->server_fd4 != -1) { FD_SET(httpd->server_fd4, &rfds); if (nfds <= httpd->server_fd4) { nfds = httpd->server_fd4+1; } } if (httpd->server_fd6 != -1) { FD_SET(httpd->server_fd6, &rfds); if (nfds <= httpd->server_fd6) { nfds = httpd->server_fd6+1; } } } for (i=0; imax_connections; i++) { int socket_fd; if (!httpd->connections[i].connected) { continue; } socket_fd = httpd->connections[i].socket_fd; FD_SET(socket_fd, &rfds); if (nfds <= socket_fd) { nfds = socket_fd+1; } } ret = select(nfds, &rfds, NULL, NULL, &tv); if (ret == 0) { /* Timeout happened */ continue; } else if (ret == -1) { logger_log(httpd->logger, LOGGER_ERR, "httpd error in select: %d %s", errno, strerror(errno)); break; } if (httpd->open_connections < httpd->max_connections && httpd->server_fd4 != -1 && FD_ISSET(httpd->server_fd4, &rfds)) { ret = httpd_accept_connection(httpd, httpd->server_fd4, 0); if (ret == -1) { logger_log(httpd->logger, LOGGER_ERR, "httpd error in accept ipv4"); break; } else if (ret == 0) { continue; } } if (httpd->open_connections < httpd->max_connections && httpd->server_fd6 != -1 && FD_ISSET(httpd->server_fd6, &rfds)) { ret = httpd_accept_connection(httpd, httpd->server_fd6, 1); if (ret == -1) { logger_log(httpd->logger, LOGGER_ERR, "httpd error in accept ipv6"); break; } else if (ret == 0) { continue; } } for (i=0; imax_connections; i++) { http_connection_t *connection = &httpd->connections[i]; if (!connection->connected) { continue; } if (!FD_ISSET(connection->socket_fd, &rfds)) { continue; } /* If not in the middle of request, allocate one */ if (!connection->request) { connection->request = http_request_init(); assert(connection->request); new_request = 1; if (connection->type == CONNECTION_TYPE_PTTH) { http_request_is_reverse(connection->request); } logger_log(httpd->logger, LOGGER_DEBUG, "new request, connection %d, socket %d type %s", i, connection->socket_fd, typename [connection->type]); } else { new_request = 0; } logger_log(httpd->logger, LOGGER_DEBUG, "httpd receiving on socket %d, connection %d", connection->socket_fd, i); if (logger_debug) { logger_log(httpd->logger, LOGGER_DEBUG,"\nhttpd: current connections:"); for (int i = 0; i < httpd->max_connections; i++) { http_connection_t *connection = &httpd->connections[i]; if(!connection->connected) { continue; } if (!FD_ISSET(connection->socket_fd, &rfds)) { logger_log(httpd->logger, LOGGER_DEBUG, "connection %d type %d socket %d conn %p %s", i, connection->type, connection->socket_fd, connection->user_data, typename [connection->type]); } else { logger_log(httpd->logger, LOGGER_DEBUG, "connection %d type %d socket %d conn %p %s ACTIVE CONNECTION", i, connection->type, connection->socket_fd, connection->user_data, typename [connection->type]); } } logger_log(httpd->logger, LOGGER_DEBUG, " "); } /* reverse-http responses from the client must not be sent to the llhttp parser: * such messages start with "HTTP/1.1" */ if (new_request) { int readstart = 0; new_request = 0; while (readstart < 8) { ret = recv(connection->socket_fd, buffer + readstart, sizeof(buffer) - 1 - readstart, 0); if (ret == 0) { logger_log(httpd->logger, LOGGER_INFO, "Connection closed for socket %d", connection->socket_fd); break; } else if (ret == -1) { if (errno == EAGAIN) { continue; } else { int sock_err = SOCKET_GET_ERROR(); logger_log(httpd->logger, LOGGER_ERR, "httpd: recv socket error %d:%s", sock_err, strerror(sock_err)); break; } } else { readstart += ret; ret = readstart; } } if (!memcmp(buffer, http, 8)) { http_request_set_reverse(connection->request); } } else { ret = recv(connection->socket_fd, buffer, sizeof(buffer) - 1, 0); if (ret == 0) { logger_log(httpd->logger, LOGGER_INFO, "Connection closed for socket %d", connection->socket_fd); httpd_remove_connection(httpd, connection); continue; } } if (http_request_is_reverse(connection->request)) { /* this is a response from the client to a * GET /event reverse HTTP request from the server */ if (ret && logger_debug) { buffer[ret] = '\0'; logger_log(httpd->logger, LOGGER_INFO, "<<<< received response from client" " (reversed HTTP = \"PTTH/1.0\") connection" " on socket %d:\n%s\n", connection->socket_fd, buffer); } if (ret == 0) { httpd_remove_connection(httpd, connection); } continue; } /* Parse HTTP request from data read from connection */ http_request_add_data(connection->request, buffer, ret); if (http_request_has_error(connection->request)) { logger_log(httpd->logger, LOGGER_ERR, "httpd error in parsing: %s", http_request_get_error_name(connection->request)); httpd_remove_connection(httpd, connection); continue; } /* If request is finished, process and deallocate */ if (http_request_is_complete(connection->request)) { http_response_t *response = NULL; // Callback the received data to raop if (logger_debug) { const char *method = http_request_get_method(connection->request); const char *url = http_request_get_url(connection->request); const char *protocol = http_request_get_protocol(connection->request); logger_log(httpd->logger, LOGGER_INFO, "httpd request received on socket %d, " "connection %d, method = %s, url = %s, protocol = %s", connection->socket_fd, i, method, url, protocol); } httpd->callbacks.conn_request(connection->user_data, connection->request, &response); http_request_destroy(connection->request); connection->request = NULL; if (response) { const char *data; int datalen; int written; int ret; /* Get response data and datalen */ data = http_response_get_data(response, &datalen); written = 0; while (written < datalen) { ret = send(connection->socket_fd, data+written, datalen-written, 0); if (ret == -1) { logger_log(httpd->logger, LOGGER_ERR, "httpd error in sending data"); break; } written += ret; } if (http_response_get_disconnect(response)) { logger_log(httpd->logger, LOGGER_INFO, "Disconnecting on software request"); httpd_remove_connection(httpd, connection); } } else { logger_log(httpd->logger, LOGGER_WARNING, "httpd didn't get response"); } http_response_destroy(response); } else { logger_log(httpd->logger, LOGGER_DEBUG, "Request not complete, waiting for more data..."); } } } /* Remove all connections that are still connected */ for (i=0; imax_connections; i++) { http_connection_t *connection = &httpd->connections[i]; if (!connection->connected) { continue; } logger_log(httpd->logger, LOGGER_INFO, "Removing connection for socket %d", connection->socket_fd); httpd_remove_connection(httpd, connection); } /* Close server sockets since they are not used any more */ if (httpd->server_fd4 != -1) { shutdown(httpd->server_fd4, SHUT_RDWR); closesocket(httpd->server_fd4); httpd->server_fd4 = -1; } if (httpd->server_fd6 != -1) { shutdown(httpd->server_fd6, SHUT_RDWR); closesocket(httpd->server_fd6); httpd->server_fd6 = -1; } // Ensure running reflects the actual state MUTEX_LOCK(httpd->run_mutex); httpd->running = 0; MUTEX_UNLOCK(httpd->run_mutex); logger_log(httpd->logger, LOGGER_DEBUG, "Exiting HTTP thread"); return 0; } int httpd_start(httpd_t *httpd, unsigned short *port) { /* How many connection attempts are kept in queue */ int backlog = 5; assert(httpd); assert(port); MUTEX_LOCK(httpd->run_mutex); if (httpd->running || !httpd->joined) { MUTEX_UNLOCK(httpd->run_mutex); return 0; } httpd->server_fd4 = netutils_init_socket(port, 0, 0); if (httpd->server_fd4 == -1) { logger_log(httpd->logger, LOGGER_ERR, "Error initialising socket %d", SOCKET_GET_ERROR()); MUTEX_UNLOCK(httpd->run_mutex); return -1; } httpd->server_fd6 = netutils_init_socket(port, 1, 0); if (httpd->server_fd6 == -1) { logger_log(httpd->logger, LOGGER_WARNING, "Error initialising IPv6 socket %d", SOCKET_GET_ERROR()); logger_log(httpd->logger, LOGGER_WARNING, "Continuing without IPv6 support"); } if (httpd->server_fd4 != -1 && listen(httpd->server_fd4, backlog) == -1) { logger_log(httpd->logger, LOGGER_ERR, "Error listening to IPv4 socket"); closesocket(httpd->server_fd4); closesocket(httpd->server_fd6); MUTEX_UNLOCK(httpd->run_mutex); return -2; } if (httpd->server_fd6 != -1 && listen(httpd->server_fd6, backlog) == -1) { logger_log(httpd->logger, LOGGER_ERR, "Error listening to IPv6 socket"); closesocket(httpd->server_fd4); closesocket(httpd->server_fd6); MUTEX_UNLOCK(httpd->run_mutex); return -2; } logger_log(httpd->logger, LOGGER_INFO, "Initialized server socket(s)"); /* Set values correctly and create new thread */ httpd->running = 1; httpd->joined = 0; THREAD_CREATE(httpd->thread, httpd_thread, httpd); MUTEX_UNLOCK(httpd->run_mutex); return 1; } int httpd_is_running(httpd_t *httpd) { int running; assert(httpd); MUTEX_LOCK(httpd->run_mutex); running = httpd->running || !httpd->joined; MUTEX_UNLOCK(httpd->run_mutex); return running; } void httpd_stop(httpd_t *httpd) { assert(httpd); MUTEX_LOCK(httpd->run_mutex); if (!httpd->running || httpd->joined) { MUTEX_UNLOCK(httpd->run_mutex); return; } httpd->running = 0; MUTEX_UNLOCK(httpd->run_mutex); THREAD_JOIN(httpd->thread); MUTEX_LOCK(httpd->run_mutex); httpd->joined = 1; MUTEX_UNLOCK(httpd->run_mutex); } UxPlay-1.71.1/lib/httpd.h000066400000000000000000000041211473013662600150730ustar00rootroot00000000000000/** * Copyright (C) 2011-2012 Juho Vähä-Herttua * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. */ #ifndef HTTPD_H #define HTTPD_H #include "logger.h" #include "http_request.h" #include "http_response.h" typedef struct httpd_s httpd_t; typedef enum connectype_type_e { CONNECTION_TYPE_UNKNOWN, CONNECTION_TYPE_RAOP, CONNECTION_TYPE_AIRPLAY, CONNECTION_TYPE_PTTH, CONNECTION_TYPE_HLS } connection_type_t; struct httpd_callbacks_s { void* opaque; void* (*conn_init)(void *opaque, unsigned char *local, int locallen, unsigned char *remote, int remotelen, unsigned int zone_id); void (*conn_request)(void *ptr, http_request_t *request, http_response_t **response); void (*conn_destroy)(void *ptr); }; typedef struct httpd_callbacks_s httpd_callbacks_t; bool httpd_nohold(httpd_t *httpd); void httpd_remove_known_connections(httpd_t *httpd); int httpd_set_connection_type (httpd_t *http, void *user_data, connection_type_t type); int httpd_count_connection_type (httpd_t *http, connection_type_t type); int httpd_get_connection_socket (httpd_t *httpd, void *user_data); int httpd_get_connection_socket_by_type (httpd_t *httpd, connection_type_t type, int instance); const char *httpd_get_connection_typename (connection_type_t type); void *httpd_get_connection_by_type (httpd_t *httpd, connection_type_t type, int instance); httpd_t *httpd_init(logger_t *logger, httpd_callbacks_t *callbacks, int nohold); int httpd_is_running(httpd_t *httpd); int httpd_start(httpd_t *httpd, unsigned short *port); void httpd_stop(httpd_t *httpd); void httpd_destroy(httpd_t *httpd); #endif UxPlay-1.71.1/lib/llhttp/000077500000000000000000000000001473013662600151105ustar00rootroot00000000000000UxPlay-1.71.1/lib/llhttp/CMakeLists.txt000066400000000000000000000002621473013662600176500ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.5) aux_source_directory(. llhttp_src) set(DIR_SRCS ${llhttp_src}) include_directories(.) add_library( llhttp STATIC ${DIR_SRCS}) UxPlay-1.71.1/lib/llhttp/LICENSE-MIT000066400000000000000000000021211473013662600165400ustar00rootroot00000000000000This software is licensed under the MIT License. Copyright Fedor Indutny, 2018. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. UxPlay-1.71.1/lib/llhttp/api.c000066400000000000000000000310341473013662600160260ustar00rootroot00000000000000#include #include #include #include "llhttp.h" #define CALLBACK_MAYBE(PARSER, NAME) \ do { \ const llhttp_settings_t* settings; \ settings = (const llhttp_settings_t*) (PARSER)->settings; \ if (settings == NULL || settings->NAME == NULL) { \ err = 0; \ break; \ } \ err = settings->NAME((PARSER)); \ } while (0) #define SPAN_CALLBACK_MAYBE(PARSER, NAME, START, LEN) \ do { \ const llhttp_settings_t* settings; \ settings = (const llhttp_settings_t*) (PARSER)->settings; \ if (settings == NULL || settings->NAME == NULL) { \ err = 0; \ break; \ } \ err = settings->NAME((PARSER), (START), (LEN)); \ if (err == -1) { \ err = HPE_USER; \ llhttp_set_error_reason((PARSER), "Span callback error in " #NAME); \ } \ } while (0) void llhttp_init(llhttp_t* parser, llhttp_type_t type, const llhttp_settings_t* settings) { llhttp__internal_init(parser); parser->type = type; parser->settings = (void*) settings; } #if defined(__wasm__) extern int wasm_on_message_begin(llhttp_t * p); extern int wasm_on_url(llhttp_t* p, const char* at, size_t length); extern int wasm_on_status(llhttp_t* p, const char* at, size_t length); extern int wasm_on_header_field(llhttp_t* p, const char* at, size_t length); extern int wasm_on_header_value(llhttp_t* p, const char* at, size_t length); extern int wasm_on_headers_complete(llhttp_t * p, int status_code, uint8_t upgrade, int should_keep_alive); extern int wasm_on_body(llhttp_t* p, const char* at, size_t length); extern int wasm_on_message_complete(llhttp_t * p); static int wasm_on_headers_complete_wrap(llhttp_t* p) { return wasm_on_headers_complete(p, p->status_code, p->upgrade, llhttp_should_keep_alive(p)); } const llhttp_settings_t wasm_settings = { wasm_on_message_begin, wasm_on_url, wasm_on_status, NULL, NULL, wasm_on_header_field, wasm_on_header_value, NULL, NULL, wasm_on_headers_complete_wrap, wasm_on_body, wasm_on_message_complete, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, }; llhttp_t* llhttp_alloc(llhttp_type_t type) { llhttp_t* parser = malloc(sizeof(llhttp_t)); llhttp_init(parser, type, &wasm_settings); return parser; } void llhttp_free(llhttp_t* parser) { free(parser); } #endif // defined(__wasm__) /* Some getters required to get stuff from the parser */ uint8_t llhttp_get_type(llhttp_t* parser) { return parser->type; } uint8_t llhttp_get_http_major(llhttp_t* parser) { return parser->http_major; } uint8_t llhttp_get_http_minor(llhttp_t* parser) { return parser->http_minor; } uint8_t llhttp_get_method(llhttp_t* parser) { return parser->method; } int llhttp_get_status_code(llhttp_t* parser) { return parser->status_code; } uint8_t llhttp_get_upgrade(llhttp_t* parser) { return parser->upgrade; } void llhttp_reset(llhttp_t* parser) { llhttp_type_t type = parser->type; const llhttp_settings_t* settings = parser->settings; void* data = parser->data; uint16_t lenient_flags = parser->lenient_flags; llhttp__internal_init(parser); parser->type = type; parser->settings = (void*) settings; parser->data = data; parser->lenient_flags = lenient_flags; } llhttp_errno_t llhttp_execute(llhttp_t* parser, const char* data, size_t len) { return llhttp__internal_execute(parser, data, data + len); } void llhttp_settings_init(llhttp_settings_t* settings) { memset(settings, 0, sizeof(*settings)); } llhttp_errno_t llhttp_finish(llhttp_t* parser) { int err; /* We're in an error state. Don't bother doing anything. */ if (parser->error != 0) { return 0; } switch (parser->finish) { case HTTP_FINISH_SAFE_WITH_CB: CALLBACK_MAYBE(parser, on_message_complete); if (err != HPE_OK) return err; /* FALLTHROUGH */ case HTTP_FINISH_SAFE: return HPE_OK; case HTTP_FINISH_UNSAFE: parser->reason = "Invalid EOF state"; return HPE_INVALID_EOF_STATE; default: abort(); } } void llhttp_pause(llhttp_t* parser) { if (parser->error != HPE_OK) { return; } parser->error = HPE_PAUSED; parser->reason = "Paused"; } void llhttp_resume(llhttp_t* parser) { if (parser->error != HPE_PAUSED) { return; } parser->error = 0; } void llhttp_resume_after_upgrade(llhttp_t* parser) { if (parser->error != HPE_PAUSED_UPGRADE) { return; } parser->error = 0; } llhttp_errno_t llhttp_get_errno(const llhttp_t* parser) { return parser->error; } const char* llhttp_get_error_reason(const llhttp_t* parser) { return parser->reason; } void llhttp_set_error_reason(llhttp_t* parser, const char* reason) { parser->reason = reason; } const char* llhttp_get_error_pos(const llhttp_t* parser) { return parser->error_pos; } const char* llhttp_errno_name(llhttp_errno_t err) { #define HTTP_ERRNO_GEN(CODE, NAME, _) case HPE_##NAME: return "HPE_" #NAME; switch (err) { HTTP_ERRNO_MAP(HTTP_ERRNO_GEN) default: abort(); } #undef HTTP_ERRNO_GEN } const char* llhttp_method_name(llhttp_method_t method) { #define HTTP_METHOD_GEN(NUM, NAME, STRING) case HTTP_##NAME: return #STRING; switch (method) { HTTP_ALL_METHOD_MAP(HTTP_METHOD_GEN) default: abort(); } #undef HTTP_METHOD_GEN } const char* llhttp_status_name(llhttp_status_t status) { #define HTTP_STATUS_GEN(NUM, NAME, STRING) case HTTP_STATUS_##NAME: return #STRING; switch (status) { HTTP_STATUS_MAP(HTTP_STATUS_GEN) default: abort(); } #undef HTTP_STATUS_GEN } void llhttp_set_lenient_headers(llhttp_t* parser, int enabled) { if (enabled) { parser->lenient_flags |= LENIENT_HEADERS; } else { parser->lenient_flags &= ~LENIENT_HEADERS; } } void llhttp_set_lenient_chunked_length(llhttp_t* parser, int enabled) { if (enabled) { parser->lenient_flags |= LENIENT_CHUNKED_LENGTH; } else { parser->lenient_flags &= ~LENIENT_CHUNKED_LENGTH; } } void llhttp_set_lenient_keep_alive(llhttp_t* parser, int enabled) { if (enabled) { parser->lenient_flags |= LENIENT_KEEP_ALIVE; } else { parser->lenient_flags &= ~LENIENT_KEEP_ALIVE; } } void llhttp_set_lenient_transfer_encoding(llhttp_t* parser, int enabled) { if (enabled) { parser->lenient_flags |= LENIENT_TRANSFER_ENCODING; } else { parser->lenient_flags &= ~LENIENT_TRANSFER_ENCODING; } } void llhttp_set_lenient_version(llhttp_t* parser, int enabled) { if (enabled) { parser->lenient_flags |= LENIENT_VERSION; } else { parser->lenient_flags &= ~LENIENT_VERSION; } } void llhttp_set_lenient_data_after_close(llhttp_t* parser, int enabled) { if (enabled) { parser->lenient_flags |= LENIENT_DATA_AFTER_CLOSE; } else { parser->lenient_flags &= ~LENIENT_DATA_AFTER_CLOSE; } } void llhttp_set_lenient_optional_lf_after_cr(llhttp_t* parser, int enabled) { if (enabled) { parser->lenient_flags |= LENIENT_OPTIONAL_LF_AFTER_CR; } else { parser->lenient_flags &= ~LENIENT_OPTIONAL_LF_AFTER_CR; } } void llhttp_set_lenient_optional_crlf_after_chunk(llhttp_t* parser, int enabled) { if (enabled) { parser->lenient_flags |= LENIENT_OPTIONAL_CRLF_AFTER_CHUNK; } else { parser->lenient_flags &= ~LENIENT_OPTIONAL_CRLF_AFTER_CHUNK; } } void llhttp_set_lenient_optional_cr_before_lf(llhttp_t* parser, int enabled) { if (enabled) { parser->lenient_flags |= LENIENT_OPTIONAL_CR_BEFORE_LF; } else { parser->lenient_flags &= ~LENIENT_OPTIONAL_CR_BEFORE_LF; } } void llhttp_set_lenient_spaces_after_chunk_size(llhttp_t* parser, int enabled) { if (enabled) { parser->lenient_flags |= LENIENT_SPACES_AFTER_CHUNK_SIZE; } else { parser->lenient_flags &= ~LENIENT_SPACES_AFTER_CHUNK_SIZE; } } /* Callbacks */ int llhttp__on_message_begin(llhttp_t* s, const char* p, const char* endp) { int err; CALLBACK_MAYBE(s, on_message_begin); return err; } int llhttp__on_url(llhttp_t* s, const char* p, const char* endp) { int err; SPAN_CALLBACK_MAYBE(s, on_url, p, endp - p); return err; } int llhttp__on_url_complete(llhttp_t* s, const char* p, const char* endp) { int err; CALLBACK_MAYBE(s, on_url_complete); return err; } int llhttp__on_status(llhttp_t* s, const char* p, const char* endp) { int err; SPAN_CALLBACK_MAYBE(s, on_status, p, endp - p); return err; } int llhttp__on_status_complete(llhttp_t* s, const char* p, const char* endp) { int err; CALLBACK_MAYBE(s, on_status_complete); return err; } int llhttp__on_method(llhttp_t* s, const char* p, const char* endp) { int err; SPAN_CALLBACK_MAYBE(s, on_method, p, endp - p); return err; } int llhttp__on_method_complete(llhttp_t* s, const char* p, const char* endp) { int err; CALLBACK_MAYBE(s, on_method_complete); return err; } int llhttp__on_version(llhttp_t* s, const char* p, const char* endp) { int err; SPAN_CALLBACK_MAYBE(s, on_version, p, endp - p); return err; } int llhttp__on_version_complete(llhttp_t* s, const char* p, const char* endp) { int err; CALLBACK_MAYBE(s, on_version_complete); return err; } int llhttp__on_header_field(llhttp_t* s, const char* p, const char* endp) { int err; SPAN_CALLBACK_MAYBE(s, on_header_field, p, endp - p); return err; } int llhttp__on_header_field_complete(llhttp_t* s, const char* p, const char* endp) { int err; CALLBACK_MAYBE(s, on_header_field_complete); return err; } int llhttp__on_header_value(llhttp_t* s, const char* p, const char* endp) { int err; SPAN_CALLBACK_MAYBE(s, on_header_value, p, endp - p); return err; } int llhttp__on_header_value_complete(llhttp_t* s, const char* p, const char* endp) { int err; CALLBACK_MAYBE(s, on_header_value_complete); return err; } int llhttp__on_headers_complete(llhttp_t* s, const char* p, const char* endp) { int err; CALLBACK_MAYBE(s, on_headers_complete); return err; } int llhttp__on_message_complete(llhttp_t* s, const char* p, const char* endp) { int err; CALLBACK_MAYBE(s, on_message_complete); return err; } int llhttp__on_body(llhttp_t* s, const char* p, const char* endp) { int err; SPAN_CALLBACK_MAYBE(s, on_body, p, endp - p); return err; } int llhttp__on_chunk_header(llhttp_t* s, const char* p, const char* endp) { int err; CALLBACK_MAYBE(s, on_chunk_header); return err; } int llhttp__on_chunk_extension_name(llhttp_t* s, const char* p, const char* endp) { int err; SPAN_CALLBACK_MAYBE(s, on_chunk_extension_name, p, endp - p); return err; } int llhttp__on_chunk_extension_name_complete(llhttp_t* s, const char* p, const char* endp) { int err; CALLBACK_MAYBE(s, on_chunk_extension_name_complete); return err; } int llhttp__on_chunk_extension_value(llhttp_t* s, const char* p, const char* endp) { int err; SPAN_CALLBACK_MAYBE(s, on_chunk_extension_value, p, endp - p); return err; } int llhttp__on_chunk_extension_value_complete(llhttp_t* s, const char* p, const char* endp) { int err; CALLBACK_MAYBE(s, on_chunk_extension_value_complete); return err; } int llhttp__on_chunk_complete(llhttp_t* s, const char* p, const char* endp) { int err; CALLBACK_MAYBE(s, on_chunk_complete); return err; } int llhttp__on_reset(llhttp_t* s, const char* p, const char* endp) { int err; CALLBACK_MAYBE(s, on_reset); return err; } /* Private */ void llhttp__debug(llhttp_t* s, const char* p, const char* endp, const char* msg) { if (p == endp) { fprintf(stderr, "p=%p type=%d flags=%02x next=null debug=%s\n", s, s->type, s->flags, msg); } else { fprintf(stderr, "p=%p type=%d flags=%02x next=%02x debug=%s\n", s, s->type, s->flags, *p, msg); } } UxPlay-1.71.1/lib/llhttp/http.c000066400000000000000000000121311473013662600162310ustar00rootroot00000000000000#include #ifndef LLHTTP__TEST # include "llhttp.h" #else # define llhttp_t llparse_t #endif /* */ int llhttp_message_needs_eof(const llhttp_t* parser); int llhttp_should_keep_alive(const llhttp_t* parser); int llhttp__before_headers_complete(llhttp_t* parser, const char* p, const char* endp) { /* Set this here so that on_headers_complete() callbacks can see it */ if ((parser->flags & F_UPGRADE) && (parser->flags & F_CONNECTION_UPGRADE)) { /* For responses, "Upgrade: foo" and "Connection: upgrade" are * mandatory only when it is a 101 Switching Protocols response, * otherwise it is purely informational, to announce support. */ parser->upgrade = (parser->type == HTTP_REQUEST || parser->status_code == 101); } else { parser->upgrade = (parser->method == HTTP_CONNECT); } return 0; } /* Return values: * 0 - No body, `restart`, message_complete * 1 - CONNECT request, `restart`, message_complete, and pause * 2 - chunk_size_start * 3 - body_identity * 4 - body_identity_eof * 5 - invalid transfer-encoding for request */ int llhttp__after_headers_complete(llhttp_t* parser, const char* p, const char* endp) { int hasBody; hasBody = parser->flags & F_CHUNKED || parser->content_length > 0; if ( (parser->upgrade && (parser->method == HTTP_CONNECT || (parser->flags & F_SKIPBODY) || !hasBody)) || /* See RFC 2616 section 4.4 - 1xx e.g. Continue */ (parser->type == HTTP_RESPONSE && parser->status_code == 101) ) { /* Exit, the rest of the message is in a different protocol. */ return 1; } if (parser->type == HTTP_RESPONSE && parser->status_code == 100) { /* No body, restart as the message is complete */ return 0; } /* See RFC 2616 section 4.4 */ if ( parser->flags & F_SKIPBODY || /* response to a HEAD request */ ( parser->type == HTTP_RESPONSE && ( parser->status_code == 102 || /* Processing */ parser->status_code == 103 || /* Early Hints */ parser->status_code == 204 || /* No Content */ parser->status_code == 304 /* Not Modified */ ) ) ) { return 0; } else if (parser->flags & F_CHUNKED) { /* chunked encoding - ignore Content-Length header, prepare for a chunk */ return 2; } else if (parser->flags & F_TRANSFER_ENCODING) { if (parser->type == HTTP_REQUEST && (parser->lenient_flags & LENIENT_CHUNKED_LENGTH) == 0 && (parser->lenient_flags & LENIENT_TRANSFER_ENCODING) == 0) { /* RFC 7230 3.3.3 */ /* If a Transfer-Encoding header field * is present in a request and the chunked transfer coding is not * the final encoding, the message body length cannot be determined * reliably; the server MUST respond with the 400 (Bad Request) * status code and then close the connection. */ return 5; } else { /* RFC 7230 3.3.3 */ /* If a Transfer-Encoding header field is present in a response and * the chunked transfer coding is not the final encoding, the * message body length is determined by reading the connection until * it is closed by the server. */ return 4; } } else { if (!(parser->flags & F_CONTENT_LENGTH)) { if (!llhttp_message_needs_eof(parser)) { /* Assume content-length 0 - read the next */ return 0; } else { /* Read body until EOF */ return 4; } } else if (parser->content_length == 0) { /* Content-Length header given but zero: Content-Length: 0\r\n */ return 0; } else { /* Content-Length header given and non-zero */ return 3; } } } int llhttp__after_message_complete(llhttp_t* parser, const char* p, const char* endp) { int should_keep_alive; should_keep_alive = llhttp_should_keep_alive(parser); parser->finish = HTTP_FINISH_SAFE; parser->flags = 0; /* NOTE: this is ignored in loose parsing mode */ return should_keep_alive; } int llhttp_message_needs_eof(const llhttp_t* parser) { if (parser->type == HTTP_REQUEST) { return 0; } /* See RFC 2616 section 4.4 */ if (parser->status_code / 100 == 1 || /* 1xx e.g. Continue */ parser->status_code == 204 || /* No Content */ parser->status_code == 304 || /* Not Modified */ (parser->flags & F_SKIPBODY)) { /* response to a HEAD request */ return 0; } /* RFC 7230 3.3.3, see `llhttp__after_headers_complete` */ if ((parser->flags & F_TRANSFER_ENCODING) && (parser->flags & F_CHUNKED) == 0) { return 1; } if (parser->flags & (F_CHUNKED | F_CONTENT_LENGTH)) { return 0; } return 1; } int llhttp_should_keep_alive(const llhttp_t* parser) { if (parser->http_major > 0 && parser->http_minor > 0) { /* HTTP/1.1 */ if (parser->flags & F_CONNECTION_CLOSE) { return 0; } } else { /* HTTP/1.0 or earlier */ if (!(parser->flags & F_CONNECTION_KEEP_ALIVE)) { return 0; } } return !llhttp_message_needs_eof(parser); } UxPlay-1.71.1/lib/llhttp/llhttp.c000066400000000000000000011370531473013662600165750ustar00rootroot00000000000000#include #include #include #ifdef __SSE4_2__ #ifdef _MSC_VER #include #else /* !_MSC_VER */ #include #endif /* _MSC_VER */ #endif /* __SSE4_2__ */ #ifdef _MSC_VER #define ALIGN(n) _declspec(align(n)) #else /* !_MSC_VER */ #define ALIGN(n) __attribute__((aligned(n))) #endif /* _MSC_VER */ #include "llhttp.h" typedef int (*llhttp__internal__span_cb)( llhttp__internal_t*, const char*, const char*); static const unsigned char llparse_blob0[] = { 'o', 'n' }; static const unsigned char llparse_blob1[] = { 'e', 'c', 't', 'i', 'o', 'n' }; static const unsigned char llparse_blob2[] = { 'l', 'o', 's', 'e' }; static const unsigned char llparse_blob3[] = { 'e', 'e', 'p', '-', 'a', 'l', 'i', 'v', 'e' }; static const unsigned char llparse_blob4[] = { 'p', 'g', 'r', 'a', 'd', 'e' }; static const unsigned char llparse_blob5[] = { 'c', 'h', 'u', 'n', 'k', 'e', 'd' }; #ifdef __SSE4_2__ static const unsigned char ALIGN(16) llparse_blob6[] = { 0x9, 0x9, ' ', '~', 0x80, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; #endif /* __SSE4_2__ */ #ifdef __SSE4_2__ static const unsigned char ALIGN(16) llparse_blob7[] = { '!', '!', '#', '\'', '*', '+', '-', '.', '0', '9', 'A', 'Z', '^', 'z', '|', '|' }; #endif /* __SSE4_2__ */ #ifdef __SSE4_2__ static const unsigned char ALIGN(16) llparse_blob8[] = { '~', '~', 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; #endif /* __SSE4_2__ */ static const unsigned char llparse_blob9[] = { 'e', 'n', 't', '-', 'l', 'e', 'n', 'g', 't', 'h' }; static const unsigned char llparse_blob10[] = { 'r', 'o', 'x', 'y', '-', 'c', 'o', 'n', 'n', 'e', 'c', 't', 'i', 'o', 'n' }; static const unsigned char llparse_blob11[] = { 'r', 'a', 'n', 's', 'f', 'e', 'r', '-', 'e', 'n', 'c', 'o', 'd', 'i', 'n', 'g' }; static const unsigned char llparse_blob12[] = { 'p', 'g', 'r', 'a', 'd', 'e' }; static const unsigned char llparse_blob13[] = { 'T', 'T', 'P', '/' }; static const unsigned char llparse_blob14[] = { 0xd, 0xa, 0xd, 0xa, 'S', 'M', 0xd, 0xa, 0xd, 0xa }; static const unsigned char llparse_blob15[] = { 'C', 'E', '/' }; static const unsigned char llparse_blob16[] = { 'T', 'S', 'P', '/' }; static const unsigned char llparse_blob17[] = { 'N', 'O', 'U', 'N', 'C', 'E' }; static const unsigned char llparse_blob18[] = { 'I', 'N', 'D' }; static const unsigned char llparse_blob19[] = { 'E', 'C', 'K', 'O', 'U', 'T' }; static const unsigned char llparse_blob20[] = { 'N', 'E', 'C', 'T' }; static const unsigned char llparse_blob21[] = { 'E', 'T', 'E' }; static const unsigned char llparse_blob22[] = { 'C', 'R', 'I', 'B', 'E' }; static const unsigned char llparse_blob23[] = { 'L', 'U', 'S', 'H' }; static const unsigned char llparse_blob24[] = { 'E', 'T' }; static const unsigned char llparse_blob25[] = { 'P', 'A', 'R', 'A', 'M', 'E', 'T', 'E', 'R' }; static const unsigned char llparse_blob26[] = { 'E', 'A', 'D' }; static const unsigned char llparse_blob27[] = { 'N', 'K' }; static const unsigned char llparse_blob28[] = { 'C', 'K' }; static const unsigned char llparse_blob29[] = { 'S', 'E', 'A', 'R', 'C', 'H' }; static const unsigned char llparse_blob30[] = { 'R', 'G', 'E' }; static const unsigned char llparse_blob31[] = { 'C', 'T', 'I', 'V', 'I', 'T', 'Y' }; static const unsigned char llparse_blob32[] = { 'L', 'E', 'N', 'D', 'A', 'R' }; static const unsigned char llparse_blob33[] = { 'V', 'E' }; static const unsigned char llparse_blob34[] = { 'O', 'T', 'I', 'F', 'Y' }; static const unsigned char llparse_blob35[] = { 'P', 'T', 'I', 'O', 'N', 'S' }; static const unsigned char llparse_blob36[] = { 'C', 'H' }; static const unsigned char llparse_blob37[] = { 'S', 'E' }; static const unsigned char llparse_blob38[] = { 'A', 'Y' }; static const unsigned char llparse_blob39[] = { 'S', 'T' }; static const unsigned char llparse_blob40[] = { 'I', 'N', 'D' }; static const unsigned char llparse_blob41[] = { 'A', 'T', 'C', 'H' }; static const unsigned char llparse_blob42[] = { 'G', 'E' }; static const unsigned char llparse_blob43[] = { 'U', 'E', 'R', 'Y' }; static const unsigned char llparse_blob44[] = { 'I', 'N', 'D' }; static const unsigned char llparse_blob45[] = { 'O', 'R', 'D' }; static const unsigned char llparse_blob46[] = { 'I', 'R', 'E', 'C', 'T' }; static const unsigned char llparse_blob47[] = { 'O', 'R', 'T' }; static const unsigned char llparse_blob48[] = { 'R', 'C', 'H' }; static const unsigned char llparse_blob49[] = { 'P', 'A', 'R', 'A', 'M', 'E', 'T', 'E', 'R' }; static const unsigned char llparse_blob50[] = { 'U', 'R', 'C', 'E' }; static const unsigned char llparse_blob51[] = { 'B', 'S', 'C', 'R', 'I', 'B', 'E' }; static const unsigned char llparse_blob52[] = { 'A', 'R', 'D', 'O', 'W', 'N' }; static const unsigned char llparse_blob53[] = { 'A', 'C', 'E' }; static const unsigned char llparse_blob54[] = { 'I', 'N', 'D' }; static const unsigned char llparse_blob55[] = { 'N', 'K' }; static const unsigned char llparse_blob56[] = { 'C', 'K' }; static const unsigned char llparse_blob57[] = { 'U', 'B', 'S', 'C', 'R', 'I', 'B', 'E' }; static const unsigned char llparse_blob58[] = { 'H', 'T', 'T', 'P', '/' }; static const unsigned char llparse_blob59[] = { 'A', 'D' }; static const unsigned char llparse_blob60[] = { 'T', 'P', '/' }; enum llparse_match_status_e { kMatchComplete, kMatchPause, kMatchMismatch }; typedef enum llparse_match_status_e llparse_match_status_t; struct llparse_match_s { llparse_match_status_t status; const unsigned char* current; }; typedef struct llparse_match_s llparse_match_t; static llparse_match_t llparse__match_sequence_to_lower( llhttp__internal_t* s, const unsigned char* p, const unsigned char* endp, const unsigned char* seq, uint32_t seq_len) { uint32_t index; llparse_match_t res; index = s->_index; for (; p != endp; p++) { unsigned char current; current = ((*p) >= 'A' && (*p) <= 'Z' ? (*p | 0x20) : (*p)); if (current == seq[index]) { if (++index == seq_len) { res.status = kMatchComplete; goto reset; } } else { res.status = kMatchMismatch; goto reset; } } s->_index = index; res.status = kMatchPause; res.current = p; return res; reset: s->_index = 0; res.current = p; return res; } static llparse_match_t llparse__match_sequence_to_lower_unsafe( llhttp__internal_t* s, const unsigned char* p, const unsigned char* endp, const unsigned char* seq, uint32_t seq_len) { uint32_t index; llparse_match_t res; index = s->_index; for (; p != endp; p++) { unsigned char current; current = ((*p) | 0x20); if (current == seq[index]) { if (++index == seq_len) { res.status = kMatchComplete; goto reset; } } else { res.status = kMatchMismatch; goto reset; } } s->_index = index; res.status = kMatchPause; res.current = p; return res; reset: s->_index = 0; res.current = p; return res; } static llparse_match_t llparse__match_sequence_id( llhttp__internal_t* s, const unsigned char* p, const unsigned char* endp, const unsigned char* seq, uint32_t seq_len) { uint32_t index; llparse_match_t res; index = s->_index; for (; p != endp; p++) { unsigned char current; current = *p; if (current == seq[index]) { if (++index == seq_len) { res.status = kMatchComplete; goto reset; } } else { res.status = kMatchMismatch; goto reset; } } s->_index = index; res.status = kMatchPause; res.current = p; return res; reset: s->_index = 0; res.current = p; return res; } enum llparse_state_e { s_error, s_n_llhttp__internal__n_closed, s_n_llhttp__internal__n_invoke_llhttp__after_message_complete, s_n_llhttp__internal__n_pause_1, s_n_llhttp__internal__n_invoke_is_equal_upgrade, s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2, s_n_llhttp__internal__n_chunk_data_almost_done_1, s_n_llhttp__internal__n_chunk_data_almost_done, s_n_llhttp__internal__n_consume_content_length, s_n_llhttp__internal__n_span_start_llhttp__on_body, s_n_llhttp__internal__n_invoke_is_equal_content_length, s_n_llhttp__internal__n_chunk_size_almost_done, s_n_llhttp__internal__n_invoke_test_lenient_flags_9, s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete, s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_1, s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_2, s_n_llhttp__internal__n_invoke_test_lenient_flags_10, s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete, s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_1, s_n_llhttp__internal__n_chunk_extension_quoted_value_done, s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_2, s_n_llhttp__internal__n_error_30, s_n_llhttp__internal__n_chunk_extension_quoted_value_quoted_pair, s_n_llhttp__internal__n_error_31, s_n_llhttp__internal__n_chunk_extension_quoted_value, s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_3, s_n_llhttp__internal__n_error_33, s_n_llhttp__internal__n_chunk_extension_value, s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_value, s_n_llhttp__internal__n_error_34, s_n_llhttp__internal__n_chunk_extension_name, s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_name, s_n_llhttp__internal__n_chunk_extensions, s_n_llhttp__internal__n_chunk_size_otherwise, s_n_llhttp__internal__n_chunk_size, s_n_llhttp__internal__n_chunk_size_digit, s_n_llhttp__internal__n_invoke_update_content_length_1, s_n_llhttp__internal__n_consume_content_length_1, s_n_llhttp__internal__n_span_start_llhttp__on_body_1, s_n_llhttp__internal__n_eof, s_n_llhttp__internal__n_span_start_llhttp__on_body_2, s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete, s_n_llhttp__internal__n_error_5, s_n_llhttp__internal__n_headers_almost_done, s_n_llhttp__internal__n_header_field_colon_discard_ws, s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete, s_n_llhttp__internal__n_span_start_llhttp__on_header_value, s_n_llhttp__internal__n_header_value_discard_lws, s_n_llhttp__internal__n_header_value_discard_ws_almost_done, s_n_llhttp__internal__n_header_value_lws, s_n_llhttp__internal__n_header_value_almost_done, s_n_llhttp__internal__n_invoke_test_lenient_flags_17, s_n_llhttp__internal__n_header_value_lenient, s_n_llhttp__internal__n_error_54, s_n_llhttp__internal__n_header_value_otherwise, s_n_llhttp__internal__n_header_value_connection_token, s_n_llhttp__internal__n_header_value_connection_ws, s_n_llhttp__internal__n_header_value_connection_1, s_n_llhttp__internal__n_header_value_connection_2, s_n_llhttp__internal__n_header_value_connection_3, s_n_llhttp__internal__n_header_value_connection, s_n_llhttp__internal__n_error_56, s_n_llhttp__internal__n_error_57, s_n_llhttp__internal__n_header_value_content_length_ws, s_n_llhttp__internal__n_header_value_content_length, s_n_llhttp__internal__n_error_59, s_n_llhttp__internal__n_error_58, s_n_llhttp__internal__n_header_value_te_token_ows, s_n_llhttp__internal__n_header_value, s_n_llhttp__internal__n_header_value_te_token, s_n_llhttp__internal__n_header_value_te_chunked_last, s_n_llhttp__internal__n_header_value_te_chunked, s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1, s_n_llhttp__internal__n_header_value_discard_ws, s_n_llhttp__internal__n_invoke_load_header_state, s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete, s_n_llhttp__internal__n_header_field_general_otherwise, s_n_llhttp__internal__n_header_field_general, s_n_llhttp__internal__n_header_field_colon, s_n_llhttp__internal__n_header_field_3, s_n_llhttp__internal__n_header_field_4, s_n_llhttp__internal__n_header_field_2, s_n_llhttp__internal__n_header_field_1, s_n_llhttp__internal__n_header_field_5, s_n_llhttp__internal__n_header_field_6, s_n_llhttp__internal__n_header_field_7, s_n_llhttp__internal__n_header_field, s_n_llhttp__internal__n_span_start_llhttp__on_header_field, s_n_llhttp__internal__n_header_field_start, s_n_llhttp__internal__n_headers_start, s_n_llhttp__internal__n_url_to_http_09, s_n_llhttp__internal__n_url_skip_to_http09, s_n_llhttp__internal__n_url_skip_lf_to_http09_1, s_n_llhttp__internal__n_url_skip_lf_to_http09, s_n_llhttp__internal__n_req_pri_upgrade, s_n_llhttp__internal__n_req_http_complete_crlf, s_n_llhttp__internal__n_req_http_complete, s_n_llhttp__internal__n_invoke_load_method_1, s_n_llhttp__internal__n_invoke_llhttp__on_version_complete, s_n_llhttp__internal__n_error_66, s_n_llhttp__internal__n_error_73, s_n_llhttp__internal__n_req_http_minor, s_n_llhttp__internal__n_error_74, s_n_llhttp__internal__n_req_http_dot, s_n_llhttp__internal__n_error_75, s_n_llhttp__internal__n_req_http_major, s_n_llhttp__internal__n_span_start_llhttp__on_version, s_n_llhttp__internal__n_req_http_start_1, s_n_llhttp__internal__n_req_http_start_2, s_n_llhttp__internal__n_req_http_start_3, s_n_llhttp__internal__n_req_http_start, s_n_llhttp__internal__n_url_to_http, s_n_llhttp__internal__n_url_skip_to_http, s_n_llhttp__internal__n_url_fragment, s_n_llhttp__internal__n_span_end_stub_query_3, s_n_llhttp__internal__n_url_query, s_n_llhttp__internal__n_url_query_or_fragment, s_n_llhttp__internal__n_url_path, s_n_llhttp__internal__n_span_start_stub_path_2, s_n_llhttp__internal__n_span_start_stub_path, s_n_llhttp__internal__n_span_start_stub_path_1, s_n_llhttp__internal__n_url_server_with_at, s_n_llhttp__internal__n_url_server, s_n_llhttp__internal__n_url_schema_delim_1, s_n_llhttp__internal__n_url_schema_delim, s_n_llhttp__internal__n_span_end_stub_schema, s_n_llhttp__internal__n_url_schema, s_n_llhttp__internal__n_url_start, s_n_llhttp__internal__n_span_start_llhttp__on_url_1, s_n_llhttp__internal__n_url_entry_normal, s_n_llhttp__internal__n_span_start_llhttp__on_url, s_n_llhttp__internal__n_url_entry_connect, s_n_llhttp__internal__n_req_spaces_before_url, s_n_llhttp__internal__n_req_first_space_before_url, s_n_llhttp__internal__n_invoke_llhttp__on_method_complete_1, s_n_llhttp__internal__n_after_start_req_2, s_n_llhttp__internal__n_after_start_req_3, s_n_llhttp__internal__n_after_start_req_1, s_n_llhttp__internal__n_after_start_req_4, s_n_llhttp__internal__n_after_start_req_6, s_n_llhttp__internal__n_after_start_req_8, s_n_llhttp__internal__n_after_start_req_9, s_n_llhttp__internal__n_after_start_req_7, s_n_llhttp__internal__n_after_start_req_5, s_n_llhttp__internal__n_after_start_req_12, s_n_llhttp__internal__n_after_start_req_13, s_n_llhttp__internal__n_after_start_req_11, s_n_llhttp__internal__n_after_start_req_10, s_n_llhttp__internal__n_after_start_req_14, s_n_llhttp__internal__n_after_start_req_17, s_n_llhttp__internal__n_after_start_req_16, s_n_llhttp__internal__n_after_start_req_15, s_n_llhttp__internal__n_after_start_req_18, s_n_llhttp__internal__n_after_start_req_20, s_n_llhttp__internal__n_after_start_req_21, s_n_llhttp__internal__n_after_start_req_19, s_n_llhttp__internal__n_after_start_req_23, s_n_llhttp__internal__n_after_start_req_24, s_n_llhttp__internal__n_after_start_req_26, s_n_llhttp__internal__n_after_start_req_28, s_n_llhttp__internal__n_after_start_req_29, s_n_llhttp__internal__n_after_start_req_27, s_n_llhttp__internal__n_after_start_req_25, s_n_llhttp__internal__n_after_start_req_30, s_n_llhttp__internal__n_after_start_req_22, s_n_llhttp__internal__n_after_start_req_31, s_n_llhttp__internal__n_after_start_req_32, s_n_llhttp__internal__n_after_start_req_35, s_n_llhttp__internal__n_after_start_req_36, s_n_llhttp__internal__n_after_start_req_34, s_n_llhttp__internal__n_after_start_req_37, s_n_llhttp__internal__n_after_start_req_38, s_n_llhttp__internal__n_after_start_req_42, s_n_llhttp__internal__n_after_start_req_43, s_n_llhttp__internal__n_after_start_req_41, s_n_llhttp__internal__n_after_start_req_40, s_n_llhttp__internal__n_after_start_req_39, s_n_llhttp__internal__n_after_start_req_45, s_n_llhttp__internal__n_after_start_req_44, s_n_llhttp__internal__n_after_start_req_33, s_n_llhttp__internal__n_after_start_req_46, s_n_llhttp__internal__n_after_start_req_49, s_n_llhttp__internal__n_after_start_req_50, s_n_llhttp__internal__n_after_start_req_51, s_n_llhttp__internal__n_after_start_req_52, s_n_llhttp__internal__n_after_start_req_48, s_n_llhttp__internal__n_after_start_req_47, s_n_llhttp__internal__n_after_start_req_55, s_n_llhttp__internal__n_after_start_req_57, s_n_llhttp__internal__n_after_start_req_58, s_n_llhttp__internal__n_after_start_req_56, s_n_llhttp__internal__n_after_start_req_54, s_n_llhttp__internal__n_after_start_req_59, s_n_llhttp__internal__n_after_start_req_60, s_n_llhttp__internal__n_after_start_req_53, s_n_llhttp__internal__n_after_start_req_62, s_n_llhttp__internal__n_after_start_req_63, s_n_llhttp__internal__n_after_start_req_61, s_n_llhttp__internal__n_after_start_req_66, s_n_llhttp__internal__n_after_start_req_68, s_n_llhttp__internal__n_after_start_req_69, s_n_llhttp__internal__n_after_start_req_67, s_n_llhttp__internal__n_after_start_req_70, s_n_llhttp__internal__n_after_start_req_65, s_n_llhttp__internal__n_after_start_req_64, s_n_llhttp__internal__n_after_start_req, s_n_llhttp__internal__n_span_start_llhttp__on_method_1, s_n_llhttp__internal__n_res_line_almost_done, s_n_llhttp__internal__n_invoke_test_lenient_flags_30, s_n_llhttp__internal__n_res_status, s_n_llhttp__internal__n_span_start_llhttp__on_status, s_n_llhttp__internal__n_res_status_code_otherwise, s_n_llhttp__internal__n_res_status_code_digit_3, s_n_llhttp__internal__n_res_status_code_digit_2, s_n_llhttp__internal__n_res_status_code_digit_1, s_n_llhttp__internal__n_res_after_version, s_n_llhttp__internal__n_invoke_llhttp__on_version_complete_1, s_n_llhttp__internal__n_error_89, s_n_llhttp__internal__n_error_103, s_n_llhttp__internal__n_res_http_minor, s_n_llhttp__internal__n_error_104, s_n_llhttp__internal__n_res_http_dot, s_n_llhttp__internal__n_error_105, s_n_llhttp__internal__n_res_http_major, s_n_llhttp__internal__n_span_start_llhttp__on_version_1, s_n_llhttp__internal__n_start_res, s_n_llhttp__internal__n_invoke_llhttp__on_method_complete, s_n_llhttp__internal__n_req_or_res_method_2, s_n_llhttp__internal__n_invoke_update_type_1, s_n_llhttp__internal__n_req_or_res_method_3, s_n_llhttp__internal__n_req_or_res_method_1, s_n_llhttp__internal__n_req_or_res_method, s_n_llhttp__internal__n_span_start_llhttp__on_method, s_n_llhttp__internal__n_start_req_or_res, s_n_llhttp__internal__n_invoke_load_type, s_n_llhttp__internal__n_invoke_update_finish, s_n_llhttp__internal__n_start, }; typedef enum llparse_state_e llparse_state_t; int llhttp__on_method( llhttp__internal_t* s, const unsigned char* p, const unsigned char* endp); int llhttp__on_url( llhttp__internal_t* s, const unsigned char* p, const unsigned char* endp); int llhttp__on_version( llhttp__internal_t* s, const unsigned char* p, const unsigned char* endp); int llhttp__on_header_field( llhttp__internal_t* s, const unsigned char* p, const unsigned char* endp); int llhttp__on_header_value( llhttp__internal_t* s, const unsigned char* p, const unsigned char* endp); int llhttp__on_body( llhttp__internal_t* s, const unsigned char* p, const unsigned char* endp); int llhttp__on_chunk_extension_name( llhttp__internal_t* s, const unsigned char* p, const unsigned char* endp); int llhttp__on_chunk_extension_value( llhttp__internal_t* s, const unsigned char* p, const unsigned char* endp); int llhttp__on_status( llhttp__internal_t* s, const unsigned char* p, const unsigned char* endp); int llhttp__internal__c_load_initial_message_completed( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { return state->initial_message_completed; } int llhttp__on_reset( llhttp__internal_t* s, const unsigned char* p, const unsigned char* endp); int llhttp__internal__c_update_finish( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { state->finish = 2; return 0; } int llhttp__on_message_begin( llhttp__internal_t* s, const unsigned char* p, const unsigned char* endp); int llhttp__internal__c_load_type( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { return state->type; } int llhttp__internal__c_store_method( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp, int match) { state->method = match; return 0; } int llhttp__on_method_complete( llhttp__internal_t* s, const unsigned char* p, const unsigned char* endp); int llhttp__internal__c_is_equal_method( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { return state->method == 5; } int llhttp__internal__c_update_http_major( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { state->http_major = 0; return 0; } int llhttp__internal__c_update_http_minor( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { state->http_minor = 9; return 0; } int llhttp__on_url_complete( llhttp__internal_t* s, const unsigned char* p, const unsigned char* endp); int llhttp__internal__c_test_lenient_flags( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { return (state->lenient_flags & 1) == 1; } int llhttp__internal__c_test_lenient_flags_1( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { return (state->lenient_flags & 256) == 256; } int llhttp__internal__c_test_flags( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { return (state->flags & 128) == 128; } int llhttp__on_chunk_complete( llhttp__internal_t* s, const unsigned char* p, const unsigned char* endp); int llhttp__on_message_complete( llhttp__internal_t* s, const unsigned char* p, const unsigned char* endp); int llhttp__internal__c_is_equal_upgrade( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { return state->upgrade == 1; } int llhttp__after_message_complete( llhttp__internal_t* s, const unsigned char* p, const unsigned char* endp); int llhttp__internal__c_update_content_length( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { state->content_length = 0; return 0; } int llhttp__internal__c_update_initial_message_completed( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { state->initial_message_completed = 1; return 0; } int llhttp__internal__c_update_finish_1( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { state->finish = 0; return 0; } int llhttp__internal__c_test_lenient_flags_2( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { return (state->lenient_flags & 4) == 4; } int llhttp__internal__c_test_lenient_flags_3( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { return (state->lenient_flags & 32) == 32; } int llhttp__before_headers_complete( llhttp__internal_t* s, const unsigned char* p, const unsigned char* endp); int llhttp__on_headers_complete( llhttp__internal_t* s, const unsigned char* p, const unsigned char* endp); int llhttp__after_headers_complete( llhttp__internal_t* s, const unsigned char* p, const unsigned char* endp); int llhttp__internal__c_mul_add_content_length( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp, int match) { /* Multiplication overflow */ if (state->content_length > 0xffffffffffffffffULL / 16) { return 1; } state->content_length *= 16; /* Addition overflow */ if (match >= 0) { if (state->content_length > 0xffffffffffffffffULL - match) { return 1; } } else { if (state->content_length < 0ULL - match) { return 1; } } state->content_length += match; return 0; } int llhttp__internal__c_test_lenient_flags_4( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { return (state->lenient_flags & 512) == 512; } int llhttp__on_chunk_header( llhttp__internal_t* s, const unsigned char* p, const unsigned char* endp); int llhttp__internal__c_is_equal_content_length( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { return state->content_length == 0; } int llhttp__internal__c_test_lenient_flags_7( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { return (state->lenient_flags & 128) == 128; } int llhttp__internal__c_or_flags( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { state->flags |= 128; return 0; } int llhttp__internal__c_test_lenient_flags_8( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { return (state->lenient_flags & 64) == 64; } int llhttp__on_chunk_extension_name_complete( llhttp__internal_t* s, const unsigned char* p, const unsigned char* endp); int llhttp__on_chunk_extension_value_complete( llhttp__internal_t* s, const unsigned char* p, const unsigned char* endp); int llhttp__internal__c_update_finish_3( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { state->finish = 1; return 0; } int llhttp__internal__c_or_flags_1( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { state->flags |= 64; return 0; } int llhttp__internal__c_update_upgrade( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { state->upgrade = 1; return 0; } int llhttp__internal__c_store_header_state( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp, int match) { state->header_state = match; return 0; } int llhttp__on_header_field_complete( llhttp__internal_t* s, const unsigned char* p, const unsigned char* endp); int llhttp__internal__c_load_header_state( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { return state->header_state; } int llhttp__internal__c_test_flags_4( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { return (state->flags & 512) == 512; } int llhttp__internal__c_test_lenient_flags_22( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { return (state->lenient_flags & 2) == 2; } int llhttp__internal__c_or_flags_5( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { state->flags |= 1; return 0; } int llhttp__internal__c_update_header_state( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { state->header_state = 1; return 0; } int llhttp__on_header_value_complete( llhttp__internal_t* s, const unsigned char* p, const unsigned char* endp); int llhttp__internal__c_or_flags_6( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { state->flags |= 2; return 0; } int llhttp__internal__c_or_flags_7( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { state->flags |= 4; return 0; } int llhttp__internal__c_or_flags_8( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { state->flags |= 8; return 0; } int llhttp__internal__c_update_header_state_3( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { state->header_state = 6; return 0; } int llhttp__internal__c_update_header_state_1( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { state->header_state = 0; return 0; } int llhttp__internal__c_update_header_state_6( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { state->header_state = 5; return 0; } int llhttp__internal__c_update_header_state_7( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { state->header_state = 7; return 0; } int llhttp__internal__c_test_flags_2( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { return (state->flags & 32) == 32; } int llhttp__internal__c_mul_add_content_length_1( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp, int match) { /* Multiplication overflow */ if (state->content_length > 0xffffffffffffffffULL / 10) { return 1; } state->content_length *= 10; /* Addition overflow */ if (match >= 0) { if (state->content_length > 0xffffffffffffffffULL - match) { return 1; } } else { if (state->content_length < 0ULL - match) { return 1; } } state->content_length += match; return 0; } int llhttp__internal__c_or_flags_17( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { state->flags |= 32; return 0; } int llhttp__internal__c_test_flags_3( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { return (state->flags & 8) == 8; } int llhttp__internal__c_test_lenient_flags_20( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { return (state->lenient_flags & 8) == 8; } int llhttp__internal__c_or_flags_18( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { state->flags |= 512; return 0; } int llhttp__internal__c_and_flags( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { state->flags &= -9; return 0; } int llhttp__internal__c_update_header_state_8( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { state->header_state = 8; return 0; } int llhttp__internal__c_or_flags_20( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { state->flags |= 16; return 0; } int llhttp__internal__c_load_method( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { return state->method; } int llhttp__internal__c_store_http_major( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp, int match) { state->http_major = match; return 0; } int llhttp__internal__c_store_http_minor( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp, int match) { state->http_minor = match; return 0; } int llhttp__internal__c_test_lenient_flags_24( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { return (state->lenient_flags & 16) == 16; } int llhttp__on_version_complete( llhttp__internal_t* s, const unsigned char* p, const unsigned char* endp); int llhttp__internal__c_load_http_major( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { return state->http_major; } int llhttp__internal__c_load_http_minor( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { return state->http_minor; } int llhttp__internal__c_update_status_code( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { state->status_code = 0; return 0; } int llhttp__internal__c_mul_add_status_code( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp, int match) { /* Multiplication overflow */ if (state->status_code > 0xffff / 10) { return 1; } state->status_code *= 10; /* Addition overflow */ if (match >= 0) { if (state->status_code > 0xffff - match) { return 1; } } else { if (state->status_code < 0 - match) { return 1; } } state->status_code += match; return 0; } int llhttp__on_status_complete( llhttp__internal_t* s, const unsigned char* p, const unsigned char* endp); int llhttp__internal__c_update_type( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { state->type = 1; return 0; } int llhttp__internal__c_update_type_1( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { state->type = 2; return 0; } int llhttp__internal_init(llhttp__internal_t* state) { memset(state, 0, sizeof(*state)); state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_start; return 0; } static llparse_state_t llhttp__internal__run( llhttp__internal_t* state, const unsigned char* p, const unsigned char* endp) { int match; switch ((llparse_state_t) (intptr_t) state->_current) { case s_n_llhttp__internal__n_closed: s_n_llhttp__internal__n_closed: { if (p == endp) { return s_n_llhttp__internal__n_closed; } switch (*p) { case 10: { p++; goto s_n_llhttp__internal__n_closed; } case 13: { p++; goto s_n_llhttp__internal__n_closed; } default: { p++; goto s_n_llhttp__internal__n_invoke_test_lenient_flags_3; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_invoke_llhttp__after_message_complete: s_n_llhttp__internal__n_invoke_llhttp__after_message_complete: { switch (llhttp__after_message_complete(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_invoke_update_content_length; default: goto s_n_llhttp__internal__n_invoke_update_finish_1; } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_pause_1: s_n_llhttp__internal__n_pause_1: { state->error = 0x16; state->reason = "Pause on CONNECT/Upgrade"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__after_message_complete; return s_error; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_invoke_is_equal_upgrade: s_n_llhttp__internal__n_invoke_is_equal_upgrade: { switch (llhttp__internal__c_is_equal_upgrade(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_invoke_llhttp__after_message_complete; default: goto s_n_llhttp__internal__n_pause_1; } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2: s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2: { switch (llhttp__on_message_complete(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_invoke_is_equal_upgrade; case 21: goto s_n_llhttp__internal__n_pause_13; default: goto s_n_llhttp__internal__n_error_38; } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_chunk_data_almost_done_1: s_n_llhttp__internal__n_chunk_data_almost_done_1: { if (p == endp) { return s_n_llhttp__internal__n_chunk_data_almost_done_1; } switch (*p) { case 10: { p++; goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete; } default: { goto s_n_llhttp__internal__n_invoke_test_lenient_flags_7; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_chunk_data_almost_done: s_n_llhttp__internal__n_chunk_data_almost_done: { if (p == endp) { return s_n_llhttp__internal__n_chunk_data_almost_done; } switch (*p) { case 10: { p++; goto s_n_llhttp__internal__n_invoke_test_lenient_flags_6; } case 13: { p++; goto s_n_llhttp__internal__n_chunk_data_almost_done_1; } default: { goto s_n_llhttp__internal__n_invoke_test_lenient_flags_7; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_consume_content_length: s_n_llhttp__internal__n_consume_content_length: { size_t avail; uint64_t need; avail = endp - p; need = state->content_length; if (avail >= need) { p += need; state->content_length = 0; goto s_n_llhttp__internal__n_span_end_llhttp__on_body; } state->content_length -= avail; return s_n_llhttp__internal__n_consume_content_length; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_span_start_llhttp__on_body: s_n_llhttp__internal__n_span_start_llhttp__on_body: { if (p == endp) { return s_n_llhttp__internal__n_span_start_llhttp__on_body; } state->_span_pos0 = (void*) p; state->_span_cb0 = llhttp__on_body; goto s_n_llhttp__internal__n_consume_content_length; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_invoke_is_equal_content_length: s_n_llhttp__internal__n_invoke_is_equal_content_length: { switch (llhttp__internal__c_is_equal_content_length(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_span_start_llhttp__on_body; default: goto s_n_llhttp__internal__n_invoke_or_flags; } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_chunk_size_almost_done: s_n_llhttp__internal__n_chunk_size_almost_done: { if (p == endp) { return s_n_llhttp__internal__n_chunk_size_almost_done; } switch (*p) { case 10: { p++; goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_header; } default: { goto s_n_llhttp__internal__n_invoke_test_lenient_flags_8; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_invoke_test_lenient_flags_9: s_n_llhttp__internal__n_invoke_test_lenient_flags_9: { switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_chunk_size_almost_done; default: goto s_n_llhttp__internal__n_error_20; } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete: s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete: { switch (llhttp__on_chunk_extension_name_complete(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_invoke_test_lenient_flags_9; case 21: goto s_n_llhttp__internal__n_pause_5; default: goto s_n_llhttp__internal__n_error_19; } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_1: s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_1: { switch (llhttp__on_chunk_extension_name_complete(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_chunk_size_almost_done; case 21: goto s_n_llhttp__internal__n_pause_6; default: goto s_n_llhttp__internal__n_error_21; } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_2: s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_2: { switch (llhttp__on_chunk_extension_name_complete(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_chunk_extensions; case 21: goto s_n_llhttp__internal__n_pause_7; default: goto s_n_llhttp__internal__n_error_22; } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_invoke_test_lenient_flags_10: s_n_llhttp__internal__n_invoke_test_lenient_flags_10: { switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_chunk_size_almost_done; default: goto s_n_llhttp__internal__n_error_25; } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete: s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete: { switch (llhttp__on_chunk_extension_value_complete(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_invoke_test_lenient_flags_10; case 21: goto s_n_llhttp__internal__n_pause_8; default: goto s_n_llhttp__internal__n_error_24; } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_1: s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_1: { switch (llhttp__on_chunk_extension_value_complete(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_chunk_size_almost_done; case 21: goto s_n_llhttp__internal__n_pause_9; default: goto s_n_llhttp__internal__n_error_26; } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_chunk_extension_quoted_value_done: s_n_llhttp__internal__n_chunk_extension_quoted_value_done: { if (p == endp) { return s_n_llhttp__internal__n_chunk_extension_quoted_value_done; } switch (*p) { case 10: { goto s_n_llhttp__internal__n_invoke_test_lenient_flags_11; } case 13: { p++; goto s_n_llhttp__internal__n_chunk_size_almost_done; } case ';': { p++; goto s_n_llhttp__internal__n_chunk_extensions; } default: { goto s_n_llhttp__internal__n_error_29; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_2: s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_2: { switch (llhttp__on_chunk_extension_value_complete(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_chunk_extension_quoted_value_done; case 21: goto s_n_llhttp__internal__n_pause_10; default: goto s_n_llhttp__internal__n_error_27; } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_error_30: s_n_llhttp__internal__n_error_30: { state->error = 0x2; state->reason = "Invalid quoted-pair in chunk extensions quoted value"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_chunk_extension_quoted_value_quoted_pair: s_n_llhttp__internal__n_chunk_extension_quoted_value_quoted_pair: { static uint8_t lookup_table[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; if (p == endp) { return s_n_llhttp__internal__n_chunk_extension_quoted_value_quoted_pair; } switch (lookup_table[(uint8_t) *p]) { case 1: { p++; goto s_n_llhttp__internal__n_chunk_extension_quoted_value; } default: { goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_3; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_error_31: s_n_llhttp__internal__n_error_31: { state->error = 0x2; state->reason = "Invalid character in chunk extensions quoted value"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_chunk_extension_quoted_value: s_n_llhttp__internal__n_chunk_extension_quoted_value: { static uint8_t lookup_table[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; if (p == endp) { return s_n_llhttp__internal__n_chunk_extension_quoted_value; } switch (lookup_table[(uint8_t) *p]) { case 1: { p++; goto s_n_llhttp__internal__n_chunk_extension_quoted_value; } case 2: { p++; goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_2; } case 3: { p++; goto s_n_llhttp__internal__n_chunk_extension_quoted_value_quoted_pair; } default: { goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_4; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_3: s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_3: { switch (llhttp__on_chunk_extension_value_complete(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_chunk_extensions; case 21: goto s_n_llhttp__internal__n_pause_11; default: goto s_n_llhttp__internal__n_error_32; } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_error_33: s_n_llhttp__internal__n_error_33: { state->error = 0x2; state->reason = "Invalid character in chunk extensions value"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_chunk_extension_value: s_n_llhttp__internal__n_chunk_extension_value: { static uint8_t lookup_table[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 3, 3, 3, 3, 3, 0, 0, 3, 3, 0, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 5, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; if (p == endp) { return s_n_llhttp__internal__n_chunk_extension_value; } switch (lookup_table[(uint8_t) *p]) { case 1: { goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value; } case 2: { goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_1; } case 3: { p++; goto s_n_llhttp__internal__n_chunk_extension_value; } case 4: { p++; goto s_n_llhttp__internal__n_chunk_extension_quoted_value; } case 5: { goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_5; } default: { goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_6; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_value: s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_value: { if (p == endp) { return s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_value; } state->_span_pos0 = (void*) p; state->_span_cb0 = llhttp__on_chunk_extension_value; goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_3; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_error_34: s_n_llhttp__internal__n_error_34: { state->error = 0x2; state->reason = "Invalid character in chunk extensions name"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_chunk_extension_name: s_n_llhttp__internal__n_chunk_extension_name: { static uint8_t lookup_table[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 3, 3, 3, 3, 3, 0, 0, 3, 3, 0, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 4, 0, 5, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; if (p == endp) { return s_n_llhttp__internal__n_chunk_extension_name; } switch (lookup_table[(uint8_t) *p]) { case 1: { goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name; } case 2: { goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name_1; } case 3: { p++; goto s_n_llhttp__internal__n_chunk_extension_name; } case 4: { goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name_2; } case 5: { goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name_3; } default: { goto s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name_4; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_name: s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_name: { if (p == endp) { return s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_name; } state->_span_pos0 = (void*) p; state->_span_cb0 = llhttp__on_chunk_extension_name; goto s_n_llhttp__internal__n_chunk_extension_name; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_chunk_extensions: s_n_llhttp__internal__n_chunk_extensions: { if (p == endp) { return s_n_llhttp__internal__n_chunk_extensions; } switch (*p) { case 13: { p++; goto s_n_llhttp__internal__n_error_17; } case ' ': { p++; goto s_n_llhttp__internal__n_error_18; } default: { goto s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_name; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_chunk_size_otherwise: s_n_llhttp__internal__n_chunk_size_otherwise: { if (p == endp) { return s_n_llhttp__internal__n_chunk_size_otherwise; } switch (*p) { case 9: { p++; goto s_n_llhttp__internal__n_invoke_test_lenient_flags_4; } case 10: { p++; goto s_n_llhttp__internal__n_invoke_test_lenient_flags_5; } case 13: { p++; goto s_n_llhttp__internal__n_chunk_size_almost_done; } case ' ': { p++; goto s_n_llhttp__internal__n_invoke_test_lenient_flags_4; } case ';': { p++; goto s_n_llhttp__internal__n_chunk_extensions; } default: { goto s_n_llhttp__internal__n_error_35; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_chunk_size: s_n_llhttp__internal__n_chunk_size: { if (p == endp) { return s_n_llhttp__internal__n_chunk_size; } switch (*p) { case '0': { p++; match = 0; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case '1': { p++; match = 1; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case '2': { p++; match = 2; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case '3': { p++; match = 3; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case '4': { p++; match = 4; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case '5': { p++; match = 5; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case '6': { p++; match = 6; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case '7': { p++; match = 7; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case '8': { p++; match = 8; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case '9': { p++; match = 9; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case 'A': { p++; match = 10; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case 'B': { p++; match = 11; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case 'C': { p++; match = 12; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case 'D': { p++; match = 13; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case 'E': { p++; match = 14; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case 'F': { p++; match = 15; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case 'a': { p++; match = 10; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case 'b': { p++; match = 11; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case 'c': { p++; match = 12; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case 'd': { p++; match = 13; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case 'e': { p++; match = 14; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case 'f': { p++; match = 15; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } default: { goto s_n_llhttp__internal__n_chunk_size_otherwise; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_chunk_size_digit: s_n_llhttp__internal__n_chunk_size_digit: { if (p == endp) { return s_n_llhttp__internal__n_chunk_size_digit; } switch (*p) { case '0': { p++; match = 0; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case '1': { p++; match = 1; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case '2': { p++; match = 2; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case '3': { p++; match = 3; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case '4': { p++; match = 4; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case '5': { p++; match = 5; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case '6': { p++; match = 6; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case '7': { p++; match = 7; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case '8': { p++; match = 8; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case '9': { p++; match = 9; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case 'A': { p++; match = 10; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case 'B': { p++; match = 11; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case 'C': { p++; match = 12; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case 'D': { p++; match = 13; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case 'E': { p++; match = 14; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case 'F': { p++; match = 15; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case 'a': { p++; match = 10; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case 'b': { p++; match = 11; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case 'c': { p++; match = 12; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case 'd': { p++; match = 13; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case 'e': { p++; match = 14; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } case 'f': { p++; match = 15; goto s_n_llhttp__internal__n_invoke_mul_add_content_length; } default: { goto s_n_llhttp__internal__n_error_37; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_invoke_update_content_length_1: s_n_llhttp__internal__n_invoke_update_content_length_1: { switch (llhttp__internal__c_update_content_length(state, p, endp)) { default: goto s_n_llhttp__internal__n_chunk_size_digit; } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_consume_content_length_1: s_n_llhttp__internal__n_consume_content_length_1: { size_t avail; uint64_t need; avail = endp - p; need = state->content_length; if (avail >= need) { p += need; state->content_length = 0; goto s_n_llhttp__internal__n_span_end_llhttp__on_body_1; } state->content_length -= avail; return s_n_llhttp__internal__n_consume_content_length_1; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_span_start_llhttp__on_body_1: s_n_llhttp__internal__n_span_start_llhttp__on_body_1: { if (p == endp) { return s_n_llhttp__internal__n_span_start_llhttp__on_body_1; } state->_span_pos0 = (void*) p; state->_span_cb0 = llhttp__on_body; goto s_n_llhttp__internal__n_consume_content_length_1; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_eof: s_n_llhttp__internal__n_eof: { if (p == endp) { return s_n_llhttp__internal__n_eof; } p++; goto s_n_llhttp__internal__n_eof; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_span_start_llhttp__on_body_2: s_n_llhttp__internal__n_span_start_llhttp__on_body_2: { if (p == endp) { return s_n_llhttp__internal__n_span_start_llhttp__on_body_2; } state->_span_pos0 = (void*) p; state->_span_cb0 = llhttp__on_body; goto s_n_llhttp__internal__n_eof; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete: s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete: { switch (llhttp__after_headers_complete(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_1; case 2: goto s_n_llhttp__internal__n_invoke_update_content_length_1; case 3: goto s_n_llhttp__internal__n_span_start_llhttp__on_body_1; case 4: goto s_n_llhttp__internal__n_invoke_update_finish_3; case 5: goto s_n_llhttp__internal__n_error_39; default: goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete; } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_error_5: s_n_llhttp__internal__n_error_5: { state->error = 0xa; state->reason = "Invalid header field char"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_headers_almost_done: s_n_llhttp__internal__n_headers_almost_done: { if (p == endp) { return s_n_llhttp__internal__n_headers_almost_done; } switch (*p) { case 10: { p++; goto s_n_llhttp__internal__n_invoke_test_flags_1; } default: { goto s_n_llhttp__internal__n_invoke_test_lenient_flags_12; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_header_field_colon_discard_ws: s_n_llhttp__internal__n_header_field_colon_discard_ws: { if (p == endp) { return s_n_llhttp__internal__n_header_field_colon_discard_ws; } switch (*p) { case ' ': { p++; goto s_n_llhttp__internal__n_header_field_colon_discard_ws; } default: { goto s_n_llhttp__internal__n_header_field_colon; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete: s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete: { switch (llhttp__on_header_value_complete(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_header_field_start; case 21: goto s_n_llhttp__internal__n_pause_18; default: goto s_n_llhttp__internal__n_error_48; } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_span_start_llhttp__on_header_value: s_n_llhttp__internal__n_span_start_llhttp__on_header_value: { if (p == endp) { return s_n_llhttp__internal__n_span_start_llhttp__on_header_value; } state->_span_pos0 = (void*) p; state->_span_cb0 = llhttp__on_header_value; goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_header_value_discard_lws: s_n_llhttp__internal__n_header_value_discard_lws: { if (p == endp) { return s_n_llhttp__internal__n_header_value_discard_lws; } switch (*p) { case 9: { p++; goto s_n_llhttp__internal__n_invoke_test_lenient_flags_15; } case ' ': { p++; goto s_n_llhttp__internal__n_invoke_test_lenient_flags_15; } default: { goto s_n_llhttp__internal__n_invoke_load_header_state_1; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_header_value_discard_ws_almost_done: s_n_llhttp__internal__n_header_value_discard_ws_almost_done: { if (p == endp) { return s_n_llhttp__internal__n_header_value_discard_ws_almost_done; } switch (*p) { case 10: { p++; goto s_n_llhttp__internal__n_header_value_discard_lws; } default: { goto s_n_llhttp__internal__n_invoke_test_lenient_flags_16; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_header_value_lws: s_n_llhttp__internal__n_header_value_lws: { if (p == endp) { return s_n_llhttp__internal__n_header_value_lws; } switch (*p) { case 9: { goto s_n_llhttp__internal__n_invoke_test_lenient_flags_18; } case ' ': { goto s_n_llhttp__internal__n_invoke_test_lenient_flags_18; } default: { goto s_n_llhttp__internal__n_invoke_load_header_state_5; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_header_value_almost_done: s_n_llhttp__internal__n_header_value_almost_done: { if (p == endp) { return s_n_llhttp__internal__n_header_value_almost_done; } switch (*p) { case 10: { p++; goto s_n_llhttp__internal__n_header_value_lws; } default: { goto s_n_llhttp__internal__n_error_53; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_invoke_test_lenient_flags_17: s_n_llhttp__internal__n_invoke_test_lenient_flags_17: { switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_header_value_almost_done; default: goto s_n_llhttp__internal__n_error_51; } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_header_value_lenient: s_n_llhttp__internal__n_header_value_lenient: { if (p == endp) { return s_n_llhttp__internal__n_header_value_lenient; } switch (*p) { case 10: { goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_4; } case 13: { goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_5; } default: { p++; goto s_n_llhttp__internal__n_header_value_lenient; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_error_54: s_n_llhttp__internal__n_error_54: { state->error = 0xa; state->reason = "Invalid header value char"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_header_value_otherwise: s_n_llhttp__internal__n_header_value_otherwise: { if (p == endp) { return s_n_llhttp__internal__n_header_value_otherwise; } switch (*p) { case 10: { goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_1; } case 13: { goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_2; } default: { goto s_n_llhttp__internal__n_invoke_test_lenient_flags_19; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_header_value_connection_token: s_n_llhttp__internal__n_header_value_connection_token: { static uint8_t lookup_table[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; if (p == endp) { return s_n_llhttp__internal__n_header_value_connection_token; } switch (lookup_table[(uint8_t) *p]) { case 1: { p++; goto s_n_llhttp__internal__n_header_value_connection_token; } case 2: { p++; goto s_n_llhttp__internal__n_header_value_connection; } default: { goto s_n_llhttp__internal__n_header_value_otherwise; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_header_value_connection_ws: s_n_llhttp__internal__n_header_value_connection_ws: { if (p == endp) { return s_n_llhttp__internal__n_header_value_connection_ws; } switch (*p) { case 10: { goto s_n_llhttp__internal__n_header_value_otherwise; } case 13: { goto s_n_llhttp__internal__n_header_value_otherwise; } case ' ': { p++; goto s_n_llhttp__internal__n_header_value_connection_ws; } case ',': { p++; goto s_n_llhttp__internal__n_invoke_load_header_state_6; } default: { goto s_n_llhttp__internal__n_invoke_update_header_state_5; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_header_value_connection_1: s_n_llhttp__internal__n_header_value_connection_1: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_header_value_connection_1; } match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob2, 4); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; goto s_n_llhttp__internal__n_invoke_update_header_state_3; } case kMatchPause: { return s_n_llhttp__internal__n_header_value_connection_1; } case kMatchMismatch: { goto s_n_llhttp__internal__n_header_value_connection_token; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_header_value_connection_2: s_n_llhttp__internal__n_header_value_connection_2: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_header_value_connection_2; } match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob3, 9); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; goto s_n_llhttp__internal__n_invoke_update_header_state_6; } case kMatchPause: { return s_n_llhttp__internal__n_header_value_connection_2; } case kMatchMismatch: { goto s_n_llhttp__internal__n_header_value_connection_token; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_header_value_connection_3: s_n_llhttp__internal__n_header_value_connection_3: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_header_value_connection_3; } match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob4, 6); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; goto s_n_llhttp__internal__n_invoke_update_header_state_7; } case kMatchPause: { return s_n_llhttp__internal__n_header_value_connection_3; } case kMatchMismatch: { goto s_n_llhttp__internal__n_header_value_connection_token; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_header_value_connection: s_n_llhttp__internal__n_header_value_connection: { if (p == endp) { return s_n_llhttp__internal__n_header_value_connection; } switch (((*p) >= 'A' && (*p) <= 'Z' ? (*p | 0x20) : (*p))) { case 9: { p++; goto s_n_llhttp__internal__n_header_value_connection; } case ' ': { p++; goto s_n_llhttp__internal__n_header_value_connection; } case 'c': { p++; goto s_n_llhttp__internal__n_header_value_connection_1; } case 'k': { p++; goto s_n_llhttp__internal__n_header_value_connection_2; } case 'u': { p++; goto s_n_llhttp__internal__n_header_value_connection_3; } default: { goto s_n_llhttp__internal__n_header_value_connection_token; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_error_56: s_n_llhttp__internal__n_error_56: { state->error = 0xb; state->reason = "Content-Length overflow"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_error_57: s_n_llhttp__internal__n_error_57: { state->error = 0xb; state->reason = "Invalid character in Content-Length"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_header_value_content_length_ws: s_n_llhttp__internal__n_header_value_content_length_ws: { if (p == endp) { return s_n_llhttp__internal__n_header_value_content_length_ws; } switch (*p) { case 10: { goto s_n_llhttp__internal__n_invoke_or_flags_17; } case 13: { goto s_n_llhttp__internal__n_invoke_or_flags_17; } case ' ': { p++; goto s_n_llhttp__internal__n_header_value_content_length_ws; } default: { goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_7; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_header_value_content_length: s_n_llhttp__internal__n_header_value_content_length: { if (p == endp) { return s_n_llhttp__internal__n_header_value_content_length; } switch (*p) { case '0': { p++; match = 0; goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; } case '1': { p++; match = 1; goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; } case '2': { p++; match = 2; goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; } case '3': { p++; match = 3; goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; } case '4': { p++; match = 4; goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; } case '5': { p++; match = 5; goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; } case '6': { p++; match = 6; goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; } case '7': { p++; match = 7; goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; } case '8': { p++; match = 8; goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; } case '9': { p++; match = 9; goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1; } default: { goto s_n_llhttp__internal__n_header_value_content_length_ws; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_error_59: s_n_llhttp__internal__n_error_59: { state->error = 0xf; state->reason = "Invalid `Transfer-Encoding` header value"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_error_58: s_n_llhttp__internal__n_error_58: { state->error = 0xf; state->reason = "Invalid `Transfer-Encoding` header value"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_header_value_te_token_ows: s_n_llhttp__internal__n_header_value_te_token_ows: { if (p == endp) { return s_n_llhttp__internal__n_header_value_te_token_ows; } switch (*p) { case 9: { p++; goto s_n_llhttp__internal__n_header_value_te_token_ows; } case ' ': { p++; goto s_n_llhttp__internal__n_header_value_te_token_ows; } default: { goto s_n_llhttp__internal__n_header_value_te_chunked; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_header_value: s_n_llhttp__internal__n_header_value: { static uint8_t lookup_table[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; if (p == endp) { return s_n_llhttp__internal__n_header_value; } #ifdef __SSE4_2__ if (endp - p >= 16) { __m128i ranges; __m128i input; int avail; int match_len; /* Load input */ input = _mm_loadu_si128((__m128i const*) p); ranges = _mm_loadu_si128((__m128i const*) llparse_blob6); /* Find first character that does not match `ranges` */ match_len = _mm_cmpestri(ranges, 6, input, 16, _SIDD_UBYTE_OPS | _SIDD_CMP_RANGES | _SIDD_NEGATIVE_POLARITY); if (match_len != 0) { p += match_len; goto s_n_llhttp__internal__n_header_value; } goto s_n_llhttp__internal__n_header_value_otherwise; } #endif /* __SSE4_2__ */ switch (lookup_table[(uint8_t) *p]) { case 1: { p++; goto s_n_llhttp__internal__n_header_value; } default: { goto s_n_llhttp__internal__n_header_value_otherwise; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_header_value_te_token: s_n_llhttp__internal__n_header_value_te_token: { static uint8_t lookup_table[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; if (p == endp) { return s_n_llhttp__internal__n_header_value_te_token; } switch (lookup_table[(uint8_t) *p]) { case 1: { p++; goto s_n_llhttp__internal__n_header_value_te_token; } case 2: { p++; goto s_n_llhttp__internal__n_header_value_te_token_ows; } default: { goto s_n_llhttp__internal__n_invoke_update_header_state_9; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_header_value_te_chunked_last: s_n_llhttp__internal__n_header_value_te_chunked_last: { if (p == endp) { return s_n_llhttp__internal__n_header_value_te_chunked_last; } switch (*p) { case 10: { goto s_n_llhttp__internal__n_invoke_update_header_state_8; } case 13: { goto s_n_llhttp__internal__n_invoke_update_header_state_8; } case ' ': { p++; goto s_n_llhttp__internal__n_header_value_te_chunked_last; } case ',': { goto s_n_llhttp__internal__n_invoke_load_type_1; } default: { goto s_n_llhttp__internal__n_header_value_te_token; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_header_value_te_chunked: s_n_llhttp__internal__n_header_value_te_chunked: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_header_value_te_chunked; } match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob5, 7); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; goto s_n_llhttp__internal__n_header_value_te_chunked_last; } case kMatchPause: { return s_n_llhttp__internal__n_header_value_te_chunked; } case kMatchMismatch: { goto s_n_llhttp__internal__n_header_value_te_token; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1: s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1: { if (p == endp) { return s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1; } state->_span_pos0 = (void*) p; state->_span_cb0 = llhttp__on_header_value; goto s_n_llhttp__internal__n_invoke_load_header_state_3; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_header_value_discard_ws: s_n_llhttp__internal__n_header_value_discard_ws: { if (p == endp) { return s_n_llhttp__internal__n_header_value_discard_ws; } switch (*p) { case 9: { p++; goto s_n_llhttp__internal__n_header_value_discard_ws; } case 10: { p++; goto s_n_llhttp__internal__n_invoke_test_lenient_flags_14; } case 13: { p++; goto s_n_llhttp__internal__n_header_value_discard_ws_almost_done; } case ' ': { p++; goto s_n_llhttp__internal__n_header_value_discard_ws; } default: { goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_invoke_load_header_state: s_n_llhttp__internal__n_invoke_load_header_state: { switch (llhttp__internal__c_load_header_state(state, p, endp)) { case 2: goto s_n_llhttp__internal__n_invoke_test_flags_4; case 3: goto s_n_llhttp__internal__n_invoke_test_flags_5; default: goto s_n_llhttp__internal__n_header_value_discard_ws; } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete: s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete: { switch (llhttp__on_header_field_complete(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_invoke_load_header_state; case 21: goto s_n_llhttp__internal__n_pause_19; default: goto s_n_llhttp__internal__n_error_45; } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_header_field_general_otherwise: s_n_llhttp__internal__n_header_field_general_otherwise: { if (p == endp) { return s_n_llhttp__internal__n_header_field_general_otherwise; } switch (*p) { case ':': { goto s_n_llhttp__internal__n_span_end_llhttp__on_header_field_2; } default: { goto s_n_llhttp__internal__n_error_62; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_header_field_general: s_n_llhttp__internal__n_header_field_general: { static uint8_t lookup_table[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; if (p == endp) { return s_n_llhttp__internal__n_header_field_general; } #ifdef __SSE4_2__ if (endp - p >= 16) { __m128i ranges; __m128i input; int avail; int match_len; /* Load input */ input = _mm_loadu_si128((__m128i const*) p); ranges = _mm_loadu_si128((__m128i const*) llparse_blob7); /* Find first character that does not match `ranges` */ match_len = _mm_cmpestri(ranges, 16, input, 16, _SIDD_UBYTE_OPS | _SIDD_CMP_RANGES | _SIDD_NEGATIVE_POLARITY); if (match_len != 0) { p += match_len; goto s_n_llhttp__internal__n_header_field_general; } ranges = _mm_loadu_si128((__m128i const*) llparse_blob8); /* Find first character that does not match `ranges` */ match_len = _mm_cmpestri(ranges, 2, input, 16, _SIDD_UBYTE_OPS | _SIDD_CMP_RANGES | _SIDD_NEGATIVE_POLARITY); if (match_len != 0) { p += match_len; goto s_n_llhttp__internal__n_header_field_general; } goto s_n_llhttp__internal__n_header_field_general_otherwise; } #endif /* __SSE4_2__ */ switch (lookup_table[(uint8_t) *p]) { case 1: { p++; goto s_n_llhttp__internal__n_header_field_general; } default: { goto s_n_llhttp__internal__n_header_field_general_otherwise; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_header_field_colon: s_n_llhttp__internal__n_header_field_colon: { if (p == endp) { return s_n_llhttp__internal__n_header_field_colon; } switch (*p) { case ' ': { goto s_n_llhttp__internal__n_invoke_test_lenient_flags_13; } case ':': { goto s_n_llhttp__internal__n_span_end_llhttp__on_header_field_1; } default: { goto s_n_llhttp__internal__n_invoke_update_header_state_10; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_header_field_3: s_n_llhttp__internal__n_header_field_3: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_header_field_3; } match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob1, 6); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 1; goto s_n_llhttp__internal__n_invoke_store_header_state; } case kMatchPause: { return s_n_llhttp__internal__n_header_field_3; } case kMatchMismatch: { goto s_n_llhttp__internal__n_invoke_update_header_state_11; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_header_field_4: s_n_llhttp__internal__n_header_field_4: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_header_field_4; } match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob9, 10); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 2; goto s_n_llhttp__internal__n_invoke_store_header_state; } case kMatchPause: { return s_n_llhttp__internal__n_header_field_4; } case kMatchMismatch: { goto s_n_llhttp__internal__n_invoke_update_header_state_11; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_header_field_2: s_n_llhttp__internal__n_header_field_2: { if (p == endp) { return s_n_llhttp__internal__n_header_field_2; } switch (((*p) >= 'A' && (*p) <= 'Z' ? (*p | 0x20) : (*p))) { case 'n': { p++; goto s_n_llhttp__internal__n_header_field_3; } case 't': { p++; goto s_n_llhttp__internal__n_header_field_4; } default: { goto s_n_llhttp__internal__n_invoke_update_header_state_11; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_header_field_1: s_n_llhttp__internal__n_header_field_1: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_header_field_1; } match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob0, 2); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; goto s_n_llhttp__internal__n_header_field_2; } case kMatchPause: { return s_n_llhttp__internal__n_header_field_1; } case kMatchMismatch: { goto s_n_llhttp__internal__n_invoke_update_header_state_11; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_header_field_5: s_n_llhttp__internal__n_header_field_5: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_header_field_5; } match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob10, 15); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 1; goto s_n_llhttp__internal__n_invoke_store_header_state; } case kMatchPause: { return s_n_llhttp__internal__n_header_field_5; } case kMatchMismatch: { goto s_n_llhttp__internal__n_invoke_update_header_state_11; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_header_field_6: s_n_llhttp__internal__n_header_field_6: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_header_field_6; } match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob11, 16); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 3; goto s_n_llhttp__internal__n_invoke_store_header_state; } case kMatchPause: { return s_n_llhttp__internal__n_header_field_6; } case kMatchMismatch: { goto s_n_llhttp__internal__n_invoke_update_header_state_11; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_header_field_7: s_n_llhttp__internal__n_header_field_7: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_header_field_7; } match_seq = llparse__match_sequence_to_lower(state, p, endp, llparse_blob12, 6); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 4; goto s_n_llhttp__internal__n_invoke_store_header_state; } case kMatchPause: { return s_n_llhttp__internal__n_header_field_7; } case kMatchMismatch: { goto s_n_llhttp__internal__n_invoke_update_header_state_11; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_header_field: s_n_llhttp__internal__n_header_field: { if (p == endp) { return s_n_llhttp__internal__n_header_field; } switch (((*p) >= 'A' && (*p) <= 'Z' ? (*p | 0x20) : (*p))) { case 'c': { p++; goto s_n_llhttp__internal__n_header_field_1; } case 'p': { p++; goto s_n_llhttp__internal__n_header_field_5; } case 't': { p++; goto s_n_llhttp__internal__n_header_field_6; } case 'u': { p++; goto s_n_llhttp__internal__n_header_field_7; } default: { goto s_n_llhttp__internal__n_invoke_update_header_state_11; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_span_start_llhttp__on_header_field: s_n_llhttp__internal__n_span_start_llhttp__on_header_field: { if (p == endp) { return s_n_llhttp__internal__n_span_start_llhttp__on_header_field; } state->_span_pos0 = (void*) p; state->_span_cb0 = llhttp__on_header_field; goto s_n_llhttp__internal__n_header_field; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_header_field_start: s_n_llhttp__internal__n_header_field_start: { if (p == endp) { return s_n_llhttp__internal__n_header_field_start; } switch (*p) { case 10: { p++; goto s_n_llhttp__internal__n_invoke_test_lenient_flags_1; } case 13: { p++; goto s_n_llhttp__internal__n_headers_almost_done; } case ':': { goto s_n_llhttp__internal__n_error_44; } default: { goto s_n_llhttp__internal__n_span_start_llhttp__on_header_field; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_headers_start: s_n_llhttp__internal__n_headers_start: { if (p == endp) { return s_n_llhttp__internal__n_headers_start; } switch (*p) { case ' ': { p++; goto s_n_llhttp__internal__n_invoke_test_lenient_flags; } default: { goto s_n_llhttp__internal__n_header_field_start; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_url_to_http_09: s_n_llhttp__internal__n_url_to_http_09: { if (p == endp) { return s_n_llhttp__internal__n_url_to_http_09; } switch (*p) { case 9: { p++; goto s_n_llhttp__internal__n_error_2; } case 12: { p++; goto s_n_llhttp__internal__n_error_2; } default: { goto s_n_llhttp__internal__n_invoke_update_http_major; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_url_skip_to_http09: s_n_llhttp__internal__n_url_skip_to_http09: { if (p == endp) { return s_n_llhttp__internal__n_url_skip_to_http09; } switch (*p) { case 9: { p++; goto s_n_llhttp__internal__n_error_2; } case 12: { p++; goto s_n_llhttp__internal__n_error_2; } default: { p++; goto s_n_llhttp__internal__n_url_to_http_09; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_url_skip_lf_to_http09_1: s_n_llhttp__internal__n_url_skip_lf_to_http09_1: { if (p == endp) { return s_n_llhttp__internal__n_url_skip_lf_to_http09_1; } switch (*p) { case 10: { p++; goto s_n_llhttp__internal__n_url_to_http_09; } default: { goto s_n_llhttp__internal__n_error_63; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_url_skip_lf_to_http09: s_n_llhttp__internal__n_url_skip_lf_to_http09: { if (p == endp) { return s_n_llhttp__internal__n_url_skip_lf_to_http09; } switch (*p) { case 9: { p++; goto s_n_llhttp__internal__n_error_2; } case 12: { p++; goto s_n_llhttp__internal__n_error_2; } case 13: { p++; goto s_n_llhttp__internal__n_url_skip_lf_to_http09_1; } default: { goto s_n_llhttp__internal__n_error_63; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_req_pri_upgrade: s_n_llhttp__internal__n_req_pri_upgrade: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_req_pri_upgrade; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob14, 10); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; goto s_n_llhttp__internal__n_error_71; } case kMatchPause: { return s_n_llhttp__internal__n_req_pri_upgrade; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_72; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_req_http_complete_crlf: s_n_llhttp__internal__n_req_http_complete_crlf: { if (p == endp) { return s_n_llhttp__internal__n_req_http_complete_crlf; } switch (*p) { case 10: { p++; goto s_n_llhttp__internal__n_headers_start; } default: { goto s_n_llhttp__internal__n_invoke_test_lenient_flags_26; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_req_http_complete: s_n_llhttp__internal__n_req_http_complete: { if (p == endp) { return s_n_llhttp__internal__n_req_http_complete; } switch (*p) { case 10: { p++; goto s_n_llhttp__internal__n_invoke_test_lenient_flags_25; } case 13: { p++; goto s_n_llhttp__internal__n_req_http_complete_crlf; } default: { goto s_n_llhttp__internal__n_error_70; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_invoke_load_method_1: s_n_llhttp__internal__n_invoke_load_method_1: { switch (llhttp__internal__c_load_method(state, p, endp)) { case 34: goto s_n_llhttp__internal__n_req_pri_upgrade; default: goto s_n_llhttp__internal__n_req_http_complete; } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_invoke_llhttp__on_version_complete: s_n_llhttp__internal__n_invoke_llhttp__on_version_complete: { switch (llhttp__on_version_complete(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_invoke_load_method_1; case 21: goto s_n_llhttp__internal__n_pause_21; default: goto s_n_llhttp__internal__n_error_67; } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_error_66: s_n_llhttp__internal__n_error_66: { state->error = 0x9; state->reason = "Invalid HTTP version"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_error_73: s_n_llhttp__internal__n_error_73: { state->error = 0x9; state->reason = "Invalid minor version"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_req_http_minor: s_n_llhttp__internal__n_req_http_minor: { if (p == endp) { return s_n_llhttp__internal__n_req_http_minor; } switch (*p) { case '0': { p++; match = 0; goto s_n_llhttp__internal__n_invoke_store_http_minor; } case '1': { p++; match = 1; goto s_n_llhttp__internal__n_invoke_store_http_minor; } case '2': { p++; match = 2; goto s_n_llhttp__internal__n_invoke_store_http_minor; } case '3': { p++; match = 3; goto s_n_llhttp__internal__n_invoke_store_http_minor; } case '4': { p++; match = 4; goto s_n_llhttp__internal__n_invoke_store_http_minor; } case '5': { p++; match = 5; goto s_n_llhttp__internal__n_invoke_store_http_minor; } case '6': { p++; match = 6; goto s_n_llhttp__internal__n_invoke_store_http_minor; } case '7': { p++; match = 7; goto s_n_llhttp__internal__n_invoke_store_http_minor; } case '8': { p++; match = 8; goto s_n_llhttp__internal__n_invoke_store_http_minor; } case '9': { p++; match = 9; goto s_n_llhttp__internal__n_invoke_store_http_minor; } default: { goto s_n_llhttp__internal__n_span_end_llhttp__on_version_2; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_error_74: s_n_llhttp__internal__n_error_74: { state->error = 0x9; state->reason = "Expected dot"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_req_http_dot: s_n_llhttp__internal__n_req_http_dot: { if (p == endp) { return s_n_llhttp__internal__n_req_http_dot; } switch (*p) { case '.': { p++; goto s_n_llhttp__internal__n_req_http_minor; } default: { goto s_n_llhttp__internal__n_span_end_llhttp__on_version_3; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_error_75: s_n_llhttp__internal__n_error_75: { state->error = 0x9; state->reason = "Invalid major version"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_req_http_major: s_n_llhttp__internal__n_req_http_major: { if (p == endp) { return s_n_llhttp__internal__n_req_http_major; } switch (*p) { case '0': { p++; match = 0; goto s_n_llhttp__internal__n_invoke_store_http_major; } case '1': { p++; match = 1; goto s_n_llhttp__internal__n_invoke_store_http_major; } case '2': { p++; match = 2; goto s_n_llhttp__internal__n_invoke_store_http_major; } case '3': { p++; match = 3; goto s_n_llhttp__internal__n_invoke_store_http_major; } case '4': { p++; match = 4; goto s_n_llhttp__internal__n_invoke_store_http_major; } case '5': { p++; match = 5; goto s_n_llhttp__internal__n_invoke_store_http_major; } case '6': { p++; match = 6; goto s_n_llhttp__internal__n_invoke_store_http_major; } case '7': { p++; match = 7; goto s_n_llhttp__internal__n_invoke_store_http_major; } case '8': { p++; match = 8; goto s_n_llhttp__internal__n_invoke_store_http_major; } case '9': { p++; match = 9; goto s_n_llhttp__internal__n_invoke_store_http_major; } default: { goto s_n_llhttp__internal__n_span_end_llhttp__on_version_4; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_span_start_llhttp__on_version: s_n_llhttp__internal__n_span_start_llhttp__on_version: { if (p == endp) { return s_n_llhttp__internal__n_span_start_llhttp__on_version; } state->_span_pos0 = (void*) p; state->_span_cb0 = llhttp__on_version; goto s_n_llhttp__internal__n_req_http_major; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_req_http_start_1: s_n_llhttp__internal__n_req_http_start_1: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_req_http_start_1; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob13, 4); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; goto s_n_llhttp__internal__n_invoke_load_method; } case kMatchPause: { return s_n_llhttp__internal__n_req_http_start_1; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_78; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_req_http_start_2: s_n_llhttp__internal__n_req_http_start_2: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_req_http_start_2; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob15, 3); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; goto s_n_llhttp__internal__n_invoke_load_method_2; } case kMatchPause: { return s_n_llhttp__internal__n_req_http_start_2; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_78; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_req_http_start_3: s_n_llhttp__internal__n_req_http_start_3: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_req_http_start_3; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob16, 4); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; goto s_n_llhttp__internal__n_invoke_load_method_3; } case kMatchPause: { return s_n_llhttp__internal__n_req_http_start_3; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_78; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_req_http_start: s_n_llhttp__internal__n_req_http_start: { if (p == endp) { return s_n_llhttp__internal__n_req_http_start; } switch (*p) { case ' ': { p++; goto s_n_llhttp__internal__n_req_http_start; } case 'H': { p++; goto s_n_llhttp__internal__n_req_http_start_1; } case 'I': { p++; goto s_n_llhttp__internal__n_req_http_start_2; } case 'R': { p++; goto s_n_llhttp__internal__n_req_http_start_3; } default: { goto s_n_llhttp__internal__n_error_78; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_url_to_http: s_n_llhttp__internal__n_url_to_http: { if (p == endp) { return s_n_llhttp__internal__n_url_to_http; } switch (*p) { case 9: { p++; goto s_n_llhttp__internal__n_error_2; } case 12: { p++; goto s_n_llhttp__internal__n_error_2; } default: { goto s_n_llhttp__internal__n_invoke_llhttp__on_url_complete_1; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_url_skip_to_http: s_n_llhttp__internal__n_url_skip_to_http: { if (p == endp) { return s_n_llhttp__internal__n_url_skip_to_http; } switch (*p) { case 9: { p++; goto s_n_llhttp__internal__n_error_2; } case 12: { p++; goto s_n_llhttp__internal__n_error_2; } default: { p++; goto s_n_llhttp__internal__n_url_to_http; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_url_fragment: s_n_llhttp__internal__n_url_fragment: { static uint8_t lookup_table[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; if (p == endp) { return s_n_llhttp__internal__n_url_fragment; } switch (lookup_table[(uint8_t) *p]) { case 1: { p++; goto s_n_llhttp__internal__n_error_2; } case 2: { goto s_n_llhttp__internal__n_span_end_llhttp__on_url_6; } case 3: { goto s_n_llhttp__internal__n_span_end_llhttp__on_url_7; } case 4: { goto s_n_llhttp__internal__n_span_end_llhttp__on_url_8; } case 5: { p++; goto s_n_llhttp__internal__n_url_fragment; } default: { goto s_n_llhttp__internal__n_error_79; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_span_end_stub_query_3: s_n_llhttp__internal__n_span_end_stub_query_3: { if (p == endp) { return s_n_llhttp__internal__n_span_end_stub_query_3; } p++; goto s_n_llhttp__internal__n_url_fragment; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_url_query: s_n_llhttp__internal__n_url_query: { static uint8_t lookup_table[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; if (p == endp) { return s_n_llhttp__internal__n_url_query; } switch (lookup_table[(uint8_t) *p]) { case 1: { p++; goto s_n_llhttp__internal__n_error_2; } case 2: { goto s_n_llhttp__internal__n_span_end_llhttp__on_url_9; } case 3: { goto s_n_llhttp__internal__n_span_end_llhttp__on_url_10; } case 4: { goto s_n_llhttp__internal__n_span_end_llhttp__on_url_11; } case 5: { p++; goto s_n_llhttp__internal__n_url_query; } case 6: { goto s_n_llhttp__internal__n_span_end_stub_query_3; } default: { goto s_n_llhttp__internal__n_error_80; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_url_query_or_fragment: s_n_llhttp__internal__n_url_query_or_fragment: { if (p == endp) { return s_n_llhttp__internal__n_url_query_or_fragment; } switch (*p) { case 9: { p++; goto s_n_llhttp__internal__n_error_2; } case 10: { goto s_n_llhttp__internal__n_span_end_llhttp__on_url_3; } case 12: { p++; goto s_n_llhttp__internal__n_error_2; } case 13: { goto s_n_llhttp__internal__n_span_end_llhttp__on_url_4; } case ' ': { goto s_n_llhttp__internal__n_span_end_llhttp__on_url_5; } case '#': { p++; goto s_n_llhttp__internal__n_url_fragment; } case '?': { p++; goto s_n_llhttp__internal__n_url_query; } default: { goto s_n_llhttp__internal__n_error_81; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_url_path: s_n_llhttp__internal__n_url_path: { static uint8_t lookup_table[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; if (p == endp) { return s_n_llhttp__internal__n_url_path; } switch (lookup_table[(uint8_t) *p]) { case 1: { p++; goto s_n_llhttp__internal__n_error_2; } case 2: { p++; goto s_n_llhttp__internal__n_url_path; } default: { goto s_n_llhttp__internal__n_url_query_or_fragment; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_span_start_stub_path_2: s_n_llhttp__internal__n_span_start_stub_path_2: { if (p == endp) { return s_n_llhttp__internal__n_span_start_stub_path_2; } p++; goto s_n_llhttp__internal__n_url_path; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_span_start_stub_path: s_n_llhttp__internal__n_span_start_stub_path: { if (p == endp) { return s_n_llhttp__internal__n_span_start_stub_path; } p++; goto s_n_llhttp__internal__n_url_path; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_span_start_stub_path_1: s_n_llhttp__internal__n_span_start_stub_path_1: { if (p == endp) { return s_n_llhttp__internal__n_span_start_stub_path_1; } p++; goto s_n_llhttp__internal__n_url_path; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_url_server_with_at: s_n_llhttp__internal__n_url_server_with_at: { static uint8_t lookup_table[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 0, 7, 8, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 0, 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; if (p == endp) { return s_n_llhttp__internal__n_url_server_with_at; } switch (lookup_table[(uint8_t) *p]) { case 1: { p++; goto s_n_llhttp__internal__n_error_2; } case 2: { goto s_n_llhttp__internal__n_span_end_llhttp__on_url_12; } case 3: { goto s_n_llhttp__internal__n_span_end_llhttp__on_url_13; } case 4: { goto s_n_llhttp__internal__n_span_end_llhttp__on_url_14; } case 5: { p++; goto s_n_llhttp__internal__n_url_server; } case 6: { goto s_n_llhttp__internal__n_span_start_stub_path_1; } case 7: { p++; goto s_n_llhttp__internal__n_url_query; } case 8: { p++; goto s_n_llhttp__internal__n_error_82; } default: { goto s_n_llhttp__internal__n_error_83; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_url_server: s_n_llhttp__internal__n_url_server: { static uint8_t lookup_table[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 0, 7, 8, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 5, 0, 5, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; if (p == endp) { return s_n_llhttp__internal__n_url_server; } switch (lookup_table[(uint8_t) *p]) { case 1: { p++; goto s_n_llhttp__internal__n_error_2; } case 2: { goto s_n_llhttp__internal__n_span_end_llhttp__on_url; } case 3: { goto s_n_llhttp__internal__n_span_end_llhttp__on_url_1; } case 4: { goto s_n_llhttp__internal__n_span_end_llhttp__on_url_2; } case 5: { p++; goto s_n_llhttp__internal__n_url_server; } case 6: { goto s_n_llhttp__internal__n_span_start_stub_path; } case 7: { p++; goto s_n_llhttp__internal__n_url_query; } case 8: { p++; goto s_n_llhttp__internal__n_url_server_with_at; } default: { goto s_n_llhttp__internal__n_error_84; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_url_schema_delim_1: s_n_llhttp__internal__n_url_schema_delim_1: { if (p == endp) { return s_n_llhttp__internal__n_url_schema_delim_1; } switch (*p) { case '/': { p++; goto s_n_llhttp__internal__n_url_server; } default: { goto s_n_llhttp__internal__n_error_85; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_url_schema_delim: s_n_llhttp__internal__n_url_schema_delim: { if (p == endp) { return s_n_llhttp__internal__n_url_schema_delim; } switch (*p) { case 9: { p++; goto s_n_llhttp__internal__n_error_2; } case 10: { p++; goto s_n_llhttp__internal__n_error_2; } case 12: { p++; goto s_n_llhttp__internal__n_error_2; } case 13: { p++; goto s_n_llhttp__internal__n_error_2; } case ' ': { p++; goto s_n_llhttp__internal__n_error_2; } case '/': { p++; goto s_n_llhttp__internal__n_url_schema_delim_1; } default: { goto s_n_llhttp__internal__n_error_85; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_span_end_stub_schema: s_n_llhttp__internal__n_span_end_stub_schema: { if (p == endp) { return s_n_llhttp__internal__n_span_end_stub_schema; } p++; goto s_n_llhttp__internal__n_url_schema_delim; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_url_schema: s_n_llhttp__internal__n_url_schema: { static uint8_t lookup_table[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; if (p == endp) { return s_n_llhttp__internal__n_url_schema; } switch (lookup_table[(uint8_t) *p]) { case 1: { p++; goto s_n_llhttp__internal__n_error_2; } case 2: { goto s_n_llhttp__internal__n_span_end_stub_schema; } case 3: { p++; goto s_n_llhttp__internal__n_url_schema; } default: { goto s_n_llhttp__internal__n_error_86; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_url_start: s_n_llhttp__internal__n_url_start: { static uint8_t lookup_table[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; if (p == endp) { return s_n_llhttp__internal__n_url_start; } switch (lookup_table[(uint8_t) *p]) { case 1: { p++; goto s_n_llhttp__internal__n_error_2; } case 2: { goto s_n_llhttp__internal__n_span_start_stub_path_2; } case 3: { goto s_n_llhttp__internal__n_url_schema; } default: { goto s_n_llhttp__internal__n_error_87; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_span_start_llhttp__on_url_1: s_n_llhttp__internal__n_span_start_llhttp__on_url_1: { if (p == endp) { return s_n_llhttp__internal__n_span_start_llhttp__on_url_1; } state->_span_pos0 = (void*) p; state->_span_cb0 = llhttp__on_url; goto s_n_llhttp__internal__n_url_start; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_url_entry_normal: s_n_llhttp__internal__n_url_entry_normal: { if (p == endp) { return s_n_llhttp__internal__n_url_entry_normal; } switch (*p) { case 9: { p++; goto s_n_llhttp__internal__n_error_2; } case 12: { p++; goto s_n_llhttp__internal__n_error_2; } default: { goto s_n_llhttp__internal__n_span_start_llhttp__on_url_1; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_span_start_llhttp__on_url: s_n_llhttp__internal__n_span_start_llhttp__on_url: { if (p == endp) { return s_n_llhttp__internal__n_span_start_llhttp__on_url; } state->_span_pos0 = (void*) p; state->_span_cb0 = llhttp__on_url; goto s_n_llhttp__internal__n_url_server; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_url_entry_connect: s_n_llhttp__internal__n_url_entry_connect: { if (p == endp) { return s_n_llhttp__internal__n_url_entry_connect; } switch (*p) { case 9: { p++; goto s_n_llhttp__internal__n_error_2; } case 12: { p++; goto s_n_llhttp__internal__n_error_2; } default: { goto s_n_llhttp__internal__n_span_start_llhttp__on_url; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_req_spaces_before_url: s_n_llhttp__internal__n_req_spaces_before_url: { if (p == endp) { return s_n_llhttp__internal__n_req_spaces_before_url; } switch (*p) { case ' ': { p++; goto s_n_llhttp__internal__n_req_spaces_before_url; } default: { goto s_n_llhttp__internal__n_invoke_is_equal_method; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_req_first_space_before_url: s_n_llhttp__internal__n_req_first_space_before_url: { if (p == endp) { return s_n_llhttp__internal__n_req_first_space_before_url; } switch (*p) { case ' ': { p++; goto s_n_llhttp__internal__n_req_spaces_before_url; } default: { goto s_n_llhttp__internal__n_error_88; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_invoke_llhttp__on_method_complete_1: s_n_llhttp__internal__n_invoke_llhttp__on_method_complete_1: { switch (llhttp__on_method_complete(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_req_first_space_before_url; case 21: goto s_n_llhttp__internal__n_pause_26; default: goto s_n_llhttp__internal__n_error_107; } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_2: s_n_llhttp__internal__n_after_start_req_2: { if (p == endp) { return s_n_llhttp__internal__n_after_start_req_2; } switch (*p) { case 'L': { p++; match = 19; goto s_n_llhttp__internal__n_invoke_store_method_1; } default: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_3: s_n_llhttp__internal__n_after_start_req_3: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_3; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob17, 6); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 36; goto s_n_llhttp__internal__n_invoke_store_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_3; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_1: s_n_llhttp__internal__n_after_start_req_1: { if (p == endp) { return s_n_llhttp__internal__n_after_start_req_1; } switch (*p) { case 'C': { p++; goto s_n_llhttp__internal__n_after_start_req_2; } case 'N': { p++; goto s_n_llhttp__internal__n_after_start_req_3; } default: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_4: s_n_llhttp__internal__n_after_start_req_4: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_4; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob18, 3); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 16; goto s_n_llhttp__internal__n_invoke_store_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_4; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_6: s_n_llhttp__internal__n_after_start_req_6: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_6; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob19, 6); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 22; goto s_n_llhttp__internal__n_invoke_store_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_6; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_8: s_n_llhttp__internal__n_after_start_req_8: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_8; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob20, 4); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 5; goto s_n_llhttp__internal__n_invoke_store_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_8; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_9: s_n_llhttp__internal__n_after_start_req_9: { if (p == endp) { return s_n_llhttp__internal__n_after_start_req_9; } switch (*p) { case 'Y': { p++; match = 8; goto s_n_llhttp__internal__n_invoke_store_method_1; } default: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_7: s_n_llhttp__internal__n_after_start_req_7: { if (p == endp) { return s_n_llhttp__internal__n_after_start_req_7; } switch (*p) { case 'N': { p++; goto s_n_llhttp__internal__n_after_start_req_8; } case 'P': { p++; goto s_n_llhttp__internal__n_after_start_req_9; } default: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_5: s_n_llhttp__internal__n_after_start_req_5: { if (p == endp) { return s_n_llhttp__internal__n_after_start_req_5; } switch (*p) { case 'H': { p++; goto s_n_llhttp__internal__n_after_start_req_6; } case 'O': { p++; goto s_n_llhttp__internal__n_after_start_req_7; } default: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_12: s_n_llhttp__internal__n_after_start_req_12: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_12; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob21, 3); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 0; goto s_n_llhttp__internal__n_invoke_store_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_12; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_13: s_n_llhttp__internal__n_after_start_req_13: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_13; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob22, 5); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 35; goto s_n_llhttp__internal__n_invoke_store_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_13; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_11: s_n_llhttp__internal__n_after_start_req_11: { if (p == endp) { return s_n_llhttp__internal__n_after_start_req_11; } switch (*p) { case 'L': { p++; goto s_n_llhttp__internal__n_after_start_req_12; } case 'S': { p++; goto s_n_llhttp__internal__n_after_start_req_13; } default: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_10: s_n_llhttp__internal__n_after_start_req_10: { if (p == endp) { return s_n_llhttp__internal__n_after_start_req_10; } switch (*p) { case 'E': { p++; goto s_n_llhttp__internal__n_after_start_req_11; } default: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_14: s_n_llhttp__internal__n_after_start_req_14: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_14; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob23, 4); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 45; goto s_n_llhttp__internal__n_invoke_store_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_14; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_17: s_n_llhttp__internal__n_after_start_req_17: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_17; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob25, 9); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 41; goto s_n_llhttp__internal__n_invoke_store_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_17; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_16: s_n_llhttp__internal__n_after_start_req_16: { if (p == endp) { return s_n_llhttp__internal__n_after_start_req_16; } switch (*p) { case '_': { p++; goto s_n_llhttp__internal__n_after_start_req_17; } default: { match = 1; goto s_n_llhttp__internal__n_invoke_store_method_1; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_15: s_n_llhttp__internal__n_after_start_req_15: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_15; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob24, 2); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; goto s_n_llhttp__internal__n_after_start_req_16; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_15; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_18: s_n_llhttp__internal__n_after_start_req_18: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_18; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob26, 3); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 2; goto s_n_llhttp__internal__n_invoke_store_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_18; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_20: s_n_llhttp__internal__n_after_start_req_20: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_20; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob27, 2); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 31; goto s_n_llhttp__internal__n_invoke_store_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_20; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_21: s_n_llhttp__internal__n_after_start_req_21: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_21; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob28, 2); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 9; goto s_n_llhttp__internal__n_invoke_store_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_21; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_19: s_n_llhttp__internal__n_after_start_req_19: { if (p == endp) { return s_n_llhttp__internal__n_after_start_req_19; } switch (*p) { case 'I': { p++; goto s_n_llhttp__internal__n_after_start_req_20; } case 'O': { p++; goto s_n_llhttp__internal__n_after_start_req_21; } default: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_23: s_n_llhttp__internal__n_after_start_req_23: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_23; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob29, 6); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 24; goto s_n_llhttp__internal__n_invoke_store_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_23; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_24: s_n_llhttp__internal__n_after_start_req_24: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_24; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob30, 3); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 23; goto s_n_llhttp__internal__n_invoke_store_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_24; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_26: s_n_llhttp__internal__n_after_start_req_26: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_26; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob31, 7); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 21; goto s_n_llhttp__internal__n_invoke_store_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_26; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_28: s_n_llhttp__internal__n_after_start_req_28: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_28; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob32, 6); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 30; goto s_n_llhttp__internal__n_invoke_store_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_28; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_29: s_n_llhttp__internal__n_after_start_req_29: { if (p == endp) { return s_n_llhttp__internal__n_after_start_req_29; } switch (*p) { case 'L': { p++; match = 10; goto s_n_llhttp__internal__n_invoke_store_method_1; } default: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_27: s_n_llhttp__internal__n_after_start_req_27: { if (p == endp) { return s_n_llhttp__internal__n_after_start_req_27; } switch (*p) { case 'A': { p++; goto s_n_llhttp__internal__n_after_start_req_28; } case 'O': { p++; goto s_n_llhttp__internal__n_after_start_req_29; } default: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_25: s_n_llhttp__internal__n_after_start_req_25: { if (p == endp) { return s_n_llhttp__internal__n_after_start_req_25; } switch (*p) { case 'A': { p++; goto s_n_llhttp__internal__n_after_start_req_26; } case 'C': { p++; goto s_n_llhttp__internal__n_after_start_req_27; } default: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_30: s_n_llhttp__internal__n_after_start_req_30: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_30; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob33, 2); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 11; goto s_n_llhttp__internal__n_invoke_store_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_30; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_22: s_n_llhttp__internal__n_after_start_req_22: { if (p == endp) { return s_n_llhttp__internal__n_after_start_req_22; } switch (*p) { case '-': { p++; goto s_n_llhttp__internal__n_after_start_req_23; } case 'E': { p++; goto s_n_llhttp__internal__n_after_start_req_24; } case 'K': { p++; goto s_n_llhttp__internal__n_after_start_req_25; } case 'O': { p++; goto s_n_llhttp__internal__n_after_start_req_30; } default: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_31: s_n_llhttp__internal__n_after_start_req_31: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_31; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob34, 5); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 25; goto s_n_llhttp__internal__n_invoke_store_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_31; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_32: s_n_llhttp__internal__n_after_start_req_32: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_32; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob35, 6); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 6; goto s_n_llhttp__internal__n_invoke_store_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_32; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_35: s_n_llhttp__internal__n_after_start_req_35: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_35; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob36, 2); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 28; goto s_n_llhttp__internal__n_invoke_store_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_35; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_36: s_n_llhttp__internal__n_after_start_req_36: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_36; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob37, 2); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 39; goto s_n_llhttp__internal__n_invoke_store_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_36; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_34: s_n_llhttp__internal__n_after_start_req_34: { if (p == endp) { return s_n_llhttp__internal__n_after_start_req_34; } switch (*p) { case 'T': { p++; goto s_n_llhttp__internal__n_after_start_req_35; } case 'U': { p++; goto s_n_llhttp__internal__n_after_start_req_36; } default: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_37: s_n_llhttp__internal__n_after_start_req_37: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_37; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob38, 2); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 38; goto s_n_llhttp__internal__n_invoke_store_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_37; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_38: s_n_llhttp__internal__n_after_start_req_38: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_38; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob39, 2); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 3; goto s_n_llhttp__internal__n_invoke_store_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_38; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_42: s_n_llhttp__internal__n_after_start_req_42: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_42; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob40, 3); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 12; goto s_n_llhttp__internal__n_invoke_store_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_42; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_43: s_n_llhttp__internal__n_after_start_req_43: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_43; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob41, 4); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 13; goto s_n_llhttp__internal__n_invoke_store_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_43; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_41: s_n_llhttp__internal__n_after_start_req_41: { if (p == endp) { return s_n_llhttp__internal__n_after_start_req_41; } switch (*p) { case 'F': { p++; goto s_n_llhttp__internal__n_after_start_req_42; } case 'P': { p++; goto s_n_llhttp__internal__n_after_start_req_43; } default: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_40: s_n_llhttp__internal__n_after_start_req_40: { if (p == endp) { return s_n_llhttp__internal__n_after_start_req_40; } switch (*p) { case 'P': { p++; goto s_n_llhttp__internal__n_after_start_req_41; } default: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_39: s_n_llhttp__internal__n_after_start_req_39: { if (p == endp) { return s_n_llhttp__internal__n_after_start_req_39; } switch (*p) { case 'I': { p++; match = 34; goto s_n_llhttp__internal__n_invoke_store_method_1; } case 'O': { p++; goto s_n_llhttp__internal__n_after_start_req_40; } default: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_45: s_n_llhttp__internal__n_after_start_req_45: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_45; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob42, 2); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 29; goto s_n_llhttp__internal__n_invoke_store_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_45; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_44: s_n_llhttp__internal__n_after_start_req_44: { if (p == endp) { return s_n_llhttp__internal__n_after_start_req_44; } switch (*p) { case 'R': { p++; goto s_n_llhttp__internal__n_after_start_req_45; } case 'T': { p++; match = 4; goto s_n_llhttp__internal__n_invoke_store_method_1; } default: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_33: s_n_llhttp__internal__n_after_start_req_33: { if (p == endp) { return s_n_llhttp__internal__n_after_start_req_33; } switch (*p) { case 'A': { p++; goto s_n_llhttp__internal__n_after_start_req_34; } case 'L': { p++; goto s_n_llhttp__internal__n_after_start_req_37; } case 'O': { p++; goto s_n_llhttp__internal__n_after_start_req_38; } case 'R': { p++; goto s_n_llhttp__internal__n_after_start_req_39; } case 'U': { p++; goto s_n_llhttp__internal__n_after_start_req_44; } default: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_46: s_n_llhttp__internal__n_after_start_req_46: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_46; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob43, 4); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 46; goto s_n_llhttp__internal__n_invoke_store_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_46; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_49: s_n_llhttp__internal__n_after_start_req_49: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_49; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob44, 3); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 17; goto s_n_llhttp__internal__n_invoke_store_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_49; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_50: s_n_llhttp__internal__n_after_start_req_50: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_50; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob45, 3); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 44; goto s_n_llhttp__internal__n_invoke_store_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_50; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_51: s_n_llhttp__internal__n_after_start_req_51: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_51; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob46, 5); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 43; goto s_n_llhttp__internal__n_invoke_store_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_51; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_52: s_n_llhttp__internal__n_after_start_req_52: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_52; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob47, 3); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 20; goto s_n_llhttp__internal__n_invoke_store_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_52; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_48: s_n_llhttp__internal__n_after_start_req_48: { if (p == endp) { return s_n_llhttp__internal__n_after_start_req_48; } switch (*p) { case 'B': { p++; goto s_n_llhttp__internal__n_after_start_req_49; } case 'C': { p++; goto s_n_llhttp__internal__n_after_start_req_50; } case 'D': { p++; goto s_n_llhttp__internal__n_after_start_req_51; } case 'P': { p++; goto s_n_llhttp__internal__n_after_start_req_52; } default: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_47: s_n_llhttp__internal__n_after_start_req_47: { if (p == endp) { return s_n_llhttp__internal__n_after_start_req_47; } switch (*p) { case 'E': { p++; goto s_n_llhttp__internal__n_after_start_req_48; } default: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_55: s_n_llhttp__internal__n_after_start_req_55: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_55; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob48, 3); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 14; goto s_n_llhttp__internal__n_invoke_store_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_55; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_57: s_n_llhttp__internal__n_after_start_req_57: { if (p == endp) { return s_n_llhttp__internal__n_after_start_req_57; } switch (*p) { case 'P': { p++; match = 37; goto s_n_llhttp__internal__n_invoke_store_method_1; } default: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_58: s_n_llhttp__internal__n_after_start_req_58: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_58; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob49, 9); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 42; goto s_n_llhttp__internal__n_invoke_store_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_58; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_56: s_n_llhttp__internal__n_after_start_req_56: { if (p == endp) { return s_n_llhttp__internal__n_after_start_req_56; } switch (*p) { case 'U': { p++; goto s_n_llhttp__internal__n_after_start_req_57; } case '_': { p++; goto s_n_llhttp__internal__n_after_start_req_58; } default: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_54: s_n_llhttp__internal__n_after_start_req_54: { if (p == endp) { return s_n_llhttp__internal__n_after_start_req_54; } switch (*p) { case 'A': { p++; goto s_n_llhttp__internal__n_after_start_req_55; } case 'T': { p++; goto s_n_llhttp__internal__n_after_start_req_56; } default: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_59: s_n_llhttp__internal__n_after_start_req_59: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_59; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob50, 4); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 33; goto s_n_llhttp__internal__n_invoke_store_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_59; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_60: s_n_llhttp__internal__n_after_start_req_60: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_60; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob51, 7); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 26; goto s_n_llhttp__internal__n_invoke_store_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_60; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_53: s_n_llhttp__internal__n_after_start_req_53: { if (p == endp) { return s_n_llhttp__internal__n_after_start_req_53; } switch (*p) { case 'E': { p++; goto s_n_llhttp__internal__n_after_start_req_54; } case 'O': { p++; goto s_n_llhttp__internal__n_after_start_req_59; } case 'U': { p++; goto s_n_llhttp__internal__n_after_start_req_60; } default: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_62: s_n_llhttp__internal__n_after_start_req_62: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_62; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob52, 6); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 40; goto s_n_llhttp__internal__n_invoke_store_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_62; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_63: s_n_llhttp__internal__n_after_start_req_63: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_63; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob53, 3); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 7; goto s_n_llhttp__internal__n_invoke_store_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_63; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_61: s_n_llhttp__internal__n_after_start_req_61: { if (p == endp) { return s_n_llhttp__internal__n_after_start_req_61; } switch (*p) { case 'E': { p++; goto s_n_llhttp__internal__n_after_start_req_62; } case 'R': { p++; goto s_n_llhttp__internal__n_after_start_req_63; } default: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_66: s_n_llhttp__internal__n_after_start_req_66: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_66; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob54, 3); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 18; goto s_n_llhttp__internal__n_invoke_store_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_66; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_68: s_n_llhttp__internal__n_after_start_req_68: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_68; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob55, 2); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 32; goto s_n_llhttp__internal__n_invoke_store_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_68; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_69: s_n_llhttp__internal__n_after_start_req_69: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_69; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob56, 2); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 15; goto s_n_llhttp__internal__n_invoke_store_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_69; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_67: s_n_llhttp__internal__n_after_start_req_67: { if (p == endp) { return s_n_llhttp__internal__n_after_start_req_67; } switch (*p) { case 'I': { p++; goto s_n_llhttp__internal__n_after_start_req_68; } case 'O': { p++; goto s_n_llhttp__internal__n_after_start_req_69; } default: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_70: s_n_llhttp__internal__n_after_start_req_70: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_after_start_req_70; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob57, 8); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 27; goto s_n_llhttp__internal__n_invoke_store_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_after_start_req_70; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_65: s_n_llhttp__internal__n_after_start_req_65: { if (p == endp) { return s_n_llhttp__internal__n_after_start_req_65; } switch (*p) { case 'B': { p++; goto s_n_llhttp__internal__n_after_start_req_66; } case 'L': { p++; goto s_n_llhttp__internal__n_after_start_req_67; } case 'S': { p++; goto s_n_llhttp__internal__n_after_start_req_70; } default: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req_64: s_n_llhttp__internal__n_after_start_req_64: { if (p == endp) { return s_n_llhttp__internal__n_after_start_req_64; } switch (*p) { case 'N': { p++; goto s_n_llhttp__internal__n_after_start_req_65; } default: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_after_start_req: s_n_llhttp__internal__n_after_start_req: { if (p == endp) { return s_n_llhttp__internal__n_after_start_req; } switch (*p) { case 'A': { p++; goto s_n_llhttp__internal__n_after_start_req_1; } case 'B': { p++; goto s_n_llhttp__internal__n_after_start_req_4; } case 'C': { p++; goto s_n_llhttp__internal__n_after_start_req_5; } case 'D': { p++; goto s_n_llhttp__internal__n_after_start_req_10; } case 'F': { p++; goto s_n_llhttp__internal__n_after_start_req_14; } case 'G': { p++; goto s_n_llhttp__internal__n_after_start_req_15; } case 'H': { p++; goto s_n_llhttp__internal__n_after_start_req_18; } case 'L': { p++; goto s_n_llhttp__internal__n_after_start_req_19; } case 'M': { p++; goto s_n_llhttp__internal__n_after_start_req_22; } case 'N': { p++; goto s_n_llhttp__internal__n_after_start_req_31; } case 'O': { p++; goto s_n_llhttp__internal__n_after_start_req_32; } case 'P': { p++; goto s_n_llhttp__internal__n_after_start_req_33; } case 'Q': { p++; goto s_n_llhttp__internal__n_after_start_req_46; } case 'R': { p++; goto s_n_llhttp__internal__n_after_start_req_47; } case 'S': { p++; goto s_n_llhttp__internal__n_after_start_req_53; } case 'T': { p++; goto s_n_llhttp__internal__n_after_start_req_61; } case 'U': { p++; goto s_n_llhttp__internal__n_after_start_req_64; } default: { goto s_n_llhttp__internal__n_error_108; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_span_start_llhttp__on_method_1: s_n_llhttp__internal__n_span_start_llhttp__on_method_1: { if (p == endp) { return s_n_llhttp__internal__n_span_start_llhttp__on_method_1; } state->_span_pos0 = (void*) p; state->_span_cb0 = llhttp__on_method; goto s_n_llhttp__internal__n_after_start_req; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_res_line_almost_done: s_n_llhttp__internal__n_res_line_almost_done: { if (p == endp) { return s_n_llhttp__internal__n_res_line_almost_done; } switch (*p) { case 10: { p++; goto s_n_llhttp__internal__n_invoke_llhttp__on_status_complete; } case 13: { p++; goto s_n_llhttp__internal__n_invoke_llhttp__on_status_complete; } default: { goto s_n_llhttp__internal__n_invoke_test_lenient_flags_29; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_invoke_test_lenient_flags_30: s_n_llhttp__internal__n_invoke_test_lenient_flags_30: { switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_invoke_llhttp__on_status_complete; default: goto s_n_llhttp__internal__n_error_94; } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_res_status: s_n_llhttp__internal__n_res_status: { if (p == endp) { return s_n_llhttp__internal__n_res_status; } switch (*p) { case 10: { goto s_n_llhttp__internal__n_span_end_llhttp__on_status; } case 13: { goto s_n_llhttp__internal__n_span_end_llhttp__on_status_1; } default: { p++; goto s_n_llhttp__internal__n_res_status; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_span_start_llhttp__on_status: s_n_llhttp__internal__n_span_start_llhttp__on_status: { if (p == endp) { return s_n_llhttp__internal__n_span_start_llhttp__on_status; } state->_span_pos0 = (void*) p; state->_span_cb0 = llhttp__on_status; goto s_n_llhttp__internal__n_res_status; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_res_status_code_otherwise: s_n_llhttp__internal__n_res_status_code_otherwise: { if (p == endp) { return s_n_llhttp__internal__n_res_status_code_otherwise; } switch (*p) { case 10: { p++; goto s_n_llhttp__internal__n_invoke_test_lenient_flags_28; } case 13: { p++; goto s_n_llhttp__internal__n_res_line_almost_done; } case ' ': { p++; goto s_n_llhttp__internal__n_span_start_llhttp__on_status; } default: { goto s_n_llhttp__internal__n_error_95; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_res_status_code_digit_3: s_n_llhttp__internal__n_res_status_code_digit_3: { if (p == endp) { return s_n_llhttp__internal__n_res_status_code_digit_3; } switch (*p) { case '0': { p++; match = 0; goto s_n_llhttp__internal__n_invoke_mul_add_status_code_2; } case '1': { p++; match = 1; goto s_n_llhttp__internal__n_invoke_mul_add_status_code_2; } case '2': { p++; match = 2; goto s_n_llhttp__internal__n_invoke_mul_add_status_code_2; } case '3': { p++; match = 3; goto s_n_llhttp__internal__n_invoke_mul_add_status_code_2; } case '4': { p++; match = 4; goto s_n_llhttp__internal__n_invoke_mul_add_status_code_2; } case '5': { p++; match = 5; goto s_n_llhttp__internal__n_invoke_mul_add_status_code_2; } case '6': { p++; match = 6; goto s_n_llhttp__internal__n_invoke_mul_add_status_code_2; } case '7': { p++; match = 7; goto s_n_llhttp__internal__n_invoke_mul_add_status_code_2; } case '8': { p++; match = 8; goto s_n_llhttp__internal__n_invoke_mul_add_status_code_2; } case '9': { p++; match = 9; goto s_n_llhttp__internal__n_invoke_mul_add_status_code_2; } default: { goto s_n_llhttp__internal__n_error_97; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_res_status_code_digit_2: s_n_llhttp__internal__n_res_status_code_digit_2: { if (p == endp) { return s_n_llhttp__internal__n_res_status_code_digit_2; } switch (*p) { case '0': { p++; match = 0; goto s_n_llhttp__internal__n_invoke_mul_add_status_code_1; } case '1': { p++; match = 1; goto s_n_llhttp__internal__n_invoke_mul_add_status_code_1; } case '2': { p++; match = 2; goto s_n_llhttp__internal__n_invoke_mul_add_status_code_1; } case '3': { p++; match = 3; goto s_n_llhttp__internal__n_invoke_mul_add_status_code_1; } case '4': { p++; match = 4; goto s_n_llhttp__internal__n_invoke_mul_add_status_code_1; } case '5': { p++; match = 5; goto s_n_llhttp__internal__n_invoke_mul_add_status_code_1; } case '6': { p++; match = 6; goto s_n_llhttp__internal__n_invoke_mul_add_status_code_1; } case '7': { p++; match = 7; goto s_n_llhttp__internal__n_invoke_mul_add_status_code_1; } case '8': { p++; match = 8; goto s_n_llhttp__internal__n_invoke_mul_add_status_code_1; } case '9': { p++; match = 9; goto s_n_llhttp__internal__n_invoke_mul_add_status_code_1; } default: { goto s_n_llhttp__internal__n_error_99; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_res_status_code_digit_1: s_n_llhttp__internal__n_res_status_code_digit_1: { if (p == endp) { return s_n_llhttp__internal__n_res_status_code_digit_1; } switch (*p) { case '0': { p++; match = 0; goto s_n_llhttp__internal__n_invoke_mul_add_status_code; } case '1': { p++; match = 1; goto s_n_llhttp__internal__n_invoke_mul_add_status_code; } case '2': { p++; match = 2; goto s_n_llhttp__internal__n_invoke_mul_add_status_code; } case '3': { p++; match = 3; goto s_n_llhttp__internal__n_invoke_mul_add_status_code; } case '4': { p++; match = 4; goto s_n_llhttp__internal__n_invoke_mul_add_status_code; } case '5': { p++; match = 5; goto s_n_llhttp__internal__n_invoke_mul_add_status_code; } case '6': { p++; match = 6; goto s_n_llhttp__internal__n_invoke_mul_add_status_code; } case '7': { p++; match = 7; goto s_n_llhttp__internal__n_invoke_mul_add_status_code; } case '8': { p++; match = 8; goto s_n_llhttp__internal__n_invoke_mul_add_status_code; } case '9': { p++; match = 9; goto s_n_llhttp__internal__n_invoke_mul_add_status_code; } default: { goto s_n_llhttp__internal__n_error_101; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_res_after_version: s_n_llhttp__internal__n_res_after_version: { if (p == endp) { return s_n_llhttp__internal__n_res_after_version; } switch (*p) { case ' ': { p++; goto s_n_llhttp__internal__n_invoke_update_status_code; } default: { goto s_n_llhttp__internal__n_error_102; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_invoke_llhttp__on_version_complete_1: s_n_llhttp__internal__n_invoke_llhttp__on_version_complete_1: { switch (llhttp__on_version_complete(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_res_after_version; case 21: goto s_n_llhttp__internal__n_pause_25; default: goto s_n_llhttp__internal__n_error_90; } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_error_89: s_n_llhttp__internal__n_error_89: { state->error = 0x9; state->reason = "Invalid HTTP version"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_error_103: s_n_llhttp__internal__n_error_103: { state->error = 0x9; state->reason = "Invalid minor version"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_res_http_minor: s_n_llhttp__internal__n_res_http_minor: { if (p == endp) { return s_n_llhttp__internal__n_res_http_minor; } switch (*p) { case '0': { p++; match = 0; goto s_n_llhttp__internal__n_invoke_store_http_minor_1; } case '1': { p++; match = 1; goto s_n_llhttp__internal__n_invoke_store_http_minor_1; } case '2': { p++; match = 2; goto s_n_llhttp__internal__n_invoke_store_http_minor_1; } case '3': { p++; match = 3; goto s_n_llhttp__internal__n_invoke_store_http_minor_1; } case '4': { p++; match = 4; goto s_n_llhttp__internal__n_invoke_store_http_minor_1; } case '5': { p++; match = 5; goto s_n_llhttp__internal__n_invoke_store_http_minor_1; } case '6': { p++; match = 6; goto s_n_llhttp__internal__n_invoke_store_http_minor_1; } case '7': { p++; match = 7; goto s_n_llhttp__internal__n_invoke_store_http_minor_1; } case '8': { p++; match = 8; goto s_n_llhttp__internal__n_invoke_store_http_minor_1; } case '9': { p++; match = 9; goto s_n_llhttp__internal__n_invoke_store_http_minor_1; } default: { goto s_n_llhttp__internal__n_span_end_llhttp__on_version_7; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_error_104: s_n_llhttp__internal__n_error_104: { state->error = 0x9; state->reason = "Expected dot"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_res_http_dot: s_n_llhttp__internal__n_res_http_dot: { if (p == endp) { return s_n_llhttp__internal__n_res_http_dot; } switch (*p) { case '.': { p++; goto s_n_llhttp__internal__n_res_http_minor; } default: { goto s_n_llhttp__internal__n_span_end_llhttp__on_version_8; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_error_105: s_n_llhttp__internal__n_error_105: { state->error = 0x9; state->reason = "Invalid major version"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_res_http_major: s_n_llhttp__internal__n_res_http_major: { if (p == endp) { return s_n_llhttp__internal__n_res_http_major; } switch (*p) { case '0': { p++; match = 0; goto s_n_llhttp__internal__n_invoke_store_http_major_1; } case '1': { p++; match = 1; goto s_n_llhttp__internal__n_invoke_store_http_major_1; } case '2': { p++; match = 2; goto s_n_llhttp__internal__n_invoke_store_http_major_1; } case '3': { p++; match = 3; goto s_n_llhttp__internal__n_invoke_store_http_major_1; } case '4': { p++; match = 4; goto s_n_llhttp__internal__n_invoke_store_http_major_1; } case '5': { p++; match = 5; goto s_n_llhttp__internal__n_invoke_store_http_major_1; } case '6': { p++; match = 6; goto s_n_llhttp__internal__n_invoke_store_http_major_1; } case '7': { p++; match = 7; goto s_n_llhttp__internal__n_invoke_store_http_major_1; } case '8': { p++; match = 8; goto s_n_llhttp__internal__n_invoke_store_http_major_1; } case '9': { p++; match = 9; goto s_n_llhttp__internal__n_invoke_store_http_major_1; } default: { goto s_n_llhttp__internal__n_span_end_llhttp__on_version_9; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_span_start_llhttp__on_version_1: s_n_llhttp__internal__n_span_start_llhttp__on_version_1: { if (p == endp) { return s_n_llhttp__internal__n_span_start_llhttp__on_version_1; } state->_span_pos0 = (void*) p; state->_span_cb0 = llhttp__on_version; goto s_n_llhttp__internal__n_res_http_major; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_start_res: s_n_llhttp__internal__n_start_res: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_start_res; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob58, 5); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; goto s_n_llhttp__internal__n_span_start_llhttp__on_version_1; } case kMatchPause: { return s_n_llhttp__internal__n_start_res; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_109; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_invoke_llhttp__on_method_complete: s_n_llhttp__internal__n_invoke_llhttp__on_method_complete: { switch (llhttp__on_method_complete(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_req_first_space_before_url; case 21: goto s_n_llhttp__internal__n_pause_23; default: goto s_n_llhttp__internal__n_error_1; } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_req_or_res_method_2: s_n_llhttp__internal__n_req_or_res_method_2: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_req_or_res_method_2; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob59, 2); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; match = 2; goto s_n_llhttp__internal__n_invoke_store_method; } case kMatchPause: { return s_n_llhttp__internal__n_req_or_res_method_2; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_106; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_invoke_update_type_1: s_n_llhttp__internal__n_invoke_update_type_1: { switch (llhttp__internal__c_update_type_1(state, p, endp)) { default: goto s_n_llhttp__internal__n_span_start_llhttp__on_version_1; } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_req_or_res_method_3: s_n_llhttp__internal__n_req_or_res_method_3: { llparse_match_t match_seq; if (p == endp) { return s_n_llhttp__internal__n_req_or_res_method_3; } match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob60, 3); p = match_seq.current; switch (match_seq.status) { case kMatchComplete: { p++; goto s_n_llhttp__internal__n_span_end_llhttp__on_method_1; } case kMatchPause: { return s_n_llhttp__internal__n_req_or_res_method_3; } case kMatchMismatch: { goto s_n_llhttp__internal__n_error_106; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_req_or_res_method_1: s_n_llhttp__internal__n_req_or_res_method_1: { if (p == endp) { return s_n_llhttp__internal__n_req_or_res_method_1; } switch (*p) { case 'E': { p++; goto s_n_llhttp__internal__n_req_or_res_method_2; } case 'T': { p++; goto s_n_llhttp__internal__n_req_or_res_method_3; } default: { goto s_n_llhttp__internal__n_error_106; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_req_or_res_method: s_n_llhttp__internal__n_req_or_res_method: { if (p == endp) { return s_n_llhttp__internal__n_req_or_res_method; } switch (*p) { case 'H': { p++; goto s_n_llhttp__internal__n_req_or_res_method_1; } default: { goto s_n_llhttp__internal__n_error_106; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_span_start_llhttp__on_method: s_n_llhttp__internal__n_span_start_llhttp__on_method: { if (p == endp) { return s_n_llhttp__internal__n_span_start_llhttp__on_method; } state->_span_pos0 = (void*) p; state->_span_cb0 = llhttp__on_method; goto s_n_llhttp__internal__n_req_or_res_method; /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_start_req_or_res: s_n_llhttp__internal__n_start_req_or_res: { if (p == endp) { return s_n_llhttp__internal__n_start_req_or_res; } switch (*p) { case 'H': { goto s_n_llhttp__internal__n_span_start_llhttp__on_method; } default: { goto s_n_llhttp__internal__n_invoke_update_type_2; } } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_invoke_load_type: s_n_llhttp__internal__n_invoke_load_type: { switch (llhttp__internal__c_load_type(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_span_start_llhttp__on_method_1; case 2: goto s_n_llhttp__internal__n_start_res; default: goto s_n_llhttp__internal__n_start_req_or_res; } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_invoke_update_finish: s_n_llhttp__internal__n_invoke_update_finish: { switch (llhttp__internal__c_update_finish(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_llhttp__on_message_begin; } /* UNREACHABLE */; abort(); } case s_n_llhttp__internal__n_start: s_n_llhttp__internal__n_start: { if (p == endp) { return s_n_llhttp__internal__n_start; } switch (*p) { case 10: { p++; goto s_n_llhttp__internal__n_start; } case 13: { p++; goto s_n_llhttp__internal__n_start; } default: { goto s_n_llhttp__internal__n_invoke_load_initial_message_completed; } } /* UNREACHABLE */; abort(); } default: /* UNREACHABLE */ abort(); } s_n_llhttp__internal__n_error_2: { state->error = 0x7; state->reason = "Invalid characters in url"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_update_finish_2: { switch (llhttp__internal__c_update_finish_1(state, p, endp)) { default: goto s_n_llhttp__internal__n_start; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_update_initial_message_completed: { switch (llhttp__internal__c_update_initial_message_completed(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_update_finish_2; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_update_content_length: { switch (llhttp__internal__c_update_content_length(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_update_initial_message_completed; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_8: { state->error = 0x5; state->reason = "Data after `Connection: close`"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_test_lenient_flags_3: { switch (llhttp__internal__c_test_lenient_flags_3(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_closed; default: goto s_n_llhttp__internal__n_error_8; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_test_lenient_flags_2: { switch (llhttp__internal__c_test_lenient_flags_2(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_invoke_update_initial_message_completed; default: goto s_n_llhttp__internal__n_closed; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_update_finish_1: { switch (llhttp__internal__c_update_finish_1(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_test_lenient_flags_2; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_pause_13: { state->error = 0x15; state->reason = "on_message_complete pause"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_is_equal_upgrade; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_38: { state->error = 0x12; state->reason = "`on_message_complete` callback error"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_pause_15: { state->error = 0x15; state->reason = "on_chunk_complete pause"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_40: { state->error = 0x14; state->reason = "`on_chunk_complete` callback error"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete_1: { switch (llhttp__on_chunk_complete(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2; case 21: goto s_n_llhttp__internal__n_pause_15; default: goto s_n_llhttp__internal__n_error_40; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_pause_2: { state->error = 0x15; state->reason = "on_message_complete pause"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_pause_1; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_9: { state->error = 0x12; state->reason = "`on_message_complete` callback error"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_1: { switch (llhttp__on_message_complete(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_pause_1; case 21: goto s_n_llhttp__internal__n_pause_2; default: goto s_n_llhttp__internal__n_error_9; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_36: { state->error = 0xc; state->reason = "Chunk size overflow"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_10: { state->error = 0xc; state->reason = "Invalid character in chunk size"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_test_lenient_flags_4: { switch (llhttp__internal__c_test_lenient_flags_4(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_chunk_size_otherwise; default: goto s_n_llhttp__internal__n_error_10; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_pause_3: { state->error = 0x15; state->reason = "on_chunk_complete pause"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_update_content_length_1; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_14: { state->error = 0x14; state->reason = "`on_chunk_complete` callback error"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete: { switch (llhttp__on_chunk_complete(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_invoke_update_content_length_1; case 21: goto s_n_llhttp__internal__n_pause_3; default: goto s_n_llhttp__internal__n_error_14; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_13: { state->error = 0x19; state->reason = "Missing expected CR after chunk data"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_test_lenient_flags_6: { switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete; default: goto s_n_llhttp__internal__n_error_13; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_15: { state->error = 0x2; state->reason = "Expected LF after chunk data"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_test_lenient_flags_7: { switch (llhttp__internal__c_test_lenient_flags_7(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete; default: goto s_n_llhttp__internal__n_error_15; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_body: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_body(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_data_almost_done; return s_error; } goto s_n_llhttp__internal__n_chunk_data_almost_done; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_or_flags: { switch (llhttp__internal__c_or_flags(state, p, endp)) { default: goto s_n_llhttp__internal__n_header_field_start; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_pause_4: { state->error = 0x15; state->reason = "on_chunk_header pause"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_is_equal_content_length; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_12: { state->error = 0x13; state->reason = "`on_chunk_header` callback error"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_llhttp__on_chunk_header: { switch (llhttp__on_chunk_header(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_invoke_is_equal_content_length; case 21: goto s_n_llhttp__internal__n_pause_4; default: goto s_n_llhttp__internal__n_error_12; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_16: { state->error = 0x2; state->reason = "Expected LF after chunk size"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_test_lenient_flags_8: { switch (llhttp__internal__c_test_lenient_flags_8(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_header; default: goto s_n_llhttp__internal__n_error_16; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_11: { state->error = 0x19; state->reason = "Missing expected CR after chunk size"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_test_lenient_flags_5: { switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_chunk_size_almost_done; default: goto s_n_llhttp__internal__n_error_11; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_17: { state->error = 0x2; state->reason = "Invalid character in chunk extensions"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_18: { state->error = 0x2; state->reason = "Invalid character in chunk extensions"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_20: { state->error = 0x19; state->reason = "Missing expected CR after chunk extension name"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_pause_5: { state->error = 0x15; state->reason = "on_chunk_extension_name pause"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_test_lenient_flags_9; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_19: { state->error = 0x22; state->reason = "`on_chunk_extension_name` callback error"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_chunk_extension_name(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete; return s_error; } goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_pause_6: { state->error = 0x15; state->reason = "on_chunk_extension_name pause"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_size_almost_done; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_21: { state->error = 0x22; state->reason = "`on_chunk_extension_name` callback error"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name_1: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_chunk_extension_name(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) (p + 1); state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_1; return s_error; } p++; goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_1; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_pause_7: { state->error = 0x15; state->reason = "on_chunk_extension_name pause"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_extensions; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_22: { state->error = 0x22; state->reason = "`on_chunk_extension_name` callback error"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name_2: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_chunk_extension_name(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) (p + 1); state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_2; return s_error; } p++; goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_2; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_25: { state->error = 0x19; state->reason = "Missing expected CR after chunk extension value"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_pause_8: { state->error = 0x15; state->reason = "on_chunk_extension_value pause"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_test_lenient_flags_10; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_24: { state->error = 0x23; state->reason = "`on_chunk_extension_value` callback error"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_chunk_extension_value(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete; return s_error; } goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_pause_9: { state->error = 0x15; state->reason = "on_chunk_extension_value pause"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_size_almost_done; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_26: { state->error = 0x23; state->reason = "`on_chunk_extension_value` callback error"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_1: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_chunk_extension_value(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) (p + 1); state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_1; return s_error; } p++; goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_1; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_28: { state->error = 0x19; state->reason = "Missing expected CR after chunk extension value"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_test_lenient_flags_11: { switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_chunk_size_almost_done; default: goto s_n_llhttp__internal__n_error_28; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_29: { state->error = 0x2; state->reason = "Invalid character in chunk extensions quote value"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_pause_10: { state->error = 0x15; state->reason = "on_chunk_extension_value pause"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_extension_quoted_value_done; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_27: { state->error = 0x23; state->reason = "`on_chunk_extension_value` callback error"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_2: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_chunk_extension_value(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_2; return s_error; } goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_2; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_3: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_chunk_extension_value(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) (p + 1); state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_30; return s_error; } p++; goto s_n_llhttp__internal__n_error_30; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_4: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_chunk_extension_value(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) (p + 1); state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_31; return s_error; } p++; goto s_n_llhttp__internal__n_error_31; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_pause_11: { state->error = 0x15; state->reason = "on_chunk_extension_value pause"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_extensions; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_32: { state->error = 0x23; state->reason = "`on_chunk_extension_value` callback error"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_5: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_chunk_extension_value(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) (p + 1); state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_3; return s_error; } p++; goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_value_complete_3; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_value_6: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_chunk_extension_value(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) (p + 1); state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_33; return s_error; } p++; goto s_n_llhttp__internal__n_error_33; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_pause_12: { state->error = 0x15; state->reason = "on_chunk_extension_name pause"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_extension_value; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_23: { state->error = 0x22; state->reason = "`on_chunk_extension_name` callback error"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_llhttp__on_chunk_extension_name_complete_3: { switch (llhttp__on_chunk_extension_name_complete(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_chunk_extension_value; case 21: goto s_n_llhttp__internal__n_pause_12; default: goto s_n_llhttp__internal__n_error_23; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name_3: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_chunk_extension_name(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) (p + 1); state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_value; return s_error; } p++; goto s_n_llhttp__internal__n_span_start_llhttp__on_chunk_extension_value; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_chunk_extension_name_4: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_chunk_extension_name(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) (p + 1); state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_34; return s_error; } p++; goto s_n_llhttp__internal__n_error_34; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_35: { state->error = 0xc; state->reason = "Invalid character in chunk size"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_mul_add_content_length: { switch (llhttp__internal__c_mul_add_content_length(state, p, endp, match)) { case 1: goto s_n_llhttp__internal__n_error_36; default: goto s_n_llhttp__internal__n_chunk_size; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_37: { state->error = 0xc; state->reason = "Invalid character in chunk size"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_body_1: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_body(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2; return s_error; } goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_update_finish_3: { switch (llhttp__internal__c_update_finish_3(state, p, endp)) { default: goto s_n_llhttp__internal__n_span_start_llhttp__on_body_2; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_39: { state->error = 0xf; state->reason = "Request has invalid `Transfer-Encoding`"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_pause: { state->error = 0x15; state->reason = "on_message_complete pause"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__after_message_complete; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_7: { state->error = 0x12; state->reason = "`on_message_complete` callback error"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_llhttp__on_message_complete: { switch (llhttp__on_message_complete(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_invoke_llhttp__after_message_complete; case 21: goto s_n_llhttp__internal__n_pause; default: goto s_n_llhttp__internal__n_error_7; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_or_flags_1: { switch (llhttp__internal__c_or_flags_1(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_or_flags_2: { switch (llhttp__internal__c_or_flags_1(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_update_upgrade: { switch (llhttp__internal__c_update_upgrade(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_or_flags_2; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_pause_14: { state->error = 0x15; state->reason = "Paused by on_headers_complete"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_6: { state->error = 0x11; state->reason = "User callback error"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_llhttp__on_headers_complete: { switch (llhttp__on_headers_complete(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete; case 1: goto s_n_llhttp__internal__n_invoke_or_flags_1; case 2: goto s_n_llhttp__internal__n_invoke_update_upgrade; case 21: goto s_n_llhttp__internal__n_pause_14; default: goto s_n_llhttp__internal__n_error_6; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_llhttp__before_headers_complete: { switch (llhttp__before_headers_complete(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_llhttp__on_headers_complete; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_test_flags: { switch (llhttp__internal__c_test_flags(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete_1; default: goto s_n_llhttp__internal__n_invoke_llhttp__before_headers_complete; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_test_lenient_flags_1: { switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_invoke_test_flags; default: goto s_n_llhttp__internal__n_error_5; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_pause_17: { state->error = 0x15; state->reason = "on_chunk_complete pause"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_42: { state->error = 0x14; state->reason = "`on_chunk_complete` callback error"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete_2: { switch (llhttp__on_chunk_complete(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2; case 21: goto s_n_llhttp__internal__n_pause_17; default: goto s_n_llhttp__internal__n_error_42; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_or_flags_3: { switch (llhttp__internal__c_or_flags_1(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_or_flags_4: { switch (llhttp__internal__c_or_flags_1(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_update_upgrade_1: { switch (llhttp__internal__c_update_upgrade(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_or_flags_4; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_pause_16: { state->error = 0x15; state->reason = "Paused by on_headers_complete"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_41: { state->error = 0x11; state->reason = "User callback error"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_llhttp__on_headers_complete_1: { switch (llhttp__on_headers_complete(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete; case 1: goto s_n_llhttp__internal__n_invoke_or_flags_3; case 2: goto s_n_llhttp__internal__n_invoke_update_upgrade_1; case 21: goto s_n_llhttp__internal__n_pause_16; default: goto s_n_llhttp__internal__n_error_41; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_llhttp__before_headers_complete_1: { switch (llhttp__before_headers_complete(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_llhttp__on_headers_complete_1; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_test_flags_1: { switch (llhttp__internal__c_test_flags(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete_2; default: goto s_n_llhttp__internal__n_invoke_llhttp__before_headers_complete_1; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_43: { state->error = 0x2; state->reason = "Expected LF after headers"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_test_lenient_flags_12: { switch (llhttp__internal__c_test_lenient_flags_8(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_invoke_test_flags_1; default: goto s_n_llhttp__internal__n_error_43; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_44: { state->error = 0xa; state->reason = "Invalid header token"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_header_field: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_header_field(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) (p + 1); state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_5; return s_error; } p++; goto s_n_llhttp__internal__n_error_5; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_test_lenient_flags_13: { switch (llhttp__internal__c_test_lenient_flags(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_header_field_colon_discard_ws; default: goto s_n_llhttp__internal__n_span_end_llhttp__on_header_field; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_60: { state->error = 0xb; state->reason = "Content-Length can't be present with Transfer-Encoding"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_47: { state->error = 0xa; state->reason = "Invalid header value char"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_test_lenient_flags_15: { switch (llhttp__internal__c_test_lenient_flags(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_header_value_discard_ws; default: goto s_n_llhttp__internal__n_error_47; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_49: { state->error = 0xb; state->reason = "Empty Content-Length"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_pause_18: { state->error = 0x15; state->reason = "on_header_value_complete pause"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_header_field_start; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_48: { state->error = 0x1d; state->reason = "`on_header_value_complete` callback error"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_header_value: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_header_value(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete; return s_error; } goto s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_update_header_state: { switch (llhttp__internal__c_update_header_state(state, p, endp)) { default: goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_or_flags_5: { switch (llhttp__internal__c_or_flags_5(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_update_header_state; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_or_flags_6: { switch (llhttp__internal__c_or_flags_6(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_update_header_state; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_or_flags_7: { switch (llhttp__internal__c_or_flags_7(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_update_header_state; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_or_flags_8: { switch (llhttp__internal__c_or_flags_8(state, p, endp)) { default: goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_load_header_state_2: { switch (llhttp__internal__c_load_header_state(state, p, endp)) { case 5: goto s_n_llhttp__internal__n_invoke_or_flags_5; case 6: goto s_n_llhttp__internal__n_invoke_or_flags_6; case 7: goto s_n_llhttp__internal__n_invoke_or_flags_7; case 8: goto s_n_llhttp__internal__n_invoke_or_flags_8; default: goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_load_header_state_1: { switch (llhttp__internal__c_load_header_state(state, p, endp)) { case 2: goto s_n_llhttp__internal__n_error_49; default: goto s_n_llhttp__internal__n_invoke_load_header_state_2; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_46: { state->error = 0xa; state->reason = "Invalid header value char"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_test_lenient_flags_14: { switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_header_value_discard_lws; default: goto s_n_llhttp__internal__n_error_46; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_50: { state->error = 0x2; state->reason = "Expected LF after CR"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_test_lenient_flags_16: { switch (llhttp__internal__c_test_lenient_flags(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_header_value_discard_lws; default: goto s_n_llhttp__internal__n_error_50; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_update_header_state_1: { switch (llhttp__internal__c_update_header_state_1(state, p, endp)) { default: goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_load_header_state_4: { switch (llhttp__internal__c_load_header_state(state, p, endp)) { case 8: goto s_n_llhttp__internal__n_invoke_update_header_state_1; default: goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_52: { state->error = 0xa; state->reason = "Unexpected whitespace after header value"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_test_lenient_flags_18: { switch (llhttp__internal__c_test_lenient_flags(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_invoke_load_header_state_4; default: goto s_n_llhttp__internal__n_error_52; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_update_header_state_2: { switch (llhttp__internal__c_update_header_state(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_or_flags_9: { switch (llhttp__internal__c_or_flags_5(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_update_header_state_2; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_or_flags_10: { switch (llhttp__internal__c_or_flags_6(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_update_header_state_2; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_or_flags_11: { switch (llhttp__internal__c_or_flags_7(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_update_header_state_2; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_or_flags_12: { switch (llhttp__internal__c_or_flags_8(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_load_header_state_5: { switch (llhttp__internal__c_load_header_state(state, p, endp)) { case 5: goto s_n_llhttp__internal__n_invoke_or_flags_9; case 6: goto s_n_llhttp__internal__n_invoke_or_flags_10; case 7: goto s_n_llhttp__internal__n_invoke_or_flags_11; case 8: goto s_n_llhttp__internal__n_invoke_or_flags_12; default: goto s_n_llhttp__internal__n_invoke_llhttp__on_header_value_complete; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_53: { state->error = 0x3; state->reason = "Missing expected LF after header value"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_51: { state->error = 0x19; state->reason = "Missing expected CR after header value"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_header_value_1: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_header_value(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_test_lenient_flags_17; return s_error; } goto s_n_llhttp__internal__n_invoke_test_lenient_flags_17; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_header_value_2: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_header_value(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) (p + 1); state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_header_value_almost_done; return s_error; } p++; goto s_n_llhttp__internal__n_header_value_almost_done; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_header_value_4: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_header_value(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_header_value_almost_done; return s_error; } goto s_n_llhttp__internal__n_header_value_almost_done; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_header_value_5: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_header_value(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) (p + 1); state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_header_value_almost_done; return s_error; } p++; goto s_n_llhttp__internal__n_header_value_almost_done; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_header_value_3: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_header_value(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_54; return s_error; } goto s_n_llhttp__internal__n_error_54; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_test_lenient_flags_19: { switch (llhttp__internal__c_test_lenient_flags(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_header_value_lenient; default: goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_3; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_update_header_state_4: { switch (llhttp__internal__c_update_header_state(state, p, endp)) { default: goto s_n_llhttp__internal__n_header_value_connection; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_or_flags_13: { switch (llhttp__internal__c_or_flags_5(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_update_header_state_4; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_or_flags_14: { switch (llhttp__internal__c_or_flags_6(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_update_header_state_4; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_or_flags_15: { switch (llhttp__internal__c_or_flags_7(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_update_header_state_4; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_or_flags_16: { switch (llhttp__internal__c_or_flags_8(state, p, endp)) { default: goto s_n_llhttp__internal__n_header_value_connection; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_load_header_state_6: { switch (llhttp__internal__c_load_header_state(state, p, endp)) { case 5: goto s_n_llhttp__internal__n_invoke_or_flags_13; case 6: goto s_n_llhttp__internal__n_invoke_or_flags_14; case 7: goto s_n_llhttp__internal__n_invoke_or_flags_15; case 8: goto s_n_llhttp__internal__n_invoke_or_flags_16; default: goto s_n_llhttp__internal__n_header_value_connection; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_update_header_state_5: { switch (llhttp__internal__c_update_header_state_1(state, p, endp)) { default: goto s_n_llhttp__internal__n_header_value_connection_token; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_update_header_state_3: { switch (llhttp__internal__c_update_header_state_3(state, p, endp)) { default: goto s_n_llhttp__internal__n_header_value_connection_ws; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_update_header_state_6: { switch (llhttp__internal__c_update_header_state_6(state, p, endp)) { default: goto s_n_llhttp__internal__n_header_value_connection_ws; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_update_header_state_7: { switch (llhttp__internal__c_update_header_state_7(state, p, endp)) { default: goto s_n_llhttp__internal__n_header_value_connection_ws; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_header_value_6: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_header_value(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_56; return s_error; } goto s_n_llhttp__internal__n_error_56; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_mul_add_content_length_1: { switch (llhttp__internal__c_mul_add_content_length_1(state, p, endp, match)) { case 1: goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_6; default: goto s_n_llhttp__internal__n_header_value_content_length; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_or_flags_17: { switch (llhttp__internal__c_or_flags_17(state, p, endp)) { default: goto s_n_llhttp__internal__n_header_value_otherwise; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_header_value_7: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_header_value(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_57; return s_error; } goto s_n_llhttp__internal__n_error_57; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_55: { state->error = 0x4; state->reason = "Duplicate Content-Length"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_test_flags_2: { switch (llhttp__internal__c_test_flags_2(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_header_value_content_length; default: goto s_n_llhttp__internal__n_error_55; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_header_value_9: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_header_value(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) (p + 1); state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_59; return s_error; } p++; goto s_n_llhttp__internal__n_error_59; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_update_header_state_8: { switch (llhttp__internal__c_update_header_state_8(state, p, endp)) { default: goto s_n_llhttp__internal__n_header_value_otherwise; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_header_value_8: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_header_value(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) (p + 1); state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_58; return s_error; } p++; goto s_n_llhttp__internal__n_error_58; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_test_lenient_flags_20: { switch (llhttp__internal__c_test_lenient_flags_20(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_8; default: goto s_n_llhttp__internal__n_header_value_te_chunked; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_load_type_1: { switch (llhttp__internal__c_load_type(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_invoke_test_lenient_flags_20; default: goto s_n_llhttp__internal__n_header_value_te_chunked; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_update_header_state_9: { switch (llhttp__internal__c_update_header_state_1(state, p, endp)) { default: goto s_n_llhttp__internal__n_header_value; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_and_flags: { switch (llhttp__internal__c_and_flags(state, p, endp)) { default: goto s_n_llhttp__internal__n_header_value_te_chunked; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_or_flags_19: { switch (llhttp__internal__c_or_flags_18(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_and_flags; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_test_lenient_flags_21: { switch (llhttp__internal__c_test_lenient_flags_20(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_9; default: goto s_n_llhttp__internal__n_invoke_or_flags_19; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_load_type_2: { switch (llhttp__internal__c_load_type(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_invoke_test_lenient_flags_21; default: goto s_n_llhttp__internal__n_invoke_or_flags_19; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_or_flags_18: { switch (llhttp__internal__c_or_flags_18(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_and_flags; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_test_flags_3: { switch (llhttp__internal__c_test_flags_3(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_invoke_load_type_2; default: goto s_n_llhttp__internal__n_invoke_or_flags_18; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_or_flags_20: { switch (llhttp__internal__c_or_flags_20(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_update_header_state_9; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_load_header_state_3: { switch (llhttp__internal__c_load_header_state(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_header_value_connection; case 2: goto s_n_llhttp__internal__n_invoke_test_flags_2; case 3: goto s_n_llhttp__internal__n_invoke_test_flags_3; case 4: goto s_n_llhttp__internal__n_invoke_or_flags_20; default: goto s_n_llhttp__internal__n_header_value; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_test_lenient_flags_22: { switch (llhttp__internal__c_test_lenient_flags_22(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_error_60; default: goto s_n_llhttp__internal__n_header_value_discard_ws; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_test_flags_4: { switch (llhttp__internal__c_test_flags_4(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_invoke_test_lenient_flags_22; default: goto s_n_llhttp__internal__n_header_value_discard_ws; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_61: { state->error = 0xf; state->reason = "Transfer-Encoding can't be present with Content-Length"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_test_lenient_flags_23: { switch (llhttp__internal__c_test_lenient_flags_22(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_error_61; default: goto s_n_llhttp__internal__n_header_value_discard_ws; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_test_flags_5: { switch (llhttp__internal__c_test_flags_2(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_invoke_test_lenient_flags_23; default: goto s_n_llhttp__internal__n_header_value_discard_ws; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_pause_19: { state->error = 0x15; state->reason = "on_header_field_complete pause"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_load_header_state; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_45: { state->error = 0x1c; state->reason = "`on_header_field_complete` callback error"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_header_field_1: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_header_field(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) (p + 1); state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete; return s_error; } p++; goto s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_header_field_2: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_header_field(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) (p + 1); state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete; return s_error; } p++; goto s_n_llhttp__internal__n_invoke_llhttp__on_header_field_complete; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_62: { state->error = 0xa; state->reason = "Invalid header token"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_update_header_state_10: { switch (llhttp__internal__c_update_header_state_1(state, p, endp)) { default: goto s_n_llhttp__internal__n_header_field_general; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_store_header_state: { switch (llhttp__internal__c_store_header_state(state, p, endp, match)) { default: goto s_n_llhttp__internal__n_header_field_colon; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_update_header_state_11: { switch (llhttp__internal__c_update_header_state_1(state, p, endp)) { default: goto s_n_llhttp__internal__n_header_field_general; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_4: { state->error = 0x1e; state->reason = "Unexpected space after start line"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_test_lenient_flags: { switch (llhttp__internal__c_test_lenient_flags(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_header_field_start; default: goto s_n_llhttp__internal__n_error_4; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_pause_20: { state->error = 0x15; state->reason = "on_url_complete pause"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_headers_start; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_3: { state->error = 0x1a; state->reason = "`on_url_complete` callback error"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_llhttp__on_url_complete: { switch (llhttp__on_url_complete(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_headers_start; case 21: goto s_n_llhttp__internal__n_pause_20; default: goto s_n_llhttp__internal__n_error_3; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_update_http_minor: { switch (llhttp__internal__c_update_http_minor(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_llhttp__on_url_complete; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_update_http_major: { switch (llhttp__internal__c_update_http_major(state, p, endp)) { default: goto s_n_llhttp__internal__n_invoke_update_http_minor; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_url_3: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_url(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http09; return s_error; } goto s_n_llhttp__internal__n_url_skip_to_http09; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_63: { state->error = 0x7; state->reason = "Expected CRLF"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_url_4: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_url(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_lf_to_http09; return s_error; } goto s_n_llhttp__internal__n_url_skip_lf_to_http09; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_71: { state->error = 0x17; state->reason = "Pause on PRI/Upgrade"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_72: { state->error = 0x9; state->reason = "Expected HTTP/2 Connection Preface"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_69: { state->error = 0x2; state->reason = "Expected CRLF after version"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_test_lenient_flags_26: { switch (llhttp__internal__c_test_lenient_flags_8(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_headers_start; default: goto s_n_llhttp__internal__n_error_69; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_68: { state->error = 0x9; state->reason = "Expected CRLF after version"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_test_lenient_flags_25: { switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_req_http_complete_crlf; default: goto s_n_llhttp__internal__n_error_68; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_70: { state->error = 0x9; state->reason = "Expected CRLF after version"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_pause_21: { state->error = 0x15; state->reason = "on_version_complete pause"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_load_method_1; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_67: { state->error = 0x21; state->reason = "`on_version_complete` callback error"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_version_1: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_version(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_version_complete; return s_error; } goto s_n_llhttp__internal__n_invoke_llhttp__on_version_complete; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_version: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_version(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_66; return s_error; } goto s_n_llhttp__internal__n_error_66; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_load_http_minor: { switch (llhttp__internal__c_load_http_minor(state, p, endp)) { case 9: goto s_n_llhttp__internal__n_span_end_llhttp__on_version_1; default: goto s_n_llhttp__internal__n_span_end_llhttp__on_version; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_load_http_minor_1: { switch (llhttp__internal__c_load_http_minor(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_span_end_llhttp__on_version_1; case 1: goto s_n_llhttp__internal__n_span_end_llhttp__on_version_1; default: goto s_n_llhttp__internal__n_span_end_llhttp__on_version; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_load_http_minor_2: { switch (llhttp__internal__c_load_http_minor(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_span_end_llhttp__on_version_1; default: goto s_n_llhttp__internal__n_span_end_llhttp__on_version; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_load_http_major: { switch (llhttp__internal__c_load_http_major(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_invoke_load_http_minor; case 1: goto s_n_llhttp__internal__n_invoke_load_http_minor_1; case 2: goto s_n_llhttp__internal__n_invoke_load_http_minor_2; default: goto s_n_llhttp__internal__n_span_end_llhttp__on_version; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_test_lenient_flags_24: { switch (llhttp__internal__c_test_lenient_flags_24(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_span_end_llhttp__on_version_1; default: goto s_n_llhttp__internal__n_invoke_load_http_major; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_store_http_minor: { switch (llhttp__internal__c_store_http_minor(state, p, endp, match)) { default: goto s_n_llhttp__internal__n_invoke_test_lenient_flags_24; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_version_2: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_version(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_73; return s_error; } goto s_n_llhttp__internal__n_error_73; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_version_3: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_version(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_74; return s_error; } goto s_n_llhttp__internal__n_error_74; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_store_http_major: { switch (llhttp__internal__c_store_http_major(state, p, endp, match)) { default: goto s_n_llhttp__internal__n_req_http_dot; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_version_4: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_version(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_75; return s_error; } goto s_n_llhttp__internal__n_error_75; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_65: { state->error = 0x8; state->reason = "Invalid method for HTTP/x.x request"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_load_method: { switch (llhttp__internal__c_load_method(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 1: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 2: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 3: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 4: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 5: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 6: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 7: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 8: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 9: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 10: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 11: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 12: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 13: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 14: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 15: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 16: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 17: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 18: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 19: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 20: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 21: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 22: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 23: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 24: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 25: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 26: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 27: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 28: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 29: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 30: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 31: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 32: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 33: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 34: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 46: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; default: goto s_n_llhttp__internal__n_error_65; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_78: { state->error = 0x8; state->reason = "Expected HTTP/"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_76: { state->error = 0x8; state->reason = "Expected SOURCE method for ICE/x.x request"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_load_method_2: { switch (llhttp__internal__c_load_method(state, p, endp)) { case 33: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; default: goto s_n_llhttp__internal__n_error_76; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_77: { state->error = 0x8; state->reason = "Invalid method for RTSP/x.x request"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_load_method_3: { switch (llhttp__internal__c_load_method(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 3: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 6: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 35: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 36: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 37: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 38: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 39: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 40: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 41: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 42: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 43: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 44: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; case 45: goto s_n_llhttp__internal__n_span_start_llhttp__on_version; default: goto s_n_llhttp__internal__n_error_77; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_pause_22: { state->error = 0x15; state->reason = "on_url_complete pause"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_req_http_start; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_64: { state->error = 0x1a; state->reason = "`on_url_complete` callback error"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_llhttp__on_url_complete_1: { switch (llhttp__on_url_complete(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_req_http_start; case 21: goto s_n_llhttp__internal__n_pause_22; default: goto s_n_llhttp__internal__n_error_64; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_url_5: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_url(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http; return s_error; } goto s_n_llhttp__internal__n_url_skip_to_http; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_url_6: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_url(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http09; return s_error; } goto s_n_llhttp__internal__n_url_skip_to_http09; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_url_7: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_url(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_lf_to_http09; return s_error; } goto s_n_llhttp__internal__n_url_skip_lf_to_http09; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_url_8: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_url(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http; return s_error; } goto s_n_llhttp__internal__n_url_skip_to_http; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_79: { state->error = 0x7; state->reason = "Invalid char in url fragment start"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_url_9: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_url(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http09; return s_error; } goto s_n_llhttp__internal__n_url_skip_to_http09; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_url_10: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_url(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_lf_to_http09; return s_error; } goto s_n_llhttp__internal__n_url_skip_lf_to_http09; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_url_11: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_url(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http; return s_error; } goto s_n_llhttp__internal__n_url_skip_to_http; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_80: { state->error = 0x7; state->reason = "Invalid char in url query"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_81: { state->error = 0x7; state->reason = "Invalid char in url path"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_url: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_url(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http09; return s_error; } goto s_n_llhttp__internal__n_url_skip_to_http09; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_url_1: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_url(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_lf_to_http09; return s_error; } goto s_n_llhttp__internal__n_url_skip_lf_to_http09; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_url_2: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_url(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http; return s_error; } goto s_n_llhttp__internal__n_url_skip_to_http; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_url_12: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_url(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http09; return s_error; } goto s_n_llhttp__internal__n_url_skip_to_http09; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_url_13: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_url(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_lf_to_http09; return s_error; } goto s_n_llhttp__internal__n_url_skip_lf_to_http09; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_url_14: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_url(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http; return s_error; } goto s_n_llhttp__internal__n_url_skip_to_http; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_82: { state->error = 0x7; state->reason = "Double @ in url"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_83: { state->error = 0x7; state->reason = "Unexpected char in url server"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_84: { state->error = 0x7; state->reason = "Unexpected char in url server"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_85: { state->error = 0x7; state->reason = "Unexpected char in url schema"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_86: { state->error = 0x7; state->reason = "Unexpected char in url schema"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_87: { state->error = 0x7; state->reason = "Unexpected start char in url"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_is_equal_method: { switch (llhttp__internal__c_is_equal_method(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_url_entry_normal; default: goto s_n_llhttp__internal__n_url_entry_connect; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_88: { state->error = 0x6; state->reason = "Expected space after method"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_pause_26: { state->error = 0x15; state->reason = "on_method_complete pause"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_req_first_space_before_url; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_107: { state->error = 0x20; state->reason = "`on_method_complete` callback error"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_method_2: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_method(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_method_complete_1; return s_error; } goto s_n_llhttp__internal__n_invoke_llhttp__on_method_complete_1; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_store_method_1: { switch (llhttp__internal__c_store_method(state, p, endp, match)) { default: goto s_n_llhttp__internal__n_span_end_llhttp__on_method_2; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_108: { state->error = 0x6; state->reason = "Invalid method encountered"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_100: { state->error = 0xd; state->reason = "Invalid status code"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_98: { state->error = 0xd; state->reason = "Invalid status code"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_96: { state->error = 0xd; state->reason = "Invalid status code"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_pause_24: { state->error = 0x15; state->reason = "on_status_complete pause"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_headers_start; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_92: { state->error = 0x1b; state->reason = "`on_status_complete` callback error"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_llhttp__on_status_complete: { switch (llhttp__on_status_complete(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_headers_start; case 21: goto s_n_llhttp__internal__n_pause_24; default: goto s_n_llhttp__internal__n_error_92; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_91: { state->error = 0xd; state->reason = "Invalid response status"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_test_lenient_flags_28: { switch (llhttp__internal__c_test_lenient_flags_1(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_invoke_llhttp__on_status_complete; default: goto s_n_llhttp__internal__n_error_91; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_93: { state->error = 0x2; state->reason = "Expected LF after CR"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_test_lenient_flags_29: { switch (llhttp__internal__c_test_lenient_flags_8(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_invoke_llhttp__on_status_complete; default: goto s_n_llhttp__internal__n_error_93; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_94: { state->error = 0x19; state->reason = "Missing expected CR after response line"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_status: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_status(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) (p + 1); state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_test_lenient_flags_30; return s_error; } p++; goto s_n_llhttp__internal__n_invoke_test_lenient_flags_30; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_status_1: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_status(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) (p + 1); state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_res_line_almost_done; return s_error; } p++; goto s_n_llhttp__internal__n_res_line_almost_done; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_95: { state->error = 0xd; state->reason = "Invalid response status"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_mul_add_status_code_2: { switch (llhttp__internal__c_mul_add_status_code(state, p, endp, match)) { case 1: goto s_n_llhttp__internal__n_error_96; default: goto s_n_llhttp__internal__n_res_status_code_otherwise; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_97: { state->error = 0xd; state->reason = "Invalid status code"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_mul_add_status_code_1: { switch (llhttp__internal__c_mul_add_status_code(state, p, endp, match)) { case 1: goto s_n_llhttp__internal__n_error_98; default: goto s_n_llhttp__internal__n_res_status_code_digit_3; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_99: { state->error = 0xd; state->reason = "Invalid status code"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_mul_add_status_code: { switch (llhttp__internal__c_mul_add_status_code(state, p, endp, match)) { case 1: goto s_n_llhttp__internal__n_error_100; default: goto s_n_llhttp__internal__n_res_status_code_digit_2; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_101: { state->error = 0xd; state->reason = "Invalid status code"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_update_status_code: { switch (llhttp__internal__c_update_status_code(state, p, endp)) { default: goto s_n_llhttp__internal__n_res_status_code_digit_1; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_102: { state->error = 0x9; state->reason = "Expected space after version"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_pause_25: { state->error = 0x15; state->reason = "on_version_complete pause"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_res_after_version; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_90: { state->error = 0x21; state->reason = "`on_version_complete` callback error"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_version_6: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_version(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_version_complete_1; return s_error; } goto s_n_llhttp__internal__n_invoke_llhttp__on_version_complete_1; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_version_5: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_version(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_89; return s_error; } goto s_n_llhttp__internal__n_error_89; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_load_http_minor_3: { switch (llhttp__internal__c_load_http_minor(state, p, endp)) { case 9: goto s_n_llhttp__internal__n_span_end_llhttp__on_version_6; default: goto s_n_llhttp__internal__n_span_end_llhttp__on_version_5; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_load_http_minor_4: { switch (llhttp__internal__c_load_http_minor(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_span_end_llhttp__on_version_6; case 1: goto s_n_llhttp__internal__n_span_end_llhttp__on_version_6; default: goto s_n_llhttp__internal__n_span_end_llhttp__on_version_5; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_load_http_minor_5: { switch (llhttp__internal__c_load_http_minor(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_span_end_llhttp__on_version_6; default: goto s_n_llhttp__internal__n_span_end_llhttp__on_version_5; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_load_http_major_1: { switch (llhttp__internal__c_load_http_major(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_invoke_load_http_minor_3; case 1: goto s_n_llhttp__internal__n_invoke_load_http_minor_4; case 2: goto s_n_llhttp__internal__n_invoke_load_http_minor_5; default: goto s_n_llhttp__internal__n_span_end_llhttp__on_version_5; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_test_lenient_flags_27: { switch (llhttp__internal__c_test_lenient_flags_24(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_span_end_llhttp__on_version_6; default: goto s_n_llhttp__internal__n_invoke_load_http_major_1; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_store_http_minor_1: { switch (llhttp__internal__c_store_http_minor(state, p, endp, match)) { default: goto s_n_llhttp__internal__n_invoke_test_lenient_flags_27; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_version_7: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_version(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_103; return s_error; } goto s_n_llhttp__internal__n_error_103; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_version_8: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_version(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_104; return s_error; } goto s_n_llhttp__internal__n_error_104; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_store_http_major_1: { switch (llhttp__internal__c_store_http_major(state, p, endp, match)) { default: goto s_n_llhttp__internal__n_res_http_dot; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_version_9: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_version(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_105; return s_error; } goto s_n_llhttp__internal__n_error_105; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_109: { state->error = 0x8; state->reason = "Expected HTTP/"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_pause_23: { state->error = 0x15; state->reason = "on_method_complete pause"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_req_first_space_before_url; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_1: { state->error = 0x20; state->reason = "`on_method_complete` callback error"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_method: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_method(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_method_complete; return s_error; } goto s_n_llhttp__internal__n_invoke_llhttp__on_method_complete; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_update_type: { switch (llhttp__internal__c_update_type(state, p, endp)) { default: goto s_n_llhttp__internal__n_span_end_llhttp__on_method; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_store_method: { switch (llhttp__internal__c_store_method(state, p, endp, match)) { default: goto s_n_llhttp__internal__n_invoke_update_type; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_106: { state->error = 0x8; state->reason = "Invalid word encountered"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_span_end_llhttp__on_method_1: { const unsigned char* start; int err; start = state->_span_pos0; state->_span_pos0 = NULL; err = llhttp__on_method(state, start, p); if (err != 0) { state->error = err; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_update_type_1; return s_error; } goto s_n_llhttp__internal__n_invoke_update_type_1; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_update_type_2: { switch (llhttp__internal__c_update_type(state, p, endp)) { default: goto s_n_llhttp__internal__n_span_start_llhttp__on_method_1; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_pause_27: { state->error = 0x15; state->reason = "on_message_begin pause"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_load_type; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error: { state->error = 0x10; state->reason = "`on_message_begin` callback error"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_llhttp__on_message_begin: { switch (llhttp__on_message_begin(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_invoke_load_type; case 21: goto s_n_llhttp__internal__n_pause_27; default: goto s_n_llhttp__internal__n_error; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_pause_28: { state->error = 0x15; state->reason = "on_reset pause"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_update_finish; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_error_110: { state->error = 0x1f; state->reason = "`on_reset` callback error"; state->error_pos = (const char*) p; state->_current = (void*) (intptr_t) s_error; return s_error; /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_llhttp__on_reset: { switch (llhttp__on_reset(state, p, endp)) { case 0: goto s_n_llhttp__internal__n_invoke_update_finish; case 21: goto s_n_llhttp__internal__n_pause_28; default: goto s_n_llhttp__internal__n_error_110; } /* UNREACHABLE */; abort(); } s_n_llhttp__internal__n_invoke_load_initial_message_completed: { switch (llhttp__internal__c_load_initial_message_completed(state, p, endp)) { case 1: goto s_n_llhttp__internal__n_invoke_llhttp__on_reset; default: goto s_n_llhttp__internal__n_invoke_update_finish; } /* UNREACHABLE */; abort(); } } int llhttp__internal_execute(llhttp__internal_t* state, const char* p, const char* endp) { llparse_state_t next; /* check lingering errors */ if (state->error != 0) { return state->error; } /* restart spans */ if (state->_span_pos0 != NULL) { state->_span_pos0 = (void*) p; } next = llhttp__internal__run(state, (const unsigned char*) p, (const unsigned char*) endp); if (next == s_error) { return state->error; } state->_current = (void*) (intptr_t) next; /* execute spans */ if (state->_span_pos0 != NULL) { int error; error = ((llhttp__internal__span_cb) state->_span_cb0)(state, state->_span_pos0, (const char*) endp); if (error != 0) { state->error = error; state->error_pos = endp; return error; } } return 0; }UxPlay-1.71.1/lib/llhttp/llhttp.h000066400000000000000000000734351473013662600166040ustar00rootroot00000000000000 #ifndef INCLUDE_LLHTTP_H_ #define INCLUDE_LLHTTP_H_ #define LLHTTP_VERSION_MAJOR 9 #define LLHTTP_VERSION_MINOR 2 #define LLHTTP_VERSION_PATCH 1 #ifndef INCLUDE_LLHTTP_ITSELF_H_ #define INCLUDE_LLHTTP_ITSELF_H_ #ifdef __cplusplus extern "C" { #endif #include typedef struct llhttp__internal_s llhttp__internal_t; struct llhttp__internal_s { int32_t _index; void* _span_pos0; void* _span_cb0; int32_t error; const char* reason; const char* error_pos; void* data; void* _current; uint64_t content_length; uint8_t type; uint8_t method; uint8_t http_major; uint8_t http_minor; uint8_t header_state; uint16_t lenient_flags; uint8_t upgrade; uint8_t finish; uint16_t flags; uint16_t status_code; uint8_t initial_message_completed; void* settings; }; int llhttp__internal_init(llhttp__internal_t* s); int llhttp__internal_execute(llhttp__internal_t* s, const char* p, const char* endp); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* INCLUDE_LLHTTP_ITSELF_H_ */ #ifndef LLLLHTTP_C_HEADERS_ #define LLLLHTTP_C_HEADERS_ #ifdef __cplusplus extern "C" { #endif enum llhttp_errno { HPE_OK = 0, HPE_INTERNAL = 1, HPE_STRICT = 2, HPE_CR_EXPECTED = 25, HPE_LF_EXPECTED = 3, HPE_UNEXPECTED_CONTENT_LENGTH = 4, HPE_UNEXPECTED_SPACE = 30, HPE_CLOSED_CONNECTION = 5, HPE_INVALID_METHOD = 6, HPE_INVALID_URL = 7, HPE_INVALID_CONSTANT = 8, HPE_INVALID_VERSION = 9, HPE_INVALID_HEADER_TOKEN = 10, HPE_INVALID_CONTENT_LENGTH = 11, HPE_INVALID_CHUNK_SIZE = 12, HPE_INVALID_STATUS = 13, HPE_INVALID_EOF_STATE = 14, HPE_INVALID_TRANSFER_ENCODING = 15, HPE_CB_MESSAGE_BEGIN = 16, HPE_CB_HEADERS_COMPLETE = 17, HPE_CB_MESSAGE_COMPLETE = 18, HPE_CB_CHUNK_HEADER = 19, HPE_CB_CHUNK_COMPLETE = 20, HPE_PAUSED = 21, HPE_PAUSED_UPGRADE = 22, HPE_PAUSED_H2_UPGRADE = 23, HPE_USER = 24, HPE_CB_URL_COMPLETE = 26, HPE_CB_STATUS_COMPLETE = 27, HPE_CB_METHOD_COMPLETE = 32, HPE_CB_VERSION_COMPLETE = 33, HPE_CB_HEADER_FIELD_COMPLETE = 28, HPE_CB_HEADER_VALUE_COMPLETE = 29, HPE_CB_CHUNK_EXTENSION_NAME_COMPLETE = 34, HPE_CB_CHUNK_EXTENSION_VALUE_COMPLETE = 35, HPE_CB_RESET = 31 }; typedef enum llhttp_errno llhttp_errno_t; enum llhttp_flags { F_CONNECTION_KEEP_ALIVE = 0x1, F_CONNECTION_CLOSE = 0x2, F_CONNECTION_UPGRADE = 0x4, F_CHUNKED = 0x8, F_UPGRADE = 0x10, F_CONTENT_LENGTH = 0x20, F_SKIPBODY = 0x40, F_TRAILING = 0x80, F_TRANSFER_ENCODING = 0x200 }; typedef enum llhttp_flags llhttp_flags_t; enum llhttp_lenient_flags { LENIENT_HEADERS = 0x1, LENIENT_CHUNKED_LENGTH = 0x2, LENIENT_KEEP_ALIVE = 0x4, LENIENT_TRANSFER_ENCODING = 0x8, LENIENT_VERSION = 0x10, LENIENT_DATA_AFTER_CLOSE = 0x20, LENIENT_OPTIONAL_LF_AFTER_CR = 0x40, LENIENT_OPTIONAL_CRLF_AFTER_CHUNK = 0x80, LENIENT_OPTIONAL_CR_BEFORE_LF = 0x100, LENIENT_SPACES_AFTER_CHUNK_SIZE = 0x200 }; typedef enum llhttp_lenient_flags llhttp_lenient_flags_t; enum llhttp_type { HTTP_BOTH = 0, HTTP_REQUEST = 1, HTTP_RESPONSE = 2 }; typedef enum llhttp_type llhttp_type_t; enum llhttp_finish { HTTP_FINISH_SAFE = 0, HTTP_FINISH_SAFE_WITH_CB = 1, HTTP_FINISH_UNSAFE = 2 }; typedef enum llhttp_finish llhttp_finish_t; enum llhttp_method { HTTP_DELETE = 0, HTTP_GET = 1, HTTP_HEAD = 2, HTTP_POST = 3, HTTP_PUT = 4, HTTP_CONNECT = 5, HTTP_OPTIONS = 6, HTTP_TRACE = 7, HTTP_COPY = 8, HTTP_LOCK = 9, HTTP_MKCOL = 10, HTTP_MOVE = 11, HTTP_PROPFIND = 12, HTTP_PROPPATCH = 13, HTTP_SEARCH = 14, HTTP_UNLOCK = 15, HTTP_BIND = 16, HTTP_REBIND = 17, HTTP_UNBIND = 18, HTTP_ACL = 19, HTTP_REPORT = 20, HTTP_MKACTIVITY = 21, HTTP_CHECKOUT = 22, HTTP_MERGE = 23, HTTP_MSEARCH = 24, HTTP_NOTIFY = 25, HTTP_SUBSCRIBE = 26, HTTP_UNSUBSCRIBE = 27, HTTP_PATCH = 28, HTTP_PURGE = 29, HTTP_MKCALENDAR = 30, HTTP_LINK = 31, HTTP_UNLINK = 32, HTTP_SOURCE = 33, HTTP_PRI = 34, HTTP_DESCRIBE = 35, HTTP_ANNOUNCE = 36, HTTP_SETUP = 37, HTTP_PLAY = 38, HTTP_PAUSE = 39, HTTP_TEARDOWN = 40, HTTP_GET_PARAMETER = 41, HTTP_SET_PARAMETER = 42, HTTP_REDIRECT = 43, HTTP_RECORD = 44, HTTP_FLUSH = 45, HTTP_QUERY = 46 }; typedef enum llhttp_method llhttp_method_t; enum llhttp_status { HTTP_STATUS_CONTINUE = 100, HTTP_STATUS_SWITCHING_PROTOCOLS = 101, HTTP_STATUS_PROCESSING = 102, HTTP_STATUS_EARLY_HINTS = 103, HTTP_STATUS_RESPONSE_IS_STALE = 110, HTTP_STATUS_REVALIDATION_FAILED = 111, HTTP_STATUS_DISCONNECTED_OPERATION = 112, HTTP_STATUS_HEURISTIC_EXPIRATION = 113, HTTP_STATUS_MISCELLANEOUS_WARNING = 199, HTTP_STATUS_OK = 200, HTTP_STATUS_CREATED = 201, HTTP_STATUS_ACCEPTED = 202, HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION = 203, HTTP_STATUS_NO_CONTENT = 204, HTTP_STATUS_RESET_CONTENT = 205, HTTP_STATUS_PARTIAL_CONTENT = 206, HTTP_STATUS_MULTI_STATUS = 207, HTTP_STATUS_ALREADY_REPORTED = 208, HTTP_STATUS_TRANSFORMATION_APPLIED = 214, HTTP_STATUS_IM_USED = 226, HTTP_STATUS_MISCELLANEOUS_PERSISTENT_WARNING = 299, HTTP_STATUS_MULTIPLE_CHOICES = 300, HTTP_STATUS_MOVED_PERMANENTLY = 301, HTTP_STATUS_FOUND = 302, HTTP_STATUS_SEE_OTHER = 303, HTTP_STATUS_NOT_MODIFIED = 304, HTTP_STATUS_USE_PROXY = 305, HTTP_STATUS_SWITCH_PROXY = 306, HTTP_STATUS_TEMPORARY_REDIRECT = 307, HTTP_STATUS_PERMANENT_REDIRECT = 308, HTTP_STATUS_BAD_REQUEST = 400, HTTP_STATUS_UNAUTHORIZED = 401, HTTP_STATUS_PAYMENT_REQUIRED = 402, HTTP_STATUS_FORBIDDEN = 403, HTTP_STATUS_NOT_FOUND = 404, HTTP_STATUS_METHOD_NOT_ALLOWED = 405, HTTP_STATUS_NOT_ACCEPTABLE = 406, HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED = 407, HTTP_STATUS_REQUEST_TIMEOUT = 408, HTTP_STATUS_CONFLICT = 409, HTTP_STATUS_GONE = 410, HTTP_STATUS_LENGTH_REQUIRED = 411, HTTP_STATUS_PRECONDITION_FAILED = 412, HTTP_STATUS_PAYLOAD_TOO_LARGE = 413, HTTP_STATUS_URI_TOO_LONG = 414, HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE = 415, HTTP_STATUS_RANGE_NOT_SATISFIABLE = 416, HTTP_STATUS_EXPECTATION_FAILED = 417, HTTP_STATUS_IM_A_TEAPOT = 418, HTTP_STATUS_PAGE_EXPIRED = 419, HTTP_STATUS_ENHANCE_YOUR_CALM = 420, HTTP_STATUS_MISDIRECTED_REQUEST = 421, HTTP_STATUS_UNPROCESSABLE_ENTITY = 422, HTTP_STATUS_LOCKED = 423, HTTP_STATUS_FAILED_DEPENDENCY = 424, HTTP_STATUS_TOO_EARLY = 425, HTTP_STATUS_UPGRADE_REQUIRED = 426, HTTP_STATUS_PRECONDITION_REQUIRED = 428, HTTP_STATUS_TOO_MANY_REQUESTS = 429, HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE_UNOFFICIAL = 430, HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE = 431, HTTP_STATUS_LOGIN_TIMEOUT = 440, HTTP_STATUS_NO_RESPONSE = 444, HTTP_STATUS_RETRY_WITH = 449, HTTP_STATUS_BLOCKED_BY_PARENTAL_CONTROL = 450, HTTP_STATUS_UNAVAILABLE_FOR_LEGAL_REASONS = 451, HTTP_STATUS_CLIENT_CLOSED_LOAD_BALANCED_REQUEST = 460, HTTP_STATUS_INVALID_X_FORWARDED_FOR = 463, HTTP_STATUS_REQUEST_HEADER_TOO_LARGE = 494, HTTP_STATUS_SSL_CERTIFICATE_ERROR = 495, HTTP_STATUS_SSL_CERTIFICATE_REQUIRED = 496, HTTP_STATUS_HTTP_REQUEST_SENT_TO_HTTPS_PORT = 497, HTTP_STATUS_INVALID_TOKEN = 498, HTTP_STATUS_CLIENT_CLOSED_REQUEST = 499, HTTP_STATUS_INTERNAL_SERVER_ERROR = 500, HTTP_STATUS_NOT_IMPLEMENTED = 501, HTTP_STATUS_BAD_GATEWAY = 502, HTTP_STATUS_SERVICE_UNAVAILABLE = 503, HTTP_STATUS_GATEWAY_TIMEOUT = 504, HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED = 505, HTTP_STATUS_VARIANT_ALSO_NEGOTIATES = 506, HTTP_STATUS_INSUFFICIENT_STORAGE = 507, HTTP_STATUS_LOOP_DETECTED = 508, HTTP_STATUS_BANDWIDTH_LIMIT_EXCEEDED = 509, HTTP_STATUS_NOT_EXTENDED = 510, HTTP_STATUS_NETWORK_AUTHENTICATION_REQUIRED = 511, HTTP_STATUS_WEB_SERVER_UNKNOWN_ERROR = 520, HTTP_STATUS_WEB_SERVER_IS_DOWN = 521, HTTP_STATUS_CONNECTION_TIMEOUT = 522, HTTP_STATUS_ORIGIN_IS_UNREACHABLE = 523, HTTP_STATUS_TIMEOUT_OCCURED = 524, HTTP_STATUS_SSL_HANDSHAKE_FAILED = 525, HTTP_STATUS_INVALID_SSL_CERTIFICATE = 526, HTTP_STATUS_RAILGUN_ERROR = 527, HTTP_STATUS_SITE_IS_OVERLOADED = 529, HTTP_STATUS_SITE_IS_FROZEN = 530, HTTP_STATUS_IDENTITY_PROVIDER_AUTHENTICATION_ERROR = 561, HTTP_STATUS_NETWORK_READ_TIMEOUT = 598, HTTP_STATUS_NETWORK_CONNECT_TIMEOUT = 599 }; typedef enum llhttp_status llhttp_status_t; #define HTTP_ERRNO_MAP(XX) \ XX(0, OK, OK) \ XX(1, INTERNAL, INTERNAL) \ XX(2, STRICT, STRICT) \ XX(25, CR_EXPECTED, CR_EXPECTED) \ XX(3, LF_EXPECTED, LF_EXPECTED) \ XX(4, UNEXPECTED_CONTENT_LENGTH, UNEXPECTED_CONTENT_LENGTH) \ XX(30, UNEXPECTED_SPACE, UNEXPECTED_SPACE) \ XX(5, CLOSED_CONNECTION, CLOSED_CONNECTION) \ XX(6, INVALID_METHOD, INVALID_METHOD) \ XX(7, INVALID_URL, INVALID_URL) \ XX(8, INVALID_CONSTANT, INVALID_CONSTANT) \ XX(9, INVALID_VERSION, INVALID_VERSION) \ XX(10, INVALID_HEADER_TOKEN, INVALID_HEADER_TOKEN) \ XX(11, INVALID_CONTENT_LENGTH, INVALID_CONTENT_LENGTH) \ XX(12, INVALID_CHUNK_SIZE, INVALID_CHUNK_SIZE) \ XX(13, INVALID_STATUS, INVALID_STATUS) \ XX(14, INVALID_EOF_STATE, INVALID_EOF_STATE) \ XX(15, INVALID_TRANSFER_ENCODING, INVALID_TRANSFER_ENCODING) \ XX(16, CB_MESSAGE_BEGIN, CB_MESSAGE_BEGIN) \ XX(17, CB_HEADERS_COMPLETE, CB_HEADERS_COMPLETE) \ XX(18, CB_MESSAGE_COMPLETE, CB_MESSAGE_COMPLETE) \ XX(19, CB_CHUNK_HEADER, CB_CHUNK_HEADER) \ XX(20, CB_CHUNK_COMPLETE, CB_CHUNK_COMPLETE) \ XX(21, PAUSED, PAUSED) \ XX(22, PAUSED_UPGRADE, PAUSED_UPGRADE) \ XX(23, PAUSED_H2_UPGRADE, PAUSED_H2_UPGRADE) \ XX(24, USER, USER) \ XX(26, CB_URL_COMPLETE, CB_URL_COMPLETE) \ XX(27, CB_STATUS_COMPLETE, CB_STATUS_COMPLETE) \ XX(32, CB_METHOD_COMPLETE, CB_METHOD_COMPLETE) \ XX(33, CB_VERSION_COMPLETE, CB_VERSION_COMPLETE) \ XX(28, CB_HEADER_FIELD_COMPLETE, CB_HEADER_FIELD_COMPLETE) \ XX(29, CB_HEADER_VALUE_COMPLETE, CB_HEADER_VALUE_COMPLETE) \ XX(34, CB_CHUNK_EXTENSION_NAME_COMPLETE, CB_CHUNK_EXTENSION_NAME_COMPLETE) \ XX(35, CB_CHUNK_EXTENSION_VALUE_COMPLETE, CB_CHUNK_EXTENSION_VALUE_COMPLETE) \ XX(31, CB_RESET, CB_RESET) \ #define HTTP_METHOD_MAP(XX) \ XX(0, DELETE, DELETE) \ XX(1, GET, GET) \ XX(2, HEAD, HEAD) \ XX(3, POST, POST) \ XX(4, PUT, PUT) \ XX(5, CONNECT, CONNECT) \ XX(6, OPTIONS, OPTIONS) \ XX(7, TRACE, TRACE) \ XX(8, COPY, COPY) \ XX(9, LOCK, LOCK) \ XX(10, MKCOL, MKCOL) \ XX(11, MOVE, MOVE) \ XX(12, PROPFIND, PROPFIND) \ XX(13, PROPPATCH, PROPPATCH) \ XX(14, SEARCH, SEARCH) \ XX(15, UNLOCK, UNLOCK) \ XX(16, BIND, BIND) \ XX(17, REBIND, REBIND) \ XX(18, UNBIND, UNBIND) \ XX(19, ACL, ACL) \ XX(20, REPORT, REPORT) \ XX(21, MKACTIVITY, MKACTIVITY) \ XX(22, CHECKOUT, CHECKOUT) \ XX(23, MERGE, MERGE) \ XX(24, MSEARCH, M-SEARCH) \ XX(25, NOTIFY, NOTIFY) \ XX(26, SUBSCRIBE, SUBSCRIBE) \ XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \ XX(28, PATCH, PATCH) \ XX(29, PURGE, PURGE) \ XX(30, MKCALENDAR, MKCALENDAR) \ XX(31, LINK, LINK) \ XX(32, UNLINK, UNLINK) \ XX(33, SOURCE, SOURCE) \ XX(46, QUERY, QUERY) \ #define RTSP_METHOD_MAP(XX) \ XX(1, GET, GET) \ XX(3, POST, POST) \ XX(6, OPTIONS, OPTIONS) \ XX(35, DESCRIBE, DESCRIBE) \ XX(36, ANNOUNCE, ANNOUNCE) \ XX(37, SETUP, SETUP) \ XX(38, PLAY, PLAY) \ XX(39, PAUSE, PAUSE) \ XX(40, TEARDOWN, TEARDOWN) \ XX(41, GET_PARAMETER, GET_PARAMETER) \ XX(42, SET_PARAMETER, SET_PARAMETER) \ XX(43, REDIRECT, REDIRECT) \ XX(44, RECORD, RECORD) \ XX(45, FLUSH, FLUSH) \ #define HTTP_ALL_METHOD_MAP(XX) \ XX(0, DELETE, DELETE) \ XX(1, GET, GET) \ XX(2, HEAD, HEAD) \ XX(3, POST, POST) \ XX(4, PUT, PUT) \ XX(5, CONNECT, CONNECT) \ XX(6, OPTIONS, OPTIONS) \ XX(7, TRACE, TRACE) \ XX(8, COPY, COPY) \ XX(9, LOCK, LOCK) \ XX(10, MKCOL, MKCOL) \ XX(11, MOVE, MOVE) \ XX(12, PROPFIND, PROPFIND) \ XX(13, PROPPATCH, PROPPATCH) \ XX(14, SEARCH, SEARCH) \ XX(15, UNLOCK, UNLOCK) \ XX(16, BIND, BIND) \ XX(17, REBIND, REBIND) \ XX(18, UNBIND, UNBIND) \ XX(19, ACL, ACL) \ XX(20, REPORT, REPORT) \ XX(21, MKACTIVITY, MKACTIVITY) \ XX(22, CHECKOUT, CHECKOUT) \ XX(23, MERGE, MERGE) \ XX(24, MSEARCH, M-SEARCH) \ XX(25, NOTIFY, NOTIFY) \ XX(26, SUBSCRIBE, SUBSCRIBE) \ XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \ XX(28, PATCH, PATCH) \ XX(29, PURGE, PURGE) \ XX(30, MKCALENDAR, MKCALENDAR) \ XX(31, LINK, LINK) \ XX(32, UNLINK, UNLINK) \ XX(33, SOURCE, SOURCE) \ XX(34, PRI, PRI) \ XX(35, DESCRIBE, DESCRIBE) \ XX(36, ANNOUNCE, ANNOUNCE) \ XX(37, SETUP, SETUP) \ XX(38, PLAY, PLAY) \ XX(39, PAUSE, PAUSE) \ XX(40, TEARDOWN, TEARDOWN) \ XX(41, GET_PARAMETER, GET_PARAMETER) \ XX(42, SET_PARAMETER, SET_PARAMETER) \ XX(43, REDIRECT, REDIRECT) \ XX(44, RECORD, RECORD) \ XX(45, FLUSH, FLUSH) \ XX(46, QUERY, QUERY) \ #define HTTP_STATUS_MAP(XX) \ XX(100, CONTINUE, CONTINUE) \ XX(101, SWITCHING_PROTOCOLS, SWITCHING_PROTOCOLS) \ XX(102, PROCESSING, PROCESSING) \ XX(103, EARLY_HINTS, EARLY_HINTS) \ XX(110, RESPONSE_IS_STALE, RESPONSE_IS_STALE) \ XX(111, REVALIDATION_FAILED, REVALIDATION_FAILED) \ XX(112, DISCONNECTED_OPERATION, DISCONNECTED_OPERATION) \ XX(113, HEURISTIC_EXPIRATION, HEURISTIC_EXPIRATION) \ XX(199, MISCELLANEOUS_WARNING, MISCELLANEOUS_WARNING) \ XX(200, OK, OK) \ XX(201, CREATED, CREATED) \ XX(202, ACCEPTED, ACCEPTED) \ XX(203, NON_AUTHORITATIVE_INFORMATION, NON_AUTHORITATIVE_INFORMATION) \ XX(204, NO_CONTENT, NO_CONTENT) \ XX(205, RESET_CONTENT, RESET_CONTENT) \ XX(206, PARTIAL_CONTENT, PARTIAL_CONTENT) \ XX(207, MULTI_STATUS, MULTI_STATUS) \ XX(208, ALREADY_REPORTED, ALREADY_REPORTED) \ XX(214, TRANSFORMATION_APPLIED, TRANSFORMATION_APPLIED) \ XX(226, IM_USED, IM_USED) \ XX(299, MISCELLANEOUS_PERSISTENT_WARNING, MISCELLANEOUS_PERSISTENT_WARNING) \ XX(300, MULTIPLE_CHOICES, MULTIPLE_CHOICES) \ XX(301, MOVED_PERMANENTLY, MOVED_PERMANENTLY) \ XX(302, FOUND, FOUND) \ XX(303, SEE_OTHER, SEE_OTHER) \ XX(304, NOT_MODIFIED, NOT_MODIFIED) \ XX(305, USE_PROXY, USE_PROXY) \ XX(306, SWITCH_PROXY, SWITCH_PROXY) \ XX(307, TEMPORARY_REDIRECT, TEMPORARY_REDIRECT) \ XX(308, PERMANENT_REDIRECT, PERMANENT_REDIRECT) \ XX(400, BAD_REQUEST, BAD_REQUEST) \ XX(401, UNAUTHORIZED, UNAUTHORIZED) \ XX(402, PAYMENT_REQUIRED, PAYMENT_REQUIRED) \ XX(403, FORBIDDEN, FORBIDDEN) \ XX(404, NOT_FOUND, NOT_FOUND) \ XX(405, METHOD_NOT_ALLOWED, METHOD_NOT_ALLOWED) \ XX(406, NOT_ACCEPTABLE, NOT_ACCEPTABLE) \ XX(407, PROXY_AUTHENTICATION_REQUIRED, PROXY_AUTHENTICATION_REQUIRED) \ XX(408, REQUEST_TIMEOUT, REQUEST_TIMEOUT) \ XX(409, CONFLICT, CONFLICT) \ XX(410, GONE, GONE) \ XX(411, LENGTH_REQUIRED, LENGTH_REQUIRED) \ XX(412, PRECONDITION_FAILED, PRECONDITION_FAILED) \ XX(413, PAYLOAD_TOO_LARGE, PAYLOAD_TOO_LARGE) \ XX(414, URI_TOO_LONG, URI_TOO_LONG) \ XX(415, UNSUPPORTED_MEDIA_TYPE, UNSUPPORTED_MEDIA_TYPE) \ XX(416, RANGE_NOT_SATISFIABLE, RANGE_NOT_SATISFIABLE) \ XX(417, EXPECTATION_FAILED, EXPECTATION_FAILED) \ XX(418, IM_A_TEAPOT, IM_A_TEAPOT) \ XX(419, PAGE_EXPIRED, PAGE_EXPIRED) \ XX(420, ENHANCE_YOUR_CALM, ENHANCE_YOUR_CALM) \ XX(421, MISDIRECTED_REQUEST, MISDIRECTED_REQUEST) \ XX(422, UNPROCESSABLE_ENTITY, UNPROCESSABLE_ENTITY) \ XX(423, LOCKED, LOCKED) \ XX(424, FAILED_DEPENDENCY, FAILED_DEPENDENCY) \ XX(425, TOO_EARLY, TOO_EARLY) \ XX(426, UPGRADE_REQUIRED, UPGRADE_REQUIRED) \ XX(428, PRECONDITION_REQUIRED, PRECONDITION_REQUIRED) \ XX(429, TOO_MANY_REQUESTS, TOO_MANY_REQUESTS) \ XX(430, REQUEST_HEADER_FIELDS_TOO_LARGE_UNOFFICIAL, REQUEST_HEADER_FIELDS_TOO_LARGE_UNOFFICIAL) \ XX(431, REQUEST_HEADER_FIELDS_TOO_LARGE, REQUEST_HEADER_FIELDS_TOO_LARGE) \ XX(440, LOGIN_TIMEOUT, LOGIN_TIMEOUT) \ XX(444, NO_RESPONSE, NO_RESPONSE) \ XX(449, RETRY_WITH, RETRY_WITH) \ XX(450, BLOCKED_BY_PARENTAL_CONTROL, BLOCKED_BY_PARENTAL_CONTROL) \ XX(451, UNAVAILABLE_FOR_LEGAL_REASONS, UNAVAILABLE_FOR_LEGAL_REASONS) \ XX(460, CLIENT_CLOSED_LOAD_BALANCED_REQUEST, CLIENT_CLOSED_LOAD_BALANCED_REQUEST) \ XX(463, INVALID_X_FORWARDED_FOR, INVALID_X_FORWARDED_FOR) \ XX(494, REQUEST_HEADER_TOO_LARGE, REQUEST_HEADER_TOO_LARGE) \ XX(495, SSL_CERTIFICATE_ERROR, SSL_CERTIFICATE_ERROR) \ XX(496, SSL_CERTIFICATE_REQUIRED, SSL_CERTIFICATE_REQUIRED) \ XX(497, HTTP_REQUEST_SENT_TO_HTTPS_PORT, HTTP_REQUEST_SENT_TO_HTTPS_PORT) \ XX(498, INVALID_TOKEN, INVALID_TOKEN) \ XX(499, CLIENT_CLOSED_REQUEST, CLIENT_CLOSED_REQUEST) \ XX(500, INTERNAL_SERVER_ERROR, INTERNAL_SERVER_ERROR) \ XX(501, NOT_IMPLEMENTED, NOT_IMPLEMENTED) \ XX(502, BAD_GATEWAY, BAD_GATEWAY) \ XX(503, SERVICE_UNAVAILABLE, SERVICE_UNAVAILABLE) \ XX(504, GATEWAY_TIMEOUT, GATEWAY_TIMEOUT) \ XX(505, HTTP_VERSION_NOT_SUPPORTED, HTTP_VERSION_NOT_SUPPORTED) \ XX(506, VARIANT_ALSO_NEGOTIATES, VARIANT_ALSO_NEGOTIATES) \ XX(507, INSUFFICIENT_STORAGE, INSUFFICIENT_STORAGE) \ XX(508, LOOP_DETECTED, LOOP_DETECTED) \ XX(509, BANDWIDTH_LIMIT_EXCEEDED, BANDWIDTH_LIMIT_EXCEEDED) \ XX(510, NOT_EXTENDED, NOT_EXTENDED) \ XX(511, NETWORK_AUTHENTICATION_REQUIRED, NETWORK_AUTHENTICATION_REQUIRED) \ XX(520, WEB_SERVER_UNKNOWN_ERROR, WEB_SERVER_UNKNOWN_ERROR) \ XX(521, WEB_SERVER_IS_DOWN, WEB_SERVER_IS_DOWN) \ XX(522, CONNECTION_TIMEOUT, CONNECTION_TIMEOUT) \ XX(523, ORIGIN_IS_UNREACHABLE, ORIGIN_IS_UNREACHABLE) \ XX(524, TIMEOUT_OCCURED, TIMEOUT_OCCURED) \ XX(525, SSL_HANDSHAKE_FAILED, SSL_HANDSHAKE_FAILED) \ XX(526, INVALID_SSL_CERTIFICATE, INVALID_SSL_CERTIFICATE) \ XX(527, RAILGUN_ERROR, RAILGUN_ERROR) \ XX(529, SITE_IS_OVERLOADED, SITE_IS_OVERLOADED) \ XX(530, SITE_IS_FROZEN, SITE_IS_FROZEN) \ XX(561, IDENTITY_PROVIDER_AUTHENTICATION_ERROR, IDENTITY_PROVIDER_AUTHENTICATION_ERROR) \ XX(598, NETWORK_READ_TIMEOUT, NETWORK_READ_TIMEOUT) \ XX(599, NETWORK_CONNECT_TIMEOUT, NETWORK_CONNECT_TIMEOUT) \ #ifdef __cplusplus } /* extern "C" */ #endif #endif /* LLLLHTTP_C_HEADERS_ */ #ifndef INCLUDE_LLHTTP_API_H_ #define INCLUDE_LLHTTP_API_H_ #ifdef __cplusplus extern "C" { #endif #include #if defined(__wasm__) #define LLHTTP_EXPORT __attribute__((visibility("default"))) #elif defined(_WIN32) #define LLHTTP_EXPORT __declspec(dllexport) #else #define LLHTTP_EXPORT #endif typedef llhttp__internal_t llhttp_t; typedef struct llhttp_settings_s llhttp_settings_t; typedef int (*llhttp_data_cb)(llhttp_t*, const char *at, size_t length); typedef int (*llhttp_cb)(llhttp_t*); struct llhttp_settings_s { /* Possible return values 0, -1, `HPE_PAUSED` */ llhttp_cb on_message_begin; /* Possible return values 0, -1, HPE_USER */ llhttp_data_cb on_url; llhttp_data_cb on_status; llhttp_data_cb on_method; llhttp_data_cb on_version; llhttp_data_cb on_header_field; llhttp_data_cb on_header_value; llhttp_data_cb on_chunk_extension_name; llhttp_data_cb on_chunk_extension_value; /* Possible return values: * 0 - Proceed normally * 1 - Assume that request/response has no body, and proceed to parsing the * next message * 2 - Assume absence of body (as above) and make `llhttp_execute()` return * `HPE_PAUSED_UPGRADE` * -1 - Error * `HPE_PAUSED` */ llhttp_cb on_headers_complete; /* Possible return values 0, -1, HPE_USER */ llhttp_data_cb on_body; /* Possible return values 0, -1, `HPE_PAUSED` */ llhttp_cb on_message_complete; llhttp_cb on_url_complete; llhttp_cb on_status_complete; llhttp_cb on_method_complete; llhttp_cb on_version_complete; llhttp_cb on_header_field_complete; llhttp_cb on_header_value_complete; llhttp_cb on_chunk_extension_name_complete; llhttp_cb on_chunk_extension_value_complete; /* When on_chunk_header is called, the current chunk length is stored * in parser->content_length. * Possible return values 0, -1, `HPE_PAUSED` */ llhttp_cb on_chunk_header; llhttp_cb on_chunk_complete; llhttp_cb on_reset; }; /* Initialize the parser with specific type and user settings. * * NOTE: lifetime of `settings` has to be at least the same as the lifetime of * the `parser` here. In practice, `settings` has to be either a static * variable or be allocated with `malloc`, `new`, etc. */ LLHTTP_EXPORT void llhttp_init(llhttp_t* parser, llhttp_type_t type, const llhttp_settings_t* settings); LLHTTP_EXPORT llhttp_t* llhttp_alloc(llhttp_type_t type); LLHTTP_EXPORT void llhttp_free(llhttp_t* parser); LLHTTP_EXPORT uint8_t llhttp_get_type(llhttp_t* parser); LLHTTP_EXPORT uint8_t llhttp_get_http_major(llhttp_t* parser); LLHTTP_EXPORT uint8_t llhttp_get_http_minor(llhttp_t* parser); LLHTTP_EXPORT uint8_t llhttp_get_method(llhttp_t* parser); LLHTTP_EXPORT int llhttp_get_status_code(llhttp_t* parser); LLHTTP_EXPORT uint8_t llhttp_get_upgrade(llhttp_t* parser); /* Reset an already initialized parser back to the start state, preserving the * existing parser type, callback settings, user data, and lenient flags. */ LLHTTP_EXPORT void llhttp_reset(llhttp_t* parser); /* Initialize the settings object */ LLHTTP_EXPORT void llhttp_settings_init(llhttp_settings_t* settings); /* Parse full or partial request/response, invoking user callbacks along the * way. * * If any of `llhttp_data_cb` returns errno not equal to `HPE_OK` - the parsing * interrupts, and such errno is returned from `llhttp_execute()`. If * `HPE_PAUSED` was used as a errno, the execution can be resumed with * `llhttp_resume()` call. * * In a special case of CONNECT/Upgrade request/response `HPE_PAUSED_UPGRADE` * is returned after fully parsing the request/response. If the user wishes to * continue parsing, they need to invoke `llhttp_resume_after_upgrade()`. * * NOTE: if this function ever returns a non-pause type error, it will continue * to return the same error upon each successive call up until `llhttp_init()` * is called. */ LLHTTP_EXPORT llhttp_errno_t llhttp_execute(llhttp_t* parser, const char* data, size_t len); /* This method should be called when the other side has no further bytes to * send (e.g. shutdown of readable side of the TCP connection.) * * Requests without `Content-Length` and other messages might require treating * all incoming bytes as the part of the body, up to the last byte of the * connection. This method will invoke `on_message_complete()` callback if the * request was terminated safely. Otherwise a error code would be returned. */ LLHTTP_EXPORT llhttp_errno_t llhttp_finish(llhttp_t* parser); /* Returns `1` if the incoming message is parsed until the last byte, and has * to be completed by calling `llhttp_finish()` on EOF */ LLHTTP_EXPORT int llhttp_message_needs_eof(const llhttp_t* parser); /* Returns `1` if there might be any other messages following the last that was * successfully parsed. */ LLHTTP_EXPORT int llhttp_should_keep_alive(const llhttp_t* parser); /* Make further calls of `llhttp_execute()` return `HPE_PAUSED` and set * appropriate error reason. * * Important: do not call this from user callbacks! User callbacks must return * `HPE_PAUSED` if pausing is required. */ LLHTTP_EXPORT void llhttp_pause(llhttp_t* parser); /* Might be called to resume the execution after the pause in user's callback. * See `llhttp_execute()` above for details. * * Call this only if `llhttp_execute()` returns `HPE_PAUSED`. */ LLHTTP_EXPORT void llhttp_resume(llhttp_t* parser); /* Might be called to resume the execution after the pause in user's callback. * See `llhttp_execute()` above for details. * * Call this only if `llhttp_execute()` returns `HPE_PAUSED_UPGRADE` */ LLHTTP_EXPORT void llhttp_resume_after_upgrade(llhttp_t* parser); /* Returns the latest return error */ LLHTTP_EXPORT llhttp_errno_t llhttp_get_errno(const llhttp_t* parser); /* Returns the verbal explanation of the latest returned error. * * Note: User callback should set error reason when returning the error. See * `llhttp_set_error_reason()` for details. */ LLHTTP_EXPORT const char* llhttp_get_error_reason(const llhttp_t* parser); /* Assign verbal description to the returned error. Must be called in user * callbacks right before returning the errno. * * Note: `HPE_USER` error code might be useful in user callbacks. */ LLHTTP_EXPORT void llhttp_set_error_reason(llhttp_t* parser, const char* reason); /* Returns the pointer to the last parsed byte before the returned error. The * pointer is relative to the `data` argument of `llhttp_execute()`. * * Note: this method might be useful for counting the number of parsed bytes. */ LLHTTP_EXPORT const char* llhttp_get_error_pos(const llhttp_t* parser); /* Returns textual name of error code */ LLHTTP_EXPORT const char* llhttp_errno_name(llhttp_errno_t err); /* Returns textual name of HTTP method */ LLHTTP_EXPORT const char* llhttp_method_name(llhttp_method_t method); /* Returns textual name of HTTP status */ LLHTTP_EXPORT const char* llhttp_status_name(llhttp_status_t status); /* Enables/disables lenient header value parsing (disabled by default). * * Lenient parsing disables header value token checks, extending llhttp's * protocol support to highly non-compliant clients/server. No * `HPE_INVALID_HEADER_TOKEN` will be raised for incorrect header values when * lenient parsing is "on". * * **Enabling this flag can pose a security issue since you will be exposed to * request smuggling attacks. USE WITH CAUTION!** */ LLHTTP_EXPORT void llhttp_set_lenient_headers(llhttp_t* parser, int enabled); /* Enables/disables lenient handling of conflicting `Transfer-Encoding` and * `Content-Length` headers (disabled by default). * * Normally `llhttp` would error when `Transfer-Encoding` is present in * conjunction with `Content-Length`. This error is important to prevent HTTP * request smuggling, but may be less desirable for small number of cases * involving legacy servers. * * **Enabling this flag can pose a security issue since you will be exposed to * request smuggling attacks. USE WITH CAUTION!** */ LLHTTP_EXPORT void llhttp_set_lenient_chunked_length(llhttp_t* parser, int enabled); /* Enables/disables lenient handling of `Connection: close` and HTTP/1.0 * requests responses. * * Normally `llhttp` would error on (in strict mode) or discard (in loose mode) * the HTTP request/response after the request/response with `Connection: close` * and `Content-Length`. This is important to prevent cache poisoning attacks, * but might interact badly with outdated and insecure clients. With this flag * the extra request/response will be parsed normally. * * **Enabling this flag can pose a security issue since you will be exposed to * poisoning attacks. USE WITH CAUTION!** */ LLHTTP_EXPORT void llhttp_set_lenient_keep_alive(llhttp_t* parser, int enabled); /* Enables/disables lenient handling of `Transfer-Encoding` header. * * Normally `llhttp` would error when a `Transfer-Encoding` has `chunked` value * and another value after it (either in a single header or in multiple * headers whose value are internally joined using `, `). * This is mandated by the spec to reliably determine request body size and thus * avoid request smuggling. * With this flag the extra value will be parsed normally. * * **Enabling this flag can pose a security issue since you will be exposed to * request smuggling attacks. USE WITH CAUTION!** */ LLHTTP_EXPORT void llhttp_set_lenient_transfer_encoding(llhttp_t* parser, int enabled); /* Enables/disables lenient handling of HTTP version. * * Normally `llhttp` would error when the HTTP version in the request or status line * is not `0.9`, `1.0`, `1.1` or `2.0`. * With this flag the invalid value will be parsed normally. * * **Enabling this flag can pose a security issue since you will allow unsupported * HTTP versions. USE WITH CAUTION!** */ LLHTTP_EXPORT void llhttp_set_lenient_version(llhttp_t* parser, int enabled); /* Enables/disables lenient handling of additional data received after a message ends * and keep-alive is disabled. * * Normally `llhttp` would error when additional unexpected data is received if the message * contains the `Connection` header with `close` value. * With this flag the extra data will discarded without throwing an error. * * **Enabling this flag can pose a security issue since you will be exposed to * poisoning attacks. USE WITH CAUTION!** */ LLHTTP_EXPORT void llhttp_set_lenient_data_after_close(llhttp_t* parser, int enabled); /* Enables/disables lenient handling of incomplete CRLF sequences. * * Normally `llhttp` would error when a CR is not followed by LF when terminating the * request line, the status line, the headers or a chunk header. * With this flag only a CR is required to terminate such sections. * * **Enabling this flag can pose a security issue since you will be exposed to * request smuggling attacks. USE WITH CAUTION!** */ LLHTTP_EXPORT void llhttp_set_lenient_optional_lf_after_cr(llhttp_t* parser, int enabled); /* * Enables/disables lenient handling of line separators. * * Normally `llhttp` would error when a LF is not preceded by CR when terminating the * request line, the status line, the headers, a chunk header or a chunk data. * With this flag only a LF is required to terminate such sections. * * **Enabling this flag can pose a security issue since you will be exposed to * request smuggling attacks. USE WITH CAUTION!** */ LLHTTP_EXPORT void llhttp_set_lenient_optional_cr_before_lf(llhttp_t* parser, int enabled); /* Enables/disables lenient handling of chunks not separated via CRLF. * * Normally `llhttp` would error when after a chunk data a CRLF is missing before * starting a new chunk. * With this flag the new chunk can start immediately after the previous one. * * **Enabling this flag can pose a security issue since you will be exposed to * request smuggling attacks. USE WITH CAUTION!** */ LLHTTP_EXPORT void llhttp_set_lenient_optional_crlf_after_chunk(llhttp_t* parser, int enabled); /* Enables/disables lenient handling of spaces after chunk size. * * Normally `llhttp` would error when after a chunk size is followed by one or more * spaces are present instead of a CRLF or `;`. * With this flag this check is disabled. * * **Enabling this flag can pose a security issue since you will be exposed to * request smuggling attacks. USE WITH CAUTION!** */ LLHTTP_EXPORT void llhttp_set_lenient_spaces_after_chunk_size(llhttp_t* parser, int enabled); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* INCLUDE_LLHTTP_API_H_ */ #endif /* INCLUDE_LLHTTP_H_ */ UxPlay-1.71.1/lib/logger.c000066400000000000000000000063651473013662600152360ustar00rootroot00000000000000/** * Copyright (C) 2011-2012 Juho Vähä-Herttua * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * *=============================================================== * modified by fduncanh 2023 */ #include #include #include #include #include "logger.h" #include "compat.h" struct logger_s { mutex_handle_t lvl_mutex; mutex_handle_t cb_mutex; int level; void *cls; logger_callback_t callback; }; logger_t * logger_init() { logger_t *logger = calloc(1, sizeof(logger_t)); assert(logger); MUTEX_CREATE(logger->lvl_mutex); MUTEX_CREATE(logger->cb_mutex); logger->level = LOGGER_WARNING; logger->callback = NULL; return logger; } void logger_destroy(logger_t *logger) { MUTEX_DESTROY(logger->lvl_mutex); MUTEX_DESTROY(logger->cb_mutex); free(logger); } void logger_set_level(logger_t *logger, int level) { assert(logger); MUTEX_LOCK(logger->lvl_mutex); logger->level = level; MUTEX_UNLOCK(logger->lvl_mutex); } int logger_get_level(logger_t *logger) { int level; assert(logger); MUTEX_LOCK(logger->lvl_mutex); level = logger->level; MUTEX_UNLOCK(logger->lvl_mutex); return level; } void logger_set_callback(logger_t *logger, logger_callback_t callback, void *cls) { assert(logger); MUTEX_LOCK(logger->cb_mutex); logger->cls = cls; logger->callback = callback; MUTEX_UNLOCK(logger->cb_mutex); } static char * logger_utf8_to_local(const char *str) { char *ret = NULL; /* FIXME: This is only implemented on Windows for now */ #if defined(_WIN32) || defined(_WIN64) int wclen, mblen; WCHAR *wcstr; BOOL failed; wclen = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); wcstr = malloc(sizeof(WCHAR) * wclen); MultiByteToWideChar(CP_UTF8, 0, str, -1, wcstr, wclen); mblen = WideCharToMultiByte(CP_ACP, 0, wcstr, wclen, NULL, 0, NULL, &failed); if (failed) { /* Invalid characters in input, conversion failed */ free(wcstr); return NULL; } ret = malloc(sizeof(CHAR) * mblen); WideCharToMultiByte(CP_ACP, 0, wcstr, wclen, ret, mblen, NULL, NULL); free(wcstr); #endif return ret; } void logger_log(logger_t *logger, int level, const char *fmt, ...) { char buffer[4096]; va_list ap; MUTEX_LOCK(logger->lvl_mutex); if (level > logger->level) { MUTEX_UNLOCK(logger->lvl_mutex); return; } MUTEX_UNLOCK(logger->lvl_mutex); buffer[sizeof(buffer)-1] = '\0'; va_start(ap, fmt); vsnprintf(buffer, sizeof(buffer)-1, fmt, ap); va_end(ap); MUTEX_LOCK(logger->cb_mutex); if (logger->callback) { logger->callback(logger->cls, level, buffer); MUTEX_UNLOCK(logger->cb_mutex); } else { char *local; MUTEX_UNLOCK(logger->cb_mutex); local = logger_utf8_to_local(buffer); if (local) { fprintf(stderr, "%s\n", local); free(local); } else { fprintf(stderr, "%s\n", buffer); } } } UxPlay-1.71.1/lib/logger.h000066400000000000000000000033371473013662600152370ustar00rootroot00000000000000/** * Copyright (C) 2011-2012 Juho Vähä-Herttua * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * *================================================================= * modified by fduncanh 2023 */ #ifndef LOGGER_H #define LOGGER_H #ifdef __cplusplus extern "C" { #endif /* Define syslog style log levels */ #define LOGGER_EMERG 0 /* system is unusable */ #define LOGGER_ALERT 1 /* action must be taken immediately */ #define LOGGER_CRIT 2 /* critical conditions */ #define LOGGER_ERR 3 /* error conditions */ #define LOGGER_WARNING 4 /* warning conditions */ #define LOGGER_NOTICE 5 /* normal but significant condition */ #define LOGGER_INFO 6 /* informational */ #define LOGGER_DEBUG 7 /* debug-level messages */ typedef void (*logger_callback_t)(void *cls, int level, const char *msg); typedef struct logger_s logger_t; logger_t *logger_init(); void logger_destroy(logger_t *logger); void logger_set_level(logger_t *logger, int level); int logger_get_level(logger_t *logger); void logger_set_callback(logger_t *logger, logger_callback_t callback, void *cls); void logger_log(logger_t *logger, int level, const char *fmt, ...); #ifdef __cplusplus } #endif #endif UxPlay-1.71.1/lib/mirror_buffer.c000066400000000000000000000105021473013662600166060ustar00rootroot00000000000000/* * Copyright (c) 2019 dsafa22, All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * *================================================================ * modified by fduncanh 2022 */ #include "mirror_buffer.h" #include "raop_rtp.h" #include "raop_rtp.h" #include #include "crypto.h" #include "compat.h" #include #include #include #include #include #include struct mirror_buffer_s { logger_t *logger; aes_ctx_t *aes_ctx; int nextDecryptCount; uint8_t og[16]; /* audio aes key is used in a hash for the video aes key and iv */ unsigned char aeskey_audio[RAOP_AESKEY_LEN]; }; void mirror_buffer_init_aes(mirror_buffer_t *mirror_buffer, const uint64_t *streamConnectionID) { unsigned char aeskey_video[64]; unsigned char aesiv_video[64]; assert(mirror_buffer); assert(streamConnectionID); /* AES key and IV */ // Need secondary processing to use snprintf((char*) aeskey_video, sizeof(aeskey_video), "AirPlayStreamKey%" PRIu64, *streamConnectionID); snprintf((char*) aesiv_video, sizeof(aesiv_video), "AirPlayStreamIV%" PRIu64, *streamConnectionID); sha_ctx_t *ctx = sha_init(); sha_update(ctx, aeskey_video, strlen((char*) aeskey_video)); sha_update(ctx, mirror_buffer->aeskey_audio, RAOP_AESKEY_LEN); sha_final(ctx, aeskey_video, NULL); sha_reset(ctx); sha_update(ctx, aesiv_video, strlen((char*) aesiv_video)); sha_update(ctx, mirror_buffer->aeskey_audio, RAOP_AESKEY_LEN); sha_final(ctx, aesiv_video, NULL); sha_destroy(ctx); // Need to be initialized externally mirror_buffer->aes_ctx = aes_ctr_init(aeskey_video, aesiv_video); } mirror_buffer_t * mirror_buffer_init(logger_t *logger, const unsigned char *aeskey) { mirror_buffer_t *mirror_buffer; assert(aeskey); mirror_buffer = calloc(1, sizeof(mirror_buffer_t)); if (!mirror_buffer) { return NULL; } memcpy(mirror_buffer->aeskey_audio, aeskey, RAOP_AESKEY_LEN); mirror_buffer->logger = logger; mirror_buffer->nextDecryptCount = 0; return mirror_buffer; } void mirror_buffer_decrypt(mirror_buffer_t *mirror_buffer, unsigned char* input, unsigned char* output, int inputLen) { // Start decrypting if (mirror_buffer->nextDecryptCount > 0) {//mirror_buffer->nextDecryptCount = 10 for (int i = 0; i < mirror_buffer->nextDecryptCount; i++) { output[i] = (input[i] ^ mirror_buffer->og[(16 - mirror_buffer->nextDecryptCount) + i]); } } // Handling encrypted bytes int encryptlen = ((inputLen - mirror_buffer->nextDecryptCount) / 16) * 16; // Aes decryption aes_ctr_start_fresh_block(mirror_buffer->aes_ctx); aes_ctr_decrypt(mirror_buffer->aes_ctx, input + mirror_buffer->nextDecryptCount, input + mirror_buffer->nextDecryptCount, encryptlen); // Copy to output memcpy(output + mirror_buffer->nextDecryptCount, input + mirror_buffer->nextDecryptCount, encryptlen); // int outputlength = mirror_buffer->nextDecryptCount + encryptlen; // Processing remaining length int restlen = (inputLen - mirror_buffer->nextDecryptCount) % 16; int reststart = inputLen - restlen; mirror_buffer->nextDecryptCount = 0; if (restlen > 0) { memset(mirror_buffer->og, 0, 16); memcpy(mirror_buffer->og, input + reststart, restlen); aes_ctr_decrypt(mirror_buffer->aes_ctx, mirror_buffer->og, mirror_buffer->og, 16); for (int j = 0; j < restlen; j++) { output[reststart + j] = mirror_buffer->og[j]; } //outputlength += restlen; mirror_buffer->nextDecryptCount = 16 - restlen;// Difference 16-6=10 bytes } } void mirror_buffer_destroy(mirror_buffer_t *mirror_buffer) { if (mirror_buffer) { aes_ctr_destroy(mirror_buffer->aes_ctx); free(mirror_buffer); } } UxPlay-1.71.1/lib/mirror_buffer.h000066400000000000000000000022631473013662600166200ustar00rootroot00000000000000/* * Copyright (c) 2019 dsafa22, All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * *================================================================= * modified by fduncanh 2022 */ #ifndef MIRROR_BUFFER_H #define MIRROR_BUFFER_H #include #include "logger.h" typedef struct mirror_buffer_s mirror_buffer_t; mirror_buffer_t *mirror_buffer_init( logger_t *logger, const unsigned char *aeskey); void mirror_buffer_init_aes(mirror_buffer_t *mirror_buffer, const uint64_t *streamConnectionID); void mirror_buffer_decrypt(mirror_buffer_t *raop_mirror, unsigned char* input, unsigned char* output, int datalen); void mirror_buffer_destroy(mirror_buffer_t *mirror_buffer); #endif //MIRROR_BUFFER_H UxPlay-1.71.1/lib/netutils.c000066400000000000000000000125541473013662600156230ustar00rootroot00000000000000/** * Copyright (C) 2011-2012 Juho Vähä-Herttua * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * *================================================================== * modified by fduncanh 2022 */ #include #include #include #include "compat.h" int netutils_init() { #ifdef WIN32 WORD wVersionRequested; WSADATA wsaData; int ret; wVersionRequested = MAKEWORD(2, 2); ret = WSAStartup(wVersionRequested, &wsaData); if (ret) { return -1; } if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) { /* Version mismatch, requested version not found */ return -1; } #endif return 0; } void netutils_cleanup() { #ifdef WIN32 WSACleanup(); #endif } unsigned char * netutils_get_address(void *sockaddr, int *length, unsigned int *zone_id) { unsigned char ipv4_prefix[] = { 0,0,0,0,0,0,0,0,0,0,255,255 }; struct sockaddr *address = sockaddr; assert(address); assert(length); assert(zone_id); if (address->sa_family == AF_INET) { struct sockaddr_in *sin; *zone_id = 0; sin = (struct sockaddr_in *)address; *length = sizeof(sin->sin_addr.s_addr); return (unsigned char *)&sin->sin_addr.s_addr; } else if (address->sa_family == AF_INET6) { struct sockaddr_in6 *sin6; sin6 = (struct sockaddr_in6 *)address; if (!memcmp(sin6->sin6_addr.s6_addr, ipv4_prefix, 12)) { /* Actually an embedded IPv4 address */ *zone_id = 0; *length = sizeof(sin6->sin6_addr.s6_addr)-12; return (sin6->sin6_addr.s6_addr+12); } *zone_id = (unsigned int) sin6->sin6_scope_id; *length = sizeof(sin6->sin6_addr.s6_addr); return sin6->sin6_addr.s6_addr; } *length = 0; return NULL; } int netutils_init_socket(unsigned short *port, int use_ipv6, int use_udp) { int family = use_ipv6 ? AF_INET6 : AF_INET; int type = use_udp ? SOCK_DGRAM : SOCK_STREAM; int proto = use_udp ? IPPROTO_UDP : IPPROTO_TCP; struct sockaddr_storage saddr; socklen_t socklen; int server_fd; int ret; #ifndef _WIN32 int reuseaddr = 1; #else const char reuseaddr = 1; #endif assert(port); server_fd = socket(family, type, proto); if (server_fd == -1) { goto cleanup; } ret = setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof (reuseaddr)); if (ret == -1) { goto cleanup; } memset(&saddr, 0, sizeof(saddr)); if (use_ipv6) { struct sockaddr_in6 *sin6ptr = (struct sockaddr_in6 *)&saddr; /* Initialize sockaddr for bind */ sin6ptr->sin6_family = family; sin6ptr->sin6_addr = in6addr_any; sin6ptr->sin6_port = htons(*port); #ifndef _WIN32 int v6only = 1; /* Make sure we only listen to IPv6 addresses */ setsockopt(server_fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &v6only, sizeof(v6only)); #endif socklen = sizeof(*sin6ptr); ret = bind(server_fd, (struct sockaddr *)sin6ptr, socklen); if (ret == -1) { goto cleanup; } ret = getsockname(server_fd, (struct sockaddr *)sin6ptr, &socklen); if (ret == -1) { goto cleanup; } *port = ntohs(sin6ptr->sin6_port); } else { struct sockaddr_in *sinptr = (struct sockaddr_in *)&saddr; /* Initialize sockaddr for bind */ sinptr->sin_family = family; sinptr->sin_addr.s_addr = INADDR_ANY; sinptr->sin_port = htons(*port); socklen = sizeof(*sinptr); ret = bind(server_fd, (struct sockaddr *)sinptr, socklen); if (ret == -1) { goto cleanup; } ret = getsockname(server_fd, (struct sockaddr *)sinptr, &socklen); if (ret == -1) { goto cleanup; } *port = ntohs(sinptr->sin_port); } return server_fd; cleanup: ret = SOCKET_GET_ERROR(); if (server_fd != -1) { closesocket(server_fd); } SOCKET_SET_ERROR(ret); return -1; } // Src is the ip address int netutils_parse_address(int family, const char *src, void *dst, int dstlen) { struct addrinfo *result; struct addrinfo *ptr; struct addrinfo hints; int length; int ret; if (family != AF_INET && family != AF_INET6) { return -1; } if (!src || !dst) { return -1; } memset(&hints, 0, sizeof(hints)); hints.ai_family = family; hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; ret = getaddrinfo(src, NULL, &hints, &result); if (ret != 0) { return -1; } length = -1; for (ptr=result; ptr!=NULL; ptr=ptr->ai_next) { if (family == ptr->ai_family && (unsigned int)dstlen >= ptr->ai_addrlen) { memcpy(dst, ptr->ai_addr, ptr->ai_addrlen); length = ptr->ai_addrlen; break; } } freeaddrinfo(result); return length; } UxPlay-1.71.1/lib/netutils.h000066400000000000000000000016341473013662600156250ustar00rootroot00000000000000/** * Copyright (C) 2011-2012 Juho Vähä-Herttua * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. */ #ifndef NETUTILS_H #define NETUTILS_H int netutils_init(); void netutils_cleanup(); int netutils_init_socket(unsigned short *port, int use_ipv6, int use_udp); unsigned char *netutils_get_address(void *sockaddr, int *length, unsigned int *zone_id); int netutils_parse_address(int family, const char *src, void *dst, int dstlen); #endif UxPlay-1.71.1/lib/pairing.c000066400000000000000000000331341473013662600154020ustar00rootroot00000000000000/** * Copyright (C) 2018 Juho Vähä-Herttua * Copyright (C) 2020 Jaslo Ziska * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. *================================================================== * modified by fduncanh 2021, 2023 */ #include #include #include #include #include // for SHA512_DIGEST_LENGTH #include "pairing.h" #include "crypto.h" #include "srp.h" #define SALT_KEY "Pair-Verify-AES-Key" #define SALT_IV "Pair-Verify-AES-IV" typedef struct srp_s { unsigned char salt[SRP_SALT_SIZE]; unsigned char verifier[SRP_VERIFIER_SIZE]; unsigned char session_key[SRP_SESSION_KEY_SIZE]; unsigned char private_key[SRP_PRIVATE_KEY_SIZE]; } srp_t; struct pairing_s { ed25519_key_t *ed; }; typedef enum { STATUS_INITIAL, STATUS_SETUP, STATUS_HANDSHAKE, STATUS_FINISHED } status_t; struct pairing_session_s { status_t status; ed25519_key_t *ed_ours; ed25519_key_t *ed_theirs; x25519_key_t *ecdh_ours; x25519_key_t *ecdh_theirs; unsigned char ecdh_secret[X25519_KEY_SIZE]; char username[SRP_USERNAME_SIZE + 1]; unsigned char client_pk[ED25519_KEY_SIZE]; bool pair_setup; /* srp items */ srp_t *srp; }; static int derive_key_internal(pairing_session_t *session, const unsigned char *salt, unsigned int saltlen, unsigned char *key, unsigned int keylen) { unsigned char hash[SHA512_DIGEST_LENGTH]; if (keylen > sizeof(hash)) { return -1; } sha_ctx_t *ctx = sha_init(); sha_update(ctx, salt, saltlen); sha_update(ctx, session->ecdh_secret, X25519_KEY_SIZE); sha_final(ctx, hash, NULL); sha_destroy(ctx); memcpy(key, hash, keylen); return 0; } pairing_t * pairing_init_generate(const char *device_id, const char *keyfile, int *result) { pairing_t *pairing; *result = 0; pairing = calloc(1, sizeof(pairing_t)); if (!pairing) { return NULL; } pairing->ed = ed25519_key_generate(device_id, keyfile, result); return pairing; } void pairing_get_public_key(pairing_t *pairing, unsigned char public_key[ED25519_KEY_SIZE]) { assert(pairing); ed25519_key_get_raw(public_key, pairing->ed); } int pairing_get_ecdh_secret_key(pairing_session_t *session, unsigned char ecdh_secret[X25519_KEY_SIZE]) { assert(session); switch (session->status) { case STATUS_INITIAL: return 0; default: memcpy(ecdh_secret, session->ecdh_secret, X25519_KEY_SIZE); return 1; } } pairing_session_t * pairing_session_init(pairing_t *pairing) { pairing_session_t *session; if (!pairing) { return NULL; } session = calloc(1, sizeof(pairing_session_t)); if (!session) { return NULL; } session->ed_ours = ed25519_key_copy(pairing->ed); session->status = STATUS_INITIAL; session->srp = NULL; session->pair_setup = false; return session; } void pairing_session_set_setup_status(pairing_session_t *session) { assert(session); session->status = STATUS_SETUP; } int pairing_session_check_handshake_status(pairing_session_t *session) { assert(session); switch (session->status) { case STATUS_SETUP: case STATUS_HANDSHAKE: return 0; default: return -1; } } int pairing_session_handshake(pairing_session_t *session, const unsigned char ecdh_key[X25519_KEY_SIZE], const unsigned char ed_key[ED25519_KEY_SIZE]) { assert(session); if (session->status == STATUS_FINISHED) { return -1; } session->ecdh_theirs = x25519_key_from_raw(ecdh_key); session->ed_theirs = ed25519_key_from_raw(ed_key); session->ecdh_ours = x25519_key_generate(); x25519_derive_secret(session->ecdh_secret, session->ecdh_ours, session->ecdh_theirs); session->status = STATUS_HANDSHAKE; return 0; } int pairing_session_get_public_key(pairing_session_t *session, unsigned char ecdh_key[X25519_KEY_SIZE]) { assert(session); if (session->status != STATUS_HANDSHAKE) { return -1; } x25519_key_get_raw(ecdh_key, session->ecdh_ours); return 0; } int pairing_session_get_signature(pairing_session_t *session, unsigned char signature[PAIRING_SIG_SIZE]) { unsigned char sig_msg[PAIRING_SIG_SIZE]; unsigned char key[AES_128_BLOCK_SIZE]; unsigned char iv[AES_128_BLOCK_SIZE]; aes_ctx_t *aes_ctx; assert(session); if (session->status != STATUS_HANDSHAKE) { return -1; } /* First sign the public ECDH keys of both parties */ x25519_key_get_raw(sig_msg, session->ecdh_ours); x25519_key_get_raw(sig_msg + X25519_KEY_SIZE, session->ecdh_theirs); ed25519_sign(signature, PAIRING_SIG_SIZE, sig_msg, PAIRING_SIG_SIZE, session->ed_ours); /* Then encrypt the result with keys derived from the shared secret */ derive_key_internal(session, (const unsigned char *) SALT_KEY, strlen(SALT_KEY), key, sizeof(key)); derive_key_internal(session, (const unsigned char *) SALT_IV, strlen(SALT_IV), iv, sizeof(iv)); aes_ctx = aes_ctr_init(key, iv); aes_ctr_encrypt(aes_ctx, signature, signature, PAIRING_SIG_SIZE); aes_ctr_destroy(aes_ctx); return 0; } int pairing_session_finish(pairing_session_t *session, const unsigned char signature[PAIRING_SIG_SIZE]) { unsigned char sig_buffer[PAIRING_SIG_SIZE]; unsigned char sig_msg[PAIRING_SIG_SIZE]; unsigned char key[AES_128_BLOCK_SIZE]; unsigned char iv[AES_128_BLOCK_SIZE]; aes_ctx_t *aes_ctx; assert(session); if (session->status != STATUS_HANDSHAKE) { return -1; } /* First decrypt the signature with keys derived from the shared secret */ derive_key_internal(session, (const unsigned char *) SALT_KEY, strlen(SALT_KEY), key, sizeof(key)); derive_key_internal(session, (const unsigned char *) SALT_IV, strlen(SALT_IV), iv, sizeof(iv)); aes_ctx = aes_ctr_init(key, iv); /* One fake round for the initial handshake encryption */ aes_ctr_encrypt(aes_ctx, sig_buffer, sig_buffer, PAIRING_SIG_SIZE); aes_ctr_encrypt(aes_ctx, signature, sig_buffer, PAIRING_SIG_SIZE); aes_ctr_destroy(aes_ctx); /* Then verify the signature with public ECDH keys of both parties */ x25519_key_get_raw(sig_msg, session->ecdh_theirs); x25519_key_get_raw(sig_msg + X25519_KEY_SIZE, session->ecdh_ours); if (!ed25519_verify(sig_buffer, PAIRING_SIG_SIZE, sig_msg, PAIRING_SIG_SIZE, session->ed_theirs)) { return -2; } session->status = STATUS_FINISHED; return 0; } void pairing_session_destroy(pairing_session_t *session) { if (session) { ed25519_key_destroy(session->ed_ours); ed25519_key_destroy(session->ed_theirs); x25519_key_destroy(session->ecdh_ours); x25519_key_destroy(session->ecdh_theirs); if (session->srp) { free(session->srp); session->srp = NULL; } free(session); } } void pairing_destroy(pairing_t *pairing) { if (pairing) { ed25519_key_destroy(pairing->ed); free(pairing); } } int random_pin() { unsigned char random_bytes[2] = { 0 }; unsigned short random_short = 0; int ret; /* create a random unsigned short in range 1-9999 */ while (!random_short) { if ((ret = get_random_bytes(random_bytes, sizeof(random_bytes)) < 1)) { return -1; } memcpy(&random_short, random_bytes, sizeof(random_bytes)); random_short = random_short % 10000; } return (int) random_short; } int srp_new_user(pairing_session_t *session, pairing_t *pairing, const char *device_id, const char *pin, const char **salt, int *len_salt, const char **pk, int *len_pk) { if (strlen(device_id) > SRP_USERNAME_SIZE) { return -1; } strncpy(session->username, device_id, SRP_USERNAME_SIZE); if (session->srp) { free (session->srp); session->srp = NULL; } session->srp = (srp_t *) calloc(1, sizeof(srp_t)); if (!session->srp) { return -2; } get_random_bytes(session->srp->private_key, SRP_PRIVATE_KEY_SIZE); const unsigned char *srp_b = session->srp->private_key; unsigned char * srp_B; unsigned char * srp_s; unsigned char * srp_v; int len_b = SRP_PRIVATE_KEY_SIZE; int len_B; int len_s; int len_v; srp_create_salted_verification_key(SRP_SHA, SRP_NG, device_id, (const unsigned char *) pin, strlen (pin), (const unsigned char **) &srp_s, &len_s, (const unsigned char **) &srp_v, &len_v, NULL, NULL); if (len_s != SRP_SALT_SIZE || len_v != SRP_VERIFIER_SIZE) { return -3; } memcpy(session->srp->salt, srp_s, SRP_SALT_SIZE); memcpy(session->srp->verifier, srp_v, SRP_VERIFIER_SIZE); *salt = (char *) session->srp->salt; *len_salt = len_s; srp_create_server_ephemeral_key(SRP_SHA, SRP_NG, srp_v, len_v, srp_b, len_b, (const unsigned char **) &srp_B, &len_B, NULL, NULL, 1); *pk = (char *) srp_B; *len_pk = len_B; return 0; } int srp_validate_proof(pairing_session_t *session, pairing_t *pairing, const unsigned char *A, int len_A, unsigned char *proof, int client_proof_len, int proof_len) { int authenticated = 0; const unsigned char *B = NULL; const unsigned char *b = session->srp->private_key; int len_b = SRP_PRIVATE_KEY_SIZE; int len_B = 0; int len_K = 0; const unsigned char *session_key = NULL; const unsigned char *M2 = NULL; struct SRPVerifier *verifier = srp_verifier_new(SRP_SHA, SRP_NG, (const char *) session->username, (const unsigned char *) session->srp->salt, SRP_SALT_SIZE, (const unsigned char *) session->srp->verifier, SRP_VERIFIER_SIZE, A, len_A, b, len_b, &B, &len_B, NULL, NULL, 1); srp_verifier_verify_session(verifier, proof, &M2); authenticated = srp_verifier_is_authenticated(verifier); if (authenticated == 0) { /* HTTP 470 should be sent to client if not verified.*/ srp_verifier_delete(verifier); free (session->srp); session->srp = NULL; return -1; } session_key = srp_verifier_get_session_key(verifier, &len_K); if (len_K != SRP_SESSION_KEY_SIZE) { return -2; } memcpy(session->srp->session_key, session_key, len_K); memcpy(proof, M2, proof_len); srp_verifier_delete(verifier); return 0; } int srp_confirm_pair_setup(pairing_session_t *session, pairing_t *pairing, unsigned char *epk, unsigned char *auth_tag) { unsigned char aesKey[16], aesIV[16]; unsigned char hash[SHA512_DIGEST_LENGTH]; unsigned char pk[ED25519_KEY_SIZE]; int pk_len_client, epk_len; /* decrypt client epk to get client pk, authenticate with auth_tag*/ const char *salt = "Pair-Setup-AES-Key"; sha_ctx_t *ctx = sha_init(); sha_update(ctx, (const unsigned char *) salt, strlen(salt)); sha_update(ctx, session->srp->session_key, SRP_SESSION_KEY_SIZE); sha_final(ctx, hash, NULL); sha_destroy(ctx); memcpy(aesKey, hash, 16); salt = "Pair-Setup-AES-IV"; ctx = sha_init(); sha_update(ctx, (const unsigned char *) salt, strlen(salt)); sha_update(ctx, session->srp->session_key, SRP_SESSION_KEY_SIZE); sha_final(ctx, hash, NULL); sha_destroy(ctx); memcpy(aesIV, hash, 16); aesIV[15]++; /* SRP6a data is no longer needed */ free(session->srp); session->srp = NULL; /* decrypt client epk to authenticate client using auth_tag */ pk_len_client = gcm_decrypt(epk, ED25519_KEY_SIZE, pk, aesKey, aesIV, auth_tag); if (pk_len_client <= 0) { /* authentication failed */ return pk_len_client; } /* success, from server viewpoint */ memcpy(session->client_pk, pk, ED25519_KEY_SIZE); session->pair_setup = true; /* encrypt server epk so client can also authenticate server using auth_tag */ pairing_get_public_key(pairing, pk); /* encryption needs this previously undocumented additional "nonce" */ aesIV[15]++; epk_len = gcm_encrypt(pk, ED25519_KEY_SIZE, epk, aesKey, aesIV, auth_tag); return epk_len; } void access_client_session_data(pairing_session_t *session, char **username, char **client_pk64, bool *setup) { int len64 = 4 * (1 + (ED25519_KEY_SIZE / 3)) + 1; setup = &(session->pair_setup); *username = session->username; if (setup) { *client_pk64 = (char *) malloc(len64); pk_to_base64(session->client_pk, ED25519_KEY_SIZE, *client_pk64, len64); } else { *client_pk64 = NULL; } } void ed25519_pk_to_base64(const unsigned char *pk, char **pk64) { int len64 = 4 * (1 + (ED25519_KEY_SIZE / 3)) + 1; *pk64 = (char *) malloc(len64); pk_to_base64(pk, ED25519_KEY_SIZE, *pk64, len64); } UxPlay-1.71.1/lib/pairing.h000066400000000000000000000056071473013662600154130ustar00rootroot00000000000000/** * Copyright (C) 2018 Juho Vähä-Herttua * Copyright (C) 2020 Jaslo Ziska * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. */ #include "crypto.h" #ifndef PAIRING_H #define PAIRING_H #define PAIRING_SIG_SIZE (2 * X25519_KEY_SIZE) #define SRP_USERNAME_SIZE 24 /* accomodates up to an 8-octet MAC address */ #define SRP_SESSION_KEY_SIZE 40 #define SRP_VERIFIER_SIZE 256 #define SRP_SALT_SIZE 16 #define SRP_PK_SIZE 256 #define SRP_SHA SRP_SHA1 #define SRP_NG SRP_NG_2048 #define SRP_M2_SIZE 64 #define SRP_PRIVATE_KEY_SIZE 32 #define GCM_AUTHTAG_SIZE 16 #define SHA512_KEY_LENGTH 64 typedef struct pairing_s pairing_t; typedef struct pairing_session_s pairing_session_t; pairing_t *pairing_init_generate(const char *device_id, const char *keyfile, int *result); void pairing_get_public_key(pairing_t *pairing, unsigned char public_key[ED25519_KEY_SIZE]); pairing_session_t *pairing_session_init(pairing_t *pairing); void pairing_session_set_setup_status(pairing_session_t *session); int pairing_session_check_handshake_status(pairing_session_t *session); int pairing_session_handshake(pairing_session_t *session, const unsigned char ecdh_key[X25519_KEY_SIZE], const unsigned char ed_key[ED25519_KEY_SIZE]); int pairing_session_get_public_key(pairing_session_t *session, unsigned char ecdh_key[X25519_KEY_SIZE]); int random_pin(); int pairing_session_get_signature(pairing_session_t *session, unsigned char signature[PAIRING_SIG_SIZE]); int pairing_session_finish(pairing_session_t *session, const unsigned char signature[PAIRING_SIG_SIZE]); void pairing_session_destroy(pairing_session_t *session); void pairing_destroy(pairing_t *pairing); int pairing_get_ecdh_secret_key(pairing_session_t *session, unsigned char ecdh_secret[X25519_KEY_SIZE]); int srp_new_user(pairing_session_t *session, pairing_t *pairing, const char *device_id, const char *pin, const char **salt, int *len_salt, const char **pk, int *len_pk); int srp_validate_proof(pairing_session_t *session, pairing_t *pairing, const unsigned char *A, int len_A, unsigned char *proof, int client_proof_len, int proof_len); int srp_confirm_pair_setup(pairing_session_t *session, pairing_t *pairing, unsigned char *epk, unsigned char *auth_tag); void access_client_session_data(pairing_session_t *session, char **username, char **client_pk, bool *setup); void ed25519_pk_to_base64(const unsigned char *pk, char **pk64); #endif UxPlay-1.71.1/lib/playfair/000077500000000000000000000000001473013662600154105ustar00rootroot00000000000000UxPlay-1.71.1/lib/playfair/CMakeLists.txt000066400000000000000000000002701473013662600201470ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.5) aux_source_directory(. playfair_src) set(DIR_SRCS ${playfair_src}) include_directories(.) add_library( playfair STATIC ${DIR_SRCS}) UxPlay-1.71.1/lib/playfair/LICENSE.md000066400000000000000000001041751473013662600170240ustar00rootroot00000000000000 # GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 [Free Software Foundation, Inc.](http://fsf.org/) 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 [http://www.gnu.org/licenses/](http://www.gnu.org/licenses/). 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 [http://www.gnu.org/philosophy/why-not-lgpl.html](http://www.gnu.org/philosophy/why-not-lgpl.html). UxPlay-1.71.1/lib/playfair/hand_garble.c000066400000000000000000000475451473013662600200210ustar00rootroot00000000000000#include #include #define printf(...) (void)0; uint8_t rol8(uint8_t x, int y); uint32_t rol8x(uint8_t x, int y); uint32_t weird_ror8(uint8_t input, int count) { if (count == 0) return 0; return ((input >> count) & 0xff) | (input & 0xff) << (8-count); } uint32_t weird_rol8(uint8_t input, int count) { if (count == 0) return 0; return ((input << count) & 0xff) | (input & 0xff) >> (8-count); } uint32_t weird_rol32(uint8_t input, int count) { if (count == 0) return 0; return (input << count) ^ (input >> (8 - count)); } // I do not know why it is doing all of this, and there is still a possibility for a gremlin or two to be lurking in the background // I DO know it is not trivial. It could be purely random garbage, of course. void garble(unsigned char* buffer0, unsigned char* buffer1, unsigned char* buffer2, unsigned char* buffer3, unsigned char* buffer4) { unsigned int tmp, tmp2, tmp3; unsigned int A, B, C, D, E, M, J, G, F, H, K, R, S, T, U, V, W, X, Y, Z; // buffer1[64] = A // (buffer1[99] / 3) = B // 0ABAAABB // Then we AND with a complex expression, and add 20 just for good measure buffer2[12] = 0x14 + (((buffer1[64] & 92) | ((buffer1[99] / 3) & 35)) & buffer4[rol8x(buffer4[(buffer1[206] % 21)],4) % 21]); printf("buffer2[12] = %02x\n", buffer2[12]); // This is a bit simpler: 2*B*B/25 buffer1[4] = (buffer1[99] / 5) * (buffer1[99] / 5) * 2; printf("buffer1[4] = %02x\n", buffer1[4]); // Simpler still! buffer2[34] = 0xb8; printf("buffer2[34] = %02x\n", buffer2[34]); // ... buffer1[153] ^= (buffer2[buffer1[203] % 35] * buffer2[buffer1[203] % 35] * buffer1[190]); printf("buffer1[153] = %02x\n", buffer1[153]); // This one looks simple, but wow was it not :( buffer0[3] -= (((buffer4[buffer1[205] % 21]>>1) & 80) | 0xe6440); printf("buffer0[3] = %02x\n", buffer0[3]); // This is always 0x93 buffer0[16] = 0x93; printf("buffer0[16] = %02x\n", buffer0[16]); // This is always 0x62 buffer0[13] = 0x62; printf("buffer0[13] = %02x\n", buffer0[13]); buffer1[33] -= (buffer4[buffer1[36] % 21] & 0xf6); printf("buffer1[33] = %02x\n", buffer1[33]); // This is always 7 tmp2 = buffer2[buffer1[67] % 35]; buffer2[12] = 0x07; printf("buffer2[12] = %02x\n", buffer2[12]); // This is pretty easy! tmp = buffer0[buffer1[181] % 20]; buffer1[2] -= 3136; printf("buffer1[2] = %02x\n", buffer1[2]); buffer0[19] = buffer4[buffer1[58] % 21]; printf("buffer0[19] = %02x\n", buffer0[19]); buffer3[0] = 92 - buffer2[buffer1[32] % 35]; printf("buffer3[0] = %02x\n", buffer3[0]); buffer3[4] = buffer2[buffer1[15] % 35] + 0x9e; printf("buffer3[4] = %02x\n", buffer3[4]); buffer1[34] += (buffer4[((buffer2[buffer1[15] % 35] + 0x9e) & 0xff) % 21] / 5); printf("buffer1[34] = %02x\n", buffer1[34]); buffer0[19] += 0xfffffee6 - ((buffer0[buffer3[4] % 20]>>1) & 102); printf("buffer0[19] = %02x\n", buffer0[19]); // This LOOKS like it should be a rol8x, but it just doesnt work out because if the shift amount is 0, then the output is 0 too :( // FIXME: Switch to weird_ror8 buffer1[15] = (3*(((buffer1[72] >> (buffer4[buffer1[190] % 21] & 7)) ^ (buffer1[72] << ((7 - (buffer4[buffer1[190] % 21]-1)&7)))) - (3*buffer4[buffer1[126] % 21]))) ^ buffer1[15]; printf("buffer1[15] = %02x\n", buffer1[15]); buffer0[15] ^= buffer2[buffer1[181] % 35] * buffer2[buffer1[181] % 35] * buffer2[buffer1[181] % 35]; printf("buffer0[15] = %02x\n", buffer0[15]); buffer2[4] ^= buffer1[202]/3; printf("buffer2[4] = %02x\n", buffer2[4]); // This could probably be quite a bit simpler. A = 92 - buffer0[buffer3[0] % 20]; E = (A & 0xc6) | (~buffer1[105] & 0xc6) | (A & (~buffer1[105])); buffer2[1] += (E*E*E); printf("buffer2[1] = %02x\n", buffer2[1]); buffer0[19] ^= ((224 | (buffer4[buffer1[92] % 21] & 27)) * buffer2[buffer1[41] % 35]) / 3; printf("buffer0[19] = %02x\n", buffer0[19]); buffer1[140] += weird_ror8(92, buffer1[5] & 7); printf("buffer1[140] = %02x\n", buffer1[140]); // Is this as simple as it could be? buffer2[12] += ((((~buffer1[4]) ^ buffer2[buffer1[12] % 35]) | buffer1[182]) & 192) | (((~buffer1[4]) ^ buffer2[buffer1[12] % 35]) & buffer1[182]); printf("buffer2[12] = %02x\n", buffer2[12]); buffer1[36] += 125; printf("buffer1[36] = %02x\n", buffer1[36]); buffer1[124] = rol8x((((74 & buffer1[138]) | ((74 | buffer1[138]) & buffer0[15])) & buffer0[buffer1[43] % 20]) | (((74 & buffer1[138]) | ((74 | buffer1[138]) & buffer0[15]) | buffer0[buffer1[43] % 20]) & 95), 4); printf("buffer1[124] = %02x\n", buffer1[124]); buffer3[8] = ((((buffer0[buffer3[4] % 20] & 95)) & ((buffer4[buffer1[68] % 21] & 46) << 1)) | 16) ^ 92; printf("buffer3[8] = %02x\n", buffer3[8]); A = buffer1[177] + buffer4[buffer1[79] % 21]; D = (((A >> 1) | ((3 * buffer1[148]) / 5)) & buffer2[1]) | ((A >> 1) & ((3 * buffer1[148])/5)); buffer3[12] = ((-34 - D)); printf("buffer3[12] = %02x\n", buffer3[12]); A = 8 - ((buffer2[22] & 7)); // FIXME: buffer2[22] = 74, so A is always 6 and B^C is just ror8(buffer1[33], 6) B = (buffer1[33] >> (A & 7)); C = buffer1[33] << (buffer2[22] & 7); buffer2[16] += ((buffer2[buffer3[0] % 35] & 159) | buffer0[buffer3[4] % 20] | 8) - ((B^C) | 128); printf("buffer2[16] = %02x\n", buffer2[16]); // This one was very easy so I just skipped ahead and did it buffer0[14] ^= buffer2[buffer3[12] % 35]; printf("buffer0[14] = %02x\n", buffer0[14]); // Monster goes here A = weird_rol8(buffer4[buffer0[buffer1[201] % 20] % 21], ((buffer2[buffer1[112] % 35] << 1) & 7)); D = (buffer0[buffer1[208] % 20] & 131) | (buffer0[buffer1[164] % 20] & 124); buffer1[19] += (A & (D/5)) | ((A | (D/5)) & 37); printf("buffer1[19] = %02x\n", buffer1[19]); buffer2[8] = weird_ror8(140, ((buffer4[buffer1[45] % 21] + 92) * (buffer4[buffer1[45] % 21] + 92)) & 7); printf("buffer2[8] = %02x\n", buffer2[8]); buffer1[190] = 56; printf("buffer1[190] = %02x\n", buffer1[190]); buffer2[8] ^= buffer3[0]; printf("buffer2[8] = %02x\n", buffer2[8]); buffer1[53] = ~((buffer0[buffer1[83] % 20] | 204)/5); printf("buffer1[53] = %02x\n", buffer1[53]); buffer0[13] += buffer0[buffer1[41] % 20]; printf("buffer0[13] = %02x\n", buffer0[13]); buffer0[10] = ((buffer2[buffer3[0] % 35] & buffer1[2]) | ((buffer2[buffer3[0] % 35] | buffer1[2]) & buffer3[12])) / 15; printf("buffer0[10] = %02x\n", buffer0[10]); A = (((56 | (buffer4[buffer1[2] % 21] & 68)) | buffer2[buffer3[8] % 35]) & 42) | (((buffer4[buffer1[2] % 21] & 68) | 56) & buffer2[buffer3[8] % 35]); buffer3[16] = (A*A) + 110; printf("buffer3[16] = %02x\n", buffer3[16]); buffer3[20] = 202 - buffer3[16]; printf("buffer3[20] = %02x\n", buffer3[20]); buffer3[24] = buffer1[151]; printf("buffer3[24] = %02x\n", buffer3[24]); buffer2[13] ^= buffer4[buffer3[0] % 21]; printf("buffer2[13] = %02x\n", buffer2[13]); B = ((buffer2[buffer1[179] % 35] - 38) & 177) | (buffer3[12] & 177); C = ((buffer2[buffer1[179] % 35] - 38)) & buffer3[12]; buffer3[28] = 30 + ((B | C) * (B | C)); printf("buffer3[28] = %02x\n", buffer3[28]); buffer3[32] = buffer3[28] + 62; printf("buffer3[32] = %02x\n", buffer3[32]); // eek A = ((buffer3[20] + (buffer3[0] & 74)) | ~buffer4[buffer3[0] % 21]) & 121; B = ((buffer3[20] + (buffer3[0] & 74)) & ~buffer4[buffer3[0] % 21]); tmp3 = (A|B); C = ((((A|B) ^ 0xffffffa6) | buffer3[0]) & 4) | (((A|B) ^ 0xffffffa6) & buffer3[0]); buffer1[47] = (buffer2[buffer1[89] % 35] + C) ^ buffer1[47]; printf("buffer1[47] = %02x\n", buffer1[47]); buffer3[36] = ((rol8((tmp & 179) + 68, 2) & buffer0[3]) | (tmp2 & ~buffer0[3])) - 15; printf("buffer3[36] = %02x\n", buffer3[36]); buffer1[123] ^= 221; printf("buffer1[123] = %02x\n", buffer1[123]); A = ((buffer4[buffer3[0] % 21]) / 3) - buffer2[buffer3[4] % 35]; C = (((buffer3[0] & 163) + 92) & 246) | (buffer3[0] & 92); E = ((C | buffer3[24]) & 54) | (C & buffer3[24]); buffer3[40] = A - E; printf("buffer3[40] = %02x\n", buffer3[40]); buffer3[44] = tmp3 ^ 81 ^ (((buffer3[0] >> 1) & 101) + 26); printf("buffer3[44] = %02x\n", buffer3[44]); buffer3[48] = buffer2[buffer3[4] % 35] & 27; printf("buffer3[48] = %02x\n", buffer3[48]); buffer3[52] = 27; printf("buffer3[52] = %02x\n", buffer3[52]); buffer3[56] = 199; printf("buffer3[56] = %02x\n", buffer3[56]); // caffeine buffer3[64] = buffer3[4] + (((((((buffer3[40] | buffer3[24]) & 177) | (buffer3[40] & buffer3[24])) & ((((buffer4[buffer3[0] % 20] & 177) | 176)) | ((buffer4[buffer3[0] % 21]) & ~3))) | ((((buffer3[40] & buffer3[24]) | ((buffer3[40] | buffer3[24]) & 177)) & 199) | ((((buffer4[buffer3[0] % 21] & 1) + 176) | (buffer4[buffer3[0] % 21] & ~3)) & buffer3[56]))) & (~buffer3[52])) | buffer3[48]); printf("buffer3[64] = %02x (want E7)\n", buffer3[64]); buffer2[33] ^= buffer1[26]; printf("buffer2[33] = %02x\n", buffer2[33]); buffer1[106] ^= buffer3[20] ^ 133; printf("buffer1[106] = %02x\n", buffer1[106]); buffer2[30] = ((buffer3[64] / 3) - (275 | (buffer3[0] & 247))) ^ buffer0[buffer1[122] % 20]; printf("buffer2[130] = %02x\n", buffer2[30]); buffer1[22] = (buffer2[buffer1[90] % 35] & 95) | 68; printf("buffer1[22] = %02x\n", buffer1[22]); A = (buffer4[buffer3[36] % 21] & 184) | (buffer2[buffer3[44] % 35] & ~184); buffer2[18] += ((A*A*A) >> 1); printf("buffer2[18] = %02x\n", buffer2[18]); buffer2[5] -= buffer4[buffer1[92] % 21]; printf("buffer2[5] = %02x\n", buffer2[5]); A = (((buffer1[41] & ~24)|(buffer2[buffer1[183] % 35] & 24)) & (buffer3[16] + 53)) | (buffer3[20] & buffer2[buffer3[20] % 35]); B = (buffer1[17] & (~buffer3[44])) | (buffer0[buffer1[59] % 20] & buffer3[44]); buffer2[18] ^= (A*B); printf("buffer2[18] = %02x\n", buffer2[18]); A = weird_ror8(buffer1[11], buffer2[buffer1[28] % 35] & 7) & 7; B = (((buffer0[buffer1[93] % 20] & ~buffer0[14]) | (buffer0[14] & 150)) & ~28) | (buffer1[7] & 28); buffer2[22] = (((((B | weird_rol8(buffer2[buffer3[0] % 35], A)) & buffer2[33]) | (B & weird_rol8(buffer2[buffer3[0] % 35], A))) + 74) & 0xff); printf("buffer2[22] = %02x\n", buffer2[22]); A = buffer4[(buffer0[buffer1[39] % 20] ^ 217) % 21]; // X5 buffer0[15] -= ((((buffer3[20] | buffer3[0]) & 214) | (buffer3[20] & buffer3[0])) & A) | ((((buffer3[20] | buffer3[0]) & 214) | (buffer3[20] & buffer3[0]) | A) & buffer3[32]); printf("buffer0[15] = %02x\n", buffer0[15]); // We need to save T here, and boy is it complicated to calculate! B = (((buffer2[buffer1[57] % 35] & buffer0[buffer3[64] % 20]) | ((buffer0[buffer3[64] % 20] | buffer2[buffer1[57] % 35]) & 95) | (buffer3[64] & 45) | 82) & 32); C = ((buffer2[buffer1[57] % 35] & buffer0[buffer3[64] % 20]) | ((buffer2[buffer1[57] % 35] | buffer0[buffer3[64] % 20]) & 95)) & ((buffer3[64] & 45) | 82); D = ((((buffer3[0]/3) - (buffer3[64]|buffer1[22]))) ^ (buffer3[28] + 62) ^ ((B|C))); T = buffer0[(D & 0xff) % 20]; buffer3[68] = (buffer0[buffer1[99] % 20] * buffer0[buffer1[99] % 20] * buffer0[buffer1[99] % 20] * buffer0[buffer1[99] % 20]) | buffer2[buffer3[64] % 35]; printf("buffer3[68] = %02x\n", buffer3[68]); U = buffer0[buffer1[50] % 20]; // this is also v100 W = buffer2[buffer1[138] % 35]; X = buffer4[buffer1[39] % 21]; Y = buffer0[buffer1[4] % 20]; // this is also v120 Z = buffer4[buffer1[202] % 21]; // also v124 V = buffer0[buffer1[151] % 20]; S = buffer2[buffer1[14] % 35]; R = buffer0[buffer1[145] % 20]; A = (buffer2[buffer3[68] % 35] & buffer0[buffer1[209] % 20]) | ((buffer2[buffer3[68] % 35] | buffer0[buffer1[209] % 20]) & 24); B = weird_rol8(buffer4[buffer1[127] % 21], buffer2[buffer3[68] % 35] & 7); C = (A & buffer0[10]) | (B & ~buffer0[10]); D = 7 ^ (buffer4[buffer2[buffer3[36] % 35] % 21] << 1); buffer3[72] = (C & 71) | (D & ~71); printf("buffer3[72] = %02x\n", buffer3[72]); buffer2[2] += (((buffer0[buffer3[20] % 20] << 1) & 159) | (buffer4[buffer1[190] % 21] & ~159)) & ((((buffer4[buffer3[64] % 21] & 110) | (buffer0[buffer1[25] % 20] & ~110)) & ~150) | (buffer1[25] & 150)); printf("buffer2[2] = %02x\n", buffer2[2]); buffer2[14] -= ((buffer2[buffer3[20] % 35] & (buffer3[72] ^ buffer2[buffer1[100] % 35])) & ~34) | (buffer1[97] & 34); printf("buffer2[14] = %02x\n", buffer2[14]); buffer0[17] = 115; printf("buffer0[17] = %02x\n", buffer0[17]); buffer1[23] ^= ((((((buffer4[buffer1[17] % 21] | buffer0[buffer3[20] % 20]) & buffer3[72]) | (buffer4[buffer1[17] % 21] & buffer0[buffer3[20] % 20])) & (buffer1[50]/3)) | ((((buffer4[buffer1[17] % 21] | buffer0[buffer3[20] % 20]) & buffer3[72]) | (buffer4[buffer1[17] % 21] & buffer0[buffer3[20] % 20]) | (buffer1[50] / 3)) & 246)) << 1); printf("buffer1[23] = %02x\n", buffer1[23]); buffer0[13] = ((((((buffer0[buffer3[40] % 20] | buffer1[10]) & 82) | (buffer0[buffer3[40] % 20] & buffer1[10])) & 209) | ((buffer0[buffer1[39] % 20] << 1) & 46)) >> 1); printf("buffer0[13] = %02x\n", buffer0[13]); buffer2[33] -= buffer1[113] & 9; printf("buffer2[33] = %02x\n", buffer2[33]); buffer2[28] -= ((((2 | (buffer1[110] & 222)) >> 1) & ~223) | (buffer3[20] & 223)); printf("buffer2[28] = %02x\n", buffer2[28]); J = weird_rol8((V | Z), (U & 7)); // OK A = (buffer2[16] & T) | (W & (~buffer2[16])); B = (buffer1[33] & 17) | (X & ~17); E = ((Y | ((A+B) / 5)) & 147) | (Y & ((A+B) / 5)); // OK M = (buffer3[40] & buffer4[((buffer3[8] + J + E) & 0xff) % 21]) | ((buffer3[40] | buffer4[((buffer3[8] + J + E) & 0xff) % 21]) & buffer2[23]); buffer0[15] = (((buffer4[buffer3[20] % 21] - 48) & (~buffer1[184])) | ((buffer4[buffer3[20] % 21] - 48) & 189) | (189 & ~buffer1[184])) & (M*M*M); printf("buffer0[15] = %02x\n", buffer0[15]); buffer2[22] += buffer1[183]; printf("buffer2[22] = %02x\n", buffer2[22]); buffer3[76] = (3 * buffer4[buffer1[1] % 21]) ^ buffer3[0]; printf("buffer3[76] = %02x\n", buffer3[76]); A = buffer2[((buffer3[8] + (J + E)) & 0xff) % 35]; F = (((buffer4[buffer1[178] % 21] & A) | ((buffer4[buffer1[178] % 21] | A) & 209)) * buffer0[buffer1[13] % 20]) * (buffer4[buffer1[26] % 21] >> 1); G = (F + 0x733ffff9) * 198 - (((F + 0x733ffff9) * 396 + 212) & 212) + 85; buffer3[80] = buffer3[36] + (G ^ 148) + ((G ^ 107) << 1) - 127; printf("buffer3[80] = %02x\n", buffer3[80]); buffer3[84] = ((buffer2[buffer3[64] % 35]) & 245) | (buffer2[buffer3[20] % 35] & 10); printf("buffer3[84] = %02x\n", buffer3[84]); A = buffer0[buffer3[68] % 20] | 81; buffer2[18] -= ((A*A*A) & ~buffer0[15]) | ((buffer3[80] / 15) & buffer0[15]); printf("buffer2[18] = %02x\n", buffer2[18]); buffer3[88] = buffer3[8] + J + E - buffer0[buffer1[160] % 20] + (buffer4[buffer0[((buffer3[8] + J + E) & 255) % 20] % 21] / 3); printf("buffer3[88] = %02x\n", buffer3[88]); B = ((R ^ buffer3[72]) & ~198) | ((S * S) & 198); F = (buffer4[buffer1[69] % 21] & buffer1[172]) | ((buffer4[buffer1[69] % 21] | buffer1[172] ) & ((buffer3[12] - B) + 77)); buffer0[16] = 147 - ((buffer3[72] & ((F & 251) | 1)) | (((F & 250) | buffer3[72]) & 198)); printf("buffer0[16] = %02x\n", buffer0[16]); C = (buffer4[buffer1[168] % 21] & buffer0[buffer1[29] % 20] & 7) | ((buffer4[buffer1[168] % 21] | buffer0[buffer1[29] % 20]) & 6); F = (buffer4[buffer1[155] % 21] & buffer1[105]) | ((buffer4[buffer1[155] % 21] | buffer1[105]) & 141); buffer0[3] -= buffer4[weird_rol32(F, C) % 21]; printf("buffer0[3] = %02x\n", buffer0[3]); buffer1[5] = weird_ror8(buffer0[12], ((buffer0[buffer1[61] % 20] / 5) & 7)) ^ (((~buffer2[buffer3[84] % 35]) & 0xffffffff) / 5); printf("buffer1[5] = %02x\n", buffer1[5]); buffer1[198] += buffer1[3]; printf("buffer1[198] = %02x\n", buffer1[198]); A = (162 | buffer2[buffer3[64] % 35]); buffer1[164] += ((A*A)/5); printf("buffer1[164] = %02x\n", buffer1[164]); G = weird_ror8(139, (buffer3[80] & 7)); C = ((buffer4[buffer3[64] % 21] * buffer4[buffer3[64] % 21] * buffer4[buffer3[64] % 21]) & 95) | (buffer0[buffer3[40] % 20] & ~95); buffer3[92] = (G & 12) | (buffer0[buffer3[20] % 20] & 12) | (G & buffer0[buffer3[20] % 20]) | C; printf("buffer3[92] = %02x\n", buffer3[92]); buffer2[12] += ((buffer1[103] & 32) | (buffer3[92] & ((buffer1[103] | 60))) | 16)/3; printf("buffer2[12] = %02x\n", buffer2[12]); buffer3[96] = buffer1[143]; printf("buffer3[96] = %02x\n", buffer3[96]); buffer3[100] = 27; printf("buffer3[100] = %02x\n", buffer3[100]); buffer3[104] = (((buffer3[40] & ~buffer2[8]) | (buffer1[35] & buffer2[8])) & buffer3[64]) ^ 119; printf("buffer3[104] = %02x\n", buffer3[104]); buffer3[108] = 238 & ((((buffer3[40] & ~buffer2[8]) | (buffer1[35] & buffer2[8])) & buffer3[64]) << 1); printf("buffer3[108] = %02x\n", buffer3[108]); buffer3[112] = (~buffer3[64] & (buffer3[84] / 3)) ^ 49; printf("buffer3[112] = %02x\n", buffer3[112]); buffer3[116] = 98 & ((~buffer3[64] & (buffer3[84] / 3)) << 1); printf("buffer3[116] = %02x\n", buffer3[116]); // finale A = (buffer1[35] & buffer2[8]) | (buffer3[40] & ~buffer2[8]); B = (A & buffer3[64]) | (((buffer3[84] / 3) & ~buffer3[64])); buffer1[143] = buffer3[96] - ((B & (86 + ((buffer1[172] & 64) >> 1))) | (((((buffer1[172] & 65) >> 1) ^ 86) | ((~buffer3[64] & (buffer3[84] / 3)) | (((buffer3[40] & ~buffer2[8]) | (buffer1[35] & buffer2[8])) & buffer3[64]))) & buffer3[100])); printf("buffer1[143] = %02x\n", buffer1[143]); buffer2[29] = 162; printf("buffer2[29] = %02x\n", buffer2[29]); A = ((((buffer4[buffer3[88] % 21]) & 160) | (buffer0[buffer1[125] % 20] & 95)) >> 1); B = buffer2[buffer1[149] % 35] ^ (buffer1[43] * buffer1[43]); buffer0[15] += (B&A) | ((A|B) & 115); printf("buffer0[15] = %02x\n", buffer0[15]); buffer3[120] = buffer3[64] - buffer0[buffer3[40] % 20]; printf("buffer3[120] = %02x\n", buffer3[120]); buffer1[95] = buffer4[buffer3[20] % 21]; printf("buffer1[95] = %02x\n", buffer1[95]); A = weird_ror8(buffer2[buffer3[80] % 35], (buffer2[buffer1[17] % 35] * buffer2[buffer1[17] % 35] * buffer2[buffer1[17] % 35]) & 7); buffer0[7] -= (A*A); printf("buffer0[7] = %02x\n", buffer0[7]); buffer2[8] = buffer2[8] - buffer1[184] + (buffer4[buffer1[202] % 21] * buffer4[buffer1[202] % 21] * buffer4[buffer1[202] % 21]); printf("buffer2[8] = %02x\n", buffer2[8]); buffer0[16] = (buffer2[buffer1[102] % 35] << 1) & 132; printf("buffer0[16] = %02x\n", buffer0[16]); buffer3[124] = (buffer4[buffer3[40] % 21] >> 1) ^ buffer3[68]; printf("buffer3[124] = %02x\n", buffer3[124]); buffer0[7] -= (buffer0[buffer1[191] % 20] - (((buffer4[buffer1[80] % 21] << 1) & ~177) | (buffer4[buffer4[buffer3[88] % 21] % 21] & 177))); printf("buffer0[7] = %02x\n", buffer0[7]); buffer0[6] = buffer0[buffer1[119] % 20]; printf("buffer0[6] = %02x\n", buffer0[6]); A = (buffer4[buffer1[190] % 21] & ~209) | (buffer1[118] & 209); B = buffer0[buffer3[120] % 20] * buffer0[buffer3[120] % 20]; buffer0[12] = (buffer0[buffer3[84] % 20] ^ (buffer2[buffer1[71] % 35] + buffer2[buffer1[15] % 35])) & ((A & B) | ((A | B) & 27)); printf("buffer0[12] = %02x\n", buffer0[12]); B = (buffer1[32] & buffer2[buffer3[88] % 35]) | ((buffer1[32] | buffer2[buffer3[88] % 35]) & 23); D = (((buffer4[buffer1[57] % 21] * 231) & 169) | (B & 86)); F = (((buffer0[buffer1[82] % 20] & ~29) | (buffer4[buffer3[124] % 21] & 29)) & 190) | (buffer4[(D/5) % 21] & ~190); H = buffer0[buffer3[40] % 20] * buffer0[buffer3[40] % 20] * buffer0[buffer3[40] % 20]; K = (H & buffer1[82]) | (H & 92) | (buffer1[82] & 92); buffer3[128] = ((F & K) | ((F | K) & 192)) ^ (D/5); printf("buffer3[128] = %02x\n", buffer3[128]); buffer2[25] ^= ((buffer0[buffer3[120] % 20] << 1) * buffer1[5]) - (weird_rol8(buffer3[76], (buffer4[buffer3[124] % 21] & 7)) & (buffer3[20] + 110)); printf("buffer2[25] = %02x\n", buffer2[25]); //exit(0); } UxPlay-1.71.1/lib/playfair/modified_md5.c000066400000000000000000000066031473013662600201060ustar00rootroot00000000000000#include #include #include #include #include #include #define printf(...) (void)0; int shift[] = {7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21}; uint32_t F(uint32_t B, uint32_t C, uint32_t D) { return (B & C) | (~B & D); } uint32_t G(uint32_t B, uint32_t C, uint32_t D) { return (B & D) | (C & ~D); } uint32_t H(uint32_t B, uint32_t C, uint32_t D) { return B ^ C ^ D; } uint32_t I(uint32_t B, uint32_t C, uint32_t D) { return C ^ (B | ~D); } uint32_t rol(uint32_t input, int count) { return ((input << count) & 0xffffffff) | (input & 0xffffffff) >> (32-count); } void swap(uint32_t* a, uint32_t* b) { printf("%08x <-> %08x\n", *a, *b); uint32_t c = *a; *a = *b; *b = c; } void modified_md5(unsigned char* originalblockIn, unsigned char* keyIn, unsigned char* keyOut) { unsigned char blockIn[64]; uint32_t* block_words = (uint32_t*)blockIn; uint32_t* key_words = (uint32_t*)keyIn; uint32_t* out_words = (uint32_t*)keyOut; uint32_t A, B, C, D, Z, tmp; int i; memcpy(blockIn, originalblockIn, 64); // Each cycle does something like this: A = key_words[0]; B = key_words[1]; C = key_words[2]; D = key_words[3]; for (i = 0; i < 64; i++) { uint32_t input; int j; if (i < 16) j = i; else if (i < 32) j = (5*i + 1) % 16; else if (i < 48) j = (3*i + 5) % 16; else if (i < 64) j = 7*i % 16; input = blockIn[4*j] << 24 | blockIn[4*j+1] << 16 | blockIn[4*j+2] << 8 | blockIn[4*j+3]; printf("Key = %08x\n", A); Z = A + input + (int)(long long)((1LL << 32) * fabs(sin(i + 1))); if (i < 16) Z = rol(Z + F(B,C,D), shift[i]); else if (i < 32) Z = rol(Z + G(B,C,D), shift[i]); else if (i < 48) Z = rol(Z + H(B,C,D), shift[i]); else if (i < 64) Z = rol(Z + I(B,C,D), shift[i]); if (i == 63) printf("Ror is %08x\n", Z); printf("Output of round %d: %08X + %08X = %08X (shift %d, constant %08X)\n", i, Z, B, Z+B, shift[i], (int)(long long)((1LL << 32) * fabs(sin(i + 1)))); Z = Z + B; tmp = D; D = C; C = B; B = Z; A = tmp; if (i == 31) { // swapsies swap(&block_words[A & 15], &block_words[B & 15]); swap(&block_words[C & 15], &block_words[D & 15]); swap(&block_words[(A & (15<<4))>>4], &block_words[(B & (15<<4))>>4]); swap(&block_words[(A & (15<<8))>>8], &block_words[(B & (15<<8))>>8]); swap(&block_words[(A & (15<<12))>>12], &block_words[(B & (15<<12))>>12]); } } printf("%08X %08X %08X %08X\n", A, B, C, D); // Now we can actually compute the output printf("Out:\n"); printf("%08x + %08x = %08x\n", key_words[0], A, key_words[0] + A); printf("%08x + %08x = %08x\n", key_words[1], B, key_words[1] + B); printf("%08x + %08x = %08x\n", key_words[2], C, key_words[2] + C); printf("%08x + %08x = %08x\n", key_words[3], D, key_words[3] + D); out_words[0] = key_words[0] + A; out_words[1] = key_words[1] + B; out_words[2] = key_words[2] + C; out_words[3] = key_words[3] + D; } UxPlay-1.71.1/lib/playfair/omg_hax.c000066400000000000000000000522201473013662600171770ustar00rootroot00000000000000void modified_md5(unsigned char* originalblockIn, unsigned char* keyIn, unsigned char* keyOut); void sap_hash(unsigned char* blockIn, unsigned char* keyOut); #include #include #include #include #include "omg_hax.h" #define printf(...) (void)0; void xor_blocks(unsigned char* a, unsigned char* b, unsigned char* out) { for (int i = 0; i < 16; i++) out[i] = a[i] ^ b[i]; } void z_xor(unsigned char* in, unsigned char* out, int blocks) { for (int j = 0; j < blocks; j++) for (int i = 0; i < 16; i++) out[j*16+i] = in[j*16+i] ^ z_key[i]; } void x_xor(unsigned char* in, unsigned char* out, int blocks) { for (int j = 0; j < blocks; j++) for (int i = 0; i < 16; i++) out[j*16+i] = in[j*16+i] ^ x_key[i]; } void t_xor(unsigned char* in, unsigned char* out) { for (int i = 0; i < 16; i++) out[i] = in[i] ^ t_key[i]; } unsigned char sap_iv[] = {0x2B,0x84,0xFB,0x79,0xDA,0x75,0xB9,0x04,0x6C,0x24,0x73,0xF7,0xD1,0xC4,0xAB,0x0E,0x2B,0x84,0xFB,0x79,0x75,0xB9,0x04,0x6C,0x24,0x73}; unsigned char sap_key_material[] = {0xA1, 0x1A, 0x4A, 0x83, 0xF2, 0x7A, 0x75, 0xEE, 0xA2, 0x1A, 0x7D, 0xB8, 0x8D, 0x77, 0x92, 0xAB}; unsigned char index_mangle[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36, 0x6C}; unsigned char* table_index(int i) { return &table_s1[((31*i) % 0x28) << 8]; } unsigned char* message_table_index(int i) { return &table_s2[(97*i % 144) << 8]; } void print_block(char* msg, unsigned char* dword) { printf("%s", msg); for (int i = 0; i < 16; i++) printf("%02X ", dword[i]); printf("\n"); } void permute_block_1(unsigned char* block) { block[0] = table_s3[block[0]]; block[4] = table_s3[0x400+block[4]]; block[8] = table_s3[0x800+block[8]]; block[12] = table_s3[0xc00+block[12]]; unsigned char tmp = block[13]; block[13] = table_s3[0x100+block[9]]; block[9] = table_s3[0xd00+block[5]]; block[5] = table_s3[0x900+block[1]]; block[1] = table_s3[0x500+tmp]; tmp = block[2]; block[2] = table_s3[0xa00+block[10]]; block[10] = table_s3[0x200+tmp]; tmp = block[6]; block[6] = table_s3[0xe00+block[14]]; block[14] = table_s3[0x600+tmp]; tmp = block[3]; block[3] = table_s3[0xf00+block[7]]; block[7] = table_s3[0x300+block[11]]; block[11] = table_s3[0x700+block[15]]; block[15] = table_s3[0xb00+tmp]; print_block("Permutation complete. Final value of block: ", block); // This looks right to me, at least for decrypt_kernel } unsigned char* permute_table_2(unsigned int i) { return &table_s4[((71 * i) % 144) << 8]; } void permute_block_2(unsigned char* block, int round) { // round is 0..8? printf("Permuting via table2, round %d... (block[0] = %02X)\n", round, block[0]); block[0] = permute_table_2(round*16+0)[block[0]]; block[4] = permute_table_2(round*16+4)[block[4]]; block[8] = permute_table_2(round*16+8)[block[8]]; block[12] = permute_table_2(round*16+12)[block[12]]; unsigned char tmp = block[13]; block[13] = permute_table_2(round*16+13)[block[9]]; block[9] = permute_table_2(round*16+9)[block[5]]; block[5] = permute_table_2(round*16+5)[block[1]]; block[1] = permute_table_2(round*16+1)[tmp]; tmp = block[2]; block[2] = permute_table_2(round*16+2)[block[10]]; block[10] = permute_table_2(round*16+10)[tmp]; tmp = block[6]; block[6] = permute_table_2(round*16+6)[block[14]]; block[14] = permute_table_2(round*16+14)[tmp]; tmp = block[3]; block[3] = permute_table_2(round*16+3)[block[7]]; block[7] = permute_table_2(round*16+7)[block[11]]; block[11] = permute_table_2(round*16+11)[block[15]]; block[15] = permute_table_2(round*16+15)[tmp]; print_block("Permutation (2) complete. Final value of block: ", block); // This looks right to me, at least for decrypt_kernel } // This COULD just be Rijndael key expansion, but with a different set of S-boxes void generate_key_schedule(unsigned char* key_material, uint32_t key_schedule[11][4]) { uint32_t key_data[4]; int i; for (i = 0; i < 11; i++) { key_schedule[i][0] = 0xdeadbeef; key_schedule[i][1] = 0xdeadbeef; key_schedule[i][2] = 0xdeadbeef; key_schedule[i][3] = 0xdeadbeef; } unsigned char* buffer = (unsigned char*)key_data; int ti = 0; printf("Generating key schedule\n"); // G print_block("Raw key material: ", key_material); t_xor(key_material, buffer); print_block("G has produced: ", buffer); for (int round = 0; round < 11; round++) { printf("Starting round %d\n", round); // H key_schedule[round][0] = key_data[0]; printf("H has set chunk 1 of round %d %08X\n", round, key_schedule[round][0]); printf("H complete\n"); // I unsigned char* table1 = table_index(ti); unsigned char* table2 = table_index(ti+1); unsigned char* table3 = table_index(ti+2); unsigned char* table4 = table_index(ti+3); ti += 4; //buffer[0] = (buffer[0] - (4 & (buffer[0] << 1)) + 2) ^ 2 ^ index_mangle[round] ^ table1[buffer[0x0d]]; printf("S-box: 0x%02x -> 0x%02x\n", buffer[0x0d], table1[buffer[0x0d]]); printf("S-box: 0x%02x -> 0x%02x\n", buffer[0x0e], table2[buffer[0x0e]]); printf("S-box: 0x%02x -> 0x%02x\n", buffer[0x0f], table3[buffer[0x0f]]); printf("S-box: 0x%02x -> 0x%02x\n", buffer[0x0c], table4[buffer[0x0c]]); buffer[0] ^= table1[buffer[0x0d]] ^ index_mangle[round]; buffer[1] ^= table2[buffer[0x0e]]; buffer[2] ^= table3[buffer[0x0f]]; buffer[3] ^= table4[buffer[0x0c]]; print_block("After I, buffer is now: ", buffer); printf("I complete\n"); // H key_schedule[round][1] = key_data[1]; printf("H has set chunk 2 to %08X\n", key_schedule[round][1]); printf("H complete\n"); // J key_data[1] ^= key_data[0]; printf("J complete\n"); print_block("Buffer is now ", buffer); // H key_schedule[round][2] = key_data[2]; printf("H has set chunk3 to %08X\n", key_schedule[round][2]); printf("H complete\n"); // J key_data[2] ^= key_data[1]; printf("J complete\n"); // K and L // Implement K and L to fill in other bits of the key schedule key_schedule[round][3] = key_data[3]; // J again key_data[3] ^= key_data[2]; printf("J complete\n"); } for (i = 0; i < 11; i++) print_block("Schedule: ", (unsigned char*)key_schedule[i]); } // This MIGHT just be AES, or some variant thereof. void cycle(unsigned char* block, uint32_t key_schedule[11][4]) { uint32_t ptr1 = 0; uint32_t ptr2 = 0; uint32_t ptr3 = 0; uint32_t ptr4 = 0; uint32_t ab; unsigned char* buffer = (unsigned char*)&ab; uint32_t* bWords = (uint32_t*)block; bWords[0] ^= key_schedule[10][0]; bWords[1] ^= key_schedule[10][1]; bWords[2] ^= key_schedule[10][2]; bWords[3] ^= key_schedule[10][3]; // First, these are permuted permute_block_1(block); for (int round = 0; round < 9; round++) { // E // Note that table_s5 is a table of 4-byte words. Therefore we do not need to <<2 these indices // TODO: Are these just T-tables? unsigned char* key0 = (unsigned char*)&key_schedule[9-round][0]; ptr1 = table_s5[block[3] ^ key0[3]]; ptr2 = table_s6[block[2] ^ key0[2]]; ptr3 = table_s8[block[0] ^ key0[0]]; ptr4 = table_s7[block[1] ^ key0[1]]; // A B ab = ptr1 ^ ptr2 ^ ptr3 ^ ptr4; printf("ab: %08X %08X %08X %08X -> %08X\n", ptr1, ptr2, ptr3, ptr4, ab); // C ((uint32_t*)block)[0] = ab; printf("f7 = %02X\n", block[7]); unsigned char* key1 = (unsigned char*)&key_schedule[9-round][1]; ptr2 = table_s5[block[7] ^ key1[3]]; ptr1 = table_s6[block[6] ^ key1[2]]; ptr4 = table_s7[block[5] ^ key1[1]]; ptr3 = table_s8[block[4] ^ key1[0]]; // A B again ab = ptr1 ^ ptr2 ^ ptr3 ^ ptr4; printf("ab: %08X %08X %08X %08X -> %08X\n", ptr1, ptr2, ptr3, ptr4, ab); // D is a bit of a nightmare, but it is really not as complicated as you might think unsigned char* key2 = (unsigned char*)&key_schedule[9-round][2]; unsigned char* key3 = (unsigned char*)&key_schedule[9-round][3]; ((uint32_t*)block)[1] = ab; ((uint32_t*)block)[2] = table_s5[block[11] ^ key2[3]] ^ table_s6[block[10] ^ key2[2]] ^ table_s7[block[9] ^ key2[1]] ^ table_s8[block[8] ^ key2[0]]; ((uint32_t*)block)[3] = table_s5[block[15] ^ key3[3]] ^ table_s6[block[14] ^ key3[2]] ^ table_s7[block[13] ^ key3[1]] ^ table_s8[block[12] ^ key3[0]]; printf("Set block2 = %08X, block3 = %08X\n", ((uint32_t*)block)[2], ((uint32_t*)block)[3]); // In the last round, instead of the permute, we do F permute_block_2(block, 8-round); } printf("Using last bit of key up: %08X xor %08X -> %08X\n", ((uint32_t*)block)[0], key_schedule[0][0], ((uint32_t*)block)[0] ^ key_schedule[0][0]); ((uint32_t*)block)[0] ^= key_schedule[0][0]; ((uint32_t*)block)[1] ^= key_schedule[0][1]; ((uint32_t*)block)[2] ^= key_schedule[0][2]; ((uint32_t*)block)[3] ^= key_schedule[0][3]; } void decrypt_sap(unsigned char* sapIn, unsigned char* sapOut) { uint32_t key_schedule[11][4]; unsigned char* iv; print_block("Base sap: ", &sapIn[0xf0]); z_xor(sapIn, sapOut, 16); generate_key_schedule(sap_key_material, key_schedule); print_block("lastSap before cycle: ", &sapOut[0xf0]); for (int i = 0xf0; i >= 0x00; i-=0x10) { printf("Ready to cycle %02X\n", i); cycle(&sapOut[i], key_schedule); print_block("After cycling, block is: ", &sapOut[i]); if (i > 0) { // xor with previous block iv = &sapOut[i-0x10]; } else { // xor with sap IV iv = sap_iv; } for (int j = 0; j < 16; j++) { printf("%02X ^ %02X -> %02X\n", sapOut[i+j], iv[j], sapOut[i+j] ^ iv[j]); sapOut[i+j] = sapOut[i+j] ^ iv[j]; } printf("Decrypted SAP %02X-%02X:\n", i, i+0xf); print_block("", &sapOut[i]); } // Lastly grind the whole thing through x_key. This is the last time we modify sap x_xor(sapOut, sapOut, 16); printf("Sap is decrypted to\n"); for (int i = 0xf0; i >= 0x00; i-=0x10) { printf("Final SAP %02X-%02X: ", i, i+0xf); print_block("", &sapOut[i]); } } unsigned char initial_session_key[] = {0xDC, 0xDC, 0xF3, 0xB9, 0x0B, 0x74, 0xDC, 0xFB, 0x86, 0x7F, 0xF7, 0x60, 0x16, 0x72, 0x90, 0x51}; void decrypt_key(unsigned char* decryptedSap, unsigned char* keyIn, unsigned char* iv, unsigned char* keyOut) { unsigned char blockIn[16]; uint32_t key_schedule[11][4]; uint32_t mode_key_schedule[11][4]; generate_key_schedule(&decryptedSap[8], key_schedule); printf("Generating mode key:\n"); generate_key_schedule(initial_session_key, mode_key_schedule); z_xor(keyIn, blockIn, 1); print_block("Input to cycle is: ", blockIn); cycle(blockIn, key_schedule); for (int j = 0; j < 16; j++) keyOut[j] = blockIn[j] ^ iv[j]; print_block("Output from cycle is: ", keyOut); x_xor(keyOut, keyOut, 1); } void decryptMessage(unsigned char* messageIn, unsigned char* decryptedMessage) { unsigned char buffer[16]; int i, j; unsigned char tmp; uint32_t key_schedule[11][4]; int mode = messageIn[12]; // 0,1,2,3 printf("mode = %02x\n", mode); generate_key_schedule(initial_session_key, key_schedule); // For M0-M6 we follow the same pattern for (i = 0; i < 8; i++) { // First, copy in the nth block (we must start with the last one) for (j = 0; j < 16; j++) { if (mode == 3) buffer[j] = messageIn[(0x80-0x10*i)+j]; else if (mode == 2 || mode == 1 || mode == 0) buffer[j] = messageIn[(0x10*(i+1))+j]; } // do this permutation and update 9 times. Could this be cycle(), or the reverse of cycle()? for (j = 0; j < 9; j++) { int base = 0x80 - 0x10*j; //print_block("About to cycle. Buffer is currently: ", buffer); buffer[0x0] = message_table_index(base+0x0)[buffer[0x0]] ^ message_key[mode][base+0x0]; buffer[0x4] = message_table_index(base+0x4)[buffer[0x4]] ^ message_key[mode][base+0x4]; buffer[0x8] = message_table_index(base+0x8)[buffer[0x8]] ^ message_key[mode][base+0x8]; buffer[0xc] = message_table_index(base+0xc)[buffer[0xc]] ^ message_key[mode][base+0xc]; tmp = buffer[0x0d]; buffer[0xd] = message_table_index(base+0xd)[buffer[0x9]] ^ message_key[mode][base+0xd]; buffer[0x9] = message_table_index(base+0x9)[buffer[0x5]] ^ message_key[mode][base+0x9]; buffer[0x5] = message_table_index(base+0x5)[buffer[0x1]] ^ message_key[mode][base+0x5]; buffer[0x1] = message_table_index(base+0x1)[tmp] ^ message_key[mode][base+0x1]; tmp = buffer[0x02]; buffer[0x2] = message_table_index(base+0x2)[buffer[0xa]] ^ message_key[mode][base+0x2]; buffer[0xa] = message_table_index(base+0xa)[tmp] ^ message_key[mode][base+0xa]; tmp = buffer[0x06]; buffer[0x6] = message_table_index(base+0x6)[buffer[0xe]] ^ message_key[mode][base+0x6]; buffer[0xe] = message_table_index(base+0xe)[tmp] ^ message_key[mode][base+0xe]; tmp = buffer[0x3]; buffer[0x3] = message_table_index(base+0x3)[buffer[0x7]] ^ message_key[mode][base+0x3]; buffer[0x7] = message_table_index(base+0x7)[buffer[0xb]] ^ message_key[mode][base+0x7]; buffer[0xb] = message_table_index(base+0xb)[buffer[0xf]] ^ message_key[mode][base+0xb]; buffer[0xf] = message_table_index(base+0xf)[tmp] ^ message_key[mode][base+0xf]; // Now we must replace the entire buffer with 4 words that we read and xor together uint32_t word; uint32_t* block = (uint32_t*)buffer; block[0] = table_s9[0x000 + buffer[0x0]] ^ table_s9[0x100 + buffer[0x1]] ^ table_s9[0x200 + buffer[0x2]] ^ table_s9[0x300 + buffer[0x3]]; block[1] = table_s9[0x000 + buffer[0x4]] ^ table_s9[0x100 + buffer[0x5]] ^ table_s9[0x200 + buffer[0x6]] ^ table_s9[0x300 + buffer[0x7]]; block[2] = table_s9[0x000 + buffer[0x8]] ^ table_s9[0x100 + buffer[0x9]] ^ table_s9[0x200 + buffer[0xa]] ^ table_s9[0x300 + buffer[0xb]]; block[3] = table_s9[0x000 + buffer[0xc]] ^ table_s9[0x100 + buffer[0xd]] ^ table_s9[0x200 + buffer[0xe]] ^ table_s9[0x300 + buffer[0xf]]; } // Next, another permute with a different table buffer[0x0] = table_s10[(0x0 << 8) + buffer[0x0]]; buffer[0x4] = table_s10[(0x4 << 8) + buffer[0x4]]; buffer[0x8] = table_s10[(0x8 << 8) + buffer[0x8]]; buffer[0xc] = table_s10[(0xc << 8) + buffer[0xc]]; tmp = buffer[0x0d]; buffer[0xd] = table_s10[(0xd << 8) + buffer[0x9]]; buffer[0x9] = table_s10[(0x9 << 8) + buffer[0x5]]; buffer[0x5] = table_s10[(0x5 << 8) + buffer[0x1]]; buffer[0x1] = table_s10[(0x1 << 8) + tmp]; tmp = buffer[0x02]; buffer[0x2] = table_s10[(0x2 << 8) + buffer[0xa]]; buffer[0xa] = table_s10[(0xa << 8) + tmp]; tmp = buffer[0x06]; buffer[0x6] = table_s10[(0x6 << 8) + buffer[0xe]]; buffer[0xe] = table_s10[(0xe << 8) + tmp]; tmp = buffer[0x3]; buffer[0x3] = table_s10[(0x3 << 8) + buffer[0x7]]; buffer[0x7] = table_s10[(0x7 << 8) + buffer[0xb]]; buffer[0xb] = table_s10[(0xb << 8) + buffer[0xf]]; buffer[0xf] = table_s10[(0xf << 8) + tmp]; // And finally xor with the previous block of the message, except in mode-2 where we do this in reverse if (mode == 2 || mode == 1 || mode == 0) { if (i > 0) { xor_blocks(buffer, &messageIn[0x10*i], &decryptedMessage[0x10*i]); // remember that the first 0x10 bytes are the header } else xor_blocks(buffer, message_iv[mode], &decryptedMessage[0x10*i]); print_block(" ", &decryptedMessage[0x10*i]); } else { if (i < 7) xor_blocks(buffer, &messageIn[0x70 - 0x10*i], &decryptedMessage[0x70 - 0x10*i]); else xor_blocks(buffer, message_iv[mode], &decryptedMessage[0x70 - 0x10*i]); printf("Decrypted message block %02X-%02X:", 0x70 - 0x10*i, 0x70 - 0x10*i+0xf); print_block(" ", &decryptedMessage[0x70 - 0x10*i]); } } } unsigned char static_source_1[] = {0xFA, 0x9C, 0xAD, 0x4D, 0x4B, 0x68, 0x26, 0x8C, 0x7F, 0xF3, 0x88, 0x99, 0xDE, 0x92, 0x2E, 0x95, 0x1E}; unsigned char static_source_2[] = {0xEC, 0x4E, 0x27, 0x5E, 0xFD, 0xF2, 0xE8, 0x30, 0x97, 0xAE, 0x70, 0xFB, 0xE0, 0x00, 0x3F, 0x1C, 0x39, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x0, 0x00, 0x00, 0x00, 0x00}; void swap_bytes(unsigned char* a, unsigned char *b) { unsigned char c = *a; *a = *b; *b = c; } void generate_session_key(unsigned char* oldSap, unsigned char* messageIn, unsigned char* sessionKey) { unsigned char decryptedMessage[128]; unsigned char newSap[320]; unsigned char Q[210]; int i; int round; unsigned char md5[16]; unsigned char otherHash[16]; decryptMessage(messageIn, decryptedMessage); // Now that we have the decrypted message, we can combine it with our initial sap to form the 5 blocks needed to generate the 5 words which, when added together, give // the session key. memcpy(&newSap[0x000], static_source_1, 0x11); memcpy(&newSap[0x011], decryptedMessage, 0x80); memcpy(&newSap[0x091], &oldSap[0x80], 0x80); memcpy(&newSap[0x111], static_source_2, 0x2f); memcpy(sessionKey, initial_session_key, 16); for (round = 0; round < 5; round++) { unsigned char* base = &newSap[round * 64]; print_block("Input block: ", &base[0]); print_block("Input block: ", &base[0x10]); print_block("Input block: ", &base[0x20]); print_block("Input block: ", &base[0x30]); modified_md5(base, sessionKey, md5); printf("MD5 OK\n"); sap_hash(base, sessionKey); printf("OtherHash OK\n"); printf("MD5 = "); for (i = 0; i < 4; i++) printf("%08x ", ((uint32_t*)md5)[i]); printf("\nOtherHash = "); for (i = 0; i < 4; i++) printf("%08x ", ((uint32_t*)sessionKey)[i]); printf("\n"); uint32_t* sessionKeyWords = (uint32_t*)sessionKey; uint32_t* md5Words = (uint32_t*)md5; for (i = 0; i < 4; i++) { sessionKeyWords[i] = (sessionKeyWords[i] + md5Words[i]) & 0xffffffff; } printf("Current key: "); for (i = 0; i < 16; i++) printf("%02x", sessionKey[i]); printf("\n"); } for (i = 0; i < 16; i+=4) { swap_bytes(&sessionKey[i], &sessionKey[i+3]); swap_bytes(&sessionKey[i+1], &sessionKey[i+2]); } // Finally the whole thing is XORd with 121: for (i = 0; i < 16; i++) sessionKey[i] ^= 121; print_block("Session key computed as: ", sessionKey); } unsigned char default_sap[] = { 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x02, 0x53, 0x00, 0x01, 0xcc, 0x34, 0x2a, 0x5e, 0x5b, 0x1a, 0x67, 0x73, 0xc2, 0x0e, 0x21, 0xb8, 0x22, 0x4d, 0xf8, 0x62, 0x48, 0x18, 0x64, 0xef, 0x81, 0x0a, 0xae, 0x2e, 0x37, 0x03, 0xc8, 0x81, 0x9c, 0x23, 0x53, 0x9d, 0xe5, 0xf5, 0xd7, 0x49, 0xbc, 0x5b, 0x7a, 0x26, 0x6c, 0x49, 0x62, 0x83, 0xce, 0x7f, 0x03, 0x93, 0x7a, 0xe1, 0xf6, 0x16, 0xde, 0x0c, 0x15, 0xff, 0x33, 0x8c, 0xca, 0xff, 0xb0, 0x9e, 0xaa, 0xbb, 0xe4, 0x0f, 0x5d, 0x5f, 0x55, 0x8f, 0xb9, 0x7f, 0x17, 0x31, 0xf8, 0xf7, 0xda, 0x60, 0xa0, 0xec, 0x65, 0x79, 0xc3, 0x3e, 0xa9, 0x83, 0x12, 0xc3, 0xb6, 0x71, 0x35, 0xa6, 0x69, 0x4f, 0xf8, 0x23, 0x05, 0xd9, 0xba, 0x5c, 0x61, 0x5f, 0xa2, 0x54, 0xd2, 0xb1, 0x83, 0x45, 0x83, 0xce, 0xe4, 0x2d, 0x44, 0x26, 0xc8, 0x35, 0xa7, 0xa5, 0xf6, 0xc8, 0x42, 0x1c, 0x0d, 0xa3, 0xf1, 0xc7, 0x00, 0x50, 0xf2, 0xe5, 0x17, 0xf8, 0xd0, 0xfa, 0x77, 0x8d, 0xfb, 0x82, 0x8d, 0x40, 0xc7, 0x8e, 0x94, 0x1e, 0x1e, 0x1e}; UxPlay-1.71.1/lib/playfair/omg_hax.h000066400000000000000000016577071473013662600172320ustar00rootroot00000000000000unsigned char message_key[4][144] = {{0x1D, 0x24, 0x03, 0x40, 0xDC, 0xAE, 0xC7, 0xA8, 0x26, 0x7C, 0x20, 0x99, 0x5D, 0x7E, 0x89, 0x2E, 0xA2, 0x58, 0xAF, 0xBE, 0xB8, 0x07, 0x9A, 0x2F, 0x87, 0x77, 0xD3, 0xCE, 0x37, 0x3E, 0x1B, 0x16, 0x41, 0x4F, 0x4E, 0xBE, 0x62, 0x5A, 0x00, 0x77, 0xC6, 0xEB, 0xDA, 0x4B, 0x97, 0x1A, 0x61, 0x8D, 0x31, 0x32, 0x1C, 0xA2, 0x78, 0x9B, 0x66, 0x72, 0x60, 0x94, 0x44, 0x86, 0xCB, 0x09, 0xBD, 0x3A, 0x77, 0x57, 0xC1, 0x72, 0x61, 0x1D, 0x32, 0xC7, 0x85, 0xD1, 0xEF, 0xE5, 0x4D, 0x95, 0x0B, 0xF0, 0xD8, 0x18, 0xE7, 0x4A, 0xDC, 0x77, 0xCA, 0x55, 0x28, 0x32, 0x93, 0x2A, 0x7B, 0x3E, 0x3A, 0xD4, 0x97, 0xFD, 0x7D, 0x6D, 0x95, 0x71, 0x27, 0x9C, 0x77, 0x6A, 0x7C, 0xD5, 0xBF, 0x9D, 0x0E, 0xF2, 0x0F, 0x55, 0x91, 0x29, 0xCF, 0xAA, 0x58, 0x1C, 0x7A, 0xE7, 0xCB, 0x8B, 0x20, 0x07, 0x53, 0xAA, 0x59, 0x40, 0x3B, 0x03, 0xBE, 0x33, 0x47, 0x47, 0x5A, 0x4F, 0x86, 0x31, 0x8D, 0x30, 0xF9, 0x1C}, {0xF1, 0xA2, 0x04, 0x7A, 0xAE, 0xE9, 0xD8, 0xBF, 0xD4, 0xC0, 0x6B, 0x77, 0xC1, 0x05, 0x8C, 0x99, 0xA9, 0xFD, 0x3D, 0x44, 0xEE, 0x7B, 0x6C, 0x28, 0x42, 0x31, 0x63, 0x87, 0x6D, 0xD2, 0x6D, 0x48, 0xCC, 0x4E, 0x93, 0x31, 0x7B, 0x27, 0x14, 0xFC, 0x2D, 0x71, 0x5D, 0xE4, 0xB0, 0xF9, 0x4B, 0x82, 0x76, 0x52, 0xD5, 0x02, 0x6C, 0xB6, 0xCF, 0x57, 0xFE, 0xB2, 0xBF, 0xB7, 0x30, 0x56, 0x7B, 0x9B, 0x3E, 0x3E, 0xB0, 0x47, 0x10, 0x63, 0xE8, 0x72, 0x1C, 0x38, 0x2D, 0x79, 0xC4, 0x77, 0x3C, 0xD1, 0xED, 0x02, 0x43, 0x03, 0x5C, 0xBC, 0x57, 0x9E, 0x43, 0x02, 0x67, 0xA1, 0x9B, 0x8C, 0xF3, 0x54, 0xE4, 0x46, 0xE1, 0x1C, 0x4F, 0xDC, 0xF7, 0x9F, 0xF4, 0x49, 0x76, 0x4F, 0x13, 0x96, 0x86, 0xCF, 0xF1, 0x7A, 0x01, 0xAC, 0xE4, 0xD5, 0x32, 0x5B, 0x5D, 0x7D, 0xEE, 0xCA, 0xBF, 0x76, 0xFB, 0x50, 0xD7, 0xEC, 0x9C, 0xA3, 0xF6, 0x2E, 0xBE, 0x9B, 0xC7, 0xC8, 0x0F, 0xF2, 0xB7, 0x3B, 0xDE, 0x8A}, {0x18, 0x6E, 0xD3, 0x73, 0x5E, 0xE9, 0x5A, 0x8F, 0x66, 0x3F, 0xF1, 0xB8, 0x4A, 0x62, 0xD9, 0xC0, 0xD2, 0x08, 0x13, 0x61, 0xCB, 0xF3, 0xAD, 0xA6, 0x26, 0x4D, 0x3A, 0x7B, 0x06, 0xB5, 0x51, 0x56, 0xFE, 0x66, 0x0A, 0xD8, 0x3A, 0xAA, 0x47, 0x49, 0xD3, 0x7C, 0xC3, 0x68, 0x70, 0xD0, 0x96, 0x80, 0x6A, 0x05, 0x90, 0xEF, 0xAF, 0x43, 0x42, 0xC4, 0x2E, 0x50, 0x4C, 0x96, 0x13, 0xB5, 0x2E, 0x4C, 0x80, 0xA2, 0x8D, 0x23, 0xEE, 0xE2, 0x5E, 0x78, 0xF4, 0x3D, 0x65, 0xCA, 0x71, 0x4F, 0x68, 0x9E, 0x4B, 0x43, 0x58, 0x7B, 0x47, 0x96, 0x40, 0x81, 0x8A, 0x98, 0x6C, 0x04, 0x33, 0x0F, 0x2F, 0x1C, 0x33, 0x8E, 0xEA, 0xA1, 0x4F, 0xA8, 0x37, 0x93, 0x17, 0x1D, 0x8D, 0x18, 0xA9, 0x6A, 0x1B, 0x07, 0x7C, 0xB6, 0x08, 0x58, 0x1F, 0x12, 0x00, 0xFA, 0x37, 0x4D, 0x7F, 0xBA, 0xA5, 0x00, 0x6B, 0x72, 0x78, 0x9C, 0x33, 0xE8, 0x41, 0x07, 0xB7, 0xC1, 0x67, 0x9B, 0x76, 0xBB, 0xDD, 0x91, 0x3D, 0x3D}, {0x47, 0x69, 0x9F, 0x08, 0xB8, 0x82, 0xFB, 0xA1, 0x95, 0xE5, 0x6F, 0x41, 0x79, 0x1E, 0x0C, 0xB6, 0xA1, 0xCA, 0x11, 0x0A, 0xE2, 0x87, 0x2C, 0x7E, 0x39, 0xBC, 0x98, 0xA5, 0x1E, 0xB2, 0xFA, 0x1F, 0xEE, 0x73, 0x42, 0xD7, 0xA9, 0x09, 0x42, 0xC0, 0xEF, 0xC4, 0x44, 0x0C, 0x0F, 0x6F, 0x97, 0x09, 0x08, 0xBC, 0x66, 0x31, 0x33, 0xFF, 0xCA, 0x7E, 0xB5, 0xE9, 0x7D, 0x77, 0x98, 0xC0, 0xD2, 0x6A, 0xFD, 0x2F, 0x0B, 0x6C, 0x9D, 0xAB, 0xAA, 0x78, 0x4C, 0x76, 0xDE, 0x21, 0xBF, 0xF4, 0x3A, 0x28, 0x2A, 0xC4, 0x74, 0xB4, 0xA9, 0x1B, 0x9A, 0x38, 0x21, 0x4C, 0xEB, 0xBD, 0x72, 0x51, 0xA6, 0x15, 0xD4, 0x9E, 0x17, 0xF3, 0x94, 0x26, 0x6D, 0x07, 0x5F, 0x92, 0xAA, 0xA4, 0x4E, 0xF2, 0xCD, 0x3F, 0x02, 0x4F, 0x05, 0x35, 0xE3, 0x58, 0xDF, 0x82, 0x7E, 0x6A, 0x17, 0xF0, 0x5F, 0x6B, 0xDC, 0xE9, 0x3A, 0xCF, 0x04, 0xB3, 0x01, 0x44, 0x87, 0xD7, 0xBC, 0xAD, 0x3D, 0x74, 0x96, 0x74, 0xA3, 0x99}}; unsigned char message_iv[4][16] = {{0x57, 0x52, 0xF1, 0xB7, 0x54, 0x9D, 0x8F, 0x87, 0x0C, 0x10, 0x48, 0x5A, 0x60, 0x88, 0xCA, 0xDB}, {0xDF, 0x7B, 0x15, 0x63, 0xF0, 0x05, 0x58, 0x77, 0x52, 0xA9, 0x04, 0x02, 0xB9, 0xA3, 0x92, 0x95}, {0x68, 0xB5, 0x46, 0x11, 0xFB, 0x04, 0xDE, 0x67, 0x6C, 0x96, 0x8E, 0xFB, 0x8C, 0x9D, 0xB0, 0xC9}, {0x27, 0x07, 0x8B, 0x21, 0x23, 0x36, 0x1E, 0x7A, 0xDC, 0x9D, 0x0B, 0x11, 0x53, 0x54, 0x69, 0x0D}}; unsigned char z_key[] = {0x1a, 0x64, 0xf9, 0x60, 0x6c, 0xe3, 0x01, 0xa9, 0x54, 0x48, 0x1b, 0xd4, 0xab, 0x81, 0xfc, 0xc6}; unsigned char x_key[] = {0x8e, 0xba, 0x07, 0xcc, 0xb6, 0x5a, 0xf6, 0x20, 0x33, 0xcf, 0xf8, 0x42, 0xe5, 0xd5, 0x5a, 0x7d}; unsigned char t_key[] = {0xd0, 0x04, 0xa9, 0x61, 0x6b, 0xa4, 0x00, 0x87, 0x68, 0x8b, 0x5f, 0x15, 0x15, 0x35, 0xd9, 0xa9}; unsigned long table_s5[] = {0x21aa8423, 0x2fa1892a, 0x3dbc9e31, 0x33b79338, 0x1986b007, 0x178dbd0e, 0x590aa15, 0xb9ba71c, 0x51f2ec6b, 0x5ff9e162, 0x4de4f679, 0x43effb70, 0x69ded84f, 0x67d5d546, 0x75c8c25d, 0x7bc3cf54, 0xc11a54b3, 0xcf1159ba, 0xdd0c4ea1, 0xd30743a8, 0xf9366097, 0xf73d6d9e, 0xe5207a85, 0xeb2b778c, 0xb1423cfb, 0xbf4931f2, 0xad5426e9, 0xa35f2be0, 0x896e08df, 0x876505d6, 0x957812cd, 0x9b731fc4, 0xfad13f18, 0xf4da3211, 0xe6c7250a, 0xe8cc2803, 0xc2fd0b3c, 0xccf60635, 0xdeeb112e, 0xd0e01c27, 0x8a895750, 0x84825a59, 0x969f4d42, 0x9894404b, 0xb2a56374, 0xbcae6e7d, 0xaeb37966, 0xa0b8746f, 0x1a61ef88, 0x146ae281, 0x677f59a, 0x87cf893, 0x224ddbac, 0x2c46d6a5, 0x3e5bc1be, 0x3050ccb7, 0x6a3987c0, 0x64328ac9, 0x762f9dd2, 0x782490db, 0x5215b3e4, 0x5c1ebeed, 0x4e03a9f6, 0x4008a4ff, 0x8c5ce955, 0x8257e45c, 0x904af347, 0x9e41fe4e, 0xb470dd71, 0xba7bd078, 0xa866c763, 0xa66dca6a, 0xfc04811d, 0xf20f8c14, 0xe0129b0f, 0xee199606, 0xc428b539, 0xca23b830, 0xd83eaf2b, 0xd635a222, 0x6cec39c5, 0x62e734cc, 0x70fa23d7, 0x7ef12ede, 0x54c00de1, 0x5acb00e8, 0x48d617f3, 0x46dd1afa, 0x1cb4518d, 0x12bf5c84, 0xa24b9f, 0xea94696, 0x249865a9, 0x2a9368a0, 0x388e7fbb, 0x368572b2, 0x5727526e, 0x592c5f67, 0x4b31487c, 0x453a4575, 0x6f0b664a, 0x61006b43, 0x731d7c58, 0x7d167151, 0x277f3a26, 0x2974372f, 0x3b692034, 0x35622d3d, 0x1f530e02, 0x1158030b, 0x3451410, 0xd4e1919, 0xb79782fe, 0xb99c8ff7, 0xab8198ec, 0xa58a95e5, 0x8fbbb6da, 0x81b0bbd3, 0x93adacc8, 0x9da6a1c1, 0xc7cfeab6, 0xc9c4e7bf, 0xdbd9f0a4, 0xd5d2fdad, 0xffe3de92, 0xf1e8d39b, 0xe3f5c480, 0xedfec989, 0x605d5ecf, 0x6e5653c6, 0x7c4b44dd, 0x724049d4, 0x58716aeb, 0x567a67e2, 0x446770f9, 0x4a6c7df0, 0x10053687, 0x1e0e3b8e, 0xc132c95, 0x218219c, 0x282902a3, 0x26220faa, 0x343f18b1, 0x3a3415b8, 0x80ed8e5f, 0x8ee68356, 0x9cfb944d, 0x92f09944, 0xb8c1ba7b, 0xb6cab772, 0xa4d7a069, 0xaadcad60, 0xf0b5e617, 0xfebeeb1e, 0xeca3fc05, 0xe2a8f10c, 0xc899d233, 0xc692df3a, 0xd48fc821, 0xda84c528, 0xbb26e5f4, 0xb52de8fd, 0xa730ffe6, 0xa93bf2ef, 0x830ad1d0, 0x8d01dcd9, 0x9f1ccbc2, 0x9117c6cb, 0xcb7e8dbc, 0xc57580b5, 0xd76897ae, 0xd9639aa7, 0xf352b998, 0xfd59b491, 0xef44a38a, 0xe14fae83, 0x5b963564, 0x559d386d, 0x47802f76, 0x498b227f, 0x63ba0140, 0x6db10c49, 0x7fac1b52, 0x71a7165b, 0x2bce5d2c, 0x25c55025, 0x37d8473e, 0x39d34a37, 0x13e26908, 0x1de96401, 0xff4731a, 0x1ff7e13, 0xcdab33b9, 0xc3a03eb0, 0xd1bd29ab, 0xdfb624a2, 0xf587079d, 0xfb8c0a94, 0xe9911d8f, 0xe79a1086, 0xbdf35bf1, 0xb3f856f8, 0xa1e541e3, 0xafee4cea, 0x85df6fd5, 0x8bd462dc, 0x99c975c7, 0x97c278ce, 0x2d1be329, 0x2310ee20, 0x310df93b, 0x3f06f432, 0x1537d70d, 0x1b3cda04, 0x921cd1f, 0x72ac016, 0x5d438b61, 0x53488668, 0x41559173, 0x4f5e9c7a, 0x656fbf45, 0x6b64b24c, 0x7979a557, 0x7772a85e, 0x16d08882, 0x18db858b, 0xac69290, 0x4cd9f99, 0x2efcbca6, 0x20f7b1af, 0x32eaa6b4, 0x3ce1abbd, 0x6688e0ca, 0x6883edc3, 0x7a9efad8, 0x7495f7d1, 0x5ea4d4ee, 0x50afd9e7, 0x42b2cefc, 0x4cb9c3f5, 0xf6605812, 0xf86b551b, 0xea764200, 0xe47d4f09, 0xce4c6c36, 0xc047613f, 0xd25a7624, 0xdc517b2d, 0x8638305a, 0x88333d53, 0x9a2e2a48, 0x94252741, 0xbe14047e, 0xb01f0977, 0xa2021e6c, 0xac091365}; unsigned long table_s6[] = {0x5ee7493, 0xce07f9e, 0x17f26289, 0x1efc6984, 0x21d658a7, 0x28d853aa, 0x33ca4ebd, 0x3ac445b0, 0x4d9e2cfb, 0x449027f6, 0x5f823ae1, 0x568c31ec, 0x69a600cf, 0x60a80bc2, 0x7bba16d5, 0x72b41dd8, 0x950ec443, 0x9c00cf4e, 0x8712d259, 0x8e1cd954, 0xb136e877, 0xb838e37a, 0xa32afe6d, 0xaa24f560, 0xdd7e9c2b, 0xd4709726, 0xcf628a31, 0xc66c813c, 0xf946b01f, 0xf048bb12, 0xeb5aa605, 0xe254ad08, 0x3e350f28, 0x373b0425, 0x2c291932, 0x2527123f, 0x1a0d231c, 0x13032811, 0x8113506, 0x11f3e0b, 0x76455740, 0x7f4b5c4d, 0x6459415a, 0x6d574a57, 0x527d7b74, 0x5b737079, 0x40616d6e, 0x496f6663, 0xaed5bff8, 0xa7dbb4f5, 0xbcc9a9e2, 0xb5c7a2ef, 0x8aed93cc, 0x83e398c1, 0x98f185d6, 0x91ff8edb, 0xe6a5e790, 0xefabec9d, 0xf4b9f18a, 0xfdb7fa87, 0xc29dcba4, 0xcb93c0a9, 0xd081ddbe, 0xd98fd6b3, 0x734382fe, 0x7a4d89f3, 0x615f94e4, 0x68519fe9, 0x577baeca, 0x5e75a5c7, 0x4567b8d0, 0x4c69b3dd, 0x3b33da96, 0x323dd19b, 0x292fcc8c, 0x2021c781, 0x1f0bf6a2, 0x1605fdaf, 0xd17e0b8, 0x419ebb5, 0xe3a3322e, 0xeaad3923, 0xf1bf2434, 0xf8b12f39, 0xc79b1e1a, 0xce951517, 0xd5870800, 0xdc89030d, 0xabd36a46, 0xa2dd614b, 0xb9cf7c5c, 0xb0c17751, 0x8feb4672, 0x86e54d7f, 0x9df75068, 0x94f95b65, 0x4898f945, 0x4196f248, 0x5a84ef5f, 0x538ae452, 0x6ca0d571, 0x65aede7c, 0x7ebcc36b, 0x77b2c866, 0xe8a12d, 0x9e6aa20, 0x12f4b737, 0x1bfabc3a, 0x24d08d19, 0x2dde8614, 0x36cc9b03, 0x3fc2900e, 0xd8784995, 0xd1764298, 0xca645f8f, 0xc36a5482, 0xfc4065a1, 0xf54e6eac, 0xee5c73bb, 0xe75278b6, 0x900811fd, 0x99061af0, 0x821407e7, 0x8b1a0cea, 0xb4303dc9, 0xbd3e36c4, 0xa62c2bd3, 0xaf2220de, 0xe9af8349, 0xe0a18844, 0xfbb39553, 0xf2bd9e5e, 0xcd97af7d, 0xc499a470, 0xdf8bb967, 0xd685b26a, 0xa1dfdb21, 0xa8d1d02c, 0xb3c3cd3b, 0xbacdc636, 0x85e7f715, 0x8ce9fc18, 0x97fbe10f, 0x9ef5ea02, 0x794f3399, 0x70413894, 0x6b532583, 0x625d2e8e, 0x5d771fad, 0x547914a0, 0x4f6b09b7, 0x466502ba, 0x313f6bf1, 0x383160fc, 0x23237deb, 0x2a2d76e6, 0x150747c5, 0x1c094cc8, 0x71b51df, 0xe155ad2, 0xd274f8f2, 0xdb7af3ff, 0xc068eee8, 0xc966e5e5, 0xf64cd4c6, 0xff42dfcb, 0xe450c2dc, 0xed5ec9d1, 0x9a04a09a, 0x930aab97, 0x8818b680, 0x8116bd8d, 0xbe3c8cae, 0xb73287a3, 0xac209ab4, 0xa52e91b9, 0x42944822, 0x4b9a432f, 0x50885e38, 0x59865535, 0x66ac6416, 0x6fa26f1b, 0x74b0720c, 0x7dbe7901, 0xae4104a, 0x3ea1b47, 0x18f80650, 0x11f60d5d, 0x2edc3c7e, 0x27d23773, 0x3cc02a64, 0x35ce2169, 0x9f027524, 0x960c7e29, 0x8d1e633e, 0x84106833, 0xbb3a5910, 0xb234521d, 0xa9264f0a, 0xa0284407, 0xd7722d4c, 0xde7c2641, 0xc56e3b56, 0xcc60305b, 0xf34a0178, 0xfa440a75, 0xe1561762, 0xe8581c6f, 0xfe2c5f4, 0x6eccef9, 0x1dfed3ee, 0x14f0d8e3, 0x2bdae9c0, 0x22d4e2cd, 0x39c6ffda, 0x30c8f4d7, 0x47929d9c, 0x4e9c9691, 0x558e8b86, 0x5c80808b, 0x63aab1a8, 0x6aa4baa5, 0x71b6a7b2, 0x78b8acbf, 0xa4d90e9f, 0xadd70592, 0xb6c51885, 0xbfcb1388, 0x80e122ab, 0x89ef29a6, 0x92fd34b1, 0x9bf33fbc, 0xeca956f7, 0xe5a75dfa, 0xfeb540ed, 0xf7bb4be0, 0xc8917ac3, 0xc19f71ce, 0xda8d6cd9, 0xd38367d4, 0x3439be4f, 0x3d37b542, 0x2625a855, 0x2f2ba358, 0x1001927b, 0x190f9976, 0x21d8461, 0xb138f6c, 0x7c49e627, 0x7547ed2a, 0x6e55f03d, 0x675bfb30, 0x5871ca13, 0x517fc11e, 0x4a6ddc09, 0x4363d704}; unsigned long table_s7[] = {0xb33a6e73, 0xbe336078, 0xa9287265, 0xa4217c6e, 0x871e565f, 0x8a175854, 0x9d0c4a49, 0x90054442, 0xdb721e2b, 0xd67b1020, 0xc160023d, 0xcc690c36, 0xef562607, 0xe25f280c, 0xf5443a11, 0xf84d341a, 0x63aa8ec3, 0x6ea380c8, 0x79b892d5, 0x74b19cde, 0x578eb6ef, 0x5a87b8e4, 0x4d9caaf9, 0x4095a4f2, 0xbe2fe9b, 0x6ebf090, 0x11f0e28d, 0x1cf9ec86, 0x3fc6c6b7, 0x32cfc8bc, 0x25d4daa1, 0x28ddd4aa, 0x801b508, 0x508bb03, 0x1213a91e, 0x1f1aa715, 0x3c258d24, 0x312c832f, 0x26379132, 0x2b3e9f39, 0x6049c550, 0x6d40cb5b, 0x7a5bd946, 0x7752d74d, 0x546dfd7c, 0x5964f377, 0x4e7fe16a, 0x4376ef61, 0xd89155b8, 0xd5985bb3, 0xc28349ae, 0xcf8a47a5, 0xecb56d94, 0xe1bc639f, 0xf6a77182, 0xfbae7f89, 0xb0d925e0, 0xbdd02beb, 0xaacb39f6, 0xa7c237fd, 0x84fd1dcc, 0x89f413c7, 0x9eef01da, 0x93e60fd1, 0xde4cc385, 0xd345cd8e, 0xc45edf93, 0xc957d198, 0xea68fba9, 0xe761f5a2, 0xf07ae7bf, 0xfd73e9b4, 0xb604b3dd, 0xbb0dbdd6, 0xac16afcb, 0xa11fa1c0, 0x82208bf1, 0x8f2985fa, 0x983297e7, 0x953b99ec, 0xedc2335, 0x3d52d3e, 0x14ce3f23, 0x19c73128, 0x3af81b19, 0x37f11512, 0x20ea070f, 0x2de30904, 0x6694536d, 0x6b9d5d66, 0x7c864f7b, 0x718f4170, 0x52b06b41, 0x5fb9654a, 0x48a27757, 0x45ab795c, 0x657718fe, 0x687e16f5, 0x7f6504e8, 0x726c0ae3, 0x515320d2, 0x5c5a2ed9, 0x4b413cc4, 0x464832cf, 0xd3f68a6, 0x3666ad, 0x172d74b0, 0x1a247abb, 0x391b508a, 0x34125e81, 0x23094c9c, 0x2e004297, 0xb5e7f84e, 0xb8eef645, 0xaff5e458, 0xa2fcea53, 0x81c3c062, 0x8ccace69, 0x9bd1dc74, 0x96d8d27f, 0xddaf8816, 0xd0a6861d, 0xc7bd9400, 0xcab49a0b, 0xe98bb03a, 0xe482be31, 0xf399ac2c, 0xfe90a227, 0x69d62f84, 0x64df218f, 0x73c43392, 0x7ecd3d99, 0x5df217a8, 0x50fb19a3, 0x47e00bbe, 0x4ae905b5, 0x19e5fdc, 0xc9751d7, 0x1b8c43ca, 0x16854dc1, 0x35ba67f0, 0x38b369fb, 0x2fa87be6, 0x22a175ed, 0xb946cf34, 0xb44fc13f, 0xa354d322, 0xae5ddd29, 0x8d62f718, 0x806bf913, 0x9770eb0e, 0x9a79e505, 0xd10ebf6c, 0xdc07b167, 0xcb1ca37a, 0xc615ad71, 0xe52a8740, 0xe823894b, 0xff389b56, 0xf231955d, 0xd2edf4ff, 0xdfe4faf4, 0xc8ffe8e9, 0xc5f6e6e2, 0xe6c9ccd3, 0xebc0c2d8, 0xfcdbd0c5, 0xf1d2dece, 0xbaa584a7, 0xb7ac8aac, 0xa0b798b1, 0xadbe96ba, 0x8e81bc8b, 0x8388b280, 0x9493a09d, 0x999aae96, 0x27d144f, 0xf741a44, 0x186f0859, 0x15660652, 0x36592c63, 0x3b502268, 0x2c4b3075, 0x21423e7e, 0x6a356417, 0x673c6a1c, 0x70277801, 0x7d2e760a, 0x5e115c3b, 0x53185230, 0x4403402d, 0x490a4e26, 0x4a08272, 0x9a98c79, 0x1eb29e64, 0x13bb906f, 0x3084ba5e, 0x3d8db455, 0x2a96a648, 0x279fa843, 0x6ce8f22a, 0x61e1fc21, 0x76faee3c, 0x7bf3e037, 0x58ccca06, 0x55c5c40d, 0x42ded610, 0x4fd7d81b, 0xd43062c2, 0xd9396cc9, 0xce227ed4, 0xc32b70df, 0xe0145aee, 0xed1d54e5, 0xfa0646f8, 0xf70f48f3, 0xbc78129a, 0xb1711c91, 0xa66a0e8c, 0xab630087, 0x885c2ab6, 0x855524bd, 0x924e36a0, 0x9f4738ab, 0xbf9b5909, 0xb2925702, 0xa589451f, 0xa8804b14, 0x8bbf6125, 0x86b66f2e, 0x91ad7d33, 0x9ca47338, 0xd7d32951, 0xdada275a, 0xcdc13547, 0xc0c83b4c, 0xe3f7117d, 0xeefe1f76, 0xf9e50d6b, 0xf4ec0360, 0x6f0bb9b9, 0x6202b7b2, 0x7519a5af, 0x7810aba4, 0x5b2f8195, 0x56268f9e, 0x413d9d83, 0x4c349388, 0x743c9e1, 0xa4ac7ea, 0x1d51d5f7, 0x1058dbfc, 0x3367f1cd, 0x3e6effc6, 0x2975eddb, 0x247ce3d0}; unsigned long table_s8[] = {0xb4469bf0, 0xbf4b92fe, 0xa25c89ec, 0xa95180e2, 0x9872bfc8, 0x937fb6c6, 0x8e68add4, 0x8565a4da, 0xec2ed380, 0xe723da8e, 0xfa34c19c, 0xf139c892, 0xc01af7b8, 0xcb17feb6, 0xd600e5a4, 0xdd0decaa, 0x4960b10, 0xf9b021e, 0x128c190c, 0x19811002, 0x28a22f28, 0x23af2626, 0x3eb83d34, 0x35b5343a, 0x5cfe4360, 0x57f34a6e, 0x4ae4517c, 0x41e95872, 0x70ca6758, 0x7bc76e56, 0x66d07544, 0x6ddd7c4a, 0xcffda02b, 0xc4f0a925, 0xd9e7b237, 0xd2eabb39, 0xe3c98413, 0xe8c48d1d, 0xf5d3960f, 0xfede9f01, 0x9795e85b, 0x9c98e155, 0x818ffa47, 0x8a82f349, 0xbba1cc63, 0xb0acc56d, 0xadbbde7f, 0xa6b6d771, 0x7f2d30cb, 0x742039c5, 0x693722d7, 0x623a2bd9, 0x531914f3, 0x58141dfd, 0x450306ef, 0x4e0e0fe1, 0x274578bb, 0x2c4871b5, 0x315f6aa7, 0x3a5263a9, 0xb715c83, 0x7c558d, 0x1d6b4e9f, 0x16664791, 0x422bed5d, 0x4926e453, 0x5431ff41, 0x5f3cf64f, 0x6e1fc965, 0x6512c06b, 0x7805db79, 0x7308d277, 0x1a43a52d, 0x114eac23, 0xc59b731, 0x754be3f, 0x36778115, 0x3d7a881b, 0x206d9309, 0x2b609a07, 0xf2fb7dbd, 0xf9f674b3, 0xe4e16fa1, 0xefec66af, 0xdecf5985, 0xd5c2508b, 0xc8d54b99, 0xc3d84297, 0xaa9335cd, 0xa19e3cc3, 0xbc8927d1, 0xb7842edf, 0x86a711f5, 0x8daa18fb, 0x90bd03e9, 0x9bb00ae7, 0x3990d686, 0x329ddf88, 0x2f8ac49a, 0x2487cd94, 0x15a4f2be, 0x1ea9fbb0, 0x3bee0a2, 0x8b3e9ac, 0x61f89ef6, 0x6af597f8, 0x77e28cea, 0x7cef85e4, 0x4dccbace, 0x46c1b3c0, 0x5bd6a8d2, 0x50dba1dc, 0x89404666, 0x824d4f68, 0x9f5a547a, 0x94575d74, 0xa574625e, 0xae796b50, 0xb36e7042, 0xb863794c, 0xd1280e16, 0xda250718, 0xc7321c0a, 0xcc3f1504, 0xfd1c2a2e, 0xf6112320, 0xeb063832, 0xe00b313c, 0x439c77b1, 0x48917ebf, 0x558665ad, 0x5e8b6ca3, 0x6fa85389, 0x64a55a87, 0x79b24195, 0x72bf489b, 0x1bf43fc1, 0x10f936cf, 0xdee2ddd, 0x6e324d3, 0x37c01bf9, 0x3ccd12f7, 0x21da09e5, 0x2ad700eb, 0xf34ce751, 0xf841ee5f, 0xe556f54d, 0xee5bfc43, 0xdf78c369, 0xd475ca67, 0xc962d175, 0xc26fd87b, 0xab24af21, 0xa029a62f, 0xbd3ebd3d, 0xb633b433, 0x87108b19, 0x8c1d8217, 0x910a9905, 0x9a07900b, 0x38274c6a, 0x332a4564, 0x2e3d5e76, 0x25305778, 0x14136852, 0x1f1e615c, 0x2097a4e, 0x9047340, 0x604f041a, 0x6b420d14, 0x76551606, 0x7d581f08, 0x4c7b2022, 0x4776292c, 0x5a61323e, 0x516c3b30, 0x88f7dc8a, 0x83fad584, 0x9eedce96, 0x95e0c798, 0xa4c3f8b2, 0xafcef1bc, 0xb2d9eaae, 0xb9d4e3a0, 0xd09f94fa, 0xdb929df4, 0xc68586e6, 0xcd888fe8, 0xfcabb0c2, 0xf7a6b9cc, 0xeab1a2de, 0xe1bcabd0, 0xb5f1011c, 0xbefc0812, 0xa3eb1300, 0xa8e61a0e, 0x99c52524, 0x92c82c2a, 0x8fdf3738, 0x84d23e36, 0xed99496c, 0xe6944062, 0xfb835b70, 0xf08e527e, 0xc1ad6d54, 0xcaa0645a, 0xd7b77f48, 0xdcba7646, 0x52191fc, 0xe2c98f2, 0x133b83e0, 0x18368aee, 0x2915b5c4, 0x2218bcca, 0x3f0fa7d8, 0x3402aed6, 0x5d49d98c, 0x5644d082, 0x4b53cb90, 0x405ec29e, 0x717dfdb4, 0x7a70f4ba, 0x6767efa8, 0x6c6ae6a6, 0xce4a3ac7, 0xc54733c9, 0xd85028db, 0xd35d21d5, 0xe27e1eff, 0xe97317f1, 0xf4640ce3, 0xff6905ed, 0x962272b7, 0x9d2f7bb9, 0x803860ab, 0x8b3569a5, 0xba16568f, 0xb11b5f81, 0xac0c4493, 0xa7014d9d, 0x7e9aaa27, 0x7597a329, 0x6880b83b, 0x638db135, 0x52ae8e1f, 0x59a38711, 0x44b49c03, 0x4fb9950d, 0x26f2e257, 0x2dffeb59, 0x30e8f04b, 0x3be5f945, 0xac6c66f, 0x1cbcf61, 0x1cdcd473, 0x17d1dd7d}; unsigned char table_s1[] = {0x66,0xac,0x60,0xcb,0x1d,0x74,0x99,0xfc,0x54,0x21,0x15,0xef,0x46,0xcc,0x63,0x55,0x5,0x3,0x17,0x80,0x25,0x84,0xf1,0x76,0x6f,0xb3,0xfe,0x14,0x1c,0x9e,0x4f,0xa2,0x1f,0x73,0xd0,0xe7,0xa,0xb6,0x4d,0x30,0xc,0x2,0x7c,0xca,0x9f,0xa0,0xe5,0xb4,0x5f,0xb0,0xbc,0x9d,0xf3,0xf9,0x95,0x6e,0xdd,0xd2,0x77,0xba,0x1e,0xec,0xf,0xc0,0xb1,0x98,0xe4,0x39,0x7f,0x4e,0x28,0x64,0xbd,0x24,0x20,0x8a,0x2c,0x33,0x38,0x34,0xd3,0xeb,0x3d,0x8f,0xe2,0x9b,0xed,0xe0,0xb5,0x16,0x8,0xbf,0x85,0xcd,0x86,0x32,0x3e,0x97,0x7e,0x5a,0x7b,0xea,0xaa,0xbe,0x79,0x70,0xb8,0x83,0xf8,0xb2,0xdc,0x69,0xa4,0x68,0xfd,0x3a,0x48,0x5d,0xcf,0xad,0x57,0xd9,0x4a,0xd5,0x4b,0x88,0x6c,0x8c,0x4,0xf2,0xc4,0xc5,0xa7,0x92,0x3b,0x50,0x53,0xe9,0xfb,0x89,0xf5,0x37,0x6a,0x61,0xc9,0x8e,0x52,0xd1,0x2e,0x7a,0x18,0xf6,0x7,0x4c,0xb9,0x41,0x3f,0x71,0xfa,0x29,0x81,0x1a,0x67,0x90,0xd4,0x51,0xc8,0xa6,0x26,0x96,0xc1,0xdb,0xae,0xb7,0xd7,0x5e,0xff,0x1b,0xf4,0x59,0xe,0xd6,0x62,0x40,0xf0,0xa9,0xd,0x27,0xc3,0xee,0xc6,0x42,0x2b,0x12,0x56,0x3c,0x8b,0xe8,0x31,0x72,0x10,0xd8,0xb,0x58,0x82,0x43,0x5c,0xa3,0x91,0x11,0x44,0x94,0x9,0xa1,0xf7,0x5b,0x6d,0x65,0xdf,0xc7,0x2f,0xce,0x0,0x93,0xde,0xda,0xab,0x36,0x8d,0x9c,0xe3,0x2d,0x6,0x49,0x6b,0x13,0xaf,0x7d,0x75,0x45,0x2a,0x35,0xe1,0x47,0x23,0x19,0xbb,0xa5,0xc2,0x9a,0x1,0xe6,0xa8,0x87,0x78,0x22,0xc7,0xa9,0x30,0xb5,0xf1,0x6,0x7b,0xe0,0x3f,0xb6,0xd6,0xcf,0xba,0xa0,0xf7,0x47,0x21,0x3,0xb7,0x6f,0x38,0x95,0x7a,0x9e,0x23,0xa7,0x8f,0xa2,0x46,0x6c,0xc8,0x91,0x31,0x5a,0xf3,0xc6,0xa4,0xa5,0x93,0x65,0x0,0xb,0x56,0x94,0xe8,0x9a,0x88,0x32,0x97,0x79,0x1b,0x4f,0xb0,0x33,0xef,0xa8,0x48,0x9b,0x10,0x5e,0x20,0xd8,0x2d,0x66,0x4c,0x82,0xfd,0xec,0x57,0xca,0xbb,0xbf,0x24,0x14,0x1c,0xce,0x72,0xa,0x28,0x67,0xc4,0xda,0x78,0x42,0x26,0x80,0x54,0x4b,0x43,0x19,0xe6,0xc9,0x87,0x60,0xfb,0xa3,0x13,0x50,0x89,0xea,0x5d,0x37,0x73,0x4a,0xc2,0x3d,0x22,0xe3,0x39,0x6a,0xb9,0x71,0x3a,0x96,0xc0,0x68,0xf5,0x25,0x70,0xf0,0xf2,0x61,0xaf,0x4e,0xa6,0xbe,0x4,0xc,0x51,0x2c,0xd7,0x6b,0x86,0xb1,0x12,0x7e,0xd5,0x84,0xc1,0xfe,0xab,0x1d,0x63,0x6d,0xf,0xf4,0x98,0x92,0xfc,0xdd,0xd1,0x3e,0xa1,0x6e,0x8d,0x7f,0xdb,0x16,0xb3,0xbc,0x9d,0xf8,0x15,0x7c,0xaa,0x1,0xcd,0x7,0x34,0x2,0xad,0x27,0x8e,0x74,0x40,0x35,0x17,0x90,0xe5,0x44,0xe1,0x76,0x62,0x64,0xc3,0x2e,0xff,0x7d,0x75,0x9f,0xd2,0xe,0xdf,0xcb,0x8b,0x1a,0x3b,0x1f,0xf6,0x5f,0x8,0xbd,0xd3,0x99,0xe2,0xd9,0x11,0x18,0xcc,0xae,0x3c,0x29,0x5b,0x9c,0x9,0xc5,0xed,0xd,0xe9,0x2a,0xb4,0x2b,0xb8,0x36,0x5,0x49,0x2f,0x1e,0x58,0x85,0xf9,0xd0,0x55,0x59,0x52,0x4d,0xeb,0x41,0x45,0xdc,0x81,0x8c,0xfa,0x83,0xee,0x5c,0x8a,0xb2,0x53,0xe7,0xac,0xe4,0xde,0x69,0x77,0xd4,0x17,0xa7,0xf0,0xea,0x9f,0x86,0xe6,0x6f,0xb0,0x2b,0x56,0xa1,0xe5,0x60,0xf9,0x97,0xc1,0x98,0x3c,0x16,0xf2,0xdf,0xf7,0x73,0xce,0x2a,0xc5,0x68,0x3f,0xe7,0x53,0x71,0x62,0xd8,0xca,0xb8,0xc4,0x6,0x5b,0x50,0x35,0xc3,0xf5,0xf4,0x96,0xa3,0xa,0x61,0x36,0x7d,0x88,0x70,0xe,0x40,0xcb,0x18,0xf8,0xbf,0x63,0xe0,0x1f,0x4b,0x29,0xc7,0x37,0x78,0x5a,0x22,0x9e,0x4c,0x44,0x74,0xef,0xeb,0x9a,0x7,0xbc,0xad,0xd2,0x1c,0xf3,0xab,0x30,0xd7,0x99,0xb6,0x49,0x13,0x1b,0x4,0xd0,0x76,0x12,0x28,0x8a,0x94,0x21,0xe9,0x3a,0x69,0xb3,0x72,0x6d,0x92,0x1a,0x23,0x67,0xd,0xba,0xd9,0x0,0x43,0x5c,0x54,0xee,0xf6,0x1e,0xff,0x31,0xa2,0xa0,0x20,0x75,0xa5,0x38,0x90,0xc6,0x6a,0x3d,0x33,0x4d,0xfb,0xae,0x91,0xd4,0x85,0x2e,0x42,0xe1,0xd6,0x3b,0x87,0x7c,0x1,0xec,0xe3,0x46,0x8b,0x2f,0xdd,0x3e,0xf1,0x6e,0x81,0x8d,0xac,0xc2,0xc8,0xa4,0x5f,0x65,0x10,0x24,0xde,0x77,0xfd,0x52,0x64,0x57,0x9d,0x51,0xfa,0x2c,0x45,0xa8,0xcd,0x5e,0x82,0xcf,0x25,0x2d,0xaf,0x7e,0x93,0x34,0x32,0x26,0xb1,0x14,0xb5,0xc0,0x47,0x48,0x41,0x89,0xb2,0xc9,0x83,0xed,0x58,0xf,0xa6,0x4f,0x6b,0x4a,0xdb,0x9b,0x8f,0x66,0xe8,0x7b,0xe4,0x7a,0xb9,0x5d,0xbd,0x95,0x59,0xcc,0xb,0x79,0x6c,0xfe,0x9c,0x8c,0x15,0x11,0xbb,0x1d,0x2,0x9,0x5,0x80,0xa9,0xd5,0x8,0x4e,0x7f,0x19,0x55,0x84,0x27,0x39,0x8e,0xb4,0xfc,0xb7,0x3,0xe2,0xda,0xc,0xbe,0xd3,0xaa,0xdc,0xd1,0x1c,0xf8,0x5e,0xf3,0xd1,0x9,0x47,0x65,0xae,0xf7,0x20,0xa,0xe9,0xc4,0x45,0xc1,0x1d,0x86,0x97,0x60,0x56,0xd3,0xa1,0xcf,0x91,0x21,0xdc,0xc6,0xb0,0xa9,0x59,0xd0,0x89,0xce,0xd6,0x55,0x7d,0x29,0xf1,0x1f,0x4b,0x0,0x46,0xbe,0x76,0x38,0x2e,0xfd,0xf5,0x3,0xc2,0xc3,0x95,0xa0,0x57,0x3c,0xee,0x54,0x8e,0xfc,0x30,0xf2,0x66,0x6d,0x32,0x2d,0x40,0xe6,0x1e,0x24,0xa2,0xbc,0x9d,0xc5,0xe1,0x6,0x80,0xaf,0x25,0x7f,0xdd,0xd9,0x31,0xac,0x9b,0x8a,0x2a,0xe4,0x4e,0x1,0x14,0x6c,0x7a,0xa8,0x42,0x72,0x16,0x96,0x93,0x43,0xa6,0xe,0x5c,0xf0,0x62,0x6a,0xc0,0xd8,0xc9,0x28,0x94,0x7,0x15,0x2c,0x3b,0x51,0xef,0x8c,0x75,0x36,0xdf,0x17,0x5f,0xc,0x44,0x85,0xa4,0x5b,0xb7,0x58,0x9a,0xbb,0xfe,0xf4,0x69,0x92,0xd5,0xda,0xbd,0x70,0xeb,0x19,0xc7,0x8,0x74,0x18,0xe0,0xd7,0xb1,0xd,0x37,0x4a,0x5,0xb,0xcd,0x7b,0xa7,0x98,0xb3,0xe2,0x4,0x2,0x87,0x10,0x83,0x22,0x71,0xf6,0xb4,0x68,0x13,0xf9,0x99,0x1b,0xa5,0x48,0xab,0x61,0xcc,0x67,0x73,0x1a,0xfb,0x9e,0x26,0x53,0xe8,0x12,0xcb,0x41,0x52,0x64,0x6f,0xa3,0x3d,0xfa,0x5a,0x4f,0xaa,0xc8,0xde,0x50,0xd2,0x4d,0x8f,0x4c,0x8b,0x6b,0x90,0x39,0x5d,0x79,0xed,0x7c,0xb9,0xad,0x77,0x7e,0x84,0xbf,0xb5,0xff,0x6e,0xdb,0xec,0xd4,0x88,0x3a,0x9c,0xe5,0xe7,0xea,0x11,0xb2,0xb8,0xf,0xca,0x82,0x35,0x81,0x9f,0xb6,0x3e,0xe3,0x49,0x78,0x63,0x2f,0x23,0xba,0x8d,0x27,0x34,0x2b,0x33,0x3f,0x3c,0x23,0xf7,0x51,0x35,0xf,0xad,0xb3,0xd4,0x8c,0x17,0xf0,0xbe,0x91,0x6e,0x34,0xc8,0xcc,0xbd,0x20,0x9b,0x8a,0xf5,0x3b,0x10,0x5f,0x7d,0x5,0xb9,0x6b,0x63,0x53,0x87,0x7,0x52,0x82,0x1f,0xb7,0xe1,0x4d,0x7b,0x73,0xc9,0xd1,0x39,0xd8,0x16,0x85,0x3d,0x4,0x40,0x2a,0x9d,0xfe,0x27,0x64,0x6,0xce,0x1d,0x4e,0x94,0x55,0x4a,0xb5,0xe9,0xd,0xe2,0x4f,0x18,0xc0,0x74,0x56,0xe6,0xbf,0x1b,0x31,0xd5,0xf8,0xd0,0x54,0x97,0xc,0x71,0x86,0xc2,0x47,0xde,0xb0,0x30,0x80,0xd7,0xcd,0xb8,0xa1,0xc1,0x48,0xdf,0x98,0x44,0xc7,0x38,0x6c,0xe,0xe0,0x11,0x5a,0xaf,0x57,0x29,0x67,0xec,0x3f,0x12,0xe4,0xd2,0xd3,0xb1,0x84,0x2d,0x46,0x45,0xff,0xed,0x9f,0xe3,0x21,0x7c,0x77,0xb2,0x7e,0xeb,0x2c,0x5e,0x4b,0xd9,0xbb,0x41,0xcf,0x5c,0xc3,0x5d,0x9e,0x7a,0x9a,0x28,0x81,0x68,0x4c,0x6d,0xfc,0xbc,0xa8,0x6f,0x66,0xae,0x95,0xee,0xa4,0xca,0x7f,0xc5,0xfd,0x2b,0x99,0xf4,0x8d,0xfb,0xf6,0xa3,0x0,0x1e,0xa9,0x93,0xdb,0x90,0x24,0xa7,0x8e,0xf2,0x2f,0x69,0x58,0x3e,0x72,0xab,0x32,0x36,0x9c,0x3a,0x25,0x2e,0x22,0x49,0xa6,0xaa,0x8b,0xe5,0xef,0x83,0x78,0xcb,0xc4,0x61,0xac,0x8,0xfa,0x19,0xd6,0x9,0x65,0xc6,0xf1,0x1c,0xa0,0x5b,0x26,0x1a,0x14,0x6a,0xdc,0x89,0xb6,0xf3,0xa2,0x13,0x15,0x1,0x96,0x33,0x92,0xe7,0x60,0x79,0xa5,0xe8,0x2,0xa,0x88,0x59,0xb4,0x70,0xba,0x76,0xdd,0xb,0x62,0x8f,0xea,0x42,0x37,0x3,0xf9,0x50,0xda,0x75,0x43,0x37,0xac,0xbd,0x4a,0x7c,0xf9,0x8b,0xe5,0xbb,0xb,0xf6,0xec,0x9a,0x83,0x73,0xfa,0x36,0xd2,0x74,0xd9,0xfb,0x23,0x6d,0x4f,0x84,0xdd,0xa,0x20,0xc3,0xee,0x6f,0xeb,0xdf,0x29,0xe8,0xe9,0xbf,0x8a,0x7d,0x16,0xc4,0x7e,0xa4,0xd6,0x1a,0xd8,0x4c,0x47,0xa3,0xe4,0xfc,0x7f,0x57,0x3,0xdb,0x35,0x61,0x2a,0x6c,0x94,0x5c,0x12,0x4,0xd7,0xf7,0xf3,0x1b,0x86,0xb1,0xa0,0x0,0xce,0x64,0x2b,0x3e,0x46,0x50,0x82,0x68,0x58,0x18,0x7,0x6a,0xcc,0x34,0xe,0x88,0x96,0xb7,0xef,0xcb,0x2c,0xaa,0x85,0xf,0x55,0x3f,0x6,0x11,0x7b,0xc5,0xa6,0x5f,0x1c,0xf5,0x3d,0x75,0x26,0x6e,0xaf,0x8e,0x71,0x3c,0xbc,0xb9,0x69,0x8c,0x24,0x76,0xda,0x48,0x40,0xea,0xf2,0xe3,0x2,0xbe,0x2d,0x5e,0x32,0xca,0xfd,0x9b,0x27,0x1d,0x60,0x2f,0x21,0xe7,0x51,0x8d,0xb2,0x99,0xc8,0x9d,0x72,0xb0,0x91,0xd4,0xde,0x43,0xb8,0xff,0xf0,0x97,0x5a,0xc1,0x33,0xed,0x22,0x81,0x4b,0xe6,0x4d,0x59,0x30,0xd1,0xb4,0xc,0x79,0xc2,0x38,0xe1,0x6b,0x78,0x4e,0x2e,0x28,0xad,0x3a,0xa9,0x8,0x5b,0xdc,0x9e,0x42,0x39,0xd3,0xb3,0x31,0x8f,0x62,0xba,0x13,0x77,0x53,0xc7,0x56,0x93,0x87,0x5d,0x54,0xae,0x95,0x9f,0xd5,0x44,0xf1,0x45,0x89,0x17,0xd0,0x70,0x65,0x80,0xe2,0xf4,0x7a,0xf8,0x67,0xa5,0x66,0xa1,0x41,0xb5,0x9c,0x14,0xc9,0x63,0x52,0x49,0x5,0x9,0x90,0xa7,0xd,0x1e,0x1,0x19,0x15,0xc6,0xfe,0xa2,0x10,0xb6,0xcf,0xcd,0xc0,0x3b,0x98,0x92,0x25,0xe0,0xa8,0x1f,0xab,0xb3,0x52,0xee,0x7d,0x18,0x10,0xba,0xa2,0xdc,0x74,0x26,0x8a,0x6c,0xec,0xe9,0x39,0x3e,0xff,0xde,0x21,0xa5,0x6d,0x25,0x76,0x95,0xf6,0xf,0x4c,0x6f,0x56,0x41,0x2b,0xfa,0xd5,0x5f,0x5,0xe7,0xbf,0x9b,0x7c,0x64,0x5e,0xd8,0xc6,0x48,0x57,0x3a,0x9c,0x0,0xd2,0x38,0x8,0x34,0x7b,0x6e,0x16,0xe1,0xf0,0x50,0x9e,0xa7,0xa3,0x4b,0xd6,0xc,0x42,0x54,0x87,0x31,0x7a,0x3c,0xc4,0x7,0x53,0x8b,0x65,0xf3,0xb4,0xac,0x2f,0x4a,0x88,0x1c,0x17,0x94,0x2e,0xf4,0x86,0xef,0xda,0x2d,0x46,0x8f,0x79,0xb8,0xb9,0x93,0xbe,0x3f,0xbb,0xd4,0x8d,0x5a,0x70,0xab,0x73,0x3d,0x1f,0x66,0x82,0x24,0x89,0xca,0xd3,0x23,0xaa,0xeb,0x5b,0xa6,0xbc,0x2c,0xa9,0xdb,0xb5,0x67,0xfc,0xed,0x1a,0xb0,0xf8,0x4f,0xfb,0x6b,0xc8,0xc2,0x75,0xe6,0x9f,0x9d,0x90,0x96,0xae,0xf2,0x40,0x4e,0x51,0x49,0x45,0x59,0xc0,0xf7,0x5d,0x33,0x2,0x19,0x55,0xe5,0xcc,0x44,0x99,0xf5,0x36,0xf1,0x11,0xa4,0x2a,0xa8,0x37,0x20,0x35,0xd0,0xb2,0x15,0xd9,0x47,0x80,0xcf,0x85,0x14,0xa1,0xd,0x4,0xfe,0xc5,0x97,0x6,0xc3,0xd7,0xea,0x43,0x27,0x3,0xe3,0x61,0xdf,0x32,0xce,0x12,0x69,0x83,0xf9,0x58,0xb,0x8c,0x7e,0x78,0xfd,0x6a,0xb1,0x3b,0x28,0x1e,0x5c,0x29,0x92,0x68,0x9,0x60,0x81,0xe4,0xd1,0x1b,0xb6,0x1d,0x91,0x63,0xbd,0x72,0xaf,0xa0,0xc7,0xa,0x84,0x8e,0x13,0xe8,0xcd,0x22,0xe0,0xc1,0xdd,0xe2,0xc9,0x98,0x7f,0x71,0xb7,0x1,0xcb,0x77,0x4d,0x30,0xe,0x62,0x9a,0xad,0x9a,0x2a,0xd7,0xcd,0xbb,0xa2,0x52,0xdb,0x16,0x8d,0x9c,0x6b,0x5d,0xd8,0xaa,0xc4,0xa5,0xfc,0x2b,0x1,0xe2,0xcf,0x4e,0xca,0x17,0xf3,0x55,0xf8,0xda,0x2,0x4c,0x6e,0xe5,0x5f,0x85,0xf7,0x3b,0xf9,0x6d,0x66,0xfe,0x8,0xc9,0xc8,0x9e,0xab,0x5c,0x37,0x40,0xb,0x4d,0xb5,0x7d,0x33,0x25,0xf6,0x82,0xc5,0xdd,0x5e,0x76,0x22,0xfa,0x14,0x45,0xa,0x1f,0x67,0x71,0xa3,0x49,0x79,0xd6,0xd2,0x3a,0xa7,0x90,0x81,0x21,0xef,0x96,0xce,0xea,0xd,0x8b,0xa4,0x2e,0x74,0x39,0x26,0x4b,0xed,0x15,0x2f,0xa9,0xb7,0xd4,0x1c,0x54,0x7,0x4f,0x8e,0xaf,0x50,0x1e,0x27,0x30,0x5a,0xe4,0x87,0x7e,0x3d,0x69,0x61,0xcb,0xd3,0xc2,0x23,0x9f,0xc,0x1d,0x9d,0x98,0x48,0xad,0x5,0x57,0xfb,0xe,0x0,0xc6,0x70,0xac,0x93,0xb8,0xe9,0x7f,0x13,0xeb,0xdc,0xba,0x6,0x3c,0x41,0xde,0xd1,0xb6,0x7b,0xe0,0x12,0xcc,0x3,0xbc,0x53,0x91,0xb0,0xf5,0xff,0x62,0x99,0x2d,0x58,0xe3,0x19,0xc0,0x4a,0x59,0x6f,0xa0,0x6a,0xc7,0x6c,0x78,0x11,0xf0,0x95,0xbf,0x63,0x18,0xf2,0x92,0x10,0xae,0x43,0xf,0x9,0x8c,0x1b,0x88,0x29,0x7a,0xfd,0x7c,0x75,0x8f,0xb4,0xbe,0xf4,0x65,0xd0,0x9b,0x32,0x56,0x72,0xe6,0x77,0xb2,0xa6,0xd5,0x5b,0xd9,0x46,0x84,0x47,0x80,0x60,0x64,0xa8,0x36,0xf1,0x51,0x44,0xa1,0xc3,0x28,0xb1,0x86,0x2c,0x3f,0x20,0x38,0x34,0x94,0xbd,0x35,0xe8,0x42,0x73,0x68,0x24,0x1a,0xb9,0xb3,0x4,0xc1,0x89,0x3e,0x8a,0xe7,0xdf,0x83,0x31,0x97,0xee,0xec,0xe1,0x44,0x2e,0x39,0x0,0x23,0x60,0x99,0xfa,0x19,0x4a,0x2,0xca,0x4e,0xb1,0x90,0x51,0x56,0x86,0x83,0x3,0xe5,0x49,0x1b,0xb3,0xcd,0xd5,0x7f,0x77,0x12,0x81,0x3d,0xdc,0xb9,0x24,0xcc,0xc8,0xf1,0x3f,0x9f,0x8e,0x79,0x1,0x14,0x5b,0x67,0x57,0xbd,0x6f,0xf3,0x55,0x38,0x27,0xa9,0xb7,0x31,0xb,0x13,0xf4,0xd0,0x88,0x6a,0x30,0xba,0x95,0xd6,0xd7,0x16,0xe0,0x29,0x42,0xb5,0x80,0xe9,0x9b,0x41,0xfb,0x78,0x73,0xe7,0x25,0x40,0xc3,0xdb,0x9c,0xa,0xe4,0x3c,0x68,0xab,0x53,0x15,0x5e,0xe8,0x3b,0x2d,0x63,0x75,0x82,0x93,0x8,0xda,0xb4,0xc6,0x43,0xd3,0xc9,0x34,0x84,0xc5,0x4c,0xbc,0xa5,0xe6,0x4b,0xed,0x9,0x70,0x52,0x1c,0xc4,0x1f,0x35,0xe2,0xbb,0xd4,0x50,0xd1,0xfc,0xf6,0x2b,0xa3,0x8a,0x3a,0x76,0x6d,0x5c,0x32,0x98,0xaf,0x36,0x2a,0x26,0x3e,0x21,0x2f,0x9d,0xc1,0xf9,0xff,0xf2,0xf0,0x89,0x1a,0xad,0xa7,0x4,0x94,0x20,0x97,0xdf,0x6c,0x48,0x2c,0x85,0xb8,0xac,0x69,0xf8,0xaa,0x91,0x6b,0x62,0xce,0x7b,0xea,0xa0,0xef,0x28,0xb6,0x7a,0xdd,0xbf,0x5a,0x4f,0x58,0xc7,0x45,0xcb,0x7e,0x9e,0x59,0x9a,0x72,0xd9,0x74,0xbe,0x8b,0xee,0xf,0x66,0x7,0xfd,0x46,0x33,0x71,0x47,0x54,0xde,0x5,0x92,0x17,0x11,0xe3,0x64,0x37,0x96,0xec,0x6,0x7d,0xa1,0x5d,0xb0,0xe,0x8c,0xc2,0xf5,0xd,0x61,0x5f,0x22,0x18,0xa4,0x6e,0xd8,0x1e,0x10,0xf7,0xa6,0x8d,0xb2,0xae,0x8f,0x4d,0xa2,0x87,0x7c,0xe1,0xeb,0x65,0xa8,0xcf,0xc0,0x1d,0xd2,0xc,0xfe,0x96,0x4a,0x31,0xdb,0xbb,0x39,0x87,0x6a,0x26,0x20,0xa5,0x32,0xa1,0x0,0x53,0xd4,0x4,0x71,0xca,0x30,0xe9,0x63,0x70,0x46,0x89,0x43,0xee,0x45,0x51,0x38,0xd9,0xbc,0xf7,0xf8,0x9f,0x52,0xc9,0x3b,0xe5,0x2a,0x95,0x7a,0xb8,0x99,0xdc,0xd6,0x4b,0xb0,0x27,0x29,0xef,0x59,0x85,0xba,0x91,0xc0,0x56,0x3a,0xc2,0xf5,0x93,0x2f,0x15,0x68,0x33,0x90,0x9a,0x2d,0xe8,0xa0,0x17,0xa3,0xce,0xf6,0xaa,0x18,0xbe,0xc7,0xc5,0xc8,0x1,0x98,0xaf,0x5,0x16,0x9,0x11,0x1d,0xbd,0x94,0x1c,0xc1,0x6b,0x5a,0x41,0xd,0xfc,0x72,0xf0,0x6f,0xad,0x6e,0xa9,0x49,0x4d,0x81,0x1f,0xd8,0x78,0x6d,0x88,0xea,0x55,0x5c,0xa6,0x9d,0x97,0xdd,0x4c,0xf9,0xb2,0x1b,0x7f,0x5b,0xcf,0x5e,0x9b,0x8f,0x69,0x22,0x64,0x9c,0x54,0x1a,0xc,0xdf,0xab,0xec,0xf4,0x77,0x5f,0xb,0xd3,0x3d,0xcc,0x76,0xac,0xde,0x12,0xd0,0x44,0x4f,0xd7,0x21,0xe0,0xe1,0xb7,0x82,0x75,0x1e,0x8c,0xd5,0x2,0x28,0xcb,0xe6,0x67,0xe3,0x3e,0xda,0x7c,0xd1,0xf3,0x2b,0x65,0x47,0xb3,0x3,0xfe,0xe4,0x92,0x8b,0x7b,0xf2,0x3f,0xa4,0xb5,0x42,0x74,0xf1,0x83,0xed,0x40,0x48,0xe2,0xfa,0xeb,0xa,0xb6,0x25,0x34,0xb4,0xb1,0x61,0x84,0x2c,0x7e,0xd2,0xfd,0x35,0x7d,0x2e,0x66,0xa7,0x86,0x79,0x37,0xe,0x19,0x73,0xcd,0xae,0x57,0x14,0xbf,0xe7,0xc3,0x24,0xa2,0x8d,0x7,0x5d,0x10,0xf,0x62,0xc4,0x3c,0x6,0x80,0x9e,0x6c,0x23,0x36,0x4e,0x58,0x8a,0x60,0x50,0xff,0xfb,0x13,0x8e,0xb9,0xa8,0x8,0xc6,0xa9,0x80,0xfc,0x21,0x67,0x56,0x30,0x7c,0xa5,0x3c,0x38,0x92,0x34,0x2b,0x20,0x2c,0xcb,0xf3,0x25,0x97,0xfa,0x83,0xf5,0xf8,0xad,0xe,0x10,0xa7,0x9d,0xd5,0x9e,0x2a,0x26,0x8f,0x66,0x42,0x63,0xf2,0xb2,0xa6,0x61,0x68,0xa0,0x9b,0xe0,0xaa,0xc4,0x71,0xbc,0x70,0xe5,0x22,0x50,0x45,0xd7,0xb5,0x4f,0xc1,0x52,0xcd,0x53,0x90,0x74,0x94,0x7e,0xb4,0x78,0xd3,0x5,0x6c,0x81,0xe4,0x4c,0x39,0xd,0xf7,0x5e,0xd4,0x7b,0x4d,0x1d,0x1b,0xf,0x98,0x3d,0x9c,0xe9,0x6e,0x77,0xab,0xe6,0xc,0x4,0x86,0x57,0xba,0x7,0x6b,0xc8,0xff,0x12,0xae,0x55,0x28,0x14,0x1a,0x64,0xd2,0x87,0xb8,0xfd,0xac,0x47,0xa8,0xa4,0x85,0xeb,0xe1,0x8d,0x76,0xc5,0xca,0x6f,0xa2,0x6,0xf4,0x17,0xd8,0x33,0xa,0x4e,0x24,0x93,0xf0,0x29,0x6a,0x8,0xc0,0x13,0x40,0x9a,0x5b,0x44,0xbb,0x89,0x9,0x5c,0x8c,0x11,0xb9,0xef,0x43,0x75,0x7d,0xc7,0xdf,0x37,0xd6,0x18,0x8b,0xc6,0xc2,0xb3,0x2e,0x95,0x84,0xfb,0x35,0x1e,0x51,0x73,0xb,0xb7,0x65,0x6d,0x5d,0x32,0x2d,0xf9,0x5f,0x3b,0x1,0xa3,0xbd,0xda,0x82,0x19,0xfe,0xb0,0x9f,0x60,0x3a,0x1c,0xea,0xdc,0xdd,0xbf,0x8a,0x23,0x48,0x4b,0xf1,0xe3,0x91,0xed,0x2f,0x72,0x79,0xd1,0x96,0x4a,0xc9,0x36,0x62,0x0,0xee,0x1f,0x54,0xa1,0x59,0x27,0x69,0xe2,0x31,0x99,0x2,0x7f,0x88,0xcc,0x49,0xd0,0xbe,0x3e,0x8e,0xd9,0xc3,0xb6,0xaf,0xcf,0x46,0xe7,0x3,0xec,0x41,0x16,0xce,0x7a,0x58,0xe8,0xb1,0x15,0x3f,0xdb,0xf6,0xde,0x5a,0x7d,0x31,0x2a,0x1b,0xb1,0x6c,0xe4,0xcd,0x6d,0x61,0x79,0x66,0x75,0xdf,0xe8,0x71,0xb8,0xb5,0xb7,0xce,0x68,0xda,0x86,0xbe,0xd3,0x67,0xd0,0x98,0x5d,0xea,0xe0,0x43,0xff,0xeb,0x2e,0xbf,0x2b,0xf,0x6b,0xc2,0x89,0x3c,0xad,0xe7,0xed,0xd6,0x2c,0x25,0x9a,0xf8,0x1d,0x8,0xa8,0x6f,0xf1,0x3d,0x39,0xd9,0x1e,0xdd,0x1f,0x80,0x2,0x8c,0xcc,0xa9,0x48,0x21,0x35,0x9e,0x33,0xf9,0x36,0x0,0x13,0x99,0x40,0xba,0x1,0x74,0xa4,0x23,0x70,0xd1,0x42,0xd5,0x50,0x56,0x1a,0xf7,0x49,0xcb,0xab,0x41,0x3a,0xe6,0x18,0x65,0x5f,0xe3,0x85,0xb2,0x4a,0x26,0xb0,0xe1,0xca,0xf5,0x29,0x9f,0x59,0x57,0xc0,0x3b,0xa6,0xac,0xe9,0xc8,0xa,0xe5,0x5a,0x95,0x4b,0xb9,0x22,0xef,0x88,0x87,0x64,0x27,0xde,0xbd,0x3,0x69,0x7e,0x47,0x9,0xf6,0xd7,0x16,0x5e,0xd,0x45,0x8d,0xa2,0xe,0x5c,0xf4,0x11,0xc1,0xc4,0x44,0x55,0xc6,0x7a,0x9b,0x8a,0x92,0x38,0x30,0xb6,0x78,0xd8,0xc9,0xfe,0x63,0x8b,0x8f,0x20,0x10,0xfa,0x28,0x3e,0x46,0x53,0x1c,0xee,0xf0,0x76,0x4c,0xb4,0x12,0x7f,0x60,0x2d,0x77,0xfd,0xd2,0x54,0xb3,0x97,0xcf,0x6e,0x5,0xf2,0xc7,0x91,0x90,0x51,0xa7,0x3f,0x34,0xa0,0x62,0xae,0xdc,0x6,0xbc,0x4d,0xa3,0x7b,0x2f,0x7,0x84,0x9c,0xdb,0xaf,0x7c,0x6a,0x24,0xec,0x14,0x52,0x19,0x9d,0xf3,0x81,0x4,0x32,0xc5,0xd4,0x4f,0x82,0xb,0xfb,0xe2,0x94,0x8e,0x73,0xc3,0x37,0x15,0x5b,0x83,0xa1,0xc,0xaa,0x4e,0x93,0x17,0x96,0xbb,0x58,0x72,0xa5,0xfc,0x5b,0x97,0x9,0xce,0x6e,0x7b,0x9e,0xfc,0xea,0x64,0xe6,0x79,0xbb,0x78,0xbf,0x5f,0xa4,0xd,0x69,0x4d,0xd9,0x48,0x8d,0x99,0x43,0x4a,0xb0,0x8b,0x81,0xcb,0x5a,0xef,0xd8,0xe0,0xbc,0xe,0xa8,0xd1,0xd3,0xde,0x25,0x86,0x8c,0x3b,0xfe,0xb6,0x1,0xb5,0xab,0x82,0xa,0xd7,0x7d,0x4c,0x57,0x1b,0x17,0x8e,0xb9,0x13,0x0,0x1f,0x7,0xb,0x83,0x6c,0xae,0x8f,0xca,0xc0,0x5d,0xa6,0xe1,0xee,0x89,0x44,0xdf,0x2d,0xf3,0x3c,0x40,0x2c,0xd4,0xe3,0x85,0x39,0x3,0x7e,0x31,0x3f,0xf9,0x4f,0x93,0xac,0x87,0xd6,0x30,0x36,0xb3,0x24,0xb7,0x16,0x45,0xc2,0x80,0x5c,0x27,0xcd,0xad,0x2f,0x91,0x7c,0x9f,0x55,0xf8,0x53,0x47,0x2e,0xcf,0xaa,0x12,0x67,0xdc,0x26,0xff,0x75,0x66,0x50,0x6,0x19,0x74,0xd2,0x2a,0x10,0x96,0x88,0xa9,0xf1,0xd5,0x32,0xb4,0x9b,0x11,0x4b,0xe9,0xed,0x5,0x98,0xaf,0xbe,0x1e,0xd0,0x7a,0x35,0x20,0x58,0x4e,0x9c,0x76,0x46,0x22,0xa2,0xa7,0x77,0x92,0x3a,0x68,0xc4,0x56,0x5e,0xf4,0xec,0xfd,0x1c,0xa0,0x33,0x21,0x18,0xf,0x65,0xdb,0xb8,0x41,0x2,0xeb,0x23,0x6b,0x38,0x70,0xb1,0x90,0x6f,0x28,0xcc,0x6a,0xc7,0xe5,0x3d,0x73,0x51,0x9a,0xc3,0x14,0x3e,0xdd,0xf0,0x71,0xf5,0x29,0xb2,0xa3,0x54,0x62,0xe7,0x95,0xfb,0xa5,0x15,0xe8,0xf2,0x84,0x9d,0x6d,0xe4,0xbd,0xfa,0xe2,0x61,0x49,0x1d,0xc5,0x2b,0x7f,0x34,0x72,0x8a,0x42,0xc,0x1a,0xc9,0xc1,0x37,0xf6,0xf7,0xa1,0x94,0x63,0x8,0xda,0x60,0xba,0xc8,0x4,0xc6,0x52,0x59,0x42,0x2e,0x8d,0xba,0x57,0xeb,0x10,0x6d,0x51,0x5f,0x21,0x97,0xc2,0xfd,0xb8,0xe9,0x2,0xed,0xe1,0xc0,0xae,0xa4,0xc8,0x33,0x80,0x8f,0x2a,0xe7,0x43,0xb1,0x52,0x9d,0x3b,0xf1,0x3d,0x96,0x40,0x29,0xc4,0xa1,0x9,0x7c,0x48,0xb2,0x1b,0x91,0x3e,0x8,0x58,0x5e,0x4a,0xdd,0x78,0xd9,0xac,0x2b,0x32,0xee,0xa3,0x49,0x41,0xc3,0x12,0xff,0x63,0xca,0x23,0x7,0x26,0xb7,0xf7,0xe3,0x24,0x2d,0xe5,0xde,0xa5,0xef,0x81,0x34,0xf9,0x35,0xa0,0x67,0x15,0x0,0x92,0xf0,0xa,0x84,0x17,0x88,0x16,0xd5,0x31,0xd1,0xec,0xc5,0xb9,0x64,0x22,0x13,0x75,0x39,0xe0,0x79,0x7d,0xd7,0x71,0x6e,0x65,0x69,0x8e,0xb6,0x60,0xd2,0xbf,0xc6,0xb0,0xbd,0xe8,0x4b,0x55,0xe2,0xd8,0x90,0xdb,0x6f,0xdc,0x47,0x3a,0xcd,0x89,0xc,0x95,0xfb,0x7b,0xcb,0x9c,0x86,0xf3,0xea,0x8a,0x3,0xa2,0x46,0xa9,0x4,0x53,0x8b,0x3f,0x1d,0xad,0xf4,0x50,0x7a,0x9e,0xb3,0x9b,0x1f,0x59,0xaf,0x99,0x98,0xfa,0xcf,0x66,0xd,0xe,0xb4,0xa6,0xd4,0xa8,0x6a,0x37,0x3c,0x94,0xd3,0xf,0x8c,0x73,0x27,0x45,0xab,0x5a,0x11,0xe4,0x1c,0x62,0x2c,0xa7,0x74,0x83,0x87,0xf6,0x6b,0xd0,0xc1,0xbe,0x70,0x5b,0x14,0x36,0x4e,0xf2,0x20,0x28,0x18,0x77,0x68,0xbc,0x1a,0x7e,0x44,0xe6,0xf8,0x9f,0xc7,0x5c,0xbb,0xf5,0xda,0x25,0x7f,0x76,0x4f,0xb,0x61,0xd6,0xb5,0x6c,0x2f,0x4d,0x85,0x56,0x5,0xdf,0x1e,0x1,0xfe,0xcc,0x4c,0x19,0xc9,0x54,0xfc,0xaa,0x6,0x30,0x38,0x82,0x9a,0x72,0x93,0x5d,0xce,0x43,0x72,0x14,0x58,0x8d,0xa4,0xd8,0x5,0x10,0xf,0x4,0x8,0x81,0x18,0x1c,0xb6,0xde,0xa7,0xd1,0xdc,0xef,0xd7,0x1,0xb3,0xb9,0xf1,0xba,0xe,0x89,0x2a,0x34,0x83,0x47,0xd6,0x96,0x82,0x2,0xab,0x42,0x66,0xc4,0x8e,0xe0,0x55,0x45,0x4c,0x84,0xbf,0x74,0x61,0xf3,0x91,0x98,0x54,0xc1,0x6,0x77,0xb4,0x50,0xb0,0x6b,0xe5,0x76,0xe9,0x21,0x48,0xa5,0xc0,0x5a,0x90,0x5c,0xf7,0x7a,0xf0,0x5f,0x69,0x68,0x1d,0x29,0xd3,0x19,0xb8,0xcd,0x4a,0x39,0x3f,0x2b,0xbc,0x20,0xa2,0x73,0x9e,0x53,0x8f,0xc2,0x28,0x36,0x8a,0x71,0xc,0x23,0x4f,0xec,0xdb,0xa3,0x9c,0xd9,0x88,0x30,0x3e,0x40,0xf6,0xcf,0xc5,0xa9,0x52,0x63,0x8c,0x80,0xa1,0x22,0xd0,0x33,0xfc,0xe1,0xee,0x4b,0x86,0xb7,0xd4,0xd,0x4e,0x17,0x2e,0x6a,0x0,0xbe,0x7f,0x60,0x9f,0x2c,0xe4,0x37,0x64,0x35,0x9d,0xcb,0x67,0xad,0x2d,0x78,0xa8,0x13,0xf2,0x3c,0xaf,0x51,0x59,0xe3,0xfb,0xb1,0xa0,0xdf,0x11,0xe2,0xe6,0x97,0xa,0x93,0x41,0x49,0x79,0x3a,0x75,0x57,0x2f,0x1f,0x25,0x87,0x99,0x16,0x9,0xdd,0x7b,0x94,0xbb,0x44,0x1e,0xfe,0xa6,0x3d,0xda,0x9b,0xae,0x7,0x6c,0x38,0xce,0xf8,0xf9,0xc9,0xb,0x56,0x5d,0x6f,0xd5,0xc7,0xb5,0x12,0x46,0x24,0xca,0xf5,0xb2,0x6e,0xed,0x3,0x4d,0xc6,0x15,0x3b,0x70,0x85,0x7d,0xe8,0x6d,0xf4,0x9a,0xbd,0x26,0x5b,0xac,0x92,0x8b,0xeb,0x62,0x1a,0xaa,0xfd,0xe7,0x32,0xea,0x5e,0x7c,0xc3,0x27,0xc8,0x65,0xff,0xd2,0xfa,0x7e,0xcc,0x95,0x31,0x1b,0x88,0x17,0x84,0xa,0xd1,0x31,0xd5,0x16,0x67,0xa0,0x35,0xf9,0xf0,0x92,0x0,0x15,0xde,0xe5,0x2d,0x24,0x34,0x81,0xef,0xa5,0x7,0x23,0xca,0x63,0xe3,0xf7,0xb7,0x26,0xe2,0x55,0x4b,0xe8,0x6f,0xdb,0x90,0xd8,0xd2,0x60,0xb6,0x8e,0xbd,0xb0,0xc6,0xbf,0xd7,0x7d,0x79,0xe0,0x69,0x65,0x6e,0x71,0x64,0xb9,0xc5,0xec,0x39,0x75,0x13,0x22,0xe7,0x2a,0x8f,0x80,0x9d,0x52,0xb1,0x43,0xc0,0xe1,0xed,0x2,0x33,0xc8,0xa4,0xae,0x97,0x21,0x5f,0x51,0xe9,0xb8,0xfd,0xc2,0xba,0x8d,0x2e,0x42,0x6d,0x10,0xeb,0x57,0x49,0xa3,0xee,0x32,0xff,0x12,0xc3,0x41,0xdd,0x4a,0x5e,0x58,0x2b,0xac,0xd9,0x78,0xb2,0x48,0x7c,0x9,0x8,0x3e,0x91,0x1b,0x96,0x3d,0xf1,0x3b,0xa1,0xc4,0x29,0x40,0xbb,0x5c,0xc7,0x9f,0x7f,0x25,0xda,0xf5,0x1a,0xbc,0x68,0x77,0xf8,0xe6,0x44,0x7e,0x4e,0x36,0x14,0x5b,0x18,0x28,0x20,0xf2,0x6b,0xf6,0x87,0x83,0x70,0xbe,0xc1,0xd0,0x9a,0x82,0x38,0x30,0xce,0x5d,0x93,0x72,0xc9,0x19,0x4c,0xcc,0x6,0xaa,0xfc,0x54,0x5,0x56,0x85,0x4d,0xfe,0x1,0x1e,0xdf,0x61,0xb,0x4f,0x76,0x2f,0x6c,0xb5,0xd6,0x7a,0x50,0xf4,0xad,0x1f,0x9b,0xb3,0x9e,0x4,0xa9,0x46,0xa2,0x1d,0x3f,0x8b,0x53,0x86,0x9c,0xcb,0x7b,0x3,0x8a,0xea,0xf3,0xcd,0x3a,0x47,0xdc,0xfb,0x95,0xc,0x89,0x1c,0xe4,0x11,0x5a,0x74,0xa7,0x2c,0x62,0x8c,0xf,0xd3,0x94,0xab,0x45,0x27,0x73,0xd4,0xa6,0xb4,0xe,0x3c,0x37,0x6a,0xa8,0x98,0x99,0xaf,0x59,0xd,0x66,0xcf,0xfa,0xce,0x57,0x53,0xf9,0x5f,0x40,0x4b,0x47,0xc2,0xeb,0x97,0x4a,0xc,0x3d,0x5b,0x17,0xc6,0x65,0x7b,0xcc,0xf6,0xbe,0xf5,0x41,0xa0,0x98,0x4e,0xfc,0x91,0xe8,0x9e,0x93,0xa,0x3,0xcb,0xf0,0x8b,0xc1,0xaf,0x1a,0x4d,0xe4,0xd,0x29,0x8,0x99,0xd9,0xcd,0x24,0xaa,0x39,0xa6,0x38,0xfb,0x1f,0xff,0xd7,0x1b,0x8e,0x49,0x3b,0x2e,0xbc,0xde,0x27,0x52,0x66,0x9c,0x35,0xbf,0x10,0x26,0x15,0xdf,0x13,0xb8,0x6e,0x7,0xea,0x8f,0x1c,0xc0,0x8d,0x67,0x6f,0xed,0x3c,0xd1,0x76,0x70,0x64,0xf3,0x56,0xf7,0x82,0x5,0x7f,0x71,0xf,0xb9,0xec,0xd3,0x96,0xc7,0x6c,0x0,0xa3,0x94,0x79,0xc5,0x3e,0x43,0xae,0xa1,0x4,0xc9,0x6d,0x9f,0x7c,0xb3,0x2c,0xc3,0xcf,0xee,0x80,0x8a,0xe6,0x1d,0x63,0xab,0x78,0x2b,0xf1,0x30,0x2f,0xd0,0x58,0x61,0x25,0x4f,0xf8,0x9b,0x42,0x1,0x1e,0x16,0xac,0xb4,0x5c,0xbd,0x73,0xe0,0xe2,0x62,0x37,0xe7,0x7a,0xd2,0x84,0x28,0x75,0x3a,0x18,0x60,0xdc,0xe,0x6,0x36,0xad,0xa9,0xd8,0x45,0xfe,0xef,0x90,0x5e,0xb1,0xe9,0x72,0x95,0xdb,0xf4,0xb,0x51,0x59,0x46,0x92,0x34,0x50,0x6a,0xc8,0xd6,0x20,0x9a,0x88,0xfa,0x86,0x44,0x19,0x12,0x77,0x81,0xb7,0xb6,0xd4,0xe1,0x48,0x23,0x74,0x3f,0xca,0x32,0x4c,0x2,0x89,0x5a,0xba,0xfd,0x21,0xa2,0x5d,0x9,0x6b,0x85,0x55,0xe5,0xb2,0xa8,0xdd,0xc4,0xa4,0x2d,0xf2,0x69,0x14,0xe3,0xa7,0x22,0xbb,0xd5,0x83,0xda,0x7e,0x54,0xb0,0x9d,0xb5,0x31,0x8c,0x68,0x87,0x2a,0x7d,0xa5,0x11,0x33,0xc,0x6f,0x96,0xd5,0xf6,0xcf,0xd8,0xb2,0xa7,0x66,0x47,0xb8,0x3c,0xf4,0xbc,0xef,0x45,0xed,0xbf,0x13,0xf5,0x75,0x70,0xa0,0x2a,0xcb,0x77,0xe4,0x81,0x89,0x23,0x3b,0x78,0x69,0xc9,0x7,0x3e,0x3a,0xd2,0x4f,0x99,0x4b,0xa1,0x91,0xad,0xe2,0xf7,0x8f,0xfd,0xc7,0x41,0x5f,0xd1,0xce,0xa3,0x5,0x63,0x4c,0xc6,0x9c,0x7e,0x26,0x2,0xe5,0x76,0x43,0xb4,0xdf,0x16,0xe0,0x21,0x20,0xd3,0x11,0x85,0x8e,0xd,0xb7,0x6d,0x1f,0x9e,0xca,0x12,0xfc,0x6a,0x2d,0x35,0xb6,0x95,0xdb,0xcd,0x1e,0xa8,0xe3,0xa5,0x5d,0xb5,0x30,0x42,0x2c,0xfe,0x65,0x74,0x83,0x53,0x4a,0xba,0x33,0x72,0xc2,0x3f,0x25,0x32,0xea,0xa4,0x86,0xff,0x1b,0xbd,0x10,0xa,0x27,0xa6,0x22,0x4d,0x14,0xc3,0xe9,0xaa,0x9b,0x80,0xcc,0x7c,0x55,0xdd,0x0,0xd7,0xc8,0xd0,0xdc,0xc0,0x59,0x6e,0xc4,0x7f,0x6,0x4,0x9,0xf,0x37,0x6b,0xd9,0x29,0x61,0xd6,0x62,0xf2,0x51,0x5b,0xec,0xe,0x9f,0x5a,0x4e,0x73,0xda,0xbe,0x9a,0x56,0x1c,0x8d,0x38,0x94,0x9d,0x67,0x5c,0xb9,0xac,0x49,0x2b,0x8c,0x40,0xde,0x19,0x6c,0xaf,0x68,0x88,0x3d,0xb3,0x31,0xae,0x90,0xf9,0x18,0x7d,0x48,0x82,0x2f,0x84,0x28,0xa2,0xb1,0x87,0xc5,0xb0,0xb,0xf1,0x60,0xc1,0x92,0x15,0xe7,0xe1,0x64,0xf3,0x7a,0xf8,0x46,0xab,0x57,0x8b,0xf0,0x1a,0x52,0xee,0xd4,0xa9,0x97,0xfb,0x3,0x34,0x44,0x7b,0x50,0x1,0xe6,0xe8,0x2e,0x98,0x1d,0x17,0x8a,0x71,0x54,0xbb,0x79,0x58,0x8,0xfa,0x24,0xeb,0x36,0x39,0x5e,0x93,0x1,0x52,0x1a,0xd2,0x56,0xa9,0x88,0x49,0x5c,0x36,0x21,0x18,0x3b,0x78,0x81,0xe2,0xd5,0xcd,0x67,0x6f,0xa,0x99,0x25,0xc4,0x4e,0x9e,0x9b,0x1b,0xfd,0x51,0x3,0xab,0x61,0x19,0xc,0x43,0x7f,0x4f,0xa5,0x77,0xa1,0x3c,0xd4,0xd0,0xe9,0x27,0x87,0x96,0xb,0xec,0xc8,0x90,0x72,0x28,0xa2,0x8d,0xeb,0x4d,0x20,0x3f,0xb1,0xaf,0x29,0x13,0xf1,0x83,0x59,0xe3,0x60,0x6b,0xff,0x3d,0xce,0xcf,0xe,0xf8,0x31,0x5a,0xad,0x98,0xb3,0x4b,0xd,0x46,0xf0,0x23,0x35,0x7b,0x58,0xdb,0xc3,0x84,0x12,0xfc,0x24,0x70,0xcb,0xd1,0x2c,0x9c,0xdd,0x54,0xa4,0xbd,0x6d,0x9a,0x8b,0x10,0xc2,0xac,0xde,0x5b,0x7,0x2d,0xfa,0xa3,0xcc,0x48,0xc9,0xe4,0xfe,0x53,0xf5,0x11,0x68,0x4a,0x4,0xdc,0x2a,0x80,0xb7,0x2e,0x32,0x3e,0x26,0x39,0xee,0x33,0xbb,0x92,0x22,0x6e,0x75,0x44,0x2,0xb5,0xbf,0x1c,0x8c,0x38,0x8f,0xc7,0x37,0x85,0xd9,0xe1,0xe7,0xea,0xe8,0x91,0xb2,0x89,0x73,0x7a,0xd6,0x63,0xf2,0xb8,0x74,0x50,0x34,0x9d,0xa0,0xb4,0x71,0xe0,0x40,0xdf,0x5d,0xd3,0x66,0x86,0x41,0x82,0xf7,0x30,0xae,0x62,0xc5,0xa7,0x42,0x57,0x1f,0xe5,0x5e,0x2b,0x69,0x5f,0x4c,0xc6,0x6a,0xc1,0x6c,0xa6,0x93,0xf6,0x17,0x7e,0xf4,0x1e,0x65,0xb9,0x45,0xa8,0x16,0x94,0x1d,0x8a,0xf,0x9,0xfb,0x7c,0x2f,0x8e,0x76,0xc0,0x6,0x8,0xef,0xbe,0x95,0xaa,0xda,0xed,0x15,0x79,0x47,0x3a,0x0,0xbc,0x7d,0xb0,0xd7,0xd8,0x5,0xca,0x14,0xe6,0xb6,0x97,0x55,0xba,0x9f,0x64,0xf9,0xf3,0x52,0x53,0x65,0x93,0xc7,0xac,0x5,0x30,0x1e,0x6c,0x7e,0xc4,0xf6,0xfd,0xa0,0x62,0x46,0xc5,0x19,0x5e,0x61,0x8f,0xed,0xb9,0xd6,0x2e,0xdb,0x90,0xbe,0x6d,0xe6,0xa8,0x7,0xf0,0x8d,0x16,0x31,0x5f,0xc6,0x43,0x4c,0x56,0x1,0xb1,0xc9,0x40,0x20,0x39,0xce,0x63,0x8c,0x68,0xd7,0xf5,0x41,0x99,0xb0,0x9a,0x3e,0x67,0xd5,0x51,0x79,0x54,0xab,0xc1,0x85,0xbc,0xe5,0xa6,0x7f,0x1c,0xcf,0x9c,0x4f,0x87,0x34,0xcb,0xd4,0x15,0x3,0xd3,0x86,0x6,0xcc,0x60,0x36,0x9e,0x50,0x48,0xf2,0xfa,0x4,0x97,0x59,0xb8,0xa1,0x3c,0x4d,0x49,0xba,0x74,0xb,0x1a,0x84,0xfc,0xde,0x91,0xd2,0xe2,0xea,0x38,0xd0,0x76,0xa2,0xbd,0x32,0x2c,0x8e,0xb4,0x71,0x96,0xd,0x55,0xb5,0xef,0x10,0x3f,0x5c,0xf7,0x3b,0xf1,0x6b,0xe,0xe3,0x8a,0x78,0x82,0xb6,0xc3,0xc2,0xf4,0x5b,0xd1,0x17,0x80,0x94,0x92,0xe1,0x66,0x13,0xb2,0x83,0x69,0x24,0xf8,0x35,0xd8,0x9,0x8b,0x70,0x47,0xe4,0x88,0xa7,0xda,0x21,0x9d,0x5d,0xeb,0x95,0x9b,0x23,0x72,0x37,0x8,0xa,0x2b,0x27,0xc8,0xf9,0x2,0x6e,0x64,0x2d,0xe0,0x45,0x4a,0x57,0x98,0x7b,0x89,0xae,0x73,0xf,0x26,0xf3,0xbf,0xd9,0xe8,0x1d,0xb7,0xb3,0x2a,0xa3,0xaf,0xa4,0xbb,0x18,0xaa,0x7c,0x44,0x77,0x7a,0xc,0x75,0x28,0x9f,0x81,0x22,0xa5,0x11,0x5a,0x12,0xcd,0xe9,0x0,0xa9,0x29,0x3d,0x7d,0xec,0x14,0x2f,0xe7,0xee,0xfe,0x4b,0x25,0x6f,0xad,0x6a,0xff,0x33,0x3a,0x58,0xca,0xdf,0x42,0xdd,0x4e,0xc0,0x1b,0xfb,0x1f,0xdc,0xab,0x6,0xe9,0xd,0xb2,0x90,0x24,0xfc,0xd5,0xff,0x5b,0x2,0xb0,0x34,0x1c,0x31,0x62,0x95,0xe8,0x73,0x54,0x3a,0xa3,0x26,0x29,0x33,0x64,0xd4,0xac,0x25,0x45,0x5c,0x23,0xa0,0x7c,0x3b,0x4,0xea,0x88,0xdc,0xb3,0x4b,0xbe,0xf5,0xdb,0x8,0x83,0xcd,0x37,0x36,0x0,0xf6,0xa2,0xc9,0x60,0x55,0x7b,0x9,0x1b,0xa1,0x93,0x98,0xc5,0x7,0xb5,0x13,0xc7,0xd8,0x57,0x49,0xeb,0xd1,0x14,0xf3,0x68,0x30,0xd0,0x8a,0x75,0x5a,0xc4,0x59,0x28,0x2c,0xdf,0x11,0x6e,0x7f,0xe1,0x99,0xbb,0xf4,0xb7,0x87,0x8f,0x5d,0x66,0xb6,0xe3,0x63,0xa9,0x5,0x53,0xfb,0x35,0x2d,0x97,0x9f,0x61,0xf2,0x3c,0xdd,0xce,0xa4,0xe0,0xd9,0x80,0xc3,0x1a,0x79,0xaa,0xf9,0x2a,0xe2,0x51,0xae,0xb1,0x70,0x6f,0x4e,0x42,0xad,0x9c,0x67,0xb,0x1,0x48,0x85,0x20,0x2f,0x32,0xfd,0x1e,0xec,0x15,0x22,0x81,0xed,0xc2,0xbf,0x44,0xf8,0x38,0x8e,0xf0,0xfe,0x46,0x17,0x52,0x6d,0x72,0xe5,0xf1,0xf7,0x84,0x3,0x76,0xd7,0xe6,0xc,0x41,0x9d,0x50,0xbd,0x6c,0xee,0x39,0x92,0x5e,0x94,0xe,0x6b,0x86,0xef,0x1d,0xe7,0xd3,0xa6,0xa7,0x91,0x3e,0xb4,0xc8,0xf,0x9a,0x56,0x5f,0x3d,0xaf,0xba,0x27,0xb8,0x2b,0xa5,0x7e,0x9e,0x7a,0xb9,0xa8,0x8c,0x65,0xcc,0x4c,0x58,0x18,0x89,0x71,0x4a,0x82,0x8b,0x9b,0x2e,0x40,0xa,0x7d,0xcf,0x19,0x21,0x12,0x1f,0x69,0x10,0x4d,0xfa,0xe4,0x47,0xc0,0x74,0x3f,0x77,0xcb,0x16,0x6a,0x43,0x96,0xda,0xbc,0x8d,0x78,0xd2,0xd6,0x4f,0xc6,0xca,0xc1,0xde,0xe8,0xd3,0x1b,0x12,0x2,0xb7,0xd9,0x93,0x31,0x15,0xfc,0x55,0xd5,0xc1,0x81,0x10,0xbe,0x21,0xb2,0x3c,0xe7,0x7,0xe3,0x20,0x51,0x96,0x3,0xcf,0xc6,0xa4,0x36,0x23,0xe1,0x4b,0x4f,0xd6,0x5f,0x53,0x58,0x47,0x52,0x8f,0xf3,0xda,0xf,0x43,0x25,0x14,0xd4,0x63,0x7d,0xde,0x59,0xed,0xa6,0xee,0xe4,0x56,0x80,0xb8,0x8b,0x86,0xf0,0x89,0xa1,0x17,0x69,0x67,0xdf,0x8e,0xcb,0xf4,0x8c,0xbb,0x18,0x74,0x5b,0x26,0xdd,0x61,0xd1,0x1c,0xb9,0xb6,0xab,0x64,0x87,0x75,0xf6,0xd7,0xdb,0x34,0x5,0xfe,0x92,0x98,0x84,0x7e,0x4a,0x3f,0x3e,0x8,0xa7,0x2d,0xa0,0xb,0xc7,0xd,0x97,0xf2,0x1f,0x76,0x7f,0x95,0xd8,0x4,0xc9,0x24,0xf5,0x77,0xeb,0x7c,0x68,0x6e,0x1d,0x9a,0xef,0x4e,0x78,0x0,0x22,0x6d,0x2e,0x1e,0x16,0xc4,0x5d,0xc0,0xb1,0xb5,0x46,0x88,0xf7,0xe6,0x8d,0x6a,0xf1,0xa9,0x49,0x13,0xec,0xc3,0x2c,0x8a,0x5e,0x41,0xce,0xd0,0x72,0x48,0x33,0x60,0xb3,0x7b,0xc8,0x37,0x28,0xe9,0x57,0x3d,0x79,0x40,0x19,0x5a,0x83,0xe0,0xac,0xb4,0xe,0x6,0xf8,0x6b,0xa5,0x44,0xff,0x2f,0x7a,0xfa,0x30,0x9c,0xca,0x62,0xb0,0xaa,0xfd,0x4d,0x35,0xbc,0xdc,0xc5,0xfb,0xc,0x71,0xea,0xcd,0xa3,0x3a,0xbf,0x4c,0x66,0xc2,0x9b,0x29,0xad,0x85,0xa8,0x32,0x9f,0x70,0x94,0x2b,0x9,0xbd,0x65,0xe2,0x90,0x82,0x38,0xa,0x1,0x5c,0x9e,0xae,0xaf,0x99,0x6f,0x3b,0x50,0xf9,0xcc,0x2a,0xd2,0x27,0x6c,0x42,0x91,0x1a,0x54,0xba,0x39,0xe5,0xa2,0x9d,0x73,0x11,0x45,0xd8,0x96,0x1d,0xce,0xe0,0xab,0x5e,0xa6,0xc9,0x9d,0xff,0x11,0x2e,0x69,0xb5,0x36,0x12,0xd0,0x8d,0x86,0xb4,0xe,0x1c,0x6e,0x40,0x75,0xdc,0xb7,0xe3,0x15,0x23,0x22,0x24,0x9,0x21,0xa5,0x17,0x4e,0xea,0xc0,0xe9,0x31,0x85,0xa7,0x18,0xfc,0x13,0xbe,0x49,0x50,0x30,0xb9,0xc1,0x71,0x26,0x3c,0x33,0xb6,0x2f,0x41,0x66,0xfd,0x80,0x77,0xc8,0x29,0xe7,0x74,0x8a,0x82,0x38,0x20,0xee,0x46,0x10,0xbc,0x76,0xf6,0xa3,0x73,0x65,0xa4,0xbb,0x44,0xf7,0x3f,0xec,0xbf,0x6c,0xf,0xd6,0x95,0xcc,0xf5,0xb1,0xdb,0x4f,0x60,0x9f,0xc5,0x25,0x7d,0xe6,0x1,0xc4,0xfe,0x5c,0x42,0xcd,0xd2,0x6,0xa0,0x48,0x9a,0x92,0xa2,0xe1,0xae,0x8c,0xf4,0x6a,0x7b,0x4,0xca,0x39,0x3d,0x4c,0xd1,0xfb,0x79,0xa8,0x45,0x88,0x54,0x19,0xf3,0xc2,0x63,0x16,0x91,0xe2,0xe4,0xf0,0x67,0xa1,0x2b,0x84,0xb2,0xb3,0xc6,0xf2,0x8,0xfa,0x93,0x7e,0x1b,0x81,0x4b,0x87,0x2c,0xf9,0xb,0xe8,0x27,0x3a,0x35,0x90,0x5d,0x14,0x1e,0x72,0x89,0xb8,0x57,0x5b,0x7a,0x78,0x47,0x2,0x53,0xeb,0xe5,0x9b,0x2d,0xed,0x51,0xaa,0xd7,0xf8,0x94,0x37,0x0,0x62,0x2a,0x61,0xd5,0x52,0xf1,0xef,0x58,0x5,0x7c,0xa,0x7,0x34,0xc,0xda,0x68,0xcb,0xd4,0xdf,0xd3,0x5a,0xc3,0xc7,0x6d,0x98,0xa9,0xcf,0x83,0x56,0x7f,0x3,0xde,0xac,0x6f,0x8b,0x6b,0xb0,0x3e,0xad,0x32,0xaf,0xba,0x28,0x4a,0x43,0x8f,0x1a,0xdd,0x1f,0x55,0x3b,0x8e,0x9e,0x97,0x5f,0x64,0x9c,0xd,0x4d,0x59,0xd9,0x70,0x99,0xbd,0x26,0x7c,0xf6,0xd9,0x5f,0xb8,0x9c,0xc4,0xe5,0xfb,0x7d,0x47,0xbf,0x19,0x74,0x6b,0x2b,0x1b,0xf1,0x23,0x35,0x4d,0x58,0x17,0xbd,0x73,0xd3,0xc2,0xf5,0x68,0x80,0x84,0x5e,0xcd,0x71,0x90,0x81,0x99,0x33,0x3b,0xa9,0x5,0x57,0xff,0x1a,0xca,0xcf,0x4f,0x2,0xfd,0xdc,0x1d,0x55,0x6,0x4e,0x86,0x6f,0x2c,0xd5,0xb6,0x8,0x62,0x75,0x4c,0x98,0x1c,0x9d,0xb0,0x53,0x79,0xae,0xf7,0x3c,0x1e,0x50,0x88,0xaa,0x7,0xa1,0x45,0x89,0x0,0xf0,0xe9,0x9f,0x85,0x78,0xc8,0x96,0xf8,0x8a,0xf,0x39,0xce,0xdf,0x44,0xa4,0x77,0x61,0x2f,0xe7,0x1f,0x59,0x12,0x46,0xa8,0x70,0x24,0xc,0x8f,0x97,0xd0,0x34,0x3f,0xab,0x69,0xa5,0xd7,0xd,0xb7,0x65,0xe,0xf9,0xcc,0x9a,0x9b,0x5a,0xac,0x32,0xd2,0x15,0xd6,0x14,0x8b,0x9,0x87,0x91,0xf3,0x16,0x3,0xa3,0x64,0xfa,0x36,0x82,0x37,0xa6,0xec,0xe6,0xdd,0x27,0x2e,0xf4,0xe0,0x25,0xb4,0x20,0x4,0x60,0xc9,0xd8,0x6c,0xdb,0x93,0x56,0xe1,0xeb,0x48,0xb3,0xbe,0xbc,0xc5,0x63,0xd1,0x8d,0xb5,0x66,0x6a,0x72,0x6d,0x7e,0xd4,0xe3,0x7a,0x76,0x3a,0x21,0x10,0xba,0x67,0xef,0xc6,0x51,0x9e,0x40,0xb2,0x29,0xe4,0x83,0x8c,0xcb,0x30,0xad,0xa7,0xe2,0xc3,0x1,0xee,0xbb,0xea,0xc1,0xfe,0x22,0x94,0x52,0x5c,0x13,0x6e,0x54,0xe8,0x8e,0xb9,0x41,0x2d,0x11,0xfc,0x42,0xc0,0xa0,0x4a,0x31,0xed,0xaf,0x28,0x7b,0xda,0x49,0xde,0x5b,0x5d,0x3d,0xb,0x18,0x92,0x4b,0xb1,0xa,0x7f,0xc7,0xa2,0x43,0x2a,0x3e,0x95,0x38,0xf2,0xe9,0xe1,0x5b,0x43,0xab,0x4a,0x84,0x17,0x15,0x95,0xc0,0x10,0x8d,0x25,0x73,0xdf,0x94,0x5c,0x8f,0xdc,0x6,0xc7,0xd8,0x27,0xaf,0x96,0xd2,0xb8,0xf,0x6c,0xb5,0xf6,0x46,0x1e,0x85,0x62,0x2c,0x3,0xfc,0xa6,0xae,0xb1,0x65,0xc3,0xa7,0x9d,0x3f,0x21,0x82,0xcd,0xef,0x97,0x2b,0xf9,0xf1,0xc1,0x5a,0x5e,0x2f,0xb2,0x9,0x18,0x67,0xa9,0x83,0xc8,0x3d,0xc5,0xbb,0xf5,0x7e,0xad,0x4d,0xa,0xd6,0x55,0xaa,0xfe,0x9c,0x72,0xd7,0x6d,0x7f,0xd,0x71,0xb3,0xee,0xe5,0x80,0x76,0x40,0x41,0x23,0x16,0xbf,0xd4,0x74,0x2d,0x89,0xa3,0x47,0x6a,0x42,0xc6,0x7b,0x9f,0x70,0xdd,0x8a,0x52,0xe6,0xc4,0xa2,0x12,0x45,0x5f,0x2a,0x33,0x53,0xda,0x5,0x9e,0xe3,0x14,0x50,0xd5,0x4c,0x22,0x31,0x92,0x8c,0x3b,0x1,0x49,0x2,0xb6,0x57,0x6f,0xb9,0xb,0x66,0x1f,0x69,0x64,0x39,0xa0,0xa4,0xe,0xa8,0xb7,0xbc,0xb0,0x35,0x1c,0x60,0xbd,0xfb,0xca,0xac,0xe0,0xd3,0x5d,0xce,0x51,0xcf,0xc,0xe8,0x8,0x20,0xec,0x79,0xbe,0xcc,0xd9,0x4b,0x29,0xfd,0xf4,0x3c,0x7,0x7c,0x36,0x58,0xed,0xba,0x13,0xfa,0xde,0xff,0x6e,0x2e,0x3a,0xeb,0x37,0x7a,0x90,0x98,0x1a,0xcb,0x26,0x81,0x87,0x93,0x4,0xa1,0x0,0x75,0xf2,0xd0,0xa5,0x91,0x6b,0xc2,0x48,0xe7,0xd1,0xe2,0x28,0xe4,0x4f,0x99,0xf0,0x1d,0x78,0x59,0x56,0xf3,0x3e,0x9a,0x68,0x8b,0x44,0xdb,0x34,0x38,0x19,0x77,0x7d,0x11,0xea,0x88,0x86,0xf8,0x4e,0x1b,0x24,0x61,0x30,0x9b,0xf7,0x54,0x63,0x8e,0x32,0xc9,0xb4,0x41,0xb,0x65,0xd0,0xc0,0xc9,0x1,0x3a,0xc2,0x53,0x13,0x7,0x87,0x2e,0xc7,0xe3,0xf2,0x31,0xd5,0x35,0xee,0x60,0xf3,0x6c,0xf1,0xe4,0x76,0x14,0x1d,0xd1,0x44,0x83,0x95,0x8a,0x81,0x8d,0x4,0x9d,0x99,0x33,0xc6,0xf7,0x91,0xdd,0x8,0x21,0x5d,0x80,0x3c,0x74,0x3f,0x8b,0xc,0xaf,0xb1,0x6,0x5b,0x22,0x54,0x59,0x6a,0x52,0x84,0x36,0x26,0x19,0x5c,0xd,0xb5,0xbb,0xc5,0x73,0xb3,0xf,0xf4,0x89,0xa6,0xca,0x69,0x5e,0xa7,0x55,0xb6,0x79,0x64,0x6b,0xce,0x3,0x4a,0x40,0x2c,0xd7,0xe6,0x9,0x5,0x24,0xff,0x75,0xda,0xec,0xed,0x98,0xac,0x56,0xa4,0xcd,0x20,0x45,0xdf,0x15,0xd9,0x72,0xa5,0x27,0xf6,0x1b,0xd6,0xa,0x47,0xad,0x9c,0x3d,0x48,0xcf,0xbc,0xba,0xae,0x39,0x16,0xc4,0xcc,0xfc,0xbf,0xf0,0xd2,0xaa,0x34,0x25,0x5a,0x94,0x67,0x63,0x12,0x8f,0x11,0x3e,0xc1,0x9b,0x7b,0x23,0xb8,0x5f,0x9a,0xa0,0x2,0x1c,0x93,0x8c,0x58,0xfe,0x3b,0xfa,0xe5,0x1a,0xa9,0x61,0xb2,0xe1,0x32,0x51,0x88,0xcb,0x92,0xab,0xef,0x85,0x96,0x77,0xb9,0x2a,0xd4,0xdc,0x66,0x7e,0xb0,0x18,0x4e,0xe2,0x28,0xa8,0xfd,0x2d,0x17,0xe,0x6e,0xe7,0x9f,0x2f,0x78,0x62,0x6d,0xe8,0x71,0x1f,0x38,0xa3,0xde,0x29,0x7a,0x57,0x7f,0xfb,0x49,0x10,0xb4,0x9e,0xb7,0x6f,0xdb,0xf9,0x46,0xa2,0x4d,0xe0,0x4c,0x8e,0xd3,0xd8,0xea,0x50,0x42,0x30,0x1e,0x2b,0x82,0xe9,0xbd,0x4b,0x7d,0x7c,0x86,0xc8,0x43,0x90,0xbe,0xf5,0x0,0xf8,0x97,0xc3,0xa1,0x4f,0x70,0x37,0xeb,0x68,0xc2,0xab,0x46,0x23,0xb9,0x73,0xbf,0x14,0x99,0x13,0xbc,0x8a,0x8b,0xfe,0xca,0x30,0xfa,0x5b,0x2e,0xa9,0xda,0xdc,0xc8,0x5f,0xc3,0x41,0x90,0x7d,0xb0,0x6c,0x21,0xcb,0xd5,0x69,0x92,0xef,0xc0,0xac,0xf,0x38,0x40,0x7f,0x3a,0x6b,0xd3,0xdd,0xa3,0x15,0x2c,0x26,0x4a,0xb1,0x80,0x6f,0x63,0x42,0xc1,0x33,0xd0,0x1f,0x2,0xd,0xa8,0x65,0xa0,0x91,0xf7,0xbb,0x6e,0x47,0x3b,0xe6,0xf3,0xec,0xe7,0xeb,0x62,0xfb,0xff,0x55,0x3d,0x44,0x32,0x3f,0xc,0x34,0xe2,0x50,0x5a,0x12,0x59,0xed,0x6a,0xc9,0xd7,0x60,0xa4,0x35,0x75,0x61,0xe1,0x48,0xa1,0x85,0x27,0x6d,0x3,0xb6,0xa6,0xaf,0x67,0x5c,0x97,0x82,0x10,0x72,0x7b,0xb7,0x22,0xe5,0x94,0x57,0xb3,0x53,0x88,0x6,0x95,0xa,0x78,0x4d,0xe4,0x8f,0xdb,0x2d,0x1b,0x1a,0x2a,0xe8,0xb5,0xbe,0x8c,0x36,0x24,0x56,0xf1,0xa5,0xc7,0x29,0x16,0x51,0x8d,0xe,0xe0,0xae,0x25,0xf6,0xd8,0x93,0x66,0x9e,0xb,0x8e,0x17,0x79,0x5e,0xc5,0xb8,0x4f,0x71,0x68,0x8,0x81,0xf9,0x49,0x1e,0x4,0xd1,0x9,0xbd,0x9f,0x20,0xc4,0x2b,0x86,0x1c,0x31,0x19,0x9d,0x2f,0x76,0xd2,0xf8,0x54,0x37,0xee,0xad,0xf4,0xcd,0x89,0xe3,0x5d,0x9c,0x83,0x7c,0xcf,0x7,0xd4,0x87,0xd6,0x7e,0x28,0x84,0x4e,0xce,0x9b,0x4b,0xf0,0x11,0xdf,0x4c,0xb2,0xba,0x0,0x18,0x52,0x43,0x3c,0xf2,0x1,0x5,0x74,0xe9,0x70,0xa2,0xaa,0x9a,0xd9,0x96,0xb4,0xcc,0xfc,0xc6,0x64,0x7a,0xf5,0xea,0x3e,0x98,0x77,0x58,0xa7,0xfd,0x1d,0x45,0xde,0x39,0xa3,0xa9,0x34,0xcf,0xea,0x5,0xc7,0xe6,0xb6,0x44,0x9a,0x55,0x88,0x87,0xe0,0x2d,0xec,0x50,0x6a,0x17,0x29,0x45,0xbd,0x8a,0xfa,0xc5,0xee,0xbf,0x58,0x56,0x90,0x26,0xde,0x7f,0x2c,0xab,0x59,0x5f,0xda,0x4d,0xc4,0x46,0xf8,0x15,0xe9,0x35,0x4e,0xa4,0x2e,0x47,0xa6,0xc3,0xf6,0x3c,0x91,0x3a,0x96,0x1c,0xf,0x39,0x7b,0xe,0xb5,0x4f,0x7,0x12,0xf7,0x95,0x32,0xfe,0x60,0xa7,0xd2,0x11,0xd6,0x36,0x83,0xd,0x8f,0x10,0xb0,0x21,0xe4,0xf0,0xcd,0x64,0x0,0x24,0xe8,0xa2,0x33,0x86,0x2a,0x23,0xd9,0xe2,0xc1,0xb8,0xba,0xb7,0xb1,0x89,0xd5,0x67,0x97,0xdf,0x68,0xdc,0x4c,0xef,0xe5,0x52,0x14,0x25,0x3e,0x72,0xc2,0xeb,0x63,0xbe,0x69,0x76,0x6e,0x62,0x7e,0xe7,0xd0,0x7a,0x8c,0x54,0x1a,0x38,0x41,0xa5,0x3,0xae,0xb4,0x99,0x18,0x9c,0xf3,0xaa,0x7d,0x57,0xb,0x8e,0xfc,0x92,0x40,0xdb,0xca,0x3d,0xed,0xf4,0x4,0x8d,0xcc,0x7c,0x81,0x9b,0x20,0x74,0xac,0x42,0xd4,0x93,0x8b,0x8,0x2b,0x65,0x73,0xa0,0x16,0x5d,0x1b,0xe3,0xc8,0xfd,0xa,0x61,0xa8,0x5e,0x9f,0x9e,0x6d,0xaf,0x3b,0x30,0xb3,0x9,0xd3,0xa1,0x43,0x79,0xff,0xe1,0x6f,0x70,0x1d,0xbb,0xdd,0xf2,0x78,0x22,0xc0,0x98,0xbc,0x5b,0xc6,0xd7,0x77,0xb9,0x80,0x84,0x6c,0xf1,0x27,0xf5,0x1f,0x2f,0x13,0x5c,0x49,0x31,0xfb,0x53,0x1,0xad,0x4b,0xcb,0xce,0x1e,0x94,0x75,0xc9,0x5a,0x3f,0x37,0x9d,0x85,0xb2,0xd1,0x28,0x6b,0x48,0x71,0x66,0xc,0x19,0xd8,0xf9,0x6,0x82,0x4a,0x2,0x51,0xe8,0xcc,0x25,0x8c,0xc,0x18,0x58,0xc9,0x31,0xa,0xc2,0xcb,0xdb,0x6e,0x0,0x4a,0x88,0x4f,0xda,0x16,0x1f,0x7d,0xef,0xfa,0x67,0xf8,0x6b,0xe5,0x3e,0xde,0x3a,0xf9,0x8b,0x56,0x2a,0x3,0xd6,0x9a,0xfc,0xcd,0x38,0x92,0x96,0xf,0x86,0x8a,0x81,0x9e,0x3d,0x8f,0x59,0x61,0x52,0x5f,0x29,0x50,0xd,0xba,0xa4,0x7,0x80,0x34,0x7f,0x37,0x55,0x62,0xc1,0xad,0x82,0xff,0x4,0xb8,0x78,0xce,0xb0,0xbe,0x6,0x57,0x12,0x2d,0x2f,0xe,0x2,0xed,0xdc,0x27,0x4b,0x41,0x8,0xc5,0x60,0x6f,0x72,0xbd,0x5e,0xac,0x79,0xd2,0x1e,0xd4,0x4e,0x2b,0xc6,0xaf,0x5d,0xa7,0x93,0xe6,0xe7,0xd1,0x7e,0xf4,0x32,0xa5,0xb1,0xb7,0xc4,0x43,0x36,0x97,0xa6,0x4c,0x1,0xdd,0x10,0xfd,0x2c,0xae,0x84,0x19,0x68,0x6c,0x9f,0x51,0x2e,0x3f,0xa1,0xd9,0xfb,0xb4,0xf7,0xc7,0xcf,0x1d,0xf5,0x53,0x87,0x98,0x17,0x9,0xab,0x91,0x54,0xb3,0x28,0x70,0x90,0xca,0x35,0x1a,0x8e,0xe4,0xa0,0x99,0xc0,0x83,0x5a,0x39,0xea,0xb9,0x6a,0xa2,0x11,0xee,0xf1,0x30,0x26,0xf6,0xa3,0x23,0xe9,0x45,0x13,0xbb,0x75,0x6d,0xd7,0xdf,0x21,0xb2,0x7c,0x9d,0x22,0xd5,0xa8,0x33,0x14,0x7a,0xe3,0x66,0x69,0x73,0x24,0x94,0xec,0x65,0x5,0x1c,0xeb,0x46,0xa9,0x4d,0xf2,0xd0,0x64,0xbc,0x95,0xbf,0x1b,0x42,0xf0,0x74,0x5c,0x71,0x77,0x76,0x40,0xb6,0xe2,0x89,0x20,0x15,0x3b,0x49,0x5b,0xe1,0xd3,0xd8,0x85,0x47,0x63,0xe0,0x3c,0x7b,0x44,0xaa,0xc8,0x9c,0xf3,0xb,0xfe,0xb5,0x9b,0x48,0xc3,0x8d,0x66,0x2e,0x65,0xd1,0x56,0xf5,0xeb,0x5c,0x1,0x78,0xe,0x3,0x30,0x8,0xde,0x6c,0xcf,0xd0,0xdb,0xd7,0x5e,0xc7,0xc3,0x69,0x9c,0xad,0xcb,0x87,0x52,0x7b,0x7,0xda,0xa8,0x6b,0x8f,0x6f,0xb4,0x3a,0xa9,0x36,0xab,0xbe,0x2c,0x4e,0x47,0x8b,0x1e,0xd9,0x1b,0x51,0x3f,0x8a,0x9a,0x93,0x5b,0x60,0x98,0x9,0x49,0x5d,0xdd,0x74,0x9d,0xb9,0xff,0x7d,0xac,0x41,0x8c,0x50,0x1d,0xf7,0xc6,0x67,0x12,0x95,0xe6,0xe0,0xf4,0x63,0xa5,0x2f,0x80,0xb6,0xb7,0xc2,0xf6,0xc,0xfe,0x97,0x7a,0x1f,0x85,0x4f,0x83,0x28,0xfd,0xf,0xec,0x23,0x3e,0x31,0x94,0x59,0x10,0x1a,0x76,0x8d,0xbc,0x53,0x5f,0x7e,0x7c,0x43,0x6,0x57,0xef,0xe1,0x9f,0x29,0xe9,0x55,0xae,0xd3,0xfc,0x90,0x33,0x4,0xcc,0x2d,0xe3,0x70,0x8e,0x86,0x3c,0x24,0xea,0x42,0x14,0xb8,0x72,0xf2,0xa7,0x77,0x61,0xa0,0xbf,0x40,0xf3,0x3b,0xe8,0xbb,0x68,0xb,0xd2,0x91,0xc8,0xf1,0xb5,0xdf,0x4b,0x64,0x9b,0xc1,0x21,0x79,0xe2,0x5,0xc0,0xfa,0x58,0x46,0xc9,0xd6,0x2,0xa4,0x4c,0x9e,0x96,0xa6,0xe5,0xaa,0x88,0xf0,0x6e,0x7f,0x0,0xce,0x3d,0x39,0x48,0xd5,0xdc,0x92,0x19,0xca,0xe4,0xaf,0x5a,0xa2,0xcd,0x99,0xfb,0x15,0x2a,0x6d,0xb1,0x32,0x16,0xd4,0x89,0x82,0xb0,0xa,0x18,0x6a,0x44,0x71,0xd8,0xb3,0xe7,0x11,0x27,0x26,0x20,0xd,0x25,0xa1,0x13,0x4a,0xee,0xc4,0xed,0x35,0x81,0xa3,0x1c,0xf8,0x17,0xba,0x4d,0x54,0x34,0xbd,0xc5,0x75,0x22,0x38,0x37,0xb2,0x2b,0x45,0x62,0xf9,0x84,0x73,0xec,0x24,0x6c,0x3f,0x77,0xb6,0x97,0x68,0x26,0x1f,0x8,0x62,0xdc,0xbf,0x46,0x5,0x51,0x59,0xf3,0xeb,0xfa,0x1b,0xa7,0x34,0x25,0xa5,0xa0,0x70,0x95,0x3d,0x6f,0xc3,0x7d,0x32,0x27,0x5f,0x49,0x9b,0x71,0x41,0xee,0xea,0x2,0x9f,0xa8,0xb9,0x19,0xd7,0xae,0xf6,0xd2,0x35,0xb3,0x9c,0x16,0x4c,0x1,0x1e,0x73,0xd5,0x2d,0x17,0x91,0x8f,0xdd,0x67,0xbd,0xcf,0x3,0xc1,0x55,0x5e,0xc6,0x30,0xf1,0xf0,0xa6,0x93,0x64,0xf,0x78,0x33,0x75,0x8d,0x45,0xb,0x1d,0xce,0xba,0xfd,0xe5,0x66,0x4e,0x1a,0xc2,0x2c,0xa2,0x12,0xef,0xf5,0x83,0x9a,0x6a,0xe3,0x2e,0xb5,0xa4,0x53,0x65,0xe0,0x92,0xfc,0x9d,0xc4,0x13,0x39,0xda,0xf7,0x76,0xf2,0x2f,0xcb,0x6d,0xc0,0xe2,0x3a,0x74,0x56,0x10,0x89,0xbe,0x14,0x7,0x18,0x0,0xc,0xac,0x85,0xd,0xd0,0x7a,0x4b,0x50,0x1c,0x22,0x81,0x8b,0x3c,0xf9,0xb1,0x6,0xb2,0xdf,0xe7,0xbb,0x9,0xaf,0xd6,0xd4,0xd9,0x44,0x4d,0xb7,0x8c,0x86,0xcc,0x5d,0xe8,0xa3,0xa,0x6e,0x4a,0xde,0x4f,0x8a,0x9e,0xed,0x63,0xe1,0x7e,0xbc,0x7f,0xb8,0x58,0x5c,0x90,0xe,0xc9,0x69,0x7c,0x99,0xfb,0x15,0x60,0xdb,0x21,0xf8,0x72,0x61,0x57,0x98,0x52,0xff,0x54,0x40,0x29,0xc8,0xad,0x87,0x5b,0x20,0xca,0xaa,0x28,0x96,0x7b,0x37,0x31,0xb4,0x23,0xb0,0x11,0x42,0xc5,0x36,0x38,0xfe,0x48,0x94,0xab,0x80,0xd1,0x47,0x2b,0xd3,0xe4,0x82,0x3e,0x4,0x79,0xe6,0xe9,0x8e,0x43,0xd8,0x2a,0xf4,0x3b,0x84,0x6b,0xa9,0x88,0xcd,0xc7,0x5a,0xa1,0x42,0x90,0x98,0xa8,0xeb,0xa4,0x86,0xfe,0x60,0x71,0xe,0xc0,0x33,0x37,0x46,0xdb,0x45,0x6a,0x95,0xcf,0x2f,0x77,0xec,0xb,0xce,0xf4,0x56,0x48,0xc7,0xd8,0xc,0xaa,0x6f,0xae,0xb1,0x4e,0xfd,0x35,0xe6,0xb5,0x66,0x5,0xdc,0x9f,0xc6,0xff,0xbb,0xd1,0xc2,0x23,0xed,0x7e,0x80,0x88,0x32,0x2a,0xe4,0x4c,0x1a,0xb6,0x7c,0xfc,0xa9,0x79,0x43,0x5a,0x3a,0xb3,0xcb,0x7b,0x2c,0x36,0x39,0xbc,0x25,0x4b,0x6c,0xf7,0x8a,0x7d,0x2e,0x3,0x2b,0xaf,0x1d,0x44,0xe0,0xca,0xe3,0x3b,0x8f,0xad,0x12,0xf6,0x19,0xb4,0x18,0xda,0x87,0x8c,0xbe,0x4,0x16,0x64,0x4a,0x7f,0xd6,0xbd,0xe9,0x1f,0x29,0x28,0xd2,0x9c,0x17,0xc4,0xea,0xa1,0x54,0xac,0xc3,0x97,0xf5,0x1b,0x24,0x63,0xbf,0x3c,0x15,0x5f,0x31,0x84,0x94,0x9d,0x55,0x6e,0x96,0x7,0x47,0x53,0xd3,0x7a,0x93,0xb7,0xa6,0x65,0x81,0x61,0xba,0x34,0xa7,0x38,0xa5,0xb0,0x22,0x40,0x49,0x85,0x10,0xd7,0xc1,0xde,0xd5,0xd9,0x50,0xc9,0xcd,0x67,0x92,0xa3,0xc5,0x89,0x5c,0x75,0x9,0xd4,0x68,0x20,0x6b,0xdf,0x58,0xfb,0xe5,0x52,0xf,0x76,0x0,0xd,0x3e,0x6,0xd0,0x62,0x72,0x4d,0x8,0x59,0xe1,0xef,0x91,0x27,0xe7,0x5b,0xa0,0xdd,0xf2,0x9e,0x3d,0xa,0xf3,0x1,0xe2,0x2d,0x30,0x3f,0x9a,0x57,0x1e,0x14,0x78,0x83,0xb2,0x5d,0x51,0x70,0xab,0x21,0x8e,0xb8,0xb9,0xcc,0xf8,0x2,0xf0,0x99,0x74,0x11,0x8b,0x41,0x8d,0x26,0xf1,0x73,0xa2,0x4f,0x82,0x5e,0x13,0xf9,0xc8,0x69,0x1c,0x9b,0xe8,0xee,0xfa,0x6d,0x66,0x21,0xfd,0x7e,0x81,0xd5,0xb7,0x59,0xa8,0xe3,0x16,0xee,0x90,0xde,0x55,0x86,0xab,0x5d,0x6b,0x6a,0x8,0x3d,0x94,0xff,0xfc,0x46,0x54,0x26,0x5a,0x98,0xc5,0xce,0x50,0xb4,0x5b,0xf6,0xa1,0x79,0xcd,0xef,0x5f,0x6,0xa2,0x88,0x6c,0x41,0x69,0xed,0x2e,0xb5,0xc8,0x3f,0x7b,0xfe,0x67,0x9,0x89,0x39,0x6e,0x74,0x1,0x18,0x78,0xf1,0x3e,0xbe,0xeb,0x3b,0xa6,0xe,0x58,0xf4,0xc2,0xca,0x70,0x68,0x80,0x61,0xaf,0x3c,0x84,0xbd,0xf9,0x93,0x24,0x47,0x9e,0xdd,0xbf,0x77,0xa4,0xf7,0x2d,0xec,0xf3,0xc,0x85,0x9a,0x4e,0xe8,0x8c,0xb6,0x14,0xa,0x6d,0x35,0xae,0x49,0x7,0x28,0xd7,0x8d,0x71,0x75,0x4,0x99,0x22,0x33,0x4c,0x82,0xa9,0xe6,0xc4,0xbc,0x0,0xd2,0xda,0xea,0xaa,0xac,0xb8,0x2f,0x8a,0x2b,0x5e,0xd9,0xc0,0x1c,0x51,0xbb,0xb3,0x31,0xe0,0xd,0xc9,0x3,0xcf,0x64,0xb2,0xdb,0x36,0x53,0xfb,0x8e,0xba,0x40,0xe9,0x63,0xcc,0xfa,0xf0,0x1f,0x13,0x32,0x5c,0x56,0x3a,0xc1,0x72,0x7d,0xd8,0x15,0xb1,0x43,0xa0,0x6f,0xb0,0xdc,0x7f,0x48,0xa5,0x19,0xe2,0x9f,0xa3,0xad,0xd3,0x65,0x30,0xf,0x4a,0x1b,0x7c,0x44,0x92,0x20,0x4d,0x34,0x42,0x4f,0x1a,0xb9,0xa7,0x10,0x2a,0x62,0x29,0x9d,0x1e,0x37,0x4b,0x96,0xd0,0xe1,0x87,0xcb,0x12,0x8b,0x8f,0x25,0x83,0x9c,0x97,0x9b,0xb,0xc7,0x52,0x95,0xe7,0xf2,0x60,0x2,0xf8,0x76,0xe5,0x7a,0xe4,0x27,0xc3,0x23,0x91,0x38,0xd1,0xf5,0xd4,0x45,0x5,0x11,0xd6,0xdf,0x17,0x2c,0x57,0x1d,0x73,0xc6,0xc1,0x99,0xbd,0x5a,0xdc,0xf3,0x79,0x23,0x6e,0x71,0x1c,0xba,0x42,0x78,0xfe,0xe0,0x12,0x5d,0x48,0x30,0x26,0xf4,0x1e,0x2e,0x81,0x85,0x6d,0xf0,0xc7,0xd6,0x76,0xb8,0x3e,0x36,0x9c,0x84,0x95,0x74,0xc8,0x5b,0x4a,0xca,0xcf,0x1f,0xfa,0x52,0x0,0xac,0x83,0x4b,0x3,0x50,0x18,0xd9,0xf8,0x7,0x49,0x70,0x67,0xd,0xb3,0xd0,0x29,0x6a,0xf2,0xab,0x7c,0x56,0xb5,0x98,0x19,0x9d,0x40,0xa4,0x2,0xaf,0x8d,0x55,0x1b,0x39,0xcd,0x7d,0x80,0x9a,0xec,0xf5,0x5,0x8c,0x41,0xda,0xcb,0x3c,0xa,0x8f,0xfd,0x93,0x17,0x5c,0x1a,0xe2,0x2a,0x64,0x72,0xa1,0xd5,0x92,0x8a,0x9,0x21,0x75,0xad,0x43,0xb2,0x8,0xd2,0xa0,0x6c,0xae,0x3a,0x31,0xa9,0x5f,0x9e,0x9f,0xc9,0xfc,0xb,0x60,0x82,0xc,0x8e,0x11,0xd3,0x10,0xd7,0x37,0x33,0xff,0x61,0xa6,0x6,0x13,0xf6,0x94,0x2b,0x22,0xd8,0xe3,0xe9,0xa3,0x32,0x87,0xcc,0x65,0x1,0x25,0xb1,0x20,0xe5,0xf1,0x4d,0xee,0xe4,0x53,0x96,0xde,0x69,0xdd,0xb0,0x88,0xd4,0x66,0xc0,0xb9,0xbb,0xb6,0x7f,0xe6,0xd1,0x7b,0x68,0x77,0x6f,0x63,0xc3,0xea,0x62,0xbf,0x15,0x24,0x3f,0x73,0x89,0x86,0xe1,0x2c,0xb7,0x45,0x9b,0x54,0xeb,0x4,0xc6,0xe7,0xa2,0xa8,0x35,0xce,0x59,0x57,0x91,0x27,0xfb,0xc4,0xef,0xbe,0x28,0x44,0xbc,0x8b,0xed,0x51,0x6b,0x16,0xe8,0x34,0x4f,0xa5,0xc5,0x47,0xf9,0x14,0x58,0x5e,0xdb,0x4c,0xdf,0x7e,0x2d,0xaa,0x7a,0xf,0xb4,0x4e,0x97,0x1d,0xe,0x38,0xf7,0x3d,0x90,0x3b,0x2f,0x46,0xa7,0xc2,0x3,0xab,0xfd,0x51,0x9b,0x1b,0x4e,0x9e,0x25,0xc4,0xa,0x99,0x67,0x6f,0xd5,0xcd,0x81,0xe2,0x3b,0x78,0x21,0x18,0x5c,0x36,0x88,0x49,0x56,0xa9,0x1a,0xd2,0x1,0x52,0x29,0x13,0xb1,0xaf,0x20,0x3f,0xeb,0x4d,0xa2,0x8d,0x72,0x28,0xc8,0x90,0xb,0xec,0x87,0x96,0xe9,0x27,0xd4,0xd0,0xa1,0x3c,0xa5,0x77,0x7f,0x4f,0xc,0x43,0x61,0x19,0x24,0x70,0x12,0xfc,0xc3,0x84,0x58,0xdb,0x35,0x7b,0xf0,0x23,0xd,0x46,0xb3,0x4b,0xad,0x98,0x31,0x5a,0xe,0xf8,0xce,0xcf,0xff,0x3d,0x60,0x6b,0x59,0xe3,0xf1,0x83,0x4,0xdc,0x68,0x4a,0xf5,0x11,0xfe,0x53,0xc9,0xe4,0xcc,0x48,0xfa,0xa3,0x7,0x2d,0xde,0x5b,0xc2,0xac,0x8b,0x10,0x6d,0x9a,0xa4,0xbd,0xdd,0x54,0x2c,0x9c,0xcb,0xd1,0xe8,0x91,0xe7,0xea,0xd9,0xe1,0x37,0x85,0x8f,0xc7,0x8c,0x38,0xbf,0x1c,0x2,0xb5,0x75,0x44,0x22,0x6e,0xbb,0x92,0xee,0x33,0x26,0x39,0x32,0x3e,0xb7,0x2e,0x2a,0x80,0x42,0x57,0xc5,0xa7,0xae,0x62,0xf7,0x30,0x41,0x82,0x66,0x86,0x5d,0xd3,0x40,0xdf,0x71,0xe0,0xa0,0xb4,0x34,0x9d,0x74,0x50,0xf2,0xb8,0xd6,0x63,0x73,0x7a,0xb2,0x89,0x2f,0x8e,0xfb,0x7c,0xf,0x9,0x1d,0x8a,0x16,0x94,0x45,0xa8,0x65,0xb9,0xf4,0x1e,0x17,0x7e,0x93,0xf6,0x6c,0xa6,0x6a,0xc1,0x4c,0xc6,0x69,0x5f,0x5e,0x2b,0x1f,0xe5,0xf9,0xf3,0x9f,0x64,0x55,0xba,0xb6,0x97,0x14,0xe6,0x5,0xca,0xd7,0xd8,0x7d,0xb0,0x0,0xbc,0x47,0x3a,0x15,0x79,0xda,0xed,0x95,0xaa,0xef,0xbe,0x6,0x8,0x76,0xc0,0x8,0x5b,0x88,0x40,0xf3,0xc,0x13,0xd2,0x6c,0x6,0x42,0x7b,0x22,0x61,0xb8,0xdb,0x97,0x8f,0x35,0x3d,0xc3,0x50,0x9e,0x7f,0xc4,0x14,0x41,0xc1,0xb,0xa7,0xf1,0x59,0x43,0x3b,0x19,0x56,0x15,0x25,0x2d,0xff,0x66,0xfb,0x8a,0x8e,0x7d,0xb3,0xcc,0xdd,0xb6,0x51,0xca,0x92,0x72,0x28,0xd7,0xf8,0x17,0xb1,0x65,0x7a,0xf5,0xeb,0x49,0x73,0xd9,0xab,0xb9,0x3,0x31,0x3a,0x67,0xa5,0x95,0x94,0xa2,0x54,0x0,0x6b,0xc2,0xf7,0x11,0xe9,0x1c,0x57,0x79,0xaa,0x21,0x6f,0x81,0x2,0xde,0x99,0xa6,0x48,0x2a,0x7e,0x8b,0x91,0xc6,0x76,0xe,0x87,0xe7,0xfe,0xc0,0x37,0x4a,0xd1,0xf6,0x98,0x1,0x84,0x77,0x5d,0xf9,0xa0,0x12,0x96,0xbe,0x93,0x9,0xa4,0x4b,0xaf,0x10,0x32,0x86,0x5e,0xda,0x70,0x74,0xed,0x64,0x68,0x63,0x7c,0x69,0xb4,0xc8,0xe1,0x34,0x78,0x1e,0x2f,0xef,0x58,0x46,0xe5,0x62,0xd6,0x9d,0xd5,0xdf,0x6d,0xbb,0x83,0xb0,0xbd,0xcb,0xb2,0xd3,0xe8,0x20,0x29,0x39,0x8c,0xe2,0xa8,0xa,0x2e,0xc7,0x6e,0xee,0xfa,0xba,0x2b,0x85,0x1a,0x89,0x7,0xdc,0x3c,0xd8,0x1b,0x6a,0xad,0x38,0xf4,0xfd,0x9f,0xd,0x18,0xbf,0x45,0x71,0x4,0x5,0x33,0x9c,0x16,0x9b,0x30,0xfc,0x36,0xac,0xc9,0x24,0x4d,0x44,0xae,0xe3,0x3f,0xf2,0x1f,0xce,0x4c,0xd0,0x47,0x53,0x55,0x26,0xa1,0xd4,0x75,0x9a,0x2c,0x52,0x5c,0xe4,0xb5,0xf0,0xcf,0xb7,0x80,0x23,0x4f,0x60,0x1d,0xe6,0x5a,0xea,0x27,0x82,0x8d,0x90,0x5f,0xbc,0x4e,0xcd,0xec,0xe0,0xf,0x3e,0xc5,0xa9,0xa3,0x1,0xf6,0xe7,0x7c,0xae,0xc0,0xb2,0x37,0xa7,0xbd,0x40,0xf0,0xb1,0x38,0xc8,0xd1,0x92,0x3f,0x99,0x7d,0x4,0x26,0x68,0xb0,0x6b,0x41,0x96,0xcf,0xa0,0x24,0xa5,0x88,0xa2,0xa3,0x62,0x94,0x5d,0x36,0xc1,0xf4,0x9d,0xef,0x35,0x8f,0xc,0x7,0x93,0x51,0x34,0xb7,0xaf,0xe8,0x7e,0x90,0x48,0x1c,0xdf,0x27,0x61,0x2a,0x9c,0x4f,0x59,0x17,0xcd,0x50,0xb8,0xbc,0x85,0x4b,0xeb,0xfa,0xd,0x75,0x60,0x2f,0x13,0x23,0xc9,0x1b,0x87,0x21,0x4c,0x53,0xdd,0xc3,0x45,0x7f,0x67,0x80,0xa4,0xfc,0x1e,0x44,0xce,0xe1,0x30,0x5a,0x4d,0x74,0x57,0x14,0xed,0x8e,0x6d,0x3e,0x76,0xbe,0x3a,0xc5,0xe4,0x25,0x22,0xf2,0xf7,0x77,0x91,0x3d,0x6f,0xc7,0xb9,0xa1,0xb,0x3,0x66,0xf5,0x49,0xa8,0xb6,0x81,0x79,0x15,0x2b,0x56,0x6c,0xd0,0x1a,0xac,0x6a,0x64,0x83,0xd2,0xf9,0xc6,0xda,0xfb,0x39,0xd6,0xf3,0x8,0x95,0x9f,0x11,0xdc,0xbb,0xb4,0x69,0xa6,0x78,0x8a,0x6,0xad,0x0,0xca,0xff,0x9a,0x7b,0x12,0x73,0x89,0x32,0x47,0x5,0x33,0x20,0xaa,0x71,0xe6,0x63,0x65,0x97,0x10,0x43,0xe2,0x98,0x72,0x9,0xd5,0x29,0xc4,0x7a,0xf8,0x18,0x3c,0x58,0xf1,0xcc,0xd8,0x1d,0x8c,0xde,0xe5,0x1f,0x16,0xba,0xf,0x9e,0xd4,0x9b,0x5c,0xc2,0xe,0xa9,0xcb,0x2e,0x3b,0x2c,0xb3,0x31,0xbf,0xa,0xea,0x2d,0xee,0x82,0x5f,0xd7,0xfe,0x4e,0x2,0x19,0x28,0x46,0xec,0xdb,0x42,0x5e,0x52,0x4a,0x55,0x5b,0xe9,0xb5,0x8d,0x8b,0x86,0x84,0xfd,0x6e,0xd9,0xd3,0x70,0xe0,0x54,0xe3,0xab,0x2c,0x80,0xd2,0x7a,0x9f,0x4f,0x4a,0xca,0xdb,0x48,0xf4,0x15,0x4,0x1c,0xb6,0xbe,0xea,0xa9,0x50,0x33,0x8d,0xe7,0xf0,0xc9,0x87,0x78,0x59,0x98,0xd0,0x83,0xcb,0x3,0x60,0x7e,0xf8,0xc2,0x3a,0x9c,0xf1,0xee,0xa3,0xf9,0x73,0x5c,0xda,0x3d,0x19,0x41,0x38,0xf6,0x56,0x47,0x70,0xed,0x5,0x1,0xae,0x9e,0x74,0xa6,0xb0,0xc8,0xdd,0x92,0xc3,0x2d,0xf5,0xa1,0x89,0xa,0x12,0x55,0x21,0xf2,0xe4,0xaa,0x62,0x9a,0xdc,0x97,0xe0,0x8b,0x7c,0x49,0x1f,0x1e,0xdf,0x29,0xb1,0xba,0x2e,0xec,0x20,0x52,0x88,0x32,0xb9,0x9b,0xd5,0xd,0x2f,0x82,0x24,0xc0,0x1d,0x99,0x18,0x35,0xd6,0xfc,0x2b,0x72,0x13,0x7d,0xf,0x8a,0xbc,0x4b,0x5a,0xc1,0xc,0x85,0x75,0x6c,0x1a,0x0,0xfd,0x4d,0x36,0x3b,0x39,0x40,0xe6,0x54,0x8,0x30,0x5d,0xe9,0x5e,0x16,0xd3,0x64,0x6e,0xcd,0xf3,0xbf,0xa4,0x95,0x3f,0xe2,0x6a,0x43,0xe3,0xef,0xf7,0xe8,0xfb,0x51,0x66,0xff,0x14,0x76,0x93,0x86,0x26,0xe1,0x7f,0xb3,0xb7,0x57,0x90,0x53,0x91,0xe,0x8c,0x2,0x71,0x65,0xa0,0x31,0xa5,0x81,0xe5,0x4c,0x7,0xb2,0x23,0x69,0x63,0x58,0xa2,0xab,0x2a,0xad,0xfe,0x5f,0xcc,0x5b,0xde,0xd8,0x94,0x79,0xc7,0x45,0x25,0xcf,0xb4,0x68,0x42,0x27,0xc6,0xaf,0xbb,0x10,0xbd,0x77,0xb8,0x8e,0x9d,0x17,0xce,0x34,0x8f,0xfa,0x4e,0xb5,0x28,0x22,0x67,0x46,0x84,0x6b,0xd4,0x1b,0xc5,0x37,0xac,0x61,0x6,0x9,0x96,0xeb,0xd1,0x6d,0xb,0x3c,0xc4,0xa8,0x3e,0x6f,0x44,0x7b,0xa7,0x11,0xd7,0xd9,0x7a,0x41,0xbb,0xb2,0x1e,0xab,0x3a,0x70,0xbc,0x98,0xfc,0x55,0x68,0x7c,0xb9,0x28,0x88,0x17,0x95,0x1b,0xae,0x4e,0x89,0x4a,0x3f,0xf8,0x66,0xaa,0xd,0x6f,0x8a,0x9f,0xe2,0x48,0x7f,0xe6,0xfa,0xf6,0xee,0xf1,0x26,0xfb,0x73,0x5a,0xea,0xa6,0xbd,0x8c,0xca,0x7d,0x77,0xd4,0x44,0xf0,0x47,0xf,0xff,0x4d,0x11,0x29,0x2f,0x22,0x20,0x59,0xbe,0x8,0xce,0xc0,0x27,0x76,0x5d,0x62,0x12,0x25,0xdd,0xb1,0x8f,0xf2,0xc8,0x74,0xb5,0x78,0x1f,0x10,0xcd,0x2,0xdc,0x2e,0x7e,0x5f,0x9d,0x72,0x57,0xac,0x31,0x3b,0xd7,0x2d,0x96,0xe3,0xa1,0x97,0x84,0xe,0xa2,0x9,0xa4,0x6e,0x5b,0x3e,0xdf,0xb6,0x3c,0xd6,0xad,0x71,0x8d,0x60,0xde,0x5c,0xd5,0x42,0xc7,0xc1,0x33,0xb4,0xe7,0x46,0xa9,0xd1,0xc4,0x8b,0xb7,0x87,0x6d,0xbf,0x69,0xf4,0x1c,0x18,0x21,0xef,0x4f,0x5e,0xc3,0x24,0x0,0x58,0xba,0xe0,0x6a,0x45,0x23,0x85,0xe8,0xf7,0x79,0x67,0xe1,0xdb,0xc9,0x9a,0xd2,0x1a,0x9e,0x61,0x40,0x81,0x94,0xfe,0xe9,0xd0,0xf3,0xb0,0x49,0x2a,0x1d,0x5,0xaf,0xa7,0xc2,0x51,0xed,0xc,0x86,0x56,0x53,0xd3,0x35,0x99,0xcb,0x63,0x3,0x19,0xe4,0x54,0x15,0x9c,0x6c,0x75,0xa5,0x52,0x43,0xd8,0xa,0x64,0x16,0x93,0xcf,0xe5,0x32,0x6b,0x4,0x80,0x1,0x2c,0x36,0x9b,0x3d,0xd9,0xa0,0x82,0xcc,0x14,0x39,0x4b,0x91,0x2b,0xa8,0xa3,0x37,0xf5,0x6,0x7,0xc6,0x30,0xf9,0x92,0x65,0x50,0x7b,0x83,0xc5,0x8e,0x38,0xeb,0xfd,0xb3,0x90,0x13,0xb,0x4c,0xda,0x34,0xec,0xb8,0xb8,0xd1,0x30,0x55,0x60,0xaa,0x7,0xac,0x0,0x8a,0x99,0xaf,0xed,0x98,0x23,0xd9,0x48,0xe9,0xba,0x3d,0xcf,0xc9,0x4c,0xdb,0x52,0xd0,0x6e,0x83,0x7f,0xa3,0xd8,0x32,0x7a,0xc6,0xfc,0x81,0xbf,0xd3,0x2b,0x1c,0x6c,0x53,0x78,0x29,0xce,0xc0,0x6,0xb0,0x35,0x3f,0xa2,0x59,0x7c,0x93,0x51,0x70,0x20,0xd2,0xc,0xc3,0x1e,0x11,0x76,0xbb,0x82,0xb3,0xa8,0xe4,0x54,0x7d,0xf5,0x28,0xff,0xe0,0xf8,0xf4,0xe8,0x71,0x46,0xec,0x57,0x2e,0x2c,0x21,0x27,0x1f,0x43,0xf1,0x1,0x49,0xfe,0x4a,0xda,0x79,0x73,0xc4,0x26,0xb7,0x72,0x66,0x5b,0xf2,0x96,0xb2,0x7e,0x34,0xa5,0x10,0xbc,0xb5,0x4f,0x74,0x91,0x84,0x61,0x3,0xa4,0x68,0xf6,0x31,0x44,0x87,0x40,0xa0,0x15,0x9b,0x19,0x86,0x5e,0x6b,0x9c,0xf7,0x3e,0xc8,0x9,0x8,0xfb,0x39,0xad,0xa6,0x25,0x9f,0x45,0x37,0xb6,0xe2,0x3a,0xd4,0x42,0x5,0x1d,0x9e,0xbd,0xf3,0xe5,0x36,0x80,0xcb,0x8d,0x75,0x9d,0x18,0x6a,0x4,0xd6,0x4d,0x5c,0xab,0x7b,0x62,0x92,0x1b,0x5a,0xea,0x17,0xd,0x1a,0xc2,0x8c,0xae,0xd7,0x33,0x95,0x38,0x22,0xf,0x8e,0xa,0x65,0x3c,0xeb,0xc1,0x24,0x47,0xbe,0xfd,0xde,0xe7,0xf0,0x9a,0x8f,0x4e,0x6f,0x90,0x14,0xdc,0x94,0xc7,0x6d,0xc5,0x97,0x3b,0xdd,0x5d,0x58,0x88,0x2,0xe3,0x5f,0xcc,0xa9,0xa1,0xb,0x13,0x50,0x41,0xe1,0x2f,0x16,0x12,0xfa,0x67,0xb1,0x63,0x89,0xb9,0x85,0xca,0xdf,0xa7,0xd5,0xef,0x69,0x77,0xf9,0xe6,0x8b,0x2d,0x4b,0x64,0xee,0xb4,0x56,0xe,0x2a,0xcd}; unsigned char table_s3[] = {0xdd,0xaa,0x28,0xa0,0xc5,0xb4,0x9c,0xe8,0xcd,0xb7,0xde,0xe2,0x1f,0xef,0x73,0xbe,0x72,0xf5,0x1,0x22,0x50,0xa8,0x4a,0x9a,0xf2,0x84,0x69,0x29,0x3c,0x79,0x67,0xe3,0xb3,0x56,0xe4,0x2c,0x55,0x26,0x5a,0x0,0xb6,0x60,0xa9,0x98,0x83,0xc4,0xd0,0x7c,0xd9,0x90,0x78,0xdb,0x25,0x96,0xee,0x49,0x61,0xfa,0xd6,0x14,0xe,0xf8,0x41,0xce,0x9,0x37,0x53,0x12,0x93,0x3d,0xb1,0x4,0xf7,0x82,0x35,0x9f,0xb0,0xe9,0xf,0x1b,0xab,0xc7,0xa6,0x7e,0x77,0xd2,0x63,0xd1,0xd3,0xb8,0x8e,0x38,0xc,0x40,0xd4,0xe0,0xfe,0x21,0x2b,0x30,0x16,0xa7,0xd5,0xbc,0xbd,0xeb,0x5f,0x65,0xfc,0x4c,0x2e,0x64,0x6,0x7,0x5e,0x3b,0x2f,0xba,0x39,0x7d,0xd8,0x88,0xf3,0x58,0x15,0x23,0x86,0xae,0x74,0xca,0x8,0x66,0x43,0xa2,0xc8,0xda,0xd7,0x46,0x19,0xe5,0xc6,0xcb,0x3,0xf6,0x91,0xcc,0x3e,0x2d,0x8c,0xcf,0x71,0x7a,0x62,0xc9,0x59,0x11,0x1a,0xc3,0x45,0x75,0x8f,0x9e,0x97,0xdc,0x54,0x4d,0x6e,0x44,0x81,0x99,0xa5,0xb9,0x70,0x13,0x34,0x24,0x95,0x5,0x1d,0x6d,0x7f,0x5b,0x94,0xac,0x3f,0xad,0xbb,0x31,0x51,0xdf,0x4f,0xa1,0x6b,0x80,0xbf,0x92,0x18,0xec,0xa4,0x42,0x68,0xaf,0xc1,0xe7,0xed,0x7b,0xe1,0x10,0x5c,0xc2,0x27,0x85,0xa,0x87,0x8b,0x33,0x5d,0xfb,0x9d,0xb2,0xea,0xf4,0x6f,0xb,0x8a,0x8d,0xfd,0x47,0x20,0x2,0xd,0x17,0xf0,0x4b,0xb5,0x2a,0x36,0x4e,0x52,0xe6,0x6a,0x57,0x76,0x89,0x1e,0x32,0x48,0x3a,0xa3,0x1c,0x9b,0xc0,0x6c,0xf1,0xf9,0xff,0xd3,0xcd,0x2c,0x48,0xdc,0x7a,0x95,0xba,0xa0,0x2d,0x14,0xac,0xe5,0x7b,0xa2,0x0,0x5c,0xca,0x37,0xc6,0x88,0x4f,0xc0,0xe6,0xcb,0x3f,0x65,0x83,0xa7,0x4c,0xb5,0x98,0xd6,0x4b,0xd8,0xde,0x3b,0x84,0xe7,0xbc,0x15,0x39,0x1d,0x6f,0x70,0x4d,0xae,0x51,0x69,0x11,0xc1,0x75,0x6c,0xd7,0xd,0x92,0x25,0x7,0x30,0x2a,0xaa,0xad,0x60,0xda,0xe4,0x3d,0x52,0x62,0xee,0x45,0x36,0x7e,0xe8,0xab,0x5d,0x56,0xeb,0xb6,0xa,0x19,0xec,0xe1,0xd1,0x24,0x61,0xf0,0xc2,0x3e,0x85,0x64,0xfd,0xef,0xed,0x53,0x41,0x2f,0xf8,0x76,0x86,0x68,0x8a,0x18,0x16,0x9c,0x7c,0x58,0x8b,0xb3,0x22,0xb2,0x4a,0x3a,0x34,0x57,0x3,0x13,0xbe,0xa6,0x9e,0x82,0x6a,0x73,0x63,0x49,0xb9,0xa8,0xfb,0xb0,0x67,0x2b,0xc7,0xf3,0x9f,0xf4,0x1f,0xa9,0xf5,0x50,0xf6,0x44,0xe0,0x8c,0x59,0x81,0xce,0x97,0x3c,0x28,0xa5,0xd0,0xb8,0x12,0x1a,0xb4,0x23,0x96,0x10,0x2e,0x35,0x74,0x4,0x32,0x89,0xa1,0xaf,0xff,0x7f,0xd4,0x9d,0x8,0x5a,0x1e,0x20,0x21,0x1c,0x79,0x6b,0xdb,0x43,0x9,0xcc,0x9a,0x42,0x78,0x80,0x31,0x9b,0xf2,0x6,0xd9,0x17,0xc,0x5e,0x1b,0xc4,0x40,0xa3,0xd5,0xe,0x4e,0x8f,0x77,0xbd,0x6d,0xd2,0x55,0x5,0x26,0xc8,0x38,0x99,0x54,0x90,0xea,0xc5,0xf9,0x93,0xe2,0xcf,0xbb,0x8d,0xfa,0x87,0xf,0xdf,0x29,0xe9,0x66,0xdd,0x46,0x33,0xf1,0xb1,0x2,0x6e,0xc9,0xb7,0xfe,0xfc,0x5f,0xe3,0xa4,0x5b,0xf7,0x47,0x91,0xbf,0x8e,0x1,0x72,0x27,0x7d,0x71,0x94,0xb,0xc3,0xb8,0x2d,0x7f,0x3b,0x5,0x4,0x39,0x5c,0x21,0x17,0xac,0x84,0x8a,0xda,0x5a,0xf1,0xa5,0x14,0xbe,0xd7,0x23,0xfc,0x32,0x29,0x4e,0xfe,0x66,0x2c,0xe9,0xbf,0x67,0x5d,0xd0,0x75,0xd3,0x61,0xc5,0xa9,0x7c,0xa4,0x42,0xe,0xe2,0xd6,0xba,0xd1,0x3a,0x8c,0x3f,0x91,0x6,0xb3,0x35,0xb,0x10,0x51,0xeb,0xb2,0x19,0xd,0x80,0xf5,0x9d,0x37,0x94,0x27,0x4b,0xec,0x92,0xdb,0xd9,0x7a,0xfa,0xc,0xcc,0x43,0xf8,0x63,0x16,0xd4,0x24,0x57,0x2,0x58,0x54,0xb1,0x2e,0xe6,0xc6,0x81,0x7e,0xd2,0x62,0xb4,0x9a,0xab,0xaa,0x52,0x98,0x48,0xf7,0x70,0x20,0x3,0x7b,0x3e,0xe1,0x65,0x86,0xf0,0x2b,0x6b,0xb6,0xc7,0xea,0x9e,0xa8,0xdf,0xa2,0x2a,0xed,0x1d,0xbc,0x71,0xb5,0xcf,0xe0,0xdc,0x30,0x1c,0x38,0x4a,0x55,0x68,0x8b,0x74,0xf3,0x6e,0xfd,0xfb,0x1e,0xa1,0xc2,0x99,0x0,0x22,0x15,0xf,0x8f,0x88,0x45,0xff,0x4c,0x34,0xe4,0x50,0x49,0xf2,0x28,0xb7,0x85,0x8,0x31,0x89,0xc0,0x5e,0x87,0x25,0xf6,0xe8,0x9,0x6d,0xf9,0x5f,0xb0,0x9f,0xee,0x1a,0x40,0xa6,0x82,0x69,0x90,0xbd,0x79,0xef,0x12,0xe3,0xad,0x6a,0xe5,0xc3,0x59,0x7d,0xae,0x96,0x7,0x97,0x6f,0x1f,0xdd,0x53,0xa3,0x4d,0xaf,0x3d,0x33,0xb9,0x4f,0x56,0x46,0x6c,0x9c,0x8d,0xde,0x95,0x11,0x72,0x26,0x36,0x9b,0x83,0xbb,0xa7,0xcd,0x8e,0x78,0x73,0xce,0x93,0x2f,0x3c,0xc1,0x18,0x77,0x47,0xcb,0x60,0x13,0x5b,0xa0,0x41,0xd8,0xca,0xc8,0x76,0x64,0xa,0xc9,0xc4,0xf4,0x1,0x44,0xd5,0xe7,0x1b,0x3d,0xe5,0x84,0xe8,0x92,0x20,0x91,0x34,0x7b,0xcd,0xfb,0x90,0xa3,0x97,0x3,0x4f,0x51,0x10,0x74,0x4a,0x47,0xf2,0x7e,0xd0,0xdc,0x76,0xc1,0xb4,0x58,0x4c,0xaa,0xf3,0x78,0x1d,0x44,0x45,0x3e,0x7a,0xf9,0x6c,0x1b,0xb0,0xcb,0x9b,0xed,0xc5,0x60,0x56,0x73,0x68,0x62,0xbd,0xff,0x96,0xe4,0x55,0x26,0x1c,0xa8,0xfe,0x27,0x6d,0xf,0xbf,0x61,0x42,0xb6,0x31,0xd9,0x9,0xeb,0x13,0x6a,0x2a,0xc7,0xb1,0xa0,0x24,0x3a,0x7f,0xe3,0x6b,0xe9,0x9e,0xab,0xdf,0xf7,0x86,0xa1,0x9d,0xf4,0x8e,0xfd,0x30,0xac,0x5c,0x98,0x3b,0xd3,0x9a,0xa,0xad,0xd5,0x66,0x57,0x95,0xb9,0x22,0x8d,0x2,0xbb,0x4d,0x6f,0xa7,0x15,0xf0,0x43,0x19,0x65,0x16,0xdb,0xea,0x23,0xf5,0x3f,0x93,0x87,0xc0,0xc6,0x64,0x81,0x1f,0x70,0xc8,0xc4,0x49,0xf1,0xde,0xb8,0x1e,0x48,0x2c,0xb7,0xa9,0xd1,0xfc,0xc3,0x28,0x1,0xe7,0xaf,0x5b,0xa4,0x82,0xec,0x2b,0x53,0xa2,0x38,0xae,0xca,0x35,0x14,0x29,0x79,0xb,0x71,0x5d,0x83,0xd8,0x5f,0xe0,0xbc,0xba,0xb2,0x2f,0x4,0xbe,0xce,0xc9,0x54,0x4e,0x41,0x63,0x69,0xf6,0x8,0xb3,0xa5,0x11,0xd,0x75,0x6e,0x7d,0x8f,0xd2,0x39,0x32,0x8c,0xcf,0x52,0x1a,0x8a,0x21,0x36,0x6,0x80,0x59,0x25,0x4b,0x89,0x37,0x99,0x8b,0xe1,0x0,0xa6,0x5a,0x5,0x94,0xb5,0x40,0x88,0x85,0x2e,0x5e,0x46,0xd6,0xef,0xd7,0x18,0x3c,0x72,0xf8,0xee,0x7c,0xe2,0xc,0x9c,0x12,0x9f,0xd4,0xdd,0xcc,0x7,0x2d,0xe,0x17,0xfa,0xe6,0xda,0xc2,0x67,0x77,0x50,0x33,0x1f,0xd8,0xb6,0x90,0x9a,0xc,0x96,0x67,0x1c,0xf7,0xc8,0xe5,0x6f,0x9b,0xd3,0x35,0x2a,0x8c,0xea,0xc5,0x9d,0x83,0x18,0x7c,0x2b,0xb5,0x50,0xf2,0x7d,0xf0,0xfc,0x44,0x87,0x3c,0xc2,0x5d,0x41,0x39,0x25,0x91,0xfd,0xfa,0x8a,0x30,0x57,0x75,0x7a,0x60,0xd4,0x6b,0xec,0xb7,0x1b,0x86,0x8e,0x88,0x1d,0x20,0x1,0xfe,0x69,0x45,0x3f,0x4d,0xa0,0x31,0x6e,0x92,0xb1,0xbc,0x74,0x81,0x3,0xbd,0x7f,0x11,0x34,0xd5,0xbf,0xad,0x15,0xbe,0x2e,0x66,0x6d,0xb4,0x32,0x2,0xe6,0xbb,0x49,0x5a,0xfb,0xb8,0x6,0xd,0xf6,0xee,0xd2,0xce,0x7,0x64,0x43,0x53,0xf8,0xe9,0xe0,0xab,0x23,0x3a,0x19,0x33,0x48,0xda,0xcc,0x46,0x26,0xa8,0x38,0xd6,0xe2,0x72,0x6a,0x1a,0x8,0x2c,0xe3,0xdb,0x80,0xf5,0x42,0xe8,0xc7,0x9e,0x78,0x6c,0x7e,0x40,0x24,0x65,0xe4,0x4a,0xc6,0x73,0xa4,0xcf,0xf9,0x4f,0x7b,0x37,0xa3,0x97,0xdc,0xb0,0xd1,0x9,0x0,0xa5,0x14,0xa6,0xca,0x9c,0x28,0x12,0x8b,0x3b,0x59,0x13,0x89,0x56,0x5c,0x47,0x61,0xd0,0xa2,0xcb,0xaf,0xff,0x84,0x2f,0x62,0x54,0xf1,0xd9,0x71,0x70,0x29,0x4c,0x58,0xcd,0x4e,0xa,0xba,0xc0,0xa9,0x95,0x68,0x98,0x4,0xc9,0xaa,0xdd,0x5f,0xd7,0xb2,0xc3,0xeb,0x9f,0x85,0xf3,0x1e,0x5e,0x4b,0xe,0x10,0x94,0x5,0x82,0x76,0x55,0x27,0xdf,0x3d,0xed,0xc1,0x17,0xde,0xef,0xf4,0xb3,0xa7,0xb,0xc4,0x21,0x93,0x5b,0x22,0x51,0x2d,0x77,0x16,0x8d,0xa1,0x63,0x79,0x8f,0x36,0xb9,0xae,0xe7,0xf,0xac,0x52,0xe1,0x99,0x3e,0xdb,0x80,0xe3,0x5c,0xb9,0xbf,0x2c,0xb1,0x36,0xc9,0x2a,0x17,0x8,0x7a,0x5e,0x72,0xf5,0x6a,0xb0,0xb,0x12,0xa6,0x76,0xe,0xbd,0x7,0xca,0xcd,0x4d,0x57,0x60,0x42,0xdd,0xf2,0x1d,0xbb,0x2f,0x4b,0xaa,0xb4,0x67,0xc5,0x1c,0x82,0xcb,0x73,0x4a,0xc7,0x81,0xa7,0x28,0xef,0xa1,0x50,0xad,0x3b,0xff,0xd2,0x2b,0xc0,0xe4,0x2,0x58,0xac,0xfb,0x71,0x7f,0xed,0xf,0xe1,0x11,0x9f,0x5d,0x2d,0xd5,0x45,0xd4,0xec,0x3f,0x1b,0xe5,0xf9,0xc1,0xd9,0x74,0x64,0x30,0x53,0xd7,0x9c,0xcf,0xde,0x2e,0x4,0x14,0xd,0x19,0x51,0x22,0x89,0x5,0x35,0x5a,0x83,0x7e,0x6d,0xd1,0x8c,0x31,0x3a,0xcc,0x8f,0x59,0xa5,0x97,0x6,0x43,0xb6,0x86,0x8b,0x48,0x26,0x34,0x8a,0x88,0x9a,0x3,0xe2,0xb3,0x18,0x98,0xc8,0xc6,0xee,0x55,0x63,0x1e,0x7b,0x46,0x47,0x79,0x3d,0x6f,0xfa,0x1f,0x25,0xfd,0xab,0x6e,0x24,0xbc,0xc,0x6b,0x70,0xbe,0x61,0x95,0xfc,0x56,0xe7,0xce,0x78,0x93,0xf8,0x94,0xa0,0x4c,0x0,0xe6,0x3e,0xeb,0x87,0x23,0x91,0x37,0x92,0x75,0xdf,0xb7,0xc2,0x4f,0x5b,0xf0,0xa9,0x13,0x52,0x49,0x77,0xf1,0x44,0xd3,0x7d,0x96,0x54,0x21,0xba,0x1,0x8e,0x4e,0xb8,0x38,0x9b,0x99,0xd0,0xae,0x9,0x65,0xd6,0xe9,0xd8,0xf6,0x20,0x90,0x3c,0xc3,0x84,0xa4,0x6c,0xf3,0x16,0x1a,0x40,0x15,0x66,0x29,0x69,0xb2,0xc4,0x27,0xa3,0x7c,0x39,0x41,0x62,0x32,0xb5,0xa,0xda,0x10,0xe8,0x9e,0xa2,0x8d,0xf7,0x33,0xfe,0x5f,0xaf,0x68,0xe0,0x9d,0xea,0xdc,0xa8,0x85,0xf4,0xa4,0x66,0x4a,0xd1,0x7e,0xf1,0x48,0xbe,0x6b,0xc8,0x20,0x69,0xf9,0x5e,0x26,0x95,0x28,0x19,0xd0,0x6,0xcc,0x60,0x74,0x33,0x9c,0x54,0xe6,0x3,0xb0,0xea,0x96,0xe5,0x99,0xd9,0x34,0x42,0x53,0xd7,0xc9,0x8c,0x92,0xb1,0x45,0xc2,0x2a,0xfa,0x18,0xe0,0x52,0x6e,0x7,0x7d,0xe,0xc3,0x5f,0xaf,0x10,0x98,0x1a,0x6d,0x58,0x2c,0x4,0x75,0xe8,0x43,0x38,0x68,0x1e,0x36,0x93,0xa5,0x8b,0xee,0xb7,0xb6,0xcd,0x89,0xa,0x9f,0xd5,0xef,0x5b,0xd,0xd4,0x9e,0xfc,0x4c,0x80,0x9b,0x91,0x4e,0xc,0x65,0x17,0xa6,0x88,0x3e,0x8,0x63,0x50,0x64,0xf0,0xbc,0xce,0x16,0x77,0x1b,0x61,0xd3,0x62,0xc7,0x2f,0x85,0x32,0x47,0xab,0xbf,0x59,0x0,0xa2,0xe3,0x87,0xb9,0xb4,0x1,0x8d,0x23,0x81,0xb,0x1d,0x8f,0x11,0xff,0x6f,0xe1,0xdd,0xad,0xb5,0x25,0x1c,0x24,0xeb,0xcf,0x9,0x15,0x29,0x31,0x94,0x84,0xa3,0xc0,0x6c,0x27,0x2e,0x3f,0xf4,0xde,0xfd,0xe4,0xa1,0xe9,0x79,0xd2,0xc5,0xf5,0x73,0xaa,0x9d,0x8e,0x7c,0x21,0xca,0xc1,0x7f,0x3c,0x55,0xa9,0xf6,0x67,0x46,0xb3,0x7b,0x76,0xd6,0xb8,0x7a,0xc4,0x6a,0x78,0x12,0xf3,0x70,0x2b,0xac,0x13,0x4f,0x49,0x41,0xdc,0x39,0xc6,0xe7,0xda,0x8a,0xf8,0x82,0xae,0x9a,0x5,0xfb,0x40,0x56,0xe2,0xfe,0x86,0xf7,0x4d,0x3d,0x3a,0xa7,0xbd,0xb2,0x90,0x2,0x2d,0x4b,0xed,0xbb,0xdf,0x44,0x5a,0x35,0x97,0x72,0xec,0x83,0x3b,0x37,0xba,0x57,0x71,0x1f,0xd8,0xa0,0x51,0xcb,0x5d,0x22,0xf,0x30,0xdb,0xf2,0x14,0x5c,0xa8,0x5,0xe3,0xab,0x5f,0xd5,0xf8,0xc7,0x2c,0x57,0xa6,0x3c,0xaa,0xa0,0x86,0xe8,0x2f,0x74,0xcc,0xc0,0x4d,0xc2,0x60,0x85,0x1b,0x4c,0x28,0xb3,0xad,0xf5,0xda,0xbc,0x1a,0x50,0x4a,0x45,0x67,0x0,0xba,0xca,0xcd,0xa1,0x15,0x9,0x71,0x6d,0xf2,0xc,0xb7,0x7d,0xf,0x75,0x59,0xce,0x31,0x10,0x2d,0xb8,0xbe,0xb6,0x2b,0x87,0xdc,0x5b,0xe4,0x9d,0x8f,0xe5,0x4,0x21,0x4f,0x8d,0x33,0xb1,0x44,0x8c,0x81,0xa2,0x5e,0x1,0x90,0x3d,0x36,0x88,0xcb,0x6a,0x79,0x8b,0xd6,0x32,0x2,0x84,0x5d,0x56,0x1e,0x8e,0x25,0x3,0x29,0xa,0x13,0x9b,0xd0,0xd9,0xc8,0x63,0x73,0x54,0x37,0xfe,0xe2,0xde,0xc6,0xeb,0xd3,0x1c,0x38,0x2a,0x5a,0x42,0xd2,0xe6,0x8,0x98,0x16,0x76,0xfc,0xea,0x78,0x43,0xf6,0x7a,0xd4,0x55,0x14,0x70,0x4e,0x5c,0x48,0xae,0xf7,0xd8,0x72,0xc5,0xb0,0x96,0x24,0x95,0x30,0x39,0xe1,0x80,0xec,0xa7,0x93,0x7,0x4b,0x7f,0xc9,0xff,0x94,0xfb,0x92,0xe0,0x51,0x77,0x6c,0x66,0xb9,0x23,0x69,0xb,0xbb,0x22,0x18,0xac,0xfa,0x3a,0x7e,0xfd,0x68,0x7c,0x19,0x40,0x41,0xe9,0xc1,0x64,0x52,0x1f,0xb4,0xcf,0x9f,0xaf,0xdb,0xf3,0x82,0xe7,0x6f,0xed,0x9a,0xf9,0x34,0xa8,0x58,0xa5,0x99,0xf0,0x8a,0xdd,0xd,0xef,0x17,0x65,0x46,0xb2,0x35,0xa4,0x20,0x3e,0x7b,0x6e,0x2e,0xc3,0xb5,0x47,0x1d,0x61,0x12,0x6b,0xa3,0x11,0xf4,0x3b,0x97,0x83,0xc4,0xdf,0xee,0x27,0xf1,0xe,0xa9,0xd1,0x62,0x9c,0x3f,0xd7,0x9e,0x89,0x6,0xbf,0x49,0x53,0x91,0xbd,0x26,0x86,0xf3,0x44,0xee,0xc1,0x98,0x7e,0x6a,0x78,0x46,0x22,0x63,0xe2,0x4c,0xc0,0x75,0xa2,0xc9,0xff,0x49,0x7d,0x31,0xa5,0x91,0xda,0xb6,0xd7,0xf,0x6,0xa3,0x12,0xa0,0xcc,0x9a,0x2e,0x14,0x8d,0x3d,0x5f,0x15,0x8f,0x50,0x5a,0x41,0x67,0xd6,0xa4,0xcd,0xa9,0xf9,0x82,0x29,0x64,0x52,0xf7,0xdf,0x77,0x76,0x2f,0x4a,0x5e,0xcb,0x48,0xc,0xbc,0xc6,0xaf,0x93,0x6e,0x9e,0x2,0xcf,0xac,0xdb,0x59,0xd1,0xb4,0xc5,0xed,0x99,0x83,0xf5,0x18,0x58,0x4d,0x8,0x16,0x92,0x3,0x84,0x70,0x53,0x21,0xd9,0x3b,0xeb,0xc7,0x11,0xd8,0xe9,0xf2,0xb5,0xa1,0xd,0xc2,0x27,0x95,0x5d,0x24,0x57,0x2b,0x71,0x10,0x8b,0xa7,0x65,0x7f,0x89,0x30,0xbf,0xa8,0xe1,0x9,0xaa,0x54,0xe7,0x9f,0x38,0x19,0xde,0xb0,0x96,0x9c,0xa,0x90,0x61,0x1a,0xf1,0xce,0xe3,0x69,0x9d,0xd5,0x33,0x2c,0x8a,0xec,0xc3,0x9b,0x85,0x1e,0x7a,0x2d,0xb3,0x56,0xf4,0x7b,0xf6,0xfa,0x42,0x81,0x3a,0xc4,0x5b,0x47,0x3f,0x23,0x97,0xfb,0xfc,0x8c,0x36,0x51,0x73,0x7c,0x66,0xd2,0x6d,0xea,0xb1,0x1d,0x80,0x88,0x8e,0x1b,0x26,0x7,0xf8,0x6f,0x43,0x39,0x4b,0xa6,0x37,0x68,0x94,0xb7,0xba,0x72,0x87,0x5,0xbb,0x79,0x17,0x32,0xd3,0xb9,0xab,0x13,0xb8,0x28,0x60,0x6b,0xb2,0x34,0x4,0xe0,0xbd,0x4f,0x5c,0xfd,0xbe,0x0,0xb,0xf0,0xe8,0xd4,0xc8,0x1,0x62,0x45,0x55,0xfe,0xef,0xe6,0xad,0x25,0x3c,0x1f,0x35,0x4e,0xdc,0xca,0x40,0x20,0xae,0x3e,0xd0,0xe4,0x74,0x6c,0x1c,0xe,0x2a,0xe5,0xdd,0x20,0xa8,0xd5,0xa2,0x94,0xe0,0xcd,0xbc,0xd6,0xea,0xc5,0xbf,0x7b,0xb6,0x17,0xe7,0x9,0x2a,0x7a,0xfd,0x42,0x92,0x58,0xa0,0x61,0x21,0xfa,0x8c,0x6f,0xeb,0x34,0x71,0xec,0x24,0xbb,0x5e,0x52,0x8,0x5d,0x2e,0xa1,0x90,0xbe,0x68,0xd8,0x74,0x8b,0xcc,0x70,0xd3,0xd1,0x98,0xe6,0x41,0x2d,0x9e,0xde,0x1c,0x69,0xf2,0x49,0xc6,0x6,0xf0,0x5b,0x1a,0x1,0x3f,0xb9,0xc,0x9b,0x35,0x3d,0x97,0xff,0x8a,0x7,0x13,0xb8,0xe1,0xae,0x76,0xa3,0xcf,0x6b,0xd9,0x7f,0xda,0x86,0x30,0xdb,0xb0,0xdc,0xe8,0x4,0x48,0x23,0x38,0xf6,0x29,0xdd,0xb4,0x1e,0xaf,0x57,0x6d,0xb5,0xe3,0x26,0x6c,0xf4,0x44,0x56,0x33,0xe,0xf,0x31,0x75,0x27,0xb2,0xfb,0x50,0xd0,0x80,0x8e,0xa6,0x1d,0x2b,0x0,0x6e,0x7c,0xc2,0xc0,0xd2,0x4b,0xaa,0x11,0xed,0xdf,0x4e,0xb,0xfe,0xce,0xc3,0x36,0x25,0x99,0xc4,0x79,0x72,0x84,0xc7,0x51,0x19,0x6a,0xc1,0x4d,0x7d,0x12,0xcb,0x9f,0xd4,0x87,0x96,0x66,0x4c,0x5c,0x45,0xad,0xb1,0x89,0x91,0x3c,0x2c,0x78,0x1b,0x15,0x65,0x9d,0xd,0x9c,0xa4,0x77,0x53,0xb3,0x39,0x37,0xa5,0x47,0xa9,0x59,0xd7,0xb7,0x9a,0x63,0x88,0xac,0x4a,0x10,0xe4,0xc9,0xef,0x60,0xa7,0xe9,0x18,0xe5,0x73,0x2f,0x8d,0x54,0xca,0x83,0x3b,0x2,0x8f,0x95,0xba,0x55,0xf3,0x67,0x3,0xe2,0xfc,0xf5,0x4f,0x82,0x85,0x5,0x1f,0x28,0xa,0xbd,0x22,0xf8,0x43,0x5a,0xee,0x3e,0x46,0x7e,0x81,0x62,0x5f,0x40,0x32,0x16,0x3a,0x93,0xc8,0xab,0x14,0xf1,0xf7,0x64,0xf9,0x4f,0xd0,0xa,0xb1,0xa8,0x1c,0xcc,0xb4,0x7,0xbd,0x70,0x77,0xf7,0xed,0xda,0xf8,0x61,0x3a,0x59,0xe6,0x3,0x5,0x96,0xb,0x8c,0x73,0x90,0xad,0xb2,0xc0,0xe4,0xc8,0x3b,0x1d,0x92,0x55,0x1b,0xea,0x17,0x81,0x45,0x68,0x91,0x7a,0x5e,0xb8,0xe2,0x16,0x67,0x48,0xa7,0x1,0x95,0xf1,0x10,0xe,0xdd,0x7f,0xa6,0x38,0x71,0xc9,0xf0,0x7d,0x5f,0x43,0x7b,0x63,0xce,0xde,0x8a,0xe9,0x6d,0x26,0x75,0x64,0x94,0xbe,0xae,0xb7,0x41,0xcb,0xc5,0x57,0xb5,0x5b,0xab,0x25,0xe7,0x97,0x6f,0xff,0x6e,0x56,0x85,0xa1,0xe3,0x1f,0x2d,0xbc,0xf9,0xc,0x3c,0x31,0xf2,0x9c,0x8e,0x30,0x32,0x20,0xb9,0x58,0xa3,0xeb,0x98,0x33,0xbf,0x8f,0xe0,0x39,0xc4,0xd7,0x6b,0x36,0x8b,0x80,0x76,0x35,0xa5,0x9f,0x47,0x11,0xd4,0x9e,0x6,0xb6,0xd1,0xca,0x4,0xdb,0x2f,0x46,0xec,0x5d,0x9,0xa2,0x22,0x72,0x7c,0x54,0xef,0xd9,0xa4,0xc1,0xfc,0xfd,0xc3,0x87,0xd5,0x40,0xcf,0x65,0xd,0x78,0xf5,0xe1,0x4a,0x13,0xa9,0xe8,0xf3,0xcd,0x4b,0xfe,0x69,0xc7,0x74,0xc2,0x29,0x42,0x2e,0x1a,0xf6,0xba,0x5c,0x84,0x51,0x3d,0x99,0x2b,0x8d,0x28,0x53,0x62,0x4c,0x9a,0x2a,0x86,0x79,0x3e,0x1e,0xd6,0x49,0xac,0xa0,0xfa,0xaf,0xdc,0x2c,0xee,0x9b,0x0,0xbb,0x34,0xf4,0x2,0x82,0x21,0x23,0x6a,0x14,0xb3,0xdf,0x6c,0x24,0x18,0x37,0x4d,0x89,0x44,0xe5,0x15,0xd2,0x5a,0x27,0x50,0x66,0x12,0x3f,0x4e,0x93,0xd3,0x8,0x7e,0x9d,0x19,0xc6,0x83,0xfb,0xd8,0x88,0xf,0xb0,0x60,0xaa,0x52,0x8,0xb2,0xc2,0xc5,0x58,0x42,0x4d,0x6f,0x65,0xfa,0x4,0xbf,0xa9,0x1d,0x1,0x79,0xc6,0x39,0x18,0x25,0x75,0x7,0x7d,0x51,0x8f,0xd4,0x53,0xec,0xb0,0xb6,0xbe,0x23,0xdd,0xf0,0xcf,0x24,0xd,0xeb,0xa3,0x57,0xa8,0x8e,0xe0,0x27,0x5f,0xae,0x34,0xa2,0xca,0x68,0x8d,0x13,0x7c,0xc4,0xc8,0x45,0xfd,0xd2,0xb4,0x12,0x44,0x20,0xbb,0xa5,0x93,0xd8,0xd1,0xc0,0xb,0x21,0x2,0x1b,0xf6,0xea,0xd6,0xce,0x6b,0x7b,0x5c,0x3f,0x22,0x52,0x4a,0xda,0xe3,0xdb,0x14,0x30,0x7e,0xf4,0xe2,0x70,0xee,0x0,0x90,0x1e,0x29,0x47,0x85,0x3b,0x95,0x87,0xed,0xc,0xaa,0x56,0x9,0x98,0xb9,0x4c,0x84,0x89,0x62,0x71,0x83,0xde,0x35,0x3e,0x80,0xc3,0x5e,0x16,0x86,0x2d,0x3a,0xa,0x8c,0x55,0x7f,0x64,0x6e,0xb1,0xf3,0x9a,0xe8,0x59,0x2a,0x10,0xa4,0xf2,0x2b,0x61,0x3,0xb3,0x74,0x11,0x48,0x49,0x32,0x76,0xf5,0x60,0x17,0xbc,0xc7,0x97,0xe1,0xc9,0x6c,0x5a,0x5d,0x1c,0x78,0x46,0x4b,0xfe,0x72,0xdc,0xd0,0x7a,0xcd,0xb8,0x54,0x40,0xa6,0xff,0x31,0xe9,0x88,0xe4,0x9e,0x2c,0x9d,0x38,0x77,0xc1,0xf7,0x9c,0xaf,0x9b,0xf,0x43,0x63,0xab,0x19,0xfc,0x4f,0x15,0x69,0x1a,0xd7,0xe6,0x2f,0xf9,0x33,0x9f,0x8b,0xcc,0x94,0x37,0xdf,0x96,0x6,0xa1,0xd9,0x6a,0x5b,0x99,0xb5,0x2e,0x81,0xe,0xb7,0x41,0xef,0x67,0xe5,0x92,0xa7,0xd3,0xfb,0x8a,0xad,0x91,0xf8,0x82,0xf1,0x3c,0xa0,0x50,0x6d,0x4e,0xba,0x3d,0xd5,0x5,0xe7,0x1f,0x66,0x26,0xcb,0xbd,0xac,0x28,0x36,0x73,0x61,0xdb,0x16,0x11,0x91,0x8b,0xbc,0x9e,0x29,0xb6,0x6c,0xd7,0xce,0x7a,0xaa,0xd2,0xea,0x15,0xf6,0xcb,0xd4,0xa6,0x82,0xae,0x7,0x5c,0x3f,0x80,0x65,0x63,0xf0,0x6d,0x23,0xe,0xf7,0x1c,0x38,0xde,0x84,0x70,0x5d,0x7b,0xf4,0x33,0x7d,0x8c,0x71,0xe7,0xbb,0x19,0xc0,0x5e,0x17,0xaf,0x96,0x1b,0x1,0x2e,0xc1,0x67,0xf3,0x97,0x76,0x68,0xb,0x40,0x13,0x2,0xf2,0xd8,0xc8,0xd1,0x39,0x25,0x1d,0x5,0xa8,0xb8,0xec,0x8f,0x81,0xf1,0x9,0x99,0x8,0x30,0xe3,0xc7,0x27,0xad,0xa3,0x31,0xd3,0x3d,0xcd,0x43,0x94,0xfa,0xe8,0x56,0x54,0x46,0xdf,0x3e,0x85,0x79,0x4b,0xda,0x9f,0x6a,0x5a,0x57,0xa2,0xb1,0xd,0x50,0xed,0xe6,0x10,0x53,0xc5,0x8d,0xfe,0x55,0xd9,0xe9,0x86,0x5f,0xb7,0xac,0x62,0xbd,0x49,0x20,0x8a,0x3b,0xc3,0xf9,0x21,0x77,0xb2,0xf8,0x60,0xd0,0xc2,0xa7,0x9a,0x9b,0xa5,0xe1,0xb3,0x26,0x6f,0xc4,0x44,0x14,0x1a,0x32,0x89,0xbf,0xcf,0x8e,0x95,0xab,0x2d,0x98,0xf,0xa1,0xa9,0x3,0x6b,0x1e,0x93,0x87,0x2c,0x75,0x3a,0xe2,0x37,0x5b,0xff,0x4d,0xeb,0x4e,0x12,0xa4,0x4f,0x24,0x48,0x7c,0x90,0xdc,0x78,0xb0,0x2f,0xca,0xc6,0x9c,0xc9,0xba,0x35,0x4,0x2a,0xfc,0x4c,0xe0,0x1f,0x58,0xe4,0x47,0x45,0xc,0x72,0xd5,0xb9,0xa,0x4a,0x88,0xfd,0x66,0xdd,0x52,0x92,0x64,0xb4,0x3c,0x41,0x36,0x0,0x74,0x59,0x28,0x42,0x7e,0x51,0x2b,0xef,0x22,0x83,0x73,0x9d,0xbe,0xee,0x69,0xd6,0x6,0xcc,0x34,0xf5,0xb5,0x6e,0x18,0xfb,0x7f,0xa0,0xe5,0x68,0xc6,0x4a,0xff,0xf2,0xcc,0xa8,0xe9,0x4b,0x12,0xf4,0xe0,0xc,0x79,0xce,0x64,0x8c,0x29,0x98,0x2a,0x50,0x3c,0x5d,0x85,0xf7,0xbb,0x2f,0x1b,0x28,0x43,0x75,0xc3,0xed,0x5c,0x2e,0x47,0x5,0xda,0xd0,0xcb,0x7,0xb7,0xd5,0x9f,0x46,0x10,0xa4,0x9e,0xd4,0x41,0xc2,0x86,0xfd,0xfc,0xa5,0xc0,0xee,0xd8,0x7d,0x55,0x23,0x73,0x8,0xa3,0x3e,0x4f,0x67,0x13,0x26,0x51,0xd3,0x5b,0xe4,0x14,0x88,0x45,0x36,0x4c,0x25,0x19,0xab,0x53,0xb1,0x61,0x89,0xe,0xfa,0xd9,0xc7,0x82,0x9c,0x18,0x9,0x7f,0x92,0xd2,0xae,0xdd,0xa1,0xfb,0x48,0xad,0x1f,0xd7,0x78,0x3f,0x2b,0x87,0x4d,0x9b,0x52,0x63,0xde,0x6d,0x15,0xb2,0x22,0x6b,0x83,0x20,0xf5,0x3,0xba,0x35,0x9a,0x1,0x2d,0xef,0xe3,0x17,0x5f,0xb9,0x90,0x7b,0x44,0x69,0x16,0x80,0x1a,0xeb,0x93,0x54,0x3a,0x1c,0xf1,0x7c,0x70,0xc8,0xa7,0x39,0xdc,0x7e,0x11,0xf,0x94,0xf0,0xa6,0x0,0x66,0x49,0xdb,0xf9,0xf6,0xec,0x71,0x76,0x6,0xbc,0xcd,0xb5,0xa9,0x1d,0xb,0xb0,0x4e,0xd1,0xe5,0xc9,0xb3,0xc1,0x91,0xac,0x8d,0x72,0x97,0xa,0x2,0x4,0x58,0xe7,0x60,0x3b,0xb8,0x59,0x33,0x21,0x8f,0x31,0xf3,0x9d,0x3d,0x30,0xf8,0xd,0x2c,0xbd,0xe2,0x1e,0x77,0x34,0x8a,0x81,0x6a,0x37,0xc5,0xd6,0xe1,0x38,0xbe,0x8e,0x99,0x32,0xa2,0xea,0xaf,0xb6,0x95,0xbf,0x74,0x65,0x6c,0x27,0x8b,0xe8,0xcf,0xdf,0x7a,0x62,0x5e,0x42,0x84,0xa0,0x6f,0x57,0x6e,0xfe,0xe6,0x96,0xaa,0x24,0xb4,0x5a,0xc4,0x56,0x40,0xca,0x50,0xc5,0x46,0x2,0x79,0x78,0x21,0x44,0x6a,0x5c,0xf9,0xd1,0xa7,0xf7,0x8c,0x27,0x69,0xd8,0xaa,0xc3,0x81,0x5e,0x54,0x4f,0x83,0x33,0x51,0x1b,0xc2,0x94,0x20,0x1a,0x8,0xad,0x1c,0xae,0xd4,0xb8,0xd9,0x1,0x73,0x3f,0xab,0x9f,0xac,0xc7,0xf1,0x47,0xec,0x42,0xce,0x7b,0x76,0x48,0x2c,0x6d,0xcf,0x96,0x70,0x64,0x88,0xfd,0x4a,0xe0,0x5a,0xe9,0x91,0x36,0xa6,0xef,0x7,0xa4,0x71,0x87,0x3e,0xb1,0x1e,0x85,0xa9,0x6b,0x2a,0x59,0x25,0x7f,0xcc,0x29,0x9b,0x53,0xfc,0xbb,0xaf,0x3,0xc9,0x1f,0xd6,0xe7,0x2f,0xd7,0x35,0xe5,0xd,0x8a,0x7e,0x5d,0x43,0x6,0x18,0x9c,0x8d,0xfb,0x16,0x56,0xba,0xcb,0xe3,0x97,0xa2,0xd5,0x57,0xdf,0x60,0x90,0xc,0xc1,0xb2,0xc8,0xa1,0x9d,0x61,0x4d,0x37,0x45,0x15,0x28,0x9,0xf6,0x13,0x8e,0x86,0x80,0xdc,0x63,0xe4,0xbf,0x5f,0x7d,0x72,0x68,0xf5,0xf2,0x82,0x38,0x49,0x31,0x2d,0x99,0x8f,0x34,0xca,0x55,0x75,0xf8,0xf4,0x4c,0x23,0xbd,0x58,0xfa,0x95,0x8b,0x10,0x74,0x22,0x84,0xe2,0xcd,0x67,0x93,0xdb,0x3d,0x14,0xff,0xc0,0xed,0x92,0x4,0x9e,0x6f,0x17,0xd0,0xbe,0x98,0x0,0x24,0xeb,0xd3,0xea,0x7a,0x62,0x12,0x2e,0xa0,0x30,0xde,0x40,0xd2,0xc4,0x4e,0x2b,0x32,0x11,0x3b,0xf0,0xe1,0xe8,0xa3,0xf,0x6c,0x4b,0x5b,0xfe,0xe6,0xda,0xc6,0xf3,0xb0,0xe,0x5,0xee,0xb3,0x41,0x52,0x65,0xbc,0x3a,0xa,0x1d,0xb6,0x26,0x6e,0x3c,0xdd,0xb7,0xa5,0xb,0xb5,0x77,0x19,0xb9,0xb4,0x7c,0x89,0xa8,0x39,0x66,0x9a,0x55,0x44,0x4d,0x6,0x8e,0x97,0xb4,0x9e,0x5b,0x43,0x7f,0x63,0xaa,0xc9,0xee,0xfe,0x4f,0xdf,0xc7,0xb7,0xa5,0x81,0x4e,0x76,0xe5,0x77,0x61,0xeb,0x8b,0x5,0x95,0x7b,0xae,0x10,0xd2,0xbc,0x99,0x78,0x12,0x0,0xd,0x9c,0xc3,0x3f,0x1c,0x11,0xd9,0x2c,0x4b,0x16,0xe4,0xf7,0x56,0x15,0xab,0xa0,0xb8,0x13,0x83,0xcb,0xc0,0x19,0x9f,0xaf,0x50,0x57,0x27,0x9d,0xfa,0xd8,0xd7,0xcd,0x2a,0x91,0x6f,0xf0,0xec,0x94,0x88,0x3c,0xb0,0x8d,0xac,0x53,0xc4,0xe8,0x92,0xe0,0x79,0xc6,0x41,0x1a,0xb6,0x2b,0x23,0x25,0xb1,0x5a,0x65,0x48,0xc2,0x36,0x7e,0x98,0xb2,0x75,0x1b,0x3d,0x37,0xa1,0x3b,0xca,0x86,0x18,0xfd,0x5f,0xd0,0x5d,0x51,0xe9,0x87,0x21,0x47,0x68,0x30,0x2e,0xb5,0xd1,0x69,0x8c,0x3e,0xf6,0x8f,0xfc,0x80,0xda,0x6c,0xba,0x73,0x42,0x59,0x1e,0xa,0xa6,0x3,0x4a,0xa2,0x1,0xff,0x4c,0x34,0x93,0xbb,0x20,0xc,0xce,0xd4,0x22,0x9b,0x14,0x7,0x70,0xf2,0x7a,0x1f,0x6e,0x46,0x32,0x17,0x6d,0x4,0x38,0xc5,0x35,0xa9,0x64,0xa8,0x2f,0xdb,0xf8,0x8a,0x72,0x90,0x40,0x28,0x5e,0xb3,0xf3,0xe6,0xa3,0xbd,0x39,0x24,0xfb,0xf1,0xea,0xcc,0x7d,0xf,0x66,0x67,0x31,0x85,0xbf,0x26,0x96,0xf4,0xbe,0xdc,0xdd,0x84,0xe1,0xf5,0x60,0xe3,0xa7,0x2,0x52,0x29,0x82,0xcf,0xf9,0x5c,0x74,0xd3,0xed,0x89,0xc8,0x49,0xe7,0x6b,0xde,0x2d,0x58,0xef,0x45,0x6a,0x33,0xd5,0xc1,0x71,0x1d,0x7c,0xa4,0xad,0x8,0xb9,0xb,0x9,0x62,0x54,0xe2,0xd6,0x9a,0xe,0x3a}; unsigned char table_s4[] = {0x5b,0x9c,0x13,0x35,0x8f,0x19,0xe4,0x15,0x74,0x9f,0x66,0x4b,0x18,0xec,0xb6,0x50,0xf,0xa9,0x46,0x69,0x0,0x1e,0xff,0x9b,0x36,0xa8,0x71,0xd3,0x73,0xfe,0xc7,0x7f,0xbf,0x4,0xde,0x41,0xba,0xc2,0x12,0xa6,0x79,0x7e,0xb3,0x9,0xf6,0xd4,0xe3,0xf9,0xe8,0x57,0x34,0x6f,0x5,0x98,0xb,0xd,0xa3,0x9e,0x7d,0x82,0xc6,0xea,0xce,0xbc,0xb2,0x23,0x11,0xed,0x3f,0x32,0x2,0xf7,0x3e,0x80,0x92,0xfc,0x56,0xb7,0x2e,0x3c,0x3d,0x96,0xe5,0xad,0x37,0xee,0x81,0xb1,0x38,0x65,0xd9,0xca,0x3b,0x78,0x8e,0x85,0x6d,0x75,0x4d,0x51,0xe7,0x84,0xd0,0xc0,0x6a,0x7b,0x28,0x63,0xb9,0xa0,0xb0,0x9a,0x59,0xcb,0xc5,0x4f,0x2b,0xa5,0x55,0xbb,0xf1,0x61,0x99,0xe9,0xaf,0x8b,0x58,0x60,0x76,0x3,0x6b,0xc1,0x1d,0x44,0xef,0xfb,0xc3,0xfd,0xe6,0xa7,0xc9,0x67,0xf0,0x45,0x4c,0x27,0xcc,0x7a,0xb4,0xf8,0x14,0x20,0x33,0x5f,0x8a,0x52,0x26,0x83,0x25,0x97,0x1f,0x49,0x91,0xab,0xb8,0x8,0x90,0xda,0xd5,0xa,0xc4,0xdf,0x53,0xe2,0x48,0x21,0x7c,0x2c,0xac,0x7,0xd7,0xe1,0x5a,0x72,0xf3,0xf2,0xcf,0xaa,0x4e,0xdb,0x89,0xcd,0x43,0x39,0x16,0x2a,0x1b,0xeb,0x4a,0x87,0x5e,0x29,0x54,0xdc,0x40,0x31,0x1c,0x68,0x70,0x6,0xdd,0x9d,0x8d,0xc8,0x17,0x93,0x1,0x86,0xd6,0xf5,0x5c,0xa4,0x6e,0xbe,0x94,0x42,0x6c,0x5d,0x30,0x77,0x88,0x24,0xa2,0x47,0xd8,0x10,0xd2,0xa1,0xf4,0xae,0xe,0x95,0xe0,0x22,0xc,0xfa,0x3a,0xb5,0x64,0x2d,0x2f,0x8c,0x62,0xd1,0xbd,0x1a,0x91,0x37,0xd8,0xf7,0x9e,0x80,0x61,0x5,0xa8,0x36,0xef,0x4d,0xed,0x60,0x59,0xe1,0xc5,0x2,0x8d,0xab,0x11,0x87,0x7a,0x8b,0xea,0x1,0xf8,0xd5,0x86,0x72,0x28,0xce,0x76,0xc9,0xaa,0xf1,0x9b,0x6,0x95,0x93,0x3d,0x0,0xe3,0x1c,0x58,0x74,0x50,0x22,0x21,0x9a,0x40,0xdf,0x24,0x5c,0x8c,0x38,0xe7,0xe0,0x2d,0x97,0x68,0x4a,0x7d,0x67,0xa3,0x8,0x7b,0x33,0xa9,0x70,0x1f,0x2f,0xa6,0xfb,0x47,0x54,0xa5,0xe6,0x10,0x1b,0x2c,0xbd,0x8f,0x73,0xa1,0xac,0x9c,0x69,0xa0,0x1e,0xc,0x62,0xc8,0x29,0xb0,0xa2,0xc7,0x55,0x5b,0xd1,0xb5,0x3b,0xcb,0x25,0x6f,0xff,0x7,0x77,0x31,0x15,0xc6,0xfe,0xf3,0xeb,0xd3,0xcf,0x79,0x1a,0x4e,0x5e,0xf4,0xe5,0xb6,0xfd,0x27,0x3e,0x2e,0x4,0xd2,0xb9,0x52,0xe4,0x2a,0x66,0x8a,0xbe,0xad,0xc1,0x14,0xcc,0xb8,0x1d,0xbb,0x9,0xe8,0x9d,0xf5,0x5f,0x83,0xda,0x71,0x65,0x5d,0x63,0x78,0x39,0x57,0xf9,0x6e,0xdb,0xe2,0xb2,0x32,0x99,0x49,0x7f,0xc4,0xec,0x6d,0x6c,0x51,0x34,0xd0,0x45,0x17,0x53,0x81,0xd7,0xf,0x35,0x26,0x96,0xe,0x44,0x4b,0x94,0x5a,0x41,0xcd,0x7c,0xd6,0xbf,0xee,0x98,0x43,0x3,0x13,0x56,0x89,0xd,0x9f,0x18,0x48,0x6b,0xc2,0x3a,0xf0,0x20,0xdd,0xa7,0x88,0xb4,0x85,0x75,0xd4,0x19,0xc0,0xb7,0xca,0x42,0xde,0xaf,0x82,0xf6,0x90,0xb,0x7e,0xbc,0x92,0x64,0xa4,0x2b,0xfa,0xb3,0xb1,0x12,0xfc,0x4f,0x23,0x84,0xa,0xdc,0xf2,0xc3,0xae,0xe9,0x16,0xba,0x3c,0xd9,0x46,0x8e,0x4c,0x3f,0x6a,0x30,0xc4,0xe9,0x10,0xfb,0xdf,0x39,0x63,0x97,0xba,0x9c,0x13,0xd4,0x9a,0x6b,0x96,0x0,0x5c,0xfe,0x27,0xb9,0xf0,0x48,0x71,0xfc,0xe6,0xc9,0x26,0x80,0x14,0x70,0x91,0x8f,0x86,0x3c,0xf1,0xf6,0x76,0x6c,0x5b,0x79,0xce,0x51,0x8b,0x30,0x29,0x9d,0x4d,0x35,0xd,0xf2,0x11,0x2c,0x33,0x41,0x65,0x49,0xe0,0xbb,0xd8,0x67,0x82,0x84,0x17,0x8a,0x73,0x1d,0xf,0xb1,0xb3,0xa1,0x38,0xd9,0x62,0x9e,0xac,0x3d,0x78,0x8d,0xbd,0xb0,0x45,0x56,0xea,0xb7,0xa,0x1,0xf7,0xb4,0x22,0x6a,0x19,0xb2,0x3e,0xe,0x61,0xb8,0xec,0xa7,0xf4,0xe5,0x15,0x3f,0x2f,0x36,0xde,0xc2,0xfa,0xe2,0x4f,0x5f,0xb,0x68,0x66,0x16,0xee,0x7e,0xef,0xd7,0x4,0x20,0xc0,0x4a,0x44,0xd6,0x34,0xda,0x2a,0xa4,0x28,0x69,0x72,0x4c,0xca,0x7f,0xe8,0x46,0x4e,0xe4,0x8c,0xf9,0x74,0x60,0xcb,0x92,0xdd,0x5,0xd0,0xbc,0x18,0xaa,0xc,0xa9,0xf5,0x43,0xa8,0xc3,0xaf,0x9b,0x77,0x3b,0x50,0x4b,0x85,0x5a,0xae,0xc7,0x6d,0xdc,0x24,0x1e,0xc6,0x90,0x55,0x1f,0x87,0x37,0x25,0x40,0x7d,0x7c,0x42,0x6,0x54,0xc1,0x88,0x23,0xa3,0xf3,0xfd,0xd5,0x6e,0x58,0x53,0xdb,0xa6,0xd1,0xe7,0x93,0xbe,0xcf,0xa5,0x99,0xb6,0xcc,0x8,0xc5,0x64,0x94,0x7a,0x59,0x9,0x8e,0x31,0xe1,0x2b,0xd3,0x12,0x52,0x89,0xff,0x1c,0x98,0x47,0x2,0x9f,0x57,0xc8,0x2d,0x21,0x7b,0x2e,0x5d,0xd2,0xe3,0xcd,0x1b,0xab,0x7,0xf8,0xbf,0x3,0xa0,0xa2,0xeb,0x95,0x32,0x5e,0xed,0xad,0x6f,0x1a,0x81,0x3a,0xb5,0x75,0x83,0xbc,0xba,0xb2,0x2f,0x83,0xd8,0x5f,0xe0,0x79,0xb,0x71,0x5d,0xca,0x35,0x14,0x29,0xa5,0x11,0xd,0x75,0x69,0xf6,0x8,0xb3,0x54,0x4e,0x41,0x63,0x4,0xbe,0xce,0xc9,0x48,0x2c,0xb7,0xa9,0xf1,0xde,0xb8,0x1e,0x70,0xc8,0xc4,0x49,0xc6,0x64,0x81,0x1f,0x53,0xa2,0x38,0xae,0xa4,0x82,0xec,0x2b,0x1,0xe7,0xaf,0x5b,0xd1,0xfc,0xc3,0x28,0xe2,0xc,0x9c,0x12,0x72,0xf8,0xee,0x7c,0xef,0xd7,0x18,0x3c,0x2e,0x5e,0x46,0xd6,0x67,0x77,0x50,0x33,0xfa,0xe6,0xda,0xc2,0x7,0x2d,0xe,0x17,0x9f,0xd4,0xdd,0xcc,0x36,0x6,0x80,0x59,0x52,0x1a,0x8a,0x21,0x39,0x32,0x8c,0xcf,0x6e,0x7d,0x8f,0xd2,0xb5,0x40,0x88,0x85,0xa6,0x5a,0x5,0x94,0x99,0x8b,0xe1,0x0,0x25,0x4b,0x89,0x37,0xed,0xc5,0x60,0x56,0x1b,0xb0,0xcb,0x9b,0x3e,0x7a,0xf9,0x6c,0x78,0x1d,0x44,0x45,0x27,0x6d,0xf,0xbf,0x26,0x1c,0xa8,0xfe,0xff,0x96,0xe4,0x55,0x73,0x68,0x62,0xbd,0xa3,0x97,0x3,0x4f,0x7b,0xcd,0xfb,0x90,0x92,0x20,0x91,0x34,0x3d,0xe5,0x84,0xe8,0x58,0x4c,0xaa,0xf3,0xdc,0x76,0xc1,0xb4,0x47,0xf2,0x7e,0xd0,0x51,0x10,0x74,0x4a,0x8d,0x2,0xbb,0x4d,0x57,0x95,0xb9,0x22,0xa,0xad,0xd5,0x66,0x98,0x3b,0xd3,0x9a,0x3f,0x93,0x87,0xc0,0xdb,0xea,0x23,0xf5,0x43,0x19,0x65,0x16,0x6f,0xa7,0x15,0xf0,0xa0,0x24,0x3a,0x7f,0x6a,0x2a,0xc7,0xb1,0xd9,0x9,0xeb,0x13,0x61,0x42,0xb6,0x31,0xfd,0x30,0xac,0x5c,0xa1,0x9d,0xf4,0x8e,0xab,0xdf,0xf7,0x86,0xe3,0x6b,0xe9,0x9e,0x8b,0x4c,0xc3,0xe5,0x5f,0xc9,0x34,0xc5,0xa4,0x4f,0xb6,0x9b,0xc8,0x3c,0x66,0x80,0xdf,0x79,0x96,0xb9,0xd0,0xce,0x2f,0x4b,0xe6,0x78,0xa1,0x3,0xa3,0x2e,0x17,0xaf,0x6f,0xd4,0xe,0x91,0x6a,0x12,0xc2,0x76,0xa9,0xae,0x63,0xd9,0x26,0x4,0x33,0x29,0x38,0x87,0xe4,0xbf,0xd5,0x48,0xdb,0xdd,0x73,0x4e,0xad,0x52,0x16,0x3a,0x1e,0x6c,0x62,0xf3,0xc1,0x3d,0xef,0xe2,0xd2,0x27,0xee,0x50,0x42,0x2c,0x86,0x67,0xfe,0xec,0xed,0x46,0x35,0x7d,0xe7,0x3e,0x51,0x61,0xe8,0xb5,0x9,0x1a,0xeb,0xa8,0x5e,0x55,0xbd,0xa5,0x9d,0x81,0x37,0x54,0x0,0x10,0xba,0xab,0xf8,0xb3,0x69,0x70,0x60,0x4a,0x89,0x1b,0x15,0x9f,0xfb,0x75,0x85,0x6b,0x21,0xb1,0x49,0x39,0x7f,0x5b,0x88,0xb0,0xa6,0xd3,0xbb,0x11,0xcd,0x94,0x3f,0x2b,0x13,0x2d,0x36,0x77,0x19,0xb7,0x20,0x95,0x9c,0xf7,0x1c,0xaa,0x64,0x28,0xc4,0xf0,0xe3,0x8f,0x5a,0x82,0xf6,0x53,0xf5,0x47,0xcf,0x99,0x41,0x7b,0x68,0xd8,0x40,0xa,0x5,0xda,0x14,0xf,0x83,0x32,0x98,0xf1,0xac,0xfc,0x7c,0xd7,0x7,0x31,0x8a,0xa2,0x23,0x22,0x1f,0x7a,0x9e,0xb,0x59,0x1d,0x93,0xe9,0xc6,0xfa,0xcb,0x3b,0x9a,0x57,0x8e,0xf9,0x84,0xc,0x90,0xe1,0xcc,0xb8,0xa0,0xd6,0xd,0x4d,0x5d,0x18,0xc7,0x43,0xd1,0x56,0x6,0x25,0x8c,0x74,0xbe,0x6e,0x44,0x92,0xbc,0x8d,0xe0,0xa7,0x58,0xf4,0x72,0x97,0x8,0xc0,0x2,0x71,0x24,0x7e,0xde,0x45,0x30,0xf2,0xdc,0x2a,0xea,0x65,0xb4,0xfd,0xff,0x5c,0xb2,0x1,0x6d,0xca,0x41,0xe7,0x8,0x27,0x4e,0x50,0xb1,0xd5,0x78,0xe6,0x3f,0x9d,0x3d,0xb0,0x89,0x31,0x15,0xd2,0x5d,0x7b,0xc1,0x57,0xaa,0x5b,0x3a,0xd1,0x28,0x5,0x56,0xa2,0xf8,0x1e,0xa6,0x19,0x7a,0x21,0x4b,0xd6,0x45,0x43,0xed,0xd0,0x33,0xcc,0x88,0xa4,0x80,0xf2,0xf1,0x4a,0x90,0xf,0xf4,0x8c,0x5c,0xe8,0x37,0x30,0xfd,0x47,0xb8,0x9a,0xad,0xb7,0x73,0xd8,0xab,0xe3,0x79,0xa0,0xcf,0xff,0x76,0x2b,0x97,0x84,0x75,0x36,0xc0,0xcb,0xfc,0x6d,0x5f,0xa3,0x71,0x7c,0x4c,0xb9,0x70,0xce,0xdc,0xb2,0x18,0xf9,0x60,0x72,0x17,0x85,0x8b,0x1,0x65,0xeb,0x1b,0xf5,0xbf,0x2f,0xd7,0xa7,0xe1,0xc5,0x16,0x2e,0x23,0x3b,0x3,0x1f,0xa9,0xca,0x9e,0x8e,0x24,0x35,0x66,0x2d,0xf7,0xee,0xfe,0xd4,0x2,0x69,0x82,0x34,0xfa,0xb6,0x5a,0x6e,0x7d,0x11,0xc4,0x1c,0x68,0xcd,0x6b,0xd9,0x38,0x4d,0x25,0x8f,0x53,0xa,0xa1,0xb5,0x8d,0xb3,0xa8,0xe9,0x87,0x29,0xbe,0xb,0x32,0x62,0xe2,0x49,0x99,0xaf,0x14,0x3c,0xbd,0xbc,0x81,0xe4,0x0,0x95,0xc7,0x83,0x51,0x7,0xdf,0xe5,0xf6,0x46,0xde,0x94,0x9b,0x44,0x8a,0x91,0x1d,0xac,0x6,0x6f,0x3e,0x48,0x93,0xd3,0xc3,0x86,0x59,0xdd,0x4f,0xc8,0x98,0xbb,0x12,0xea,0x20,0xf0,0xd,0x77,0x58,0x64,0x55,0xa5,0x4,0xc9,0x10,0x67,0x1a,0x92,0xe,0x7f,0x52,0x26,0x40,0xdb,0xae,0x6c,0x42,0xb4,0x74,0xfb,0x2a,0x63,0x61,0xc2,0x2c,0x9f,0xf3,0x54,0xda,0xc,0x22,0x13,0x7e,0x39,0xc6,0x6a,0xec,0x9,0x96,0x5e,0x9c,0xef,0xba,0xe0,0xb,0x26,0xdf,0x34,0x10,0xf6,0xac,0x58,0x75,0x53,0xdc,0x1b,0x55,0xa4,0x59,0xcf,0x93,0x31,0xe8,0x76,0x3f,0x87,0xbe,0x33,0x29,0x6,0xe9,0x4f,0xdb,0xbf,0x5e,0x40,0x49,0xf3,0x3e,0x39,0xb9,0xa3,0x94,0xb6,0x1,0x9e,0x44,0xff,0xe6,0x52,0x82,0xfa,0xc2,0x3d,0xde,0xe3,0xfc,0x8e,0xaa,0x86,0x2f,0x74,0x17,0xa8,0x4d,0x4b,0xd8,0x45,0xbc,0xd2,0xc0,0x7e,0x7c,0x6e,0xf7,0x16,0xad,0x51,0x63,0xf2,0xb7,0x42,0x72,0x7f,0x8a,0x99,0x25,0x78,0xc5,0xce,0x38,0x7b,0xed,0xa5,0xd6,0x7d,0xf1,0xc1,0xae,0x77,0x23,0x68,0x3b,0x2a,0xda,0xf0,0xe0,0xf9,0x11,0xd,0x35,0x2d,0x80,0x90,0xc4,0xa7,0xa9,0xd9,0x21,0xb1,0x20,0x18,0xcb,0xef,0xf,0x85,0x8b,0x19,0xfb,0x15,0xe5,0x6b,0xe7,0xa6,0xbd,0x83,0x5,0xb0,0x27,0x89,0x81,0x2b,0x43,0x36,0xbb,0xaf,0x4,0x5d,0x12,0xca,0x1f,0x73,0xd7,0x65,0xc3,0x66,0x3a,0x8c,0x67,0xc,0x60,0x54,0xb8,0xf4,0x9f,0x84,0x4a,0x95,0x61,0x8,0xa2,0x13,0xeb,0xd1,0x9,0x5f,0x9a,0xd0,0x48,0xf8,0xea,0x8f,0xb2,0xb3,0x8d,0xc9,0x9b,0xe,0x47,0xec,0x6c,0x3c,0x32,0x1a,0xa1,0x97,0x9c,0x14,0x69,0x1e,0x28,0x5c,0x71,0x0,0x6a,0x56,0x79,0x3,0xc7,0xa,0xab,0x5b,0xb5,0x96,0xc6,0x41,0xfe,0x2e,0xe4,0x1c,0xdd,0x9d,0x46,0x30,0xd3,0x57,0x88,0xcd,0x50,0x98,0x7,0xe2,0xee,0xb4,0xe1,0x92,0x1d,0x2c,0x2,0xd4,0x64,0xc8,0x37,0x70,0xcc,0x6f,0x6d,0x24,0x5a,0xfd,0x91,0x22,0x62,0xa0,0xd5,0x4e,0xf5,0x7a,0xba,0x4c,0x3d,0x3b,0x33,0xae,0x2,0x59,0xde,0x61,0xf8,0x8a,0xf0,0xdc,0x4b,0xb4,0x95,0xa8,0x24,0x90,0x8c,0xf4,0xe8,0x77,0x89,0x32,0xd5,0xcf,0xc0,0xe2,0x85,0x3f,0x4f,0x48,0xc9,0xad,0x36,0x28,0x70,0x5f,0x39,0x9f,0xf1,0x49,0x45,0xc8,0x47,0xe5,0x0,0x9e,0xd2,0x23,0xb9,0x2f,0x25,0x3,0x6d,0xaa,0x80,0x66,0x2e,0xda,0x50,0x7d,0x42,0xa9,0x63,0x8d,0x1d,0x93,0xf3,0x79,0x6f,0xfd,0x6e,0x56,0x99,0xbd,0xaf,0xdf,0xc7,0x57,0xe6,0xf6,0xd1,0xb2,0x7b,0x67,0x5b,0x43,0x86,0xac,0x8f,0x96,0x1e,0x55,0x5c,0x4d,0xb7,0x87,0x1,0xd8,0xd3,0x9b,0xb,0xa0,0xb8,0xb3,0xd,0x4e,0xef,0xfc,0xe,0x53,0x34,0xc1,0x9,0x4,0x27,0xdb,0x84,0x15,0x18,0xa,0x60,0x81,0xa4,0xca,0x8,0xb6,0x6c,0x44,0xe1,0xd7,0x9a,0x31,0x4a,0x1a,0xbf,0xfb,0x78,0xed,0xf9,0x9c,0xc5,0xc4,0xa6,0xec,0x8e,0x3e,0xa7,0x9d,0x29,0x7f,0x7e,0x17,0x65,0xd4,0xf2,0xe9,0xe3,0x3c,0x22,0x16,0x82,0xce,0xfa,0x4c,0x7a,0x11,0x13,0xa1,0x10,0xb5,0xbc,0x64,0x5,0x69,0xd9,0xcd,0x2b,0x72,0x5d,0xf7,0x40,0x35,0xc6,0x73,0xff,0x51,0xd0,0x91,0xf5,0xcb,0xc,0x83,0x3a,0xcc,0xd6,0x14,0x38,0xa3,0x8b,0x2c,0x54,0xe7,0x19,0xba,0x52,0x1b,0xbe,0x12,0x6,0x41,0x5a,0x6b,0xa2,0x74,0xc2,0x98,0xe4,0x97,0xee,0x26,0x94,0x71,0x21,0xa5,0xbb,0xfe,0xeb,0xab,0x46,0x30,0x58,0x88,0x6a,0x92,0xe0,0xc3,0x37,0xb0,0x7c,0xb1,0x2d,0xdd,0x20,0x1c,0x75,0xf,0x2a,0x5e,0x76,0x7,0x62,0xea,0x68,0x1f,0x60,0xa7,0x28,0xe,0xb4,0x22,0xdf,0x2e,0x4f,0xa4,0x5d,0x70,0x23,0xd7,0x8d,0x6b,0x34,0x92,0x7d,0x52,0x3b,0x25,0xc4,0xa0,0xd,0x93,0x4a,0xe8,0x48,0xc5,0xfc,0x44,0x84,0x3f,0xe5,0x7a,0x81,0xf9,0x29,0x9d,0x42,0x45,0x88,0x32,0xcd,0xef,0xd8,0xc2,0xd3,0x6c,0xf,0x54,0x3e,0xa3,0x30,0x36,0x98,0xa5,0x46,0xb9,0xfd,0xd1,0xf5,0x87,0x89,0x18,0x2a,0xd6,0x4,0x9,0x39,0xcc,0x5,0xbb,0xa9,0xc7,0x6d,0x8c,0x15,0x7,0x6,0xad,0xde,0x96,0xc,0xd5,0xba,0x8a,0x3,0x5e,0xe2,0xf1,0x0,0x43,0xb5,0xbe,0x56,0x4e,0x76,0x6a,0xdc,0xbf,0xeb,0xfb,0x51,0x40,0x13,0x58,0x82,0x9b,0x8b,0xa1,0x62,0xf0,0xfe,0x74,0x10,0x9e,0x6e,0x80,0xca,0x5a,0xa2,0xd2,0x94,0xb0,0x63,0x5b,0x4d,0x38,0x50,0xfa,0x26,0x7f,0xd4,0xc0,0xf8,0xc6,0xdd,0x9c,0xf2,0x5c,0xcb,0x7e,0x77,0x1c,0xf7,0x41,0x8f,0xc3,0x2f,0x1b,0x8,0x64,0xb1,0x69,0x1d,0xb8,0x1e,0xac,0x24,0x72,0xaa,0x90,0x83,0x33,0xab,0xe1,0xee,0x31,0xff,0xe4,0x68,0xd9,0x73,0x1a,0x47,0x17,0x97,0x3c,0xec,0xda,0x61,0x49,0xc8,0xc9,0xf4,0x91,0x75,0xe0,0xb2,0xf6,0x78,0x2,0x2d,0x11,0x20,0xd0,0x71,0xbc,0x65,0x12,0x6f,0xe7,0x7b,0xa,0x27,0x53,0x4b,0x3d,0xe6,0xa6,0xb6,0xf3,0x2c,0xa8,0x3a,0xbd,0xed,0xce,0x67,0x9f,0x55,0x85,0xaf,0x79,0x57,0x66,0xb,0x4c,0xb3,0x1f,0x99,0x7c,0xe3,0x2b,0xe9,0x9a,0xcf,0x95,0x35,0xae,0xdb,0x19,0x37,0xc1,0x1,0x8e,0x5f,0x16,0x14,0xb7,0x59,0xea,0x86,0x21,0xaa,0xc,0xe3,0xcc,0xa5,0xbb,0x5a,0x3e,0x93,0xd,0xd4,0x76,0xd6,0x5b,0x62,0xda,0xfe,0x39,0xb6,0x90,0x2a,0xbc,0x41,0xb0,0xd1,0x3a,0xc3,0xee,0xbd,0x49,0x13,0xf5,0x4d,0xf2,0x91,0xca,0xa0,0x3d,0xae,0xa8,0x6,0x3b,0xd8,0x27,0x63,0x4f,0x6b,0x19,0x1a,0xa1,0x7b,0xe4,0x1f,0x67,0xb7,0x3,0xdc,0xdb,0x16,0xac,0x53,0x71,0x46,0x5c,0x98,0x33,0x40,0x8,0x92,0x4b,0x24,0x14,0x9d,0xc0,0x7c,0x6f,0x9e,0xdd,0x2b,0x20,0x17,0x86,0xb4,0x48,0x9a,0x97,0xa7,0x52,0x9b,0x25,0x37,0x59,0xf3,0x12,0x8b,0x99,0xfc,0x6e,0x60,0xea,0x8e,0x0,0xf0,0x1e,0x54,0xc4,0x3c,0x4c,0xa,0x2e,0xfd,0xc5,0xc8,0xd0,0xe8,0xf4,0x42,0x21,0x75,0x65,0xcf,0xde,0x8d,0xc6,0x1c,0x5,0x15,0x3f,0xe9,0x82,0x69,0xdf,0x11,0x5d,0xb1,0x85,0x96,0xfa,0x2f,0xf7,0x83,0x26,0x80,0x32,0xd3,0xa6,0xce,0x64,0xb8,0xe1,0x4a,0x5e,0x66,0x58,0x43,0x2,0x6c,0xc2,0x55,0xe0,0xd9,0x89,0x9,0xa2,0x72,0x44,0xff,0xd7,0x56,0x57,0x6a,0xf,0xeb,0x7e,0x2c,0x68,0xba,0xec,0x34,0xe,0x1d,0xad,0x35,0x7f,0x70,0xaf,0x61,0x7a,0xf6,0x47,0xed,0x84,0xd5,0xa3,0x78,0x38,0x28,0x6d,0xb2,0x36,0xa4,0x23,0x73,0x50,0xf9,0x1,0xcb,0x1b,0xe6,0x9c,0xb3,0x8f,0xbe,0x4e,0xef,0x22,0xfb,0x8c,0xf1,0x79,0xe5,0x94,0xb9,0xcd,0xab,0x30,0x45,0x87,0xa9,0x5f,0x9f,0x10,0xc1,0x88,0x8a,0x29,0xc7,0x74,0x18,0xbf,0x31,0xe7,0xc9,0xf8,0x95,0xd2,0x2d,0x81,0x7,0xe2,0x7d,0xb5,0x77,0x4,0x51,0xb,0xf3,0xde,0x27,0xcc,0xe8,0xe,0x54,0xa0,0x8d,0xab,0x24,0xe3,0xad,0x5c,0xa1,0x37,0x6b,0xc9,0x10,0x8e,0xc7,0x7f,0x46,0xcb,0xd1,0xfe,0x11,0xb7,0x23,0x47,0xa6,0xb8,0xb1,0xb,0xc6,0xc1,0x41,0x5b,0x6c,0x4e,0xf9,0x66,0xbc,0x7,0x1e,0xaa,0x7a,0x2,0x3a,0xc5,0x26,0x1b,0x4,0x76,0x52,0x7e,0xd7,0x8c,0xef,0x50,0xb5,0xb3,0x20,0xbd,0x44,0x2a,0x38,0x86,0x84,0x96,0xf,0xee,0x55,0xa9,0x9b,0xa,0x4f,0xba,0x8a,0x87,0x72,0x61,0xdd,0x80,0x3d,0x36,0xc0,0x83,0x15,0x5d,0x2e,0x85,0x9,0x39,0x56,0x8f,0xdb,0x90,0xc3,0xd2,0x22,0x8,0x18,0x1,0xe9,0xf5,0xcd,0xd5,0x78,0x68,0x3c,0x5f,0x51,0x21,0xd9,0x49,0xd8,0xe0,0x33,0x17,0xf7,0x7d,0x73,0xe1,0x3,0xed,0x1d,0x93,0x1f,0x5e,0x45,0x7b,0xfd,0x48,0xdf,0x71,0x79,0xd3,0xbb,0xce,0x43,0x57,0xfc,0xa5,0xea,0x32,0xe7,0x8b,0x2f,0x9d,0x3b,0x9e,0xc2,0x74,0x9f,0xf4,0x98,0xac,0x40,0xc,0x67,0x7c,0xb2,0x6d,0x99,0xf0,0x5a,0xeb,0x13,0x29,0xf1,0xa7,0x62,0x28,0xb0,0x0,0x12,0x77,0x4a,0x4b,0x75,0x31,0x63,0xf6,0xbf,0x14,0x94,0xc4,0xca,0xe2,0x59,0x6f,0x64,0xec,0x91,0xe6,0xd0,0xa4,0x89,0xf8,0x92,0xae,0x81,0xfb,0x3f,0xf2,0x53,0xa3,0x4d,0x6e,0x3e,0xb9,0x6,0xd6,0x1c,0xe4,0x25,0x65,0xbe,0xc8,0x2b,0xaf,0x70,0x35,0xa8,0x60,0xff,0x1a,0x16,0x4c,0x19,0x6a,0xe5,0xd4,0xfa,0x2c,0x9c,0x30,0xcf,0x88,0x34,0x97,0x95,0xdc,0xa2,0x5,0x69,0xda,0x9a,0x58,0x2d,0xb6,0xd,0x82,0x42,0xb4,0xb,0xd,0x5,0x98,0x34,0x6f,0xe8,0x57,0xce,0xbc,0xc6,0xea,0x7d,0x82,0xa3,0x9e,0x12,0xa6,0xba,0xc2,0xde,0x41,0xbf,0x4,0xe3,0xf9,0xf6,0xd4,0xb3,0x9,0x79,0x7e,0xff,0x9b,0x0,0x1e,0x46,0x69,0xf,0xa9,0xc7,0x7f,0x73,0xfe,0x71,0xd3,0x36,0xa8,0xe4,0x15,0x8f,0x19,0x13,0x35,0x5b,0x9c,0xb6,0x50,0x18,0xec,0x66,0x4b,0x74,0x9f,0x55,0xbb,0x2b,0xa5,0xc5,0x4f,0x59,0xcb,0x58,0x60,0xaf,0x8b,0x99,0xe9,0xf1,0x61,0xd0,0xc0,0xe7,0x84,0x4d,0x51,0x6d,0x75,0xb0,0x9a,0xb9,0xa0,0x28,0x63,0x6a,0x7b,0x81,0xb1,0x37,0xee,0xe5,0xad,0x3d,0x96,0x8e,0x85,0x3b,0x78,0xd9,0xca,0x38,0x65,0x2,0xf7,0x3f,0x32,0x11,0xed,0xb2,0x23,0x2e,0x3c,0x56,0xb7,0x92,0xfc,0x3e,0x80,0x5a,0x72,0xd7,0xe1,0xac,0x7,0x7c,0x2c,0x89,0xcd,0x4e,0xdb,0xcf,0xaa,0xf3,0xf2,0x90,0xda,0xb8,0x8,0x91,0xab,0x1f,0x49,0x48,0x21,0x53,0xe2,0xc4,0xdf,0xd5,0xa,0x14,0x20,0xb4,0xf8,0xcc,0x7a,0x4c,0x27,0x25,0x97,0x26,0x83,0x8a,0x52,0x33,0x5f,0xef,0xfb,0x1d,0x44,0x6b,0xc1,0x76,0x3,0xf0,0x45,0xc9,0x67,0xe6,0xa7,0xc3,0xfd,0x3a,0xb5,0xc,0xfa,0xe0,0x22,0xe,0x95,0xbd,0x1a,0x62,0xd1,0x2f,0x8c,0x64,0x2d,0x88,0x24,0x30,0x77,0x6c,0x5d,0x94,0x42,0xf4,0xae,0xd2,0xa1,0xd8,0x10,0xa2,0x47,0x17,0x93,0x8d,0xc8,0xdd,0x9d,0x70,0x6,0x6e,0xbe,0x5c,0xa4,0xd6,0xf5,0x1,0x86,0x4a,0x87,0x1b,0xeb,0x16,0x2a,0x43,0x39,0x1c,0x68,0x40,0x31,0x54,0xdc,0x5e,0x29,0x11,0xd6,0x59,0x7f,0xc5,0x53,0xae,0x5f,0x3e,0xd5,0x2c,0x1,0x52,0xa6,0xfc,0x1a,0x45,0xe3,0xc,0x23,0x4a,0x54,0xb5,0xd1,0x7c,0xe2,0x3b,0x99,0x39,0xb4,0x8d,0x35,0xf5,0x4e,0x94,0xb,0xf0,0x88,0x58,0xec,0x33,0x34,0xf9,0x43,0xbc,0x9e,0xa9,0xb3,0xa2,0x1d,0x7e,0x25,0x4f,0xd2,0x41,0x47,0xe9,0xd4,0x37,0xc8,0x8c,0xa0,0x84,0xf6,0xf8,0x69,0x5b,0xa7,0x75,0x78,0x48,0xbd,0x74,0xca,0xd8,0xb6,0x1c,0xfd,0x64,0x76,0x77,0xdc,0xaf,0xe7,0x7d,0xa4,0xcb,0xfb,0x72,0x2f,0x93,0x80,0x71,0x32,0xc4,0xcf,0x27,0x3f,0x7,0x1b,0xad,0xce,0x9a,0x8a,0x20,0x31,0x62,0x29,0xf3,0xea,0xfa,0xd0,0x13,0x81,0x8f,0x5,0x61,0xef,0x1f,0xf1,0xbb,0x2b,0xd3,0xa3,0xe5,0xc1,0x12,0x2a,0x3c,0x49,0x21,0x8b,0x57,0xe,0xa5,0xb1,0x89,0xb7,0xac,0xed,0x83,0x2d,0xba,0xf,0x6,0x6d,0x86,0x30,0xfe,0xb2,0x5e,0x6a,0x79,0x15,0xc0,0x18,0x6c,0xc9,0x6f,0xdd,0x55,0x3,0xdb,0xe1,0xf2,0x42,0xda,0x90,0x9f,0x40,0x8e,0x95,0x19,0xa8,0x2,0x6b,0x36,0x66,0xe6,0x4d,0x9d,0xab,0x10,0x38,0xb9,0xb8,0x85,0xe0,0x4,0x91,0xc3,0x87,0x9,0x73,0x5c,0x60,0x51,0xa1,0x0,0xcd,0x14,0x63,0x1e,0x96,0xa,0x7b,0x56,0x22,0x3a,0x4c,0x97,0xd7,0xc7,0x82,0x5d,0xd9,0x4b,0xcc,0x9c,0xbf,0x16,0xee,0x24,0xf4,0xde,0x8,0x26,0x17,0x7a,0x3d,0xc2,0x6e,0xe8,0xd,0x92,0x5a,0x98,0xeb,0xbe,0xe4,0x44,0xdf,0xaa,0x68,0x46,0xb0,0x70,0xff,0x2e,0x67,0x65,0xc6,0x28,0x9b,0xf7,0x50,0x2f,0x89,0x66,0x49,0x20,0x3e,0xdf,0xbb,0x16,0x88,0x51,0xf3,0x53,0xde,0xe7,0x5f,0x7b,0xbc,0x33,0x15,0xaf,0x39,0xc4,0x35,0x54,0xbf,0x46,0x6b,0x38,0xcc,0x96,0x70,0xc8,0x77,0x14,0x4f,0x25,0xb8,0x2b,0x2d,0x83,0xbe,0x5d,0xa2,0xe6,0xca,0xee,0x9c,0x9f,0x24,0xfe,0x61,0x9a,0xe2,0x32,0x86,0x59,0x5e,0x93,0x29,0xd6,0xf4,0xc3,0xd9,0x1d,0xb6,0xc5,0x8d,0x17,0xce,0xa1,0x91,0x18,0x45,0xf9,0xea,0x1b,0x58,0xae,0xa5,0x92,0x3,0x31,0xcd,0x1f,0x12,0x22,0xd7,0x1e,0xa0,0xb2,0xdc,0x76,0x97,0xe,0x1c,0x79,0xeb,0xe5,0x6f,0xb,0x85,0x75,0x9b,0xd1,0x41,0xb9,0xc9,0x8f,0xab,0x78,0x40,0x4d,0x55,0x6d,0x71,0xc7,0xa4,0xf0,0xe0,0x4a,0x5b,0x8,0x43,0x99,0x80,0x90,0xba,0x6c,0x7,0xec,0x5a,0x94,0xd8,0x34,0x0,0x13,0x7f,0xaa,0x72,0x6,0xa3,0x5,0xb7,0x56,0x23,0x4b,0xe1,0x3d,0x64,0xcf,0xdb,0xe3,0xdd,0xc6,0x87,0xe9,0x47,0xd0,0x65,0x5c,0xc,0x8c,0x27,0xf7,0xc1,0x7a,0x52,0xd3,0xd2,0xef,0x8a,0x6e,0xfb,0xa9,0xed,0x3f,0x69,0xb1,0x8b,0x98,0x28,0xb0,0xfa,0xf5,0x2a,0xe4,0xff,0x73,0xc2,0x68,0x1,0x50,0x26,0xfd,0xbd,0xad,0xe8,0x37,0xb3,0x21,0xa6,0xf6,0xd5,0x7c,0x84,0x4e,0x9e,0x63,0x19,0x36,0xa,0x3b,0xcb,0x6a,0xa7,0x7e,0x9,0x74,0xfc,0x60,0x11,0x3c,0x48,0x2e,0xb5,0xc0,0x2,0x2c,0xda,0x1a,0x95,0x44,0xd,0xf,0xac,0x42,0xf1,0x9d,0x3a,0xb4,0x62,0x4c,0x7d,0x10,0x57,0xa8,0x4,0x82,0x67,0xf8,0x30,0xf2,0x81,0xd4,0x8e,0x36,0x1b,0xe2,0x9,0x2d,0xcb,0x91,0x65,0x48,0x6e,0xe1,0x26,0x68,0x99,0x64,0xf2,0xae,0xc,0xd5,0x4b,0x2,0xba,0x83,0xe,0x14,0x3b,0xd4,0x72,0xe6,0x82,0x63,0x7d,0x74,0xce,0x3,0x4,0x84,0x9e,0xa9,0x8b,0x3c,0xa3,0x79,0xc2,0xdb,0x6f,0xbf,0xc7,0xff,0x0,0xe3,0xde,0xc1,0xb3,0x97,0xbb,0x12,0x49,0x2a,0x95,0x70,0x76,0xe5,0x78,0x81,0xef,0xfd,0x43,0x41,0x53,0xca,0x2b,0x90,0x6c,0x5e,0xcf,0x8a,0x7f,0x4f,0x42,0xb7,0xa4,0x18,0x45,0xf8,0xf3,0x5,0x46,0xd0,0x98,0xeb,0x40,0xcc,0xfc,0x93,0x4a,0x1e,0x55,0x6,0x17,0xe7,0xcd,0xdd,0xc4,0x2c,0x30,0x8,0x10,0xbd,0xad,0xf9,0x9a,0x94,0xe4,0x1c,0x8c,0x1d,0x25,0xf6,0xd2,0x32,0xb8,0xb6,0x24,0xc6,0x28,0xd8,0x56,0xda,0x9b,0x80,0xbe,0x38,0x8d,0x1a,0xb4,0xbc,0x16,0x7e,0xb,0x86,0x92,0x39,0x60,0x2f,0xf7,0x22,0x4e,0xea,0x58,0xfe,0x5b,0x7,0xb1,0x5a,0x31,0x5d,0x69,0x85,0xc9,0xa2,0xb9,0x77,0xa8,0x5c,0x35,0x9f,0x2e,0xd6,0xec,0x34,0x62,0xa7,0xed,0x75,0xc5,0xd7,0xb2,0x8f,0x8e,0xb0,0xf4,0xa6,0x33,0x7a,0xd1,0x51,0x1,0xf,0x27,0x9c,0xaa,0xa1,0x29,0x54,0x23,0x15,0x61,0x4c,0x3d,0x57,0x6b,0x44,0x3e,0xfa,0x37,0x96,0x66,0x88,0xab,0xfb,0x7c,0xc3,0x13,0xd9,0x21,0xe0,0xa0,0x7b,0xd,0xee,0x6a,0xb5,0xf0,0x6d,0xa5,0x3a,0xdf,0xd3,0x89,0xdc,0xaf,0x20,0x11,0x3f,0xe9,0x59,0xf5,0xa,0x4d,0xf1,0x52,0x50,0x19,0x67,0xc0,0xac,0x1f,0x5f,0x9d,0xe8,0x73,0xc8,0x47,0x87,0x71,0x85,0x83,0x8b,0x16,0xba,0xe1,0x66,0xd9,0x40,0x32,0x48,0x64,0xf3,0xc,0x2d,0x10,0x9c,0x28,0x34,0x4c,0x50,0xcf,0x31,0x8a,0x6d,0x77,0x78,0x5a,0x3d,0x87,0xf7,0xf0,0x71,0x15,0x8e,0x90,0xc8,0xe7,0x81,0x27,0x49,0xf1,0xfd,0x70,0xff,0x5d,0xb8,0x26,0x6a,0x9b,0x1,0x97,0x9d,0xbb,0xd5,0x12,0x38,0xde,0x96,0x62,0xe8,0xc5,0xfa,0x11,0xdb,0x35,0xa5,0x2b,0x4b,0xc1,0xd7,0x45,0xd6,0xee,0x21,0x5,0x17,0x67,0x7f,0xef,0x5e,0x4e,0x69,0xa,0xc3,0xdf,0xe3,0xfb,0x3e,0x14,0x37,0x2e,0xa6,0xed,0xe4,0xf5,0xf,0x3f,0xb9,0x60,0x6b,0x23,0xb3,0x18,0x0,0xb,0xb5,0xf6,0x57,0x44,0xb6,0xeb,0x8c,0x79,0xb1,0xbc,0x9f,0x63,0x3c,0xad,0xa0,0xb2,0xd8,0x39,0x1c,0x72,0xb0,0xe,0xd4,0xfc,0x59,0x6f,0x22,0x89,0xf2,0xa2,0x7,0x43,0xc0,0x55,0x41,0x24,0x7d,0x7c,0x1e,0x54,0x36,0x86,0x1f,0x25,0x91,0xc7,0xc6,0xaf,0xdd,0x6c,0x4a,0x51,0x5b,0x84,0x9a,0xae,0x3a,0x76,0x42,0xf4,0xc2,0xa9,0xab,0x19,0xa8,0xd,0x4,0xdc,0xbd,0xd1,0x61,0x75,0x93,0xca,0xe5,0x4f,0xf8,0x8d,0x7e,0xcb,0x47,0xe9,0x68,0x29,0x4d,0x73,0xb4,0x3b,0x82,0x74,0x6e,0xac,0x80,0x1b,0x33,0x94,0xec,0x5f,0xa1,0x2,0xea,0xa3,0x6,0xaa,0xbe,0xf9,0xe2,0xd3,0x1a,0xcc,0x7a,0x20,0x5c,0x2f,0x56,0x9e,0x2c,0xc9,0x99,0x1d,0x3,0x46,0x53,0x13,0xfe,0x88,0xe0,0x30,0xd2,0x2a,0x58,0x7b,0x8f,0x8,0xc4,0x9,0x95,0x65,0x98,0xa4,0xcd,0xb7,0x92,0xe6,0xce,0xbf,0xda,0x52,0xd0,0xa7,0x4f,0x88,0x7,0x21,0x9b,0xd,0xf0,0x1,0x60,0x8b,0x72,0x5f,0xc,0xf8,0xa2,0x44,0x1b,0xbd,0x52,0x7d,0x14,0xa,0xeb,0x8f,0x22,0xbc,0x65,0xc7,0x67,0xea,0xd3,0x6b,0xab,0x10,0xca,0x55,0xae,0xd6,0x6,0xb2,0x6d,0x6a,0xa7,0x1d,0xe2,0xc0,0xf7,0xed,0xfc,0x43,0x20,0x7b,0x11,0x8c,0x1f,0x19,0xb7,0x8a,0x69,0x96,0xd2,0xfe,0xda,0xa8,0xa6,0x37,0x5,0xf9,0x2b,0x26,0x16,0xe3,0x2a,0x94,0x86,0xe8,0x42,0xa3,0x3a,0x28,0x29,0x82,0xf1,0xb9,0x23,0xfa,0x95,0xa5,0x2c,0x71,0xcd,0xde,0x2f,0x6c,0x9a,0x91,0x79,0x61,0x59,0x45,0xf3,0x90,0xc4,0xd4,0x7e,0x6f,0x3c,0x77,0xad,0xb4,0xa4,0x8e,0x4d,0xdf,0xd1,0x5b,0x3f,0xb1,0x41,0xaf,0xe5,0x75,0x8d,0xfd,0xbb,0x9f,0x4c,0x74,0x62,0x17,0x7f,0xd5,0x9,0x50,0xfb,0xef,0xd7,0xe9,0xf2,0xb3,0xdd,0x73,0xe4,0x51,0x58,0x33,0xd8,0x6e,0xa0,0xec,0x0,0x34,0x27,0x4b,0x9e,0x46,0x32,0x97,0x31,0x83,0xb,0x5d,0x85,0xbf,0xac,0x1c,0x84,0xce,0xc1,0x1e,0xd0,0xcb,0x47,0xf6,0x5c,0x35,0x68,0x38,0xb8,0x13,0xc3,0xf5,0x4e,0x66,0xe7,0xe6,0xdb,0xbe,0x5a,0xcf,0x9d,0xd9,0x57,0x2d,0x2,0x3e,0xf,0xff,0x5e,0x93,0x4a,0x3d,0x40,0xc8,0x54,0x25,0x8,0x7c,0x64,0x12,0xc9,0x89,0x99,0xdc,0x3,0x87,0x15,0x92,0xc2,0xe1,0x48,0xb0,0x7a,0xaa,0x80,0x56,0x78,0x49,0x24,0x63,0x9c,0x30,0xb6,0x53,0xcc,0x4,0xc6,0xb5,0xe0,0xba,0x1a,0x81,0xf4,0x36,0x18,0xee,0x2e,0xa1,0x70,0x39,0x3b,0x98,0x76,0xc5,0xa9,0xe,0xe2,0x44,0xab,0x84,0xed,0xf3,0x12,0x76,0xdb,0x45,0x9c,0x3e,0x9e,0x13,0x2a,0x92,0xb6,0x71,0xfe,0xd8,0x62,0xf4,0x9,0xf8,0x99,0x72,0x8b,0xa6,0xf5,0x1,0x5b,0xbd,0x5,0xba,0xd9,0x82,0xe8,0x75,0xe6,0xe0,0x4e,0x73,0x90,0x6f,0x2b,0x7,0x23,0x51,0x52,0xe9,0x33,0xac,0x57,0x2f,0xff,0x4b,0x94,0x93,0x5e,0xe4,0x1b,0x39,0xe,0x14,0xd0,0x7b,0x8,0x40,0xda,0x3,0x6c,0x5c,0xd5,0x88,0x34,0x27,0xd6,0x95,0x63,0x68,0x5f,0xce,0xfc,0x0,0xd2,0xdf,0xef,0x1a,0xd3,0x6d,0x7f,0x11,0xbb,0x5a,0xc3,0xd1,0xb4,0x26,0x28,0xa2,0xc6,0x48,0xb8,0x56,0x1c,0x8c,0x74,0x4,0x42,0x66,0xb5,0x8d,0x80,0x98,0xa0,0xbc,0xa,0x69,0x3d,0x2d,0x87,0x96,0xc5,0x8e,0x54,0x4d,0x5d,0x77,0xa1,0xca,0x21,0x97,0x59,0x15,0xf9,0xcd,0xde,0xb2,0x67,0xbf,0xcb,0x6e,0xc8,0x7a,0x9b,0xee,0x86,0x2c,0xf0,0xa9,0x2,0x16,0x2e,0x10,0xb,0x4a,0x24,0x8a,0x1d,0xa8,0x91,0xc1,0x41,0xea,0x3a,0xc,0xb7,0x9f,0x1e,0x1f,0x22,0x47,0xa3,0x36,0x64,0x20,0xf2,0xa4,0x7c,0x46,0x55,0xe5,0x7d,0x37,0x38,0xe7,0x29,0x32,0xbe,0xf,0xa5,0xcc,0x9d,0xeb,0x30,0x70,0x60,0x25,0xfa,0x7e,0xec,0x6b,0x3b,0x18,0xb1,0x49,0x83,0x53,0xae,0xd4,0xfb,0xc7,0xf6,0x6,0xa7,0x6a,0xb3,0xc4,0xb9,0x31,0xad,0xdc,0xf1,0x85,0xe3,0x78,0xd,0xcf,0xe1,0x17,0xd7,0x58,0x89,0xc0,0xc2,0x61,0x8f,0x3c,0x50,0xf7,0x79,0xaf,0x81,0xb0,0xdd,0x9a,0x65,0xc9,0x4f,0xaa,0x35,0xfd,0x3f,0x4c,0x19,0x43,0xb9,0x94,0x6d,0x86,0xa2,0x44,0x1e,0xea,0xc7,0xe1,0x6e,0xa9,0xe7,0x16,0xeb,0x7d,0x21,0x83,0x5a,0xc4,0x8d,0x35,0xc,0x81,0x9b,0xb4,0x5b,0xfd,0x69,0xd,0xec,0xf2,0xfb,0x41,0x8c,0x8b,0xb,0x11,0x26,0x4,0xb3,0x2c,0xf6,0x4d,0x54,0xe0,0x30,0x48,0x70,0x8f,0x6c,0x51,0x4e,0x3c,0x18,0x34,0x9d,0xc6,0xa5,0x1a,0xff,0xf9,0x6a,0xf7,0xe,0x60,0x72,0xcc,0xce,0xdc,0x45,0xa4,0x1f,0xe3,0xd1,0x40,0x5,0xf0,0xc0,0xcd,0x38,0x2b,0x97,0xca,0x77,0x7c,0x8a,0xc9,0x5f,0x17,0x64,0xcf,0x43,0x73,0x1c,0xc5,0x91,0xda,0x89,0x98,0x68,0x42,0x52,0x4b,0xa3,0xbf,0x87,0x9f,0x32,0x22,0x76,0x15,0x1b,0x6b,0x93,0x3,0x92,0xaa,0x79,0x5d,0xbd,0x37,0x39,0xab,0x49,0xa7,0x57,0xd9,0x55,0x14,0xf,0x31,0xb7,0x2,0x95,0x3b,0x33,0x99,0xf1,0x84,0x9,0x1d,0xb6,0xef,0xa0,0x78,0xad,0xc1,0x65,0xd7,0x71,0xd4,0x88,0x3e,0xd5,0xbe,0xd2,0xe6,0xa,0x46,0x2d,0x36,0xf8,0x27,0xd3,0xba,0x10,0xa1,0x59,0x63,0xbb,0xed,0x28,0x62,0xfa,0x4a,0x58,0x3d,0x0,0x1,0x3f,0x7b,0x29,0xbc,0xf5,0x5e,0xde,0x8e,0x80,0xa8,0x13,0x25,0x2e,0xa6,0xdb,0xac,0x9a,0xee,0xc3,0xb2,0xd8,0xe4,0xcb,0xb1,0x75,0xb8,0x19,0xe9,0x7,0x24,0x74,0xf3,0x4c,0x9c,0x56,0xae,0x6f,0x2f,0xf4,0x82,0x61,0xe5,0x3a,0x7f,0xe2,0x2a,0xb5,0x50,0x5c,0x6,0x53,0x20,0xaf,0x9e,0xb0,0x66,0xd6,0x7a,0x85,0xc2,0x7e,0xdd,0xdf,0x96,0xe8,0x4f,0x23,0x90,0xd0,0x12,0x67,0xfc,0x47,0xc8,0x8,0xfe,0xb7,0xb1,0xb9,0x24,0x88,0xd3,0x54,0xeb,0x72,0x0,0x7a,0x56,0xc1,0x3e,0x1f,0x22,0xae,0x1a,0x6,0x7e,0x62,0xfd,0x3,0xb8,0x5f,0x45,0x4a,0x68,0xf,0xb5,0xc5,0xc2,0x43,0x27,0xbc,0xa2,0xfa,0xd5,0xb3,0x15,0x7b,0xc3,0xcf,0x42,0xcd,0x6f,0x8a,0x14,0x58,0xa9,0x33,0xa5,0xaf,0x89,0xe7,0x20,0xa,0xec,0xa4,0x50,0xda,0xf7,0xc8,0x23,0xe9,0x7,0x97,0x19,0x79,0xf3,0xe5,0x77,0xe4,0xdc,0x13,0x37,0x25,0x55,0x4d,0xdd,0x6c,0x7c,0x5b,0x38,0xf1,0xed,0xd1,0xc9,0xc,0x26,0x5,0x1c,0x94,0xdf,0xd6,0xc7,0x3d,0xd,0x8b,0x52,0x59,0x11,0x81,0x2a,0x32,0x39,0x87,0xc4,0x65,0x76,0x84,0xd9,0xbe,0x4b,0x83,0x8e,0xad,0x51,0xe,0x9f,0x92,0x80,0xea,0xb,0x2e,0x40,0x82,0x3c,0xe6,0xce,0x6b,0x5d,0x10,0xbb,0xc0,0x90,0x35,0x71,0xf2,0x67,0x73,0x16,0x4f,0x4e,0x2c,0x66,0x4,0xb4,0x2d,0x17,0xa3,0xf5,0xf4,0x9d,0xef,0x5e,0x78,0x63,0x69,0xb6,0xa8,0x9c,0x8,0x44,0x70,0xc6,0xf0,0x9b,0x99,0x2b,0x9a,0x3f,0x36,0xee,0x8f,0xe3,0x53,0x47,0xa1,0xf8,0xd7,0x7d,0xca,0xbf,0x4c,0xf9,0x75,0xdb,0x5a,0x1b,0x7f,0x41,0x86,0x9,0xb0,0x46,0x5c,0x9e,0xb2,0x29,0x1,0xa6,0xde,0x6d,0x93,0x30,0xd8,0x91,0x34,0x98,0x8c,0xcb,0xd0,0xe1,0x28,0xfe,0x48,0x12,0x6e,0x1d,0x64,0xac,0x1e,0xfb,0xab,0x2f,0x31,0x74,0x61,0x21,0xcc,0xba,0xd2,0x2,0xe0,0x18,0x6a,0x49,0xbd,0x3a,0xf6,0x3b,0xa7,0x57,0xaa,0x96,0xff,0x85,0xa0,0xd4,0xfc,0x8d,0xe8,0x60,0xe2,0x95,0x8d,0x4a,0xc5,0xe3,0x59,0xcf,0x32,0xc3,0xa2,0x49,0xb0,0x9d,0xce,0x3a,0x60,0x86,0xd9,0x7f,0x90,0xbf,0xd6,0xc8,0x29,0x4d,0xe0,0x7e,0xa7,0x5,0xa5,0x28,0x11,0xa9,0x69,0xd2,0x8,0x97,0x6c,0x14,0xc4,0x70,0xaf,0xa8,0x65,0xdf,0x20,0x2,0x35,0x2f,0x3e,0x81,0xe2,0xb9,0xd3,0x4e,0xdd,0xdb,0x75,0x48,0xab,0x54,0x10,0x3c,0x18,0x6a,0x64,0xf5,0xc7,0x3b,0xe9,0xe4,0xd4,0x21,0xe8,0x56,0x44,0x2a,0x80,0x61,0xf8,0xea,0xeb,0x40,0x33,0x7b,0xe1,0x38,0x57,0x67,0xee,0xb3,0xf,0x1c,0xed,0xae,0x58,0x53,0xbb,0xa3,0x9b,0x87,0x31,0x52,0x6,0x16,0xbc,0xad,0xfe,0xb5,0x6f,0x76,0x66,0x4c,0x8f,0x1d,0x13,0x99,0xfd,0x73,0x83,0x6d,0x27,0xb7,0x4f,0x3f,0x79,0x5d,0x8e,0xb6,0xa0,0xd5,0xbd,0x17,0xcb,0x92,0x39,0x2d,0x15,0x2b,0x30,0x71,0x1f,0xb1,0x26,0x93,0x9a,0xf1,0x1a,0xac,0x62,0x2e,0xc2,0xf6,0xe5,0x89,0x5c,0x84,0xf0,0x55,0xf3,0x41,0xc9,0x9f,0x47,0x7d,0x6e,0xde,0x46,0xc,0x3,0xdc,0x12,0x9,0x85,0x34,0x9e,0xf7,0xaa,0xfa,0x7a,0xd1,0x1,0x37,0x8c,0xa4,0x25,0x24,0x19,0x7c,0x98,0xd,0x5f,0x1b,0x95,0xef,0xc0,0xfc,0xcd,0x3d,0x9c,0x51,0x88,0xff,0x82,0xa,0x96,0xe7,0xca,0xbe,0xa6,0xd0,0xb,0x4b,0x5b,0x1e,0xc1,0x45,0xd7,0x50,0x0,0x23,0x8a,0x72,0xb8,0x68,0x42,0x94,0xba,0x8b,0xe6,0xa1,0x5e,0xf2,0x74,0x91,0xe,0xc6,0x4,0x77,0x22,0x78,0xd8,0x43,0x36,0xf4,0xda,0x2c,0xec,0x63,0xb2,0xfb,0xf9,0x5a,0xb4,0x7,0x6b,0xcc,0xb7,0x11,0xfe,0xd1,0xb8,0xa6,0x47,0x23,0x8e,0x10,0xc9,0x6b,0xcb,0x46,0x7f,0xc7,0xe3,0x24,0xab,0x8d,0x37,0xa1,0x5c,0xad,0xcc,0x27,0xde,0xf3,0xa0,0x54,0xe,0xe8,0x50,0xef,0x8c,0xd7,0xbd,0x20,0xb3,0xb5,0x1b,0x26,0xc5,0x3a,0x7e,0x52,0x76,0x4,0x7,0xbc,0x66,0xf9,0x2,0x7a,0xaa,0x1e,0xc1,0xc6,0xb,0xb1,0x4e,0x6c,0x5b,0x41,0x85,0x2e,0x5d,0x15,0x8f,0x56,0x39,0x9,0x80,0xdd,0x61,0x72,0x83,0xc0,0x36,0x3d,0xa,0x9b,0xa9,0x55,0x87,0x8a,0xba,0x4f,0x86,0x38,0x2a,0x44,0xee,0xf,0x96,0x84,0xe1,0x73,0x7d,0xf7,0x93,0x1d,0xed,0x3,0x49,0xd9,0x21,0x51,0x17,0x33,0xe0,0xd8,0xd5,0xcd,0xf5,0xe9,0x5f,0x3c,0x68,0x78,0xd2,0xc3,0x90,0xdb,0x1,0x18,0x8,0x22,0xf4,0x9f,0x74,0xc2,0xc,0x40,0xac,0x98,0x8b,0xe7,0x32,0xea,0x9e,0x3b,0x9d,0x2f,0xce,0xbb,0xd3,0x79,0xa5,0xfc,0x57,0x43,0x7b,0x45,0x5e,0x1f,0x71,0xdf,0x48,0xfd,0xc4,0x94,0x14,0xbf,0x6f,0x59,0xe2,0xca,0x4b,0x4a,0x77,0x12,0xf6,0x63,0x31,0x75,0xa7,0xf1,0x29,0x13,0x0,0xb0,0x28,0x62,0x6d,0xb2,0x7c,0x67,0xeb,0x5a,0xf0,0x99,0xc8,0xbe,0x65,0x25,0x35,0x70,0xaf,0x2b,0xb9,0x3e,0x6e,0x4d,0xe4,0x1c,0xd6,0x6,0xfb,0x81,0xae,0x92,0xa3,0x53,0xf2,0x3f,0xe6,0x91,0xec,0x64,0xf8,0x89,0xa4,0xd0,0xb6,0x2d,0x58,0x9a,0xb4,0x42,0x82,0xd,0xdc,0x95,0x97,0x34,0xda,0x69,0x5,0xa2,0x2c,0xfa,0xd4,0xe5,0x88,0xcf,0x30,0x9c,0x1a,0xff,0x60,0xa8,0x6a,0x19,0x4c,0x16,0x8e,0xa3,0x5a,0xb1,0x95,0x73,0x29,0xdd,0xf0,0xd6,0x59,0x9e,0xd0,0x21,0xdc,0x4a,0x16,0xb4,0x6d,0xf3,0xba,0x2,0x3b,0xb6,0xac,0x83,0x6c,0xca,0x5e,0x3a,0xdb,0xc5,0xcc,0x76,0xbb,0xbc,0x3c,0x26,0x11,0x33,0x84,0x1b,0xc1,0x7a,0x63,0xd7,0x7,0x7f,0x47,0xb8,0x5b,0x66,0x79,0xb,0x2f,0x3,0xaa,0xf1,0x92,0x2d,0xc8,0xce,0x5d,0xc0,0x39,0x57,0x45,0xfb,0xf9,0xeb,0x72,0x93,0x28,0xd4,0xe6,0x77,0x32,0xc7,0xf7,0xfa,0xf,0x1c,0xa0,0xfd,0x40,0x4b,0xbd,0xfe,0x68,0x20,0x53,0xf8,0x74,0x44,0x2b,0xf2,0xa6,0xed,0xbe,0xaf,0x5f,0x75,0x65,0x7c,0x94,0x88,0xb0,0xa8,0x5,0x15,0x41,0x22,0x2c,0x5c,0xa4,0x34,0xa5,0x9d,0x4e,0x6a,0x8a,0x0,0xe,0x9c,0x7e,0x90,0x60,0xee,0x62,0x23,0x38,0x6,0x80,0x35,0xa2,0xc,0x4,0xae,0xc6,0xb3,0x3e,0x2a,0x81,0xd8,0x97,0x4f,0x9a,0xf6,0x52,0xe0,0x46,0xe3,0xbf,0x9,0xe2,0x89,0xe5,0xd1,0x3d,0x71,0x1a,0x1,0xcf,0x10,0xe4,0x8d,0x27,0x96,0x6e,0x54,0x8c,0xda,0x1f,0x55,0xcd,0x7d,0x6f,0xa,0x37,0x36,0x8,0x4c,0x1e,0x8b,0xc2,0x69,0xe9,0xb9,0xb7,0x9f,0x24,0x12,0x19,0x91,0xec,0x9b,0xad,0xd9,0xf4,0x85,0xef,0xd3,0xfc,0x86,0x42,0x8f,0x2e,0xde,0x30,0x13,0x43,0xc4,0x7b,0xab,0x61,0x99,0x58,0x18,0xc3,0xb5,0x56,0xd2,0xd,0x48,0xd5,0x1d,0x82,0x67,0x6b,0x31,0x64,0x17,0x98,0xa9,0x87,0x51,0xe1,0x4d,0xb2,0xf5,0x49,0xea,0xe8,0xa1,0xdf,0x78,0x14,0xa7,0xe7,0x25,0x50,0xcb,0x70,0xff,0x3f,0xc9,0x75,0x73,0x7b,0xe6,0x4a,0x11,0x96,0x29,0xb0,0xc2,0xb8,0x94,0x3,0xfc,0xdd,0xe0,0x6c,0xd8,0xc4,0xbc,0xa0,0x3f,0xc1,0x7a,0x9d,0x87,0x88,0xaa,0xcd,0x77,0x7,0x0,0x81,0xe5,0x7e,0x60,0x38,0x17,0x71,0xd7,0xb9,0x1,0xd,0x80,0xf,0xad,0x48,0xd6,0x9a,0x6b,0xf1,0x67,0x6d,0x4b,0x25,0xe2,0xc8,0x2e,0x66,0x92,0x18,0x35,0xa,0xe1,0x2b,0xc5,0x55,0xdb,0xbb,0x31,0x27,0xb5,0x26,0x1e,0xd1,0xf5,0xe7,0x97,0x8f,0x1f,0xae,0xbe,0x99,0xfa,0x33,0x2f,0x13,0xb,0xce,0xe4,0xc7,0xde,0x56,0x1d,0x14,0x5,0xff,0xcf,0x49,0x90,0x9b,0xd3,0x43,0xe8,0xf0,0xfb,0x45,0x6,0xa7,0xb4,0x46,0x1b,0x7c,0x89,0x41,0x4c,0x6f,0x93,0xcc,0x5d,0x50,0x42,0x28,0xc9,0xec,0x82,0x40,0xfe,0x24,0xc,0xa9,0x9f,0xd2,0x79,0x2,0x52,0xf7,0xb3,0x30,0xa5,0xb1,0xd4,0x8d,0x8c,0xee,0xa4,0xc6,0x76,0xef,0xd5,0x61,0x37,0x36,0x5f,0x2d,0x9c,0xba,0xa1,0xab,0x74,0x6a,0x5e,0xca,0x86,0xb2,0x4,0x32,0x59,0x5b,0xe9,0x58,0xfd,0xf4,0x2c,0x4d,0x21,0x91,0x85,0x63,0x3a,0x15,0xbf,0x8,0x7d,0x8e,0x3b,0xb7,0x19,0x98,0xd9,0xbd,0x83,0x44,0xcb,0x72,0x84,0x9e,0x5c,0x70,0xeb,0xc3,0x64,0x1c,0xaf,0x51,0xf2,0x1a,0x53,0xf6,0x5a,0x4e,0x9,0x12,0x23,0xea,0x3c,0x8a,0xd0,0xac,0xdf,0xa6,0x6e,0xdc,0x39,0x69,0xed,0xf3,0xb6,0xa3,0xe3,0xe,0x78,0x10,0xc0,0x22,0xda,0xa8,0x8b,0x7f,0xf8,0x34,0xf9,0x65,0x95,0x68,0x54,0x3d,0x47,0x62,0x16,0x3e,0x4f,0x2a,0xa2,0x20,0x57,0x17,0xd0,0x5f,0x79,0xc3,0x55,0xa8,0x59,0x38,0xd3,0x2a,0x7,0x54,0xa0,0xfa,0x1c,0x43,0xe5,0xa,0x25,0x4c,0x52,0xb3,0xd7,0x7a,0xe4,0x3d,0x9f,0x3f,0xb2,0x8b,0x33,0xf3,0x48,0x92,0xd,0xf6,0x8e,0x5e,0xea,0x35,0x32,0xff,0x45,0xba,0x98,0xaf,0xb5,0xa4,0x1b,0x78,0x23,0x49,0xd4,0x47,0x41,0xef,0xd2,0x31,0xce,0x8a,0xa6,0x82,0xf0,0xfe,0x6f,0x5d,0xa1,0x73,0x7e,0x4e,0xbb,0x72,0xcc,0xde,0xb0,0x1a,0xfb,0x62,0x70,0x71,0xda,0xa9,0xe1,0x7b,0xa2,0xcd,0xfd,0x74,0x29,0x95,0x86,0x77,0x34,0xc2,0xc9,0x21,0x39,0x1,0x1d,0xab,0xc8,0x9c,0x8c,0x26,0x37,0x64,0x2f,0xf5,0xec,0xfc,0xd6,0x15,0x87,0x89,0x3,0x67,0xe9,0x19,0xf7,0xbd,0x2d,0xd5,0xa5,0xe3,0xc7,0x14,0x2c,0x3a,0x4f,0x27,0x8d,0x51,0x8,0xa3,0xb7,0x8f,0xb1,0xaa,0xeb,0x85,0x2b,0xbc,0x9,0x0,0x6b,0x80,0x36,0xf8,0xb4,0x58,0x6c,0x7f,0x13,0xc6,0x1e,0x6a,0xcf,0x69,0xdb,0x53,0x5,0xdd,0xe7,0xf4,0x44,0xdc,0x96,0x99,0x46,0x88,0x93,0x1f,0xae,0x4,0x6d,0x30,0x60,0xe0,0x4b,0x9b,0xad,0x16,0x3e,0xbf,0xbe,0x83,0xe6,0x2,0x97,0xc5,0x81,0xf,0x75,0x5a,0x66,0x57,0xa7,0x6,0xcb,0x12,0x65,0x18,0x90,0xc,0x7d,0x50,0x24,0x3c,0x4a,0x91,0xd1,0xc1,0x84,0x5b,0xdf,0x4d,0xca,0x9a,0xb9,0x10,0xe8,0x22,0xf2,0xd8,0xe,0x20,0x11,0x7c,0x3b,0xc4,0x68,0xee,0xb,0x94,0x5c,0x9e,0xed,0xb8,0xe2,0x42,0xd9,0xac,0x6e,0x40,0xb6,0x76,0xf9,0x28,0x61,0x63,0xc0,0x2e,0x9d,0xf1,0x56,0xb7,0x11,0xfe,0xd1,0xb8,0xa6,0x47,0x23,0x8e,0x10,0xc9,0x6b,0xcb,0x46,0x7f,0xc7,0xe3,0x24,0xab,0x8d,0x37,0xa1,0x5c,0xad,0xcc,0x27,0xde,0xf3,0xa0,0x54,0xe,0xe8,0x50,0xef,0x8c,0xd7,0xbd,0x20,0xb3,0xb5,0x1b,0x26,0xc5,0x3a,0x7e,0x52,0x76,0x4,0x7,0xbc,0x66,0xf9,0x2,0x7a,0xaa,0x1e,0xc1,0xc6,0xb,0xb1,0x4e,0x6c,0x5b,0x41,0x85,0x2e,0x5d,0x15,0x8f,0x56,0x39,0x9,0x80,0xdd,0x61,0x72,0x83,0xc0,0x36,0x3d,0xa,0x9b,0xa9,0x55,0x87,0x8a,0xba,0x4f,0x86,0x38,0x2a,0x44,0xee,0xf,0x96,0x84,0xe1,0x73,0x7d,0xf7,0x93,0x1d,0xed,0x3,0x49,0xd9,0x21,0x51,0x17,0x33,0xe0,0xd8,0xd5,0xcd,0xf5,0xe9,0x5f,0x3c,0x68,0x78,0xd2,0xc3,0x90,0xdb,0x1,0x18,0x8,0x22,0xf4,0x9f,0x74,0xc2,0xc,0x40,0xac,0x98,0x8b,0xe7,0x32,0xea,0x9e,0x3b,0x9d,0x2f,0xce,0xbb,0xd3,0x79,0xa5,0xfc,0x57,0x43,0x7b,0x45,0x5e,0x1f,0x71,0xdf,0x48,0xfd,0xc4,0x94,0x14,0xbf,0x6f,0x59,0xe2,0xca,0x4b,0x4a,0x77,0x12,0xf6,0x63,0x31,0x75,0xa7,0xf1,0x29,0x13,0x0,0xb0,0x28,0x62,0x6d,0xb2,0x7c,0x67,0xeb,0x5a,0xf0,0x99,0xc8,0xbe,0x65,0x25,0x35,0x70,0xaf,0x2b,0xb9,0x3e,0x6e,0x4d,0xe4,0x1c,0xd6,0x6,0xfb,0x81,0xae,0x92,0xa3,0x53,0xf2,0x3f,0xe6,0x91,0xec,0x64,0xf8,0x89,0xa4,0xd0,0xb6,0x2d,0x58,0x9a,0xb4,0x42,0x82,0xd,0xdc,0x95,0x97,0x34,0xda,0x69,0x5,0xa2,0x2c,0xfa,0xd4,0xe5,0x88,0xcf,0x30,0x9c,0x1a,0xff,0x60,0xa8,0x6a,0x19,0x4c,0x16,0xb3,0x9e,0x67,0x8c,0xa8,0x4e,0x14,0xe0,0xcd,0xeb,0x64,0xa3,0xed,0x1c,0xe1,0x77,0x2b,0x89,0x50,0xce,0x87,0x3f,0x6,0x8b,0x91,0xbe,0x51,0xf7,0x63,0x7,0xe6,0xf8,0xf1,0x4b,0x86,0x81,0x1,0x1b,0x2c,0xe,0xb9,0x26,0xfc,0x47,0x5e,0xea,0x3a,0x42,0x7a,0x85,0x66,0x5b,0x44,0x36,0x12,0x3e,0x97,0xcc,0xaf,0x10,0xf5,0xf3,0x60,0xfd,0x4,0x6a,0x78,0xc6,0xc4,0xd6,0x4f,0xae,0x15,0xe9,0xdb,0x4a,0xf,0xfa,0xca,0xc7,0x32,0x21,0x9d,0xc0,0x7d,0x76,0x80,0xc3,0x55,0x1d,0x6e,0xc5,0x49,0x79,0x16,0xcf,0x9b,0xd0,0x83,0x92,0x62,0x48,0x58,0x41,0xa9,0xb5,0x8d,0x95,0x38,0x28,0x7c,0x1f,0x11,0x61,0x99,0x9,0x98,0xa0,0x73,0x57,0xb7,0x3d,0x33,0xa1,0x43,0xad,0x5d,0xd3,0x5f,0x1e,0x5,0x3b,0xbd,0x8,0x9f,0x31,0x39,0x93,0xfb,0x8e,0x3,0x17,0xbc,0xe5,0xaa,0x72,0xa7,0xcb,0x6f,0xdd,0x7b,0xde,0x82,0x34,0xdf,0xb4,0xd8,0xec,0x0,0x4c,0x27,0x3c,0xf2,0x2d,0xd9,0xb0,0x1a,0xab,0x53,0x69,0xb1,0xe7,0x22,0x68,0xf0,0x40,0x52,0x37,0xa,0xb,0x35,0x71,0x23,0xb6,0xff,0x54,0xd4,0x84,0x8a,0xa2,0x19,0x2f,0x24,0xac,0xd1,0xa6,0x90,0xe4,0xc9,0xb8,0xd2,0xee,0xc1,0xbb,0x7f,0xb2,0x13,0xe3,0xd,0x2e,0x7e,0xf9,0x46,0x96,0x5c,0xa4,0x65,0x25,0xfe,0x88,0x6b,0xef,0x30,0x75,0xe8,0x20,0xbf,0x5a,0x56,0xc,0x59,0x2a,0xa5,0x94,0xba,0x6c,0xdc,0x70,0x8f,0xc8,0x74,0xd7,0xd5,0x9c,0xe2,0x45,0x29,0x9a,0xda,0x18,0x6d,0xf6,0x4d,0xc2,0x2,0xf4,0xb8,0xbe,0xb6,0x2b,0x87,0xdc,0x5b,0xe4,0x7d,0xf,0x75,0x59,0xce,0x31,0x10,0x2d,0xa1,0x15,0x9,0x71,0x6d,0xf2,0xc,0xb7,0x50,0x4a,0x45,0x67,0x0,0xba,0xca,0xcd,0x4c,0x28,0xb3,0xad,0xf5,0xda,0xbc,0x1a,0x74,0xcc,0xc0,0x4d,0xc2,0x60,0x85,0x1b,0x57,0xa6,0x3c,0xaa,0xa0,0x86,0xe8,0x2f,0x5,0xe3,0xab,0x5f,0xd5,0xf8,0xc7,0x2c,0xe6,0x8,0x98,0x16,0x76,0xfc,0xea,0x78,0xeb,0xd3,0x1c,0x38,0x2a,0x5a,0x42,0xd2,0x63,0x73,0x54,0x37,0xfe,0xe2,0xde,0xc6,0x3,0x29,0xa,0x13,0x9b,0xd0,0xd9,0xc8,0x32,0x2,0x84,0x5d,0x56,0x1e,0x8e,0x25,0x3d,0x36,0x88,0xcb,0x6a,0x79,0x8b,0xd6,0xb1,0x44,0x8c,0x81,0xa2,0x5e,0x1,0x90,0x9d,0x8f,0xe5,0x4,0x21,0x4f,0x8d,0x33,0xe9,0xc1,0x64,0x52,0x1f,0xb4,0xcf,0x9f,0x3a,0x7e,0xfd,0x68,0x7c,0x19,0x40,0x41,0x23,0x69,0xb,0xbb,0x22,0x18,0xac,0xfa,0xfb,0x92,0xe0,0x51,0x77,0x6c,0x66,0xb9,0xa7,0x93,0x7,0x4b,0x7f,0xc9,0xff,0x94,0x96,0x24,0x95,0x30,0x39,0xe1,0x80,0xec,0x5c,0x48,0xae,0xf7,0xd8,0x72,0xc5,0xb0,0x43,0xf6,0x7a,0xd4,0x55,0x14,0x70,0x4e,0x89,0x6,0xbf,0x49,0x53,0x91,0xbd,0x26,0xe,0xa9,0xd1,0x62,0x9c,0x3f,0xd7,0x9e,0x3b,0x97,0x83,0xc4,0xdf,0xee,0x27,0xf1,0x47,0x1d,0x61,0x12,0x6b,0xa3,0x11,0xf4,0xa4,0x20,0x3e,0x7b,0x6e,0x2e,0xc3,0xb5,0xdd,0xd,0xef,0x17,0x65,0x46,0xb2,0x35,0xf9,0x34,0xa8,0x58,0xa5,0x99,0xf0,0x8a,0xaf,0xdb,0xf3,0x82,0xe7,0x6f,0xed,0x9a,0x38,0xff,0x70,0x56,0xec,0x7a,0x87,0x76,0x17,0xfc,0x5,0x28,0x7b,0x8f,0xd5,0x33,0x6c,0xca,0x25,0xa,0x63,0x7d,0x9c,0xf8,0x55,0xcb,0x12,0xb0,0x10,0x9d,0xa4,0x1c,0xdc,0x67,0xbd,0x22,0xd9,0xa1,0x71,0xc5,0x1a,0x1d,0xd0,0x6a,0x95,0xb7,0x80,0x9a,0x8b,0x34,0x57,0xc,0x66,0xfb,0x68,0x6e,0xc0,0xfd,0x1e,0xe1,0xa5,0x89,0xad,0xdf,0xd1,0x40,0x72,0x8e,0x5c,0x51,0x61,0x94,0x5d,0xe3,0xf1,0x9f,0x35,0xd4,0x4d,0x5f,0x5e,0xf5,0x86,0xce,0x54,0x8d,0xe2,0xd2,0x5b,0x6,0xba,0xa9,0x58,0x1b,0xed,0xe6,0xe,0x16,0x2e,0x32,0x84,0xe7,0xb3,0xa3,0x9,0x18,0x4b,0x0,0xda,0xc3,0xd3,0xf9,0x3a,0xa8,0xa6,0x2c,0x48,0xc6,0x36,0xd8,0x92,0x2,0xfa,0x8a,0xcc,0xe8,0x3b,0x3,0x15,0x60,0x8,0xa2,0x7e,0x27,0x8c,0x98,0xa0,0x9e,0x85,0xc4,0xaa,0x4,0x93,0x26,0x2f,0x44,0xaf,0x19,0xd7,0x9b,0x77,0x43,0x50,0x3c,0xe9,0x31,0x45,0xe0,0x46,0xf4,0x7c,0x2a,0xf2,0xc8,0xdb,0x6b,0xf3,0xb9,0xb6,0x69,0xa7,0xbc,0x30,0x81,0x2b,0x42,0x1f,0x4f,0xcf,0x64,0xb4,0x82,0x39,0x11,0x90,0x91,0xac,0xc9,0x2d,0xb8,0xea,0xae,0x20,0x5a,0x75,0x49,0x78,0x88,0x29,0xe4,0x3d,0x4a,0x37,0xbf,0x23,0x52,0x7f,0xb,0x13,0x65,0xbe,0xfe,0xee,0xab,0x74,0xf0,0x62,0xe5,0xb5,0x96,0x3f,0xc7,0xd,0xdd,0xf7,0x21,0xf,0x3e,0x53,0x14,0xeb,0x47,0xc1,0x24,0xbb,0x73,0xb1,0xc2,0x97,0xcd,0x6d,0xf6,0x83,0x41,0x6f,0x99,0x59,0xd6,0x7,0x4e,0x4c,0xef,0x1,0xb2,0xde,0x79,0xff,0x59,0xb6,0x99,0xf0,0xee,0xf,0x6b,0xc6,0x58,0x81,0x23,0x83,0xe,0x37,0x8f,0xab,0x6c,0xe3,0xc5,0x7f,0xe9,0x14,0xe5,0x84,0x6f,0x96,0xbb,0xe8,0x1c,0x46,0xa0,0x18,0xa7,0xc4,0x9f,0xf5,0x68,0xfb,0xfd,0x53,0x6e,0x8d,0x72,0x36,0x1a,0x3e,0x4c,0x4f,0xf4,0x2e,0xb1,0x4a,0x32,0xe2,0x56,0x89,0x8e,0x43,0xf9,0x6,0x24,0x13,0x9,0xcd,0x66,0x15,0x5d,0xc7,0x1e,0x71,0x41,0xc8,0x95,0x29,0x3a,0xcb,0x88,0x7e,0x75,0x42,0xd3,0xe1,0x1d,0xcf,0xc2,0xf2,0x7,0xce,0x70,0x62,0xc,0xa6,0x47,0xde,0xcc,0xa9,0x3b,0x35,0xbf,0xdb,0x55,0xa5,0x4b,0x1,0x91,0x69,0x19,0x5f,0x7b,0xa8,0x90,0x9d,0x85,0xbd,0xa1,0x17,0x74,0x20,0x30,0x9a,0x8b,0xd8,0x93,0x49,0x50,0x40,0x6a,0xbc,0xd7,0x3c,0x8a,0x44,0x8,0xe4,0xd0,0xc3,0xaf,0x7a,0xa2,0xd6,0x73,0xd5,0x67,0x86,0xf3,0x9b,0x31,0xed,0xb4,0x1f,0xb,0x33,0xd,0x16,0x57,0x39,0x97,0x0,0xb5,0x8c,0xdc,0x5c,0xf7,0x27,0x11,0xaa,0x82,0x3,0x2,0x3f,0x5a,0xbe,0x2b,0x79,0x3d,0xef,0xb9,0x61,0x5b,0x48,0xf8,0x60,0x2a,0x25,0xfa,0x34,0x2f,0xa3,0x12,0xb8,0xd1,0x80,0xf6,0x2d,0x6d,0x7d,0x38,0xe7,0x63,0xf1,0x76,0x26,0x5,0xac,0x54,0x9e,0x4e,0xb3,0xc9,0xe6,0xda,0xeb,0x1b,0xba,0x77,0xae,0xd9,0xa4,0x2c,0xb0,0xc1,0xec,0x98,0xfe,0x65,0x10,0xd2,0xfc,0xa,0xca,0x45,0x94,0xdd,0xdf,0x7c,0x92,0x21,0x4d,0xea,0x64,0xb2,0x9c,0xad,0xc0,0x87,0x78,0xd4,0x52,0xb7,0x28,0xe0,0x22,0x51,0x4,0x5e,0x61,0x4c,0xb5,0x5e,0x7a,0x9c,0xc6,0x32,0x1f,0x39,0xb6,0x71,0x3f,0xce,0x33,0xa5,0xf9,0x5b,0x82,0x1c,0x55,0xed,0xd4,0x59,0x43,0x6c,0x83,0x25,0xb1,0xd5,0x34,0x2a,0x23,0x99,0x54,0x53,0xd3,0xc9,0xfe,0xdc,0x6b,0xf4,0x2e,0x95,0x8c,0x38,0xe8,0x90,0xa8,0x57,0xb4,0x89,0x96,0xe4,0xc0,0xec,0x45,0x1e,0x7d,0xc2,0x27,0x21,0xb2,0x2f,0xd6,0xb8,0xaa,0x14,0x16,0x4,0x9d,0x7c,0xc7,0x3b,0x9,0x98,0xdd,0x28,0x18,0x15,0xe0,0xf3,0x4f,0x12,0xaf,0xa4,0x52,0x11,0x87,0xcf,0xbc,0x17,0x9b,0xab,0xc4,0x1d,0x49,0x2,0x51,0x40,0xb0,0x9a,0x8a,0x93,0x7b,0x67,0x5f,0x47,0xea,0xfa,0xae,0xcd,0xc3,0xb3,0x4b,0xdb,0x4a,0x72,0xa1,0x85,0x65,0xef,0xe1,0x73,0x91,0x7f,0x8f,0x1,0x8d,0xcc,0xd7,0xe9,0x6f,0xda,0x4d,0xe3,0xeb,0x41,0x29,0x5c,0xd1,0xc5,0x6e,0x37,0x78,0xa0,0x75,0x19,0xbd,0xf,0xa9,0xc,0x50,0xe6,0xd,0x66,0xa,0x3e,0xd2,0x9e,0xf5,0xee,0x20,0xff,0xb,0x62,0xc8,0x79,0x81,0xbb,0x63,0x35,0xf0,0xba,0x22,0x92,0x80,0xe5,0xd8,0xd9,0xe7,0xa3,0xf1,0x64,0x2d,0x86,0x6,0x56,0x58,0x70,0xcb,0xfd,0xf6,0x7e,0x3,0x74,0x42,0x36,0x1b,0x6a,0x0,0x3c,0x13,0x69,0xad,0x60,0xc1,0x31,0xdf,0xfc,0xac,0x2b,0x94,0x44,0x8e,0x76,0xb7,0xf7,0x2c,0x5a,0xb9,0x3d,0xe2,0xa7,0x3a,0xf2,0x6d,0x88,0x84,0xde,0x8b,0xf8,0x77,0x46,0x68,0xbe,0xe,0xa2,0x5d,0x1a,0xa6,0x5,0x7,0x4e,0x30,0x97,0xfb,0x48,0x8,0xca,0xbf,0x24,0x9f,0x10,0xd0,0x26,0x4,0x2,0xa,0x97,0x3b,0x60,0xe7,0x58,0xc1,0xb3,0xc9,0xe5,0x72,0x8d,0xac,0x91,0x1d,0xa9,0xb5,0xcd,0xd1,0x4e,0xb0,0xb,0xec,0xf6,0xf9,0xdb,0xbc,0x6,0x76,0x71,0xf0,0x94,0xf,0x11,0x49,0x66,0x0,0xa6,0xc8,0x70,0x7c,0xf1,0x7e,0xdc,0x39,0xa7,0xeb,0x1a,0x80,0x16,0x1c,0x3a,0x54,0x93,0xb9,0x5f,0x17,0xe3,0x69,0x44,0x7b,0x90,0x5a,0xb4,0x24,0xaa,0xca,0x40,0x56,0xc4,0x57,0x6f,0xa0,0x84,0x96,0xe6,0xfe,0x6e,0xdf,0xcf,0xe8,0x8b,0x42,0x5e,0x62,0x7a,0xbf,0x95,0xb6,0xaf,0x27,0x6c,0x65,0x74,0x8e,0xbe,0x38,0xe1,0xea,0xa2,0x32,0x99,0x81,0x8a,0x34,0x77,0xd6,0xc5,0x37,0x6a,0xd,0xf8,0x30,0x3d,0x1e,0xe2,0xbd,0x2c,0x21,0x33,0x59,0xb8,0x9d,0xf3,0x31,0x8f,0x55,0x7d,0xd8,0xee,0xa3,0x8,0x73,0x23,0x86,0xc2,0x41,0xd4,0xc0,0xa5,0xfc,0xfd,0x9f,0xd5,0xb7,0x7,0x9e,0xa4,0x10,0x46,0x47,0x2e,0x5c,0xed,0xcb,0xd0,0xda,0x5,0x1b,0x2f,0xbb,0xf7,0xc3,0x75,0x43,0x28,0x2a,0x98,0x29,0x8c,0x85,0x5d,0x3c,0x50,0xe0,0xf4,0x12,0x4b,0x64,0xce,0x79,0xc,0xff,0x4a,0xc6,0x68,0xe9,0xa8,0xcc,0xf2,0x35,0xba,0x3,0xf5,0xef,0x2d,0x1,0x9a,0xb2,0x15,0x6d,0xde,0x20,0x83,0x6b,0x22,0x87,0x2b,0x3f,0x78,0x63,0x52,0x9b,0x4d,0xfb,0xa1,0xdd,0xae,0xd7,0x1f,0xad,0x48,0x18,0x9c,0x82,0xc7,0xd2,0x92,0x7f,0x9,0x61,0xb1,0x53,0xab,0xd9,0xfa,0xe,0x89,0x45,0x88,0x14,0xe4,0x19,0x25,0x4c,0x36,0x13,0x67,0x4f,0x3e,0x5b,0xd3,0x51,0x26,0xb2,0x75,0xfa,0xdc,0x66,0xf0,0xd,0xfc,0x9d,0x76,0x8f,0xa2,0xf1,0x5,0x5f,0xb9,0xe6,0x40,0xaf,0x80,0xe9,0xf7,0x16,0x72,0xdf,0x41,0x98,0x3a,0x9a,0x17,0x2e,0x96,0x56,0xed,0x37,0xa8,0x53,0x2b,0xfb,0x4f,0x90,0x97,0x5a,0xe0,0x1f,0x3d,0xa,0x10,0x1,0xbe,0xdd,0x86,0xec,0x71,0xe2,0xe4,0x4a,0x77,0x94,0x6b,0x2f,0x3,0x27,0x55,0x5b,0xca,0xf8,0x4,0xd6,0xdb,0xeb,0x1e,0xd7,0x69,0x7b,0x15,0xbf,0x5e,0xc7,0xd5,0xd4,0x7f,0xc,0x44,0xde,0x7,0x68,0x58,0xd1,0x8c,0x30,0x23,0xd2,0x91,0x67,0x6c,0x84,0x9c,0xa4,0xb8,0xe,0x6d,0x39,0x29,0x83,0x92,0xc1,0x8a,0x50,0x49,0x59,0x73,0xb0,0x22,0x2c,0xa6,0xc2,0x4c,0xbc,0x52,0x18,0x88,0x70,0x0,0x46,0x62,0xb1,0x89,0x9f,0xea,0x82,0x28,0xf4,0xad,0x6,0x12,0x2a,0x14,0xf,0x4e,0x20,0x8e,0x19,0xac,0xa5,0xce,0x25,0x93,0x5d,0x11,0xfd,0xc9,0xda,0xb6,0x63,0xbb,0xcf,0x6a,0xcc,0x7e,0xf6,0xa0,0x78,0x42,0x51,0xe1,0x79,0x33,0x3c,0xe3,0x2d,0x36,0xba,0xb,0xa1,0xc8,0x95,0xc5,0x45,0xee,0x3e,0x8,0xb3,0x9b,0x1a,0x1b,0x26,0x43,0xa7,0x32,0x60,0x24,0xaa,0xd0,0xff,0xc3,0xf2,0x2,0xa3,0x6e,0xb7,0xc0,0xbd,0x35,0xa9,0xd8,0xf5,0x81,0x99,0xef,0x34,0x74,0x64,0x21,0xfe,0x7a,0xe8,0x6f,0x3f,0x1c,0xb5,0x4d,0x87,0x57,0x7d,0xab,0x85,0xb4,0xd9,0x9e,0x61,0xcd,0x4b,0xae,0x31,0xf9,0x3b,0x48,0x1d,0x47,0xe7,0x7c,0x9,0xcb,0xe5,0x13,0xd3,0x5c,0x8d,0xc4,0xc6,0x65,0x8b,0x38,0x54,0xf3,0x67,0xc1,0x2e,0x1,0x68,0x76,0x97,0xf3,0x5e,0xc0,0x19,0xbb,0x1b,0x96,0xaf,0x17,0x33,0xf4,0x7b,0x5d,0xe7,0x71,0x8c,0x7d,0x1c,0xf7,0xe,0x23,0x70,0x84,0xde,0x38,0x80,0x3f,0x5c,0x7,0x6d,0xf0,0x63,0x65,0xcb,0xf6,0x15,0xea,0xae,0x82,0xa6,0xd4,0xd7,0x6c,0xb6,0x29,0xd2,0xaa,0x7a,0xce,0x11,0x16,0xdb,0x61,0x9e,0xbc,0x8b,0x91,0x55,0xfe,0x8d,0xc5,0x5f,0x86,0xe9,0xd9,0x50,0xd,0xb1,0xa2,0x53,0x10,0xe6,0xed,0xda,0x4b,0x79,0x85,0x57,0x5a,0x6a,0x9f,0x56,0xe8,0xfa,0x94,0x3e,0xdf,0x46,0x54,0x31,0xa3,0xad,0x27,0x43,0xcd,0x3d,0xd3,0x99,0x9,0xf1,0x81,0xc7,0xe3,0x30,0x8,0x5,0x1d,0x25,0x39,0x8f,0xec,0xb8,0xa8,0x2,0x13,0x40,0xb,0xd1,0xc8,0xd8,0xf2,0x24,0x4f,0xa4,0x12,0xdc,0x90,0x7c,0x48,0x5b,0x37,0xe2,0x3a,0x4e,0xeb,0x4d,0xff,0x1e,0x6b,0x3,0xa9,0x75,0x2c,0x87,0x93,0xab,0x95,0x8e,0xcf,0xa1,0xf,0x98,0x2d,0x14,0x44,0xc4,0x6f,0xbf,0x89,0x32,0x1a,0x9b,0x9a,0xa7,0xc2,0x26,0xb3,0xe1,0xa5,0x77,0x21,0xf9,0xc3,0xd0,0x60,0xf8,0xb2,0xbd,0x62,0xac,0xb7,0x3b,0x8a,0x20,0x49,0x18,0x6e,0xb5,0xf5,0xe5,0xa0,0x7f,0xfb,0x69,0xee,0xbe,0x9d,0x34,0xcc,0x6,0xd6,0x2b,0x51,0x7e,0x42,0x73,0x83,0x22,0xef,0x36,0x41,0x3c,0xb4,0x28,0x59,0x74,0x0,0x66,0xfd,0x88,0x4a,0x64,0x92,0x52,0xdd,0xc,0x45,0x47,0xe4,0xa,0xb9,0xd5,0x72,0xfc,0x2a,0x4,0x35,0x58,0x1f,0xe0,0x4c,0xca,0x2f,0xb0,0x78,0xba,0xc9,0x9c,0xc6,0x41,0x6c,0x95,0x7e,0x5a,0xbc,0xe6,0x12,0x3f,0x19,0x96,0x51,0x1f,0xee,0x13,0x85,0xd9,0x7b,0xa2,0x3c,0x75,0xcd,0xf4,0x79,0x63,0x4c,0xa3,0x5,0x91,0xf5,0x14,0xa,0x3,0xb9,0x74,0x73,0xf3,0xe9,0xde,0xfc,0x4b,0xd4,0xe,0xb5,0xac,0x18,0xc8,0xb0,0x88,0x77,0x94,0xa9,0xb6,0xc4,0xe0,0xcc,0x65,0x3e,0x5d,0xe2,0x7,0x1,0x92,0xf,0xf6,0x98,0x8a,0x34,0x36,0x24,0xbd,0x5c,0xe7,0x1b,0x29,0xb8,0xfd,0x8,0x38,0x35,0xc0,0xd3,0x6f,0x32,0x8f,0x84,0x72,0x31,0xa7,0xef,0x9c,0x37,0xbb,0x8b,0xe4,0x3d,0x69,0x22,0x71,0x60,0x90,0xba,0xaa,0xb3,0x5b,0x47,0x7f,0x67,0xca,0xda,0x8e,0xed,0xe3,0x93,0x6b,0xfb,0x6a,0x52,0x81,0xa5,0x45,0xcf,0xc1,0x53,0xb1,0x5f,0xaf,0x21,0xad,0xec,0xf7,0xc9,0x4f,0xfa,0x6d,0xc3,0xcb,0x61,0x9,0x7c,0xf1,0xe5,0x4e,0x17,0x58,0x80,0x55,0x39,0x9d,0x2f,0x89,0x2c,0x70,0xc6,0x2d,0x46,0x2a,0x1e,0xf2,0xbe,0xd5,0xce,0x0,0xdf,0x2b,0x42,0xe8,0x59,0xa1,0x9b,0x43,0x15,0xd0,0x9a,0x2,0xb2,0xa0,0xc5,0xf8,0xf9,0xc7,0x83,0xd1,0x44,0xd,0xa6,0x26,0x76,0x78,0x50,0xeb,0xdd,0xd6,0x5e,0x23,0x54,0x62,0x16,0x3b,0x4a,0x20,0x1c,0x33,0x49,0x8d,0x40,0xe1,0x11,0xff,0xdc,0x8c,0xb,0xb4,0x64,0xae,0x56,0x97,0xd7,0xc,0x7a,0x99,0x1d,0xc2,0x87,0x1a,0xd2,0x4d,0xa8,0xa4,0xfe,0xab,0xd8,0x57,0x66,0x48,0x9e,0x2e,0x82,0x7d,0x3a,0x86,0x25,0x27,0x6e,0x10,0xb7,0xdb,0x68,0x28,0xea,0x9f,0x4,0xbf,0x30,0xf0,0x6,0xf4,0xf2,0xfa,0x67,0xcb,0x90,0x17,0xa8,0x31,0x43,0x39,0x15,0x82,0x7d,0x5c,0x61,0xed,0x59,0x45,0x3d,0x21,0xbe,0x40,0xfb,0x1c,0x6,0x9,0x2b,0x4c,0xf6,0x86,0x81,0x0,0x64,0xff,0xe1,0xb9,0x96,0xf0,0x56,0x38,0x80,0x8c,0x1,0x8e,0x2c,0xc9,0x57,0x1b,0xea,0x70,0xe6,0xec,0xca,0xa4,0x63,0x49,0xaf,0xe7,0x13,0x99,0xb4,0x8b,0x60,0xaa,0x44,0xd4,0x5a,0x3a,0xb0,0xa6,0x34,0xa7,0x9f,0x50,0x74,0x66,0x16,0xe,0x9e,0x2f,0x3f,0x18,0x7b,0xb2,0xae,0x92,0x8a,0x4f,0x65,0x46,0x5f,0xd7,0x9c,0x95,0x84,0x7e,0x4e,0xc8,0x11,0x1a,0x52,0xc2,0x69,0x71,0x7a,0xc4,0x87,0x26,0x35,0xc7,0x9a,0xfd,0x8,0xc0,0xcd,0xee,0x12,0x4d,0xdc,0xd1,0xc3,0xa9,0x48,0x6d,0x3,0xc1,0x7f,0xa5,0x8d,0x28,0x1e,0x53,0xf8,0x83,0xd3,0x76,0x32,0xb1,0x24,0x30,0x55,0xc,0xd,0x6f,0x25,0x47,0xf7,0x6e,0x54,0xe0,0xb6,0xb7,0xde,0xac,0x1d,0x3b,0x20,0x2a,0xf5,0xeb,0xdf,0x4b,0x7,0x33,0x85,0xb3,0xd8,0xda,0x68,0xd9,0x7c,0x75,0xad,0xcc,0xa0,0x10,0x4,0xe2,0xbb,0x94,0x3e,0x89,0xfc,0xf,0xba,0x36,0x98,0x19,0x58,0x3c,0x2,0xc5,0x4a,0xf3,0x5,0x1f,0xdd,0xf1,0x6a,0x42,0xe5,0x9d,0x2e,0xd0,0x73,0x9b,0xd2,0x77,0xdb,0xcf,0x88,0x93,0xa2,0x6b,0xbd,0xb,0x51,0x2d,0x5e,0x27,0xef,0x5d,0xb8,0xe8,0x6c,0x72,0x37,0x22,0x62,0x8f,0xf9,0x91,0x41,0xa3,0x5b,0x29,0xa,0xfe,0x79,0xb5,0x78,0xe4,0x14,0xe9,0xd5,0xbc,0xc6,0xe3,0x97,0xbf,0xce,0xab,0x23,0xa1,0xd6,0xfc,0x3b,0xb4,0x92,0x28,0xbe,0x43,0xb2,0xd3,0x38,0xc1,0xec,0xbf,0x4b,0x11,0xf7,0xa8,0xe,0xe1,0xce,0xa7,0xb9,0x58,0x3c,0x91,0xf,0xd6,0x74,0xd4,0x59,0x60,0xd8,0x18,0xa3,0x79,0xe6,0x1d,0x65,0xb5,0x1,0xde,0xd9,0x14,0xae,0x51,0x73,0x44,0x5e,0x4f,0xf0,0x93,0xc8,0xa2,0x3f,0xac,0xaa,0x4,0x39,0xda,0x25,0x61,0x4d,0x69,0x1b,0x15,0x84,0xb6,0x4a,0x98,0x95,0xa5,0x50,0x99,0x27,0x35,0x5b,0xf1,0x10,0x89,0x9b,0x9a,0x31,0x42,0xa,0x90,0x49,0x26,0x16,0x9f,0xc2,0x7e,0x6d,0x9c,0xdf,0x29,0x22,0xca,0xd2,0xea,0xf6,0x40,0x23,0x77,0x67,0xcd,0xdc,0x8f,0xc4,0x1e,0x7,0x17,0x3d,0xfe,0x6c,0x62,0xe8,0x8c,0x2,0xf2,0x1c,0x56,0xc6,0x3e,0x4e,0x8,0x2c,0xff,0xc7,0xd1,0xa4,0xcc,0x66,0xba,0xe3,0x48,0x5c,0x64,0x5a,0x41,0x0,0x6e,0xc0,0x57,0xe2,0xeb,0x80,0x6b,0xdd,0x13,0x5f,0xb3,0x87,0x94,0xf8,0x2d,0xf5,0x81,0x24,0x82,0x30,0xb8,0xee,0x36,0xc,0x1f,0xaf,0x37,0x7d,0x72,0xad,0x63,0x78,0xf4,0x45,0xef,0x86,0xdb,0x8b,0xb,0xa0,0x70,0x46,0xfd,0xd5,0x54,0x55,0x68,0xd,0xe9,0x7c,0x2e,0x6a,0xe4,0x9e,0xb1,0x8d,0xbc,0x4c,0xed,0x20,0xf9,0x8e,0xf3,0x7b,0xe7,0x96,0xbb,0xcf,0xd7,0xa1,0x7a,0x3a,0x2a,0x6f,0xb0,0x34,0xa6,0x21,0x71,0x52,0xfb,0x3,0xc9,0x19,0x33,0xe5,0xcb,0xfa,0x97,0xd0,0x2f,0x83,0x5,0xe0,0x7f,0xb7,0x75,0x6,0x53,0x9,0xa9,0x32,0x47,0x85,0xab,0x5d,0x9d,0x12,0xc3,0x8a,0x88,0x2b,0xc5,0x76,0x1a,0xbd,0x93,0x35,0xda,0xf5,0x9c,0x82,0x63,0x7,0xaa,0x34,0xed,0x4f,0xef,0x62,0x5b,0xe3,0xc7,0x0,0x8f,0xa9,0x13,0x85,0x78,0x89,0xe8,0x3,0xfa,0xd7,0x84,0x70,0x2a,0xcc,0x74,0xcb,0xa8,0xf3,0x99,0x4,0x97,0x91,0x3f,0x2,0xe1,0x1e,0x5a,0x76,0x52,0x20,0x23,0x98,0x42,0xdd,0x26,0x5e,0x8e,0x3a,0xe5,0xe2,0x2f,0x95,0x6a,0x48,0x7f,0x65,0xa1,0xa,0x79,0x31,0xab,0x72,0x1d,0x2d,0xa4,0xf9,0x45,0x56,0xa7,0xe4,0x12,0x19,0x2e,0xbf,0x8d,0x71,0xa3,0xae,0x9e,0x6b,0xa2,0x1c,0xe,0x60,0xca,0x2b,0xb2,0xa0,0xc5,0x57,0x59,0xd3,0xb7,0x39,0xc9,0x27,0x6d,0xfd,0x5,0x75,0x33,0x17,0xc4,0xfc,0xf1,0xe9,0xd1,0xcd,0x7b,0x18,0x4c,0x5c,0xf6,0xe7,0xb4,0xff,0x25,0x3c,0x2c,0x6,0xd0,0xbb,0x50,0xe6,0x28,0x64,0x88,0xbc,0xaf,0xc3,0x16,0xce,0xba,0x1f,0xb9,0xb,0xea,0x9f,0xf7,0x5d,0x81,0xd8,0x73,0x67,0x5f,0x61,0x7a,0x3b,0x55,0xfb,0x6c,0xd9,0xe0,0xb0,0x30,0x9b,0x4b,0x7d,0xc6,0xee,0x6f,0x6e,0x53,0x36,0xd2,0x47,0x15,0x51,0x83,0xd5,0xd,0x37,0x24,0x94,0xc,0x46,0x49,0x96,0x58,0x43,0xcf,0x7e,0xd4,0xbd,0xec,0x9a,0x41,0x1,0x11,0x54,0x8b,0xf,0x9d,0x1a,0x4a,0x69,0xc0,0x38,0xf2,0x22,0xdf,0xa5,0x8a,0xb6,0x87,0x77,0xd6,0x1b,0xc2,0xb5,0xc8,0x40,0xdc,0xad,0x80,0xf4,0x92,0x9,0x7c,0xbe,0x90,0x66,0xa6,0x29,0xf8,0xb1,0xb3,0x10,0xfe,0x4d,0x21,0x86,0x8,0xde,0xf0,0xc1,0xac,0xeb,0x14,0xb8,0x3e,0xdb,0x44,0x8c,0x4e,0x3d,0x68,0x32,0x4b,0x66,0x9f,0x74,0x50,0xb6,0xec,0x18,0x35,0x13,0x9c,0x5b,0x15,0xe4,0x19,0x8f,0xd3,0x71,0xa8,0x36,0x7f,0xc7,0xfe,0x73,0x69,0x46,0xa9,0xf,0x9b,0xff,0x1e,0x0,0x9,0xb3,0x7e,0x79,0xf9,0xe3,0xd4,0xf6,0x41,0xde,0x4,0xbf,0xa6,0x12,0xc2,0xba,0x82,0x7d,0x9e,0xa3,0xbc,0xce,0xea,0xc6,0x6f,0x34,0x57,0xe8,0xd,0xb,0x98,0x5,0xfc,0x92,0x80,0x3e,0x3c,0x2e,0xb7,0x56,0xed,0x11,0x23,0xb2,0xf7,0x2,0x32,0x3f,0xca,0xd9,0x65,0x38,0x85,0x8e,0x78,0x3b,0xad,0xe5,0x96,0x3d,0xb1,0x81,0xee,0x37,0x63,0x28,0x7b,0x6a,0x9a,0xb0,0xa0,0xb9,0x51,0x4d,0x75,0x6d,0xc0,0xd0,0x84,0xe7,0xe9,0x99,0x61,0xf1,0x60,0x58,0x8b,0xaf,0x4f,0xc5,0xcb,0x59,0xbb,0x55,0xa5,0x2b,0xa7,0xe6,0xfd,0xc3,0x45,0xf0,0x67,0xc9,0xc1,0x6b,0x3,0x76,0xfb,0xef,0x44,0x1d,0x52,0x8a,0x5f,0x33,0x97,0x25,0x83,0x26,0x7a,0xcc,0x27,0x4c,0x20,0x14,0xf8,0xb4,0xdf,0xc4,0xa,0xd5,0x21,0x48,0xe2,0x53,0xab,0x91,0x49,0x1f,0xda,0x90,0x8,0xb8,0xaa,0xcf,0xf2,0xf3,0xcd,0x89,0xdb,0x4e,0x7,0xac,0x2c,0x7c,0x72,0x5a,0xe1,0xd7,0xdc,0x54,0x29,0x5e,0x68,0x1c,0x31,0x40,0x2a,0x16,0x39,0x43,0x87,0x4a,0xeb,0x1b,0xf5,0xd6,0x86,0x1,0xbe,0x6e,0xa4,0x5c,0x9d,0xdd,0x6,0x70,0x93,0x17,0xc8,0x8d,0x10,0xd8,0x47,0xa2,0xae,0xf4,0xa1,0xd2,0x5d,0x6c,0x42,0x94,0x24,0x88,0x77,0x30,0x8c,0x2f,0x2d,0x64,0x1a,0xbd,0xd1,0x62,0x22,0xe0,0x95,0xe,0xb5,0x3a,0xfa,0xc,0xf6,0xf0,0xf8,0x65,0xc9,0x92,0x15,0xaa,0x33,0x41,0x3b,0x17,0x80,0x7f,0x5e,0x63,0xef,0x5b,0x47,0x3f,0x23,0xbc,0x42,0xf9,0x1e,0x4,0xb,0x29,0x4e,0xf4,0x84,0x83,0x2,0x66,0xfd,0xe3,0xbb,0x94,0xf2,0x54,0x3a,0x82,0x8e,0x3,0x8c,0x2e,0xcb,0x55,0x19,0xe8,0x72,0xe4,0xee,0xc8,0xa6,0x61,0x4b,0xad,0xe5,0x11,0x9b,0xb6,0x89,0x62,0xa8,0x46,0xd6,0x58,0x38,0xb2,0xa4,0x36,0xa5,0x9d,0x52,0x76,0x64,0x14,0xc,0x9c,0x2d,0x3d,0x1a,0x79,0xb0,0xac,0x90,0x88,0x4d,0x67,0x44,0x5d,0xd5,0x9e,0x97,0x86,0x7c,0x4c,0xca,0x13,0x18,0x50,0xc0,0x6b,0x73,0x78,0xc6,0x85,0x24,0x37,0xc5,0x98,0xff,0xa,0xc2,0xcf,0xec,0x10,0x4f,0xde,0xd3,0xc1,0xab,0x4a,0x6f,0x1,0xc3,0x7d,0xa7,0x8f,0x2a,0x1c,0x51,0xfa,0x81,0xd1,0x74,0x30,0xb3,0x26,0x32,0x57,0xe,0xf,0x6d,0x27,0x45,0xf5,0x6c,0x56,0xe2,0xb4,0xb5,0xdc,0xae,0x1f,0x39,0x22,0x28,0xf7,0xe9,0xdd,0x49,0x5,0x31,0x87,0xb1,0xda,0xd8,0x6a,0xdb,0x7e,0x77,0xaf,0xce,0xa2,0x12,0x6,0xe0,0xb9,0x96,0x3c,0x8b,0xfe,0xd,0xb8,0x34,0x9a,0x1b,0x5a,0x3e,0x0,0xc7,0x48,0xf1,0x7,0x1d,0xdf,0xf3,0x68,0x40,0xe7,0x9f,0x2c,0xd2,0x71,0x99,0xd0,0x75,0xd9,0xcd,0x8a,0x91,0xa0,0x69,0xbf,0x9,0x53,0x2f,0x5c,0x25,0xed,0x5f,0xba,0xea,0x6e,0x70,0x35,0x20,0x60,0x8d,0xfb,0x93,0x43,0xa1,0x59,0x2b,0x8,0xfc,0x7b,0xb7,0x7a,0xe6,0x16,0xeb,0xd7,0xbe,0xc4,0xe1,0x95,0xbd,0xcc,0xa9,0x21,0xa3,0xd4,0x49,0x8e,0x1,0x27,0x9d,0xb,0xf6,0x7,0x66,0x8d,0x74,0x59,0xa,0xfe,0xa4,0x42,0x1d,0xbb,0x54,0x7b,0x12,0xc,0xed,0x89,0x24,0xba,0x63,0xc1,0x61,0xec,0xd5,0x6d,0xad,0x16,0xcc,0x53,0xa8,0xd0,0x0,0xb4,0x6b,0x6c,0xa1,0x1b,0xe4,0xc6,0xf1,0xeb,0xfa,0x45,0x26,0x7d,0x17,0x8a,0x19,0x1f,0xb1,0x8c,0x6f,0x90,0xd4,0xf8,0xdc,0xae,0xa0,0x31,0x3,0xff,0x2d,0x20,0x10,0xe5,0x2c,0x92,0x80,0xee,0x44,0xa5,0x3c,0x2e,0x2f,0x84,0xf7,0xbf,0x25,0xfc,0x93,0xa3,0x2a,0x77,0xcb,0xd8,0x29,0x6a,0x9c,0x97,0x7f,0x67,0x5f,0x43,0xf5,0x96,0xc2,0xd2,0x78,0x69,0x3a,0x71,0xab,0xb2,0xa2,0x88,0x4b,0xd9,0xd7,0x5d,0x39,0xb7,0x47,0xa9,0xe3,0x73,0x8b,0xfb,0xbd,0x99,0x4a,0x72,0x64,0x11,0x79,0xd3,0xf,0x56,0xfd,0xe9,0xd1,0xef,0xf4,0xb5,0xdb,0x75,0xe2,0x57,0x5e,0x35,0xde,0x68,0xa6,0xea,0x6,0x32,0x21,0x4d,0x98,0x40,0x34,0x91,0x37,0x85,0xd,0x5b,0x83,0xb9,0xaa,0x1a,0x82,0xc8,0xc7,0x18,0xd6,0xcd,0x41,0xf0,0x5a,0x33,0x6e,0x3e,0xbe,0x15,0xc5,0xf3,0x48,0x60,0xe1,0xe0,0xdd,0xb8,0x5c,0xc9,0x9b,0xdf,0x51,0x2b,0x4,0x38,0x9,0xf9,0x58,0x95,0x4c,0x3b,0x46,0xce,0x52,0x23,0xe,0x7a,0x62,0x14,0xcf,0x8f,0x9f,0xda,0x5,0x81,0x13,0x94,0xc4,0xe7,0x4e,0xb6,0x7c,0xac,0x86,0x50,0x7e,0x4f,0x22,0x65,0x9a,0x36,0xb0,0x55,0xca,0x2,0xc0,0xb3,0xe6,0xbc,0x1c,0x87,0xf2,0x30,0x1e,0xe8,0x28,0xa7,0x76,0x3f,0x3d,0x9e,0x70,0xc3,0xaf,0x8,0x7a,0xdc,0x33,0x1c,0x75,0x6b,0x8a,0xee,0x43,0xdd,0x4,0xa6,0x6,0x8b,0xb2,0xa,0x2e,0xe9,0x66,0x40,0xfa,0x6c,0x91,0x60,0x1,0xea,0x13,0x3e,0x6d,0x99,0xc3,0x25,0x9d,0x22,0x41,0x1a,0x70,0xed,0x7e,0x78,0xd6,0xeb,0x8,0xf7,0xb3,0x9f,0xbb,0xc9,0xca,0x71,0xab,0x34,0xcf,0xb7,0x67,0xd3,0xc,0xb,0xc6,0x7c,0x83,0xa1,0x96,0x8c,0x48,0xe3,0x90,0xd8,0x42,0x9b,0xf4,0xc4,0x4d,0x10,0xac,0xbf,0x4e,0xd,0xfb,0xf0,0xc7,0x56,0x64,0x98,0x4a,0x47,0x77,0x82,0x4b,0xf5,0xe7,0x89,0x23,0xc2,0x5b,0x49,0x2c,0xbe,0xb0,0x3a,0x5e,0xd0,0x20,0xce,0x84,0x14,0xec,0x9c,0xda,0xfe,0x2d,0x15,0x18,0x0,0x38,0x24,0x92,0xf1,0xa5,0xb5,0x1f,0xe,0x5d,0x16,0xcc,0xd5,0xc5,0xef,0x39,0x52,0xb9,0xf,0xc1,0x8d,0x61,0x55,0x46,0x2a,0xff,0x27,0x53,0xf6,0x50,0xe2,0x3,0x76,0x1e,0xb4,0x68,0x31,0x9a,0x8e,0xb6,0x88,0x93,0xd2,0xbc,0x12,0x85,0x30,0x9,0x59,0xd9,0x72,0xa2,0x94,0x2f,0x7,0x86,0x87,0xba,0xdf,0x3b,0xae,0xfc,0xb8,0x6a,0x3c,0xe4,0xde,0xcd,0x7d,0xe5,0xaf,0xa0,0x7f,0xb1,0xaa,0x26,0x97,0x3d,0x54,0x5,0x73,0xa8,0xe8,0xf8,0xbd,0x62,0xe6,0x74,0xf3,0xa3,0x80,0x29,0xd1,0x1b,0xcb,0x36,0x4c,0x63,0x5f,0x6e,0x9e,0x3f,0xf2,0x2b,0x5c,0x21,0xa9,0x35,0x44,0x69,0x1d,0x7b,0xe0,0x95,0x57,0x79,0x8f,0x4f,0xc0,0x11,0x58,0x5a,0xf9,0x17,0xa4,0xc8,0x6f,0xe1,0x37,0x19,0x28,0x45,0x2,0xfd,0x51,0xd7,0x32,0xad,0x65,0xa7,0xd4,0x81,0xdb,0xa4,0x89,0x70,0x9b,0xbf,0x59,0x3,0xf7,0xda,0xfc,0x73,0xb4,0xfa,0xb,0xf6,0x60,0x3c,0x9e,0x47,0xd9,0x90,0x28,0x11,0x9c,0x86,0xa9,0x46,0xe0,0x74,0x10,0xf1,0xef,0xe6,0x5c,0x91,0x96,0x16,0xc,0x3b,0x19,0xae,0x31,0xeb,0x50,0x49,0xfd,0x2d,0x55,0x6d,0x92,0x71,0x4c,0x53,0x21,0x5,0x29,0x80,0xdb,0xb8,0x7,0xe2,0xe4,0x77,0xea,0x13,0x7d,0x6f,0xd1,0xd3,0xc1,0x58,0xb9,0x2,0xfe,0xcc,0x5d,0x18,0xed,0xdd,0xd0,0x25,0x36,0x8a,0xd7,0x6a,0x61,0x97,0xd4,0x42,0xa,0x79,0xd2,0x5e,0x6e,0x1,0xd8,0x8c,0xc7,0x94,0x85,0x75,0x5f,0x4f,0x56,0xbe,0xa2,0x9a,0x82,0x2f,0x3f,0x6b,0x8,0x6,0x76,0x8e,0x1e,0x8f,0xb7,0x64,0x40,0xa0,0x2a,0x24,0xb6,0x54,0xba,0x4a,0xc4,0x48,0x9,0x12,0x2c,0xaa,0x1f,0x88,0x26,0x2e,0x84,0xec,0x99,0x14,0x0,0xab,0xf2,0xbd,0x65,0xb0,0xdc,0x78,0xca,0x6c,0xc9,0x95,0x23,0xc8,0xa3,0xcf,0xfb,0x17,0x5b,0x30,0x2b,0xe5,0x3a,0xce,0xa7,0xd,0xbc,0x44,0x7e,0xa6,0xf0,0x35,0x7f,0xe7,0x57,0x45,0x20,0x1d,0x1c,0x22,0x66,0x34,0xa1,0xe8,0x43,0xc3,0x93,0x9d,0xb5,0xe,0x38,0x33,0xbb,0xc6,0xb1,0x87,0xf3,0xde,0xaf,0xc5,0xf9,0xd6,0xac,0x68,0xa5,0x4,0xf4,0x1a,0x39,0x69,0xee,0x51,0x81,0x4b,0xb3,0x72,0x32,0xe9,0x9f,0x7c,0xf8,0x27,0x62,0xff,0x37,0xa8,0x4d,0x41,0x1b,0x4e,0x3d,0xb2,0x83,0xad,0x7b,0xcb,0x67,0x98,0xdf,0x63,0xc0,0xc2,0x8b,0xf5,0x52,0x3e,0x8d,0xcd,0xf,0x7a,0xe1,0x5a,0xd5,0x15,0xe3,0x8a,0x8c,0x84,0x19,0xb5,0xee,0x69,0xd6,0x4f,0x3d,0x47,0x6b,0xfc,0x3,0x22,0x1f,0x93,0x27,0x3b,0x43,0x5f,0xc0,0x3e,0x85,0x62,0x78,0x77,0x55,0x32,0x88,0xf8,0xff,0x7e,0x1a,0x81,0x9f,0xc7,0xe8,0x8e,0x28,0x46,0xfe,0xf2,0x7f,0xf0,0x52,0xb7,0x29,0x65,0x94,0xe,0x98,0x92,0xb4,0xda,0x1d,0x37,0xd1,0x99,0x6d,0xe7,0xca,0xf5,0x1e,0xd4,0x3a,0xaa,0x24,0x44,0xce,0xd8,0x4a,0xd9,0xe1,0x2e,0xa,0x18,0x68,0x70,0xe0,0x51,0x41,0x66,0x5,0xcc,0xd0,0xec,0xf4,0x31,0x1b,0x38,0x21,0xa9,0xe2,0xeb,0xfa,0x0,0x30,0xb6,0x6f,0x64,0x2c,0xbc,0x17,0xf,0x4,0xba,0xf9,0x58,0x4b,0xb9,0xe4,0x83,0x76,0xbe,0xb3,0x90,0x6c,0x33,0xa2,0xaf,0xbd,0xd7,0x36,0x13,0x7d,0xbf,0x1,0xdb,0xf3,0x56,0x60,0x2d,0x86,0xfd,0xad,0x8,0x4c,0xcf,0x5a,0x4e,0x2b,0x72,0x73,0x11,0x5b,0x39,0x89,0x10,0x2a,0x9e,0xc8,0xc9,0xa0,0xd2,0x63,0x45,0x5e,0x54,0x8b,0x95,0xa1,0x35,0x79,0x4d,0xfb,0xcd,0xa6,0xa4,0x16,0xa7,0x2,0xb,0xd3,0xb2,0xde,0x6e,0x7a,0x9c,0xc5,0xea,0x40,0xf7,0x82,0x71,0xc4,0x48,0xe6,0x67,0x26,0x42,0x7c,0xbb,0x34,0x8d,0x7b,0x61,0xa3,0x8f,0x14,0x3c,0x9b,0xe3,0x50,0xae,0xd,0xe5,0xac,0x9,0xa5,0xb1,0xf6,0xed,0xdc,0x15,0xc3,0x75,0x2f,0x53,0x20,0x59,0x91,0x23,0xc6,0x96,0x12,0xc,0x49,0x5c,0x1c,0xf1,0x87,0xef,0x3f,0xdd,0x25,0x57,0x74,0x80,0x7,0xcb,0x6,0x9a,0x6a,0x97,0xab,0xc2,0xb8,0x9d,0xe9,0xc1,0xb0,0xd5,0x5d,0xdf,0xa8,0xec,0x2b,0xa4,0x82,0x38,0xae,0x53,0xa2,0xc3,0x28,0xd1,0xfc,0xaf,0x5b,0x1,0xe7,0xb8,0x1e,0xf1,0xde,0xb7,0xa9,0x48,0x2c,0x81,0x1f,0xc6,0x64,0xc4,0x49,0x70,0xc8,0x8,0xb3,0x69,0xf6,0xd,0x75,0xa5,0x11,0xce,0xc9,0x4,0xbe,0x41,0x63,0x54,0x4e,0x5f,0xe0,0x83,0xd8,0xb2,0x2f,0xbc,0xba,0x14,0x29,0xca,0x35,0x71,0x5d,0x79,0xb,0x5,0x94,0xa6,0x5a,0x88,0x85,0xb5,0x40,0x89,0x37,0x25,0x4b,0xe1,0x0,0x99,0x8b,0x8a,0x21,0x52,0x1a,0x80,0x59,0x36,0x6,0x8f,0xd2,0x6e,0x7d,0x8c,0xcf,0x39,0x32,0xda,0xc2,0xfa,0xe6,0x50,0x33,0x67,0x77,0xdd,0xcc,0x9f,0xd4,0xe,0x17,0x7,0x2d,0xee,0x7c,0x72,0xf8,0x9c,0x12,0xe2,0xc,0x46,0xd6,0x2e,0x5e,0x18,0x3c,0xef,0xd7,0xc1,0xb4,0xdc,0x76,0xaa,0xf3,0x58,0x4c,0x74,0x4a,0x51,0x10,0x7e,0xd0,0x47,0xf2,0xfb,0x90,0x7b,0xcd,0x3,0x4f,0xa3,0x97,0x84,0xe8,0x3d,0xe5,0x91,0x34,0x92,0x20,0xa8,0xfe,0x26,0x1c,0xf,0xbf,0x27,0x6d,0x62,0xbd,0x73,0x68,0xe4,0x55,0xff,0x96,0xcb,0x9b,0x1b,0xb0,0x60,0x56,0xed,0xc5,0x44,0x45,0x78,0x1d,0xf9,0x6c,0x3e,0x7a,0xf4,0x8e,0xa1,0x9d,0xac,0x5c,0xfd,0x30,0xe9,0x9e,0xe3,0x6b,0xf7,0x86,0xab,0xdf,0xc7,0xb1,0x6a,0x2a,0x3a,0x7f,0xa0,0x24,0xb6,0x31,0x61,0x42,0xeb,0x13,0xd9,0x9,0x23,0xf5,0xdb,0xea,0x87,0xc0,0x3f,0x93,0x15,0xf0,0x6f,0xa7,0x65,0x16,0x43,0x19,0xb9,0x22,0x57,0x95,0xbb,0x4d,0x8d,0x2,0xd3,0x9a,0x98,0x3b,0xd5,0x66,0xa,0xad,0xaa,0xc,0xe3,0xcc,0xa5,0xbb,0x5a,0x3e,0x93,0xd,0xd4,0x76,0xd6,0x5b,0x62,0xda,0xfe,0x39,0xb6,0x90,0x2a,0xbc,0x41,0xb0,0xd1,0x3a,0xc3,0xee,0xbd,0x49,0x13,0xf5,0x4d,0xf2,0x91,0xca,0xa0,0x3d,0xae,0xa8,0x6,0x3b,0xd8,0x27,0x63,0x4f,0x6b,0x19,0x1a,0xa1,0x7b,0xe4,0x1f,0x67,0xb7,0x3,0xdc,0xdb,0x16,0xac,0x53,0x71,0x46,0x5c,0x98,0x33,0x40,0x8,0x92,0x4b,0x24,0x14,0x9d,0xc0,0x7c,0x6f,0x9e,0xdd,0x2b,0x20,0x17,0x86,0xb4,0x48,0x9a,0x97,0xa7,0x52,0x9b,0x25,0x37,0x59,0xf3,0x12,0x8b,0x99,0xfc,0x6e,0x60,0xea,0x8e,0x0,0xf0,0x1e,0x54,0xc4,0x3c,0x4c,0xa,0x2e,0xfd,0xc5,0xc8,0xd0,0xe8,0xf4,0x42,0x21,0x75,0x65,0xcf,0xde,0x8d,0xc6,0x1c,0x5,0x15,0x3f,0xe9,0x82,0x69,0xdf,0x11,0x5d,0xb1,0x85,0x96,0xfa,0x2f,0xf7,0x83,0x26,0x80,0x32,0xd3,0xa6,0xce,0x64,0xb8,0xe1,0x4a,0x5e,0x66,0x58,0x43,0x2,0x6c,0xc2,0x55,0xe0,0xd9,0x89,0x9,0xa2,0x72,0x44,0xff,0xd7,0x56,0x57,0x6a,0xf,0xeb,0x7e,0x2c,0x68,0xba,0xec,0x34,0xe,0x1d,0xad,0x35,0x7f,0x70,0xaf,0x61,0x7a,0xf6,0x47,0xed,0x84,0xd5,0xa3,0x78,0x38,0x28,0x6d,0xb2,0x36,0xa4,0x23,0x73,0x50,0xf9,0x1,0xcb,0x1b,0xe6,0x9c,0xb3,0x8f,0xbe,0x4e,0xef,0x22,0xfb,0x8c,0xf1,0x79,0xe5,0x94,0xb9,0xcd,0xab,0x30,0x45,0x87,0xa9,0x5f,0x9f,0x10,0xc1,0x88,0x8a,0x29,0xc7,0x74,0x18,0xbf,0x31,0xe7,0xc9,0xf8,0x95,0xd2,0x2d,0x81,0x7,0xe2,0x7d,0xb5,0x77,0x4,0x51,0xb,0x53,0x7e,0x87,0x6c,0x48,0xae,0xf4,0x0,0x2d,0xb,0x84,0x43,0xd,0xfc,0x1,0x97,0xcb,0x69,0xb0,0x2e,0x67,0xdf,0xe6,0x6b,0x71,0x5e,0xb1,0x17,0x83,0xe7,0x6,0x18,0x11,0xab,0x66,0x61,0xe1,0xfb,0xcc,0xee,0x59,0xc6,0x1c,0xa7,0xbe,0xa,0xda,0xa2,0x9a,0x65,0x86,0xbb,0xa4,0xd6,0xf2,0xde,0x77,0x2c,0x4f,0xf0,0x15,0x13,0x80,0x1d,0xe4,0x8a,0x98,0x26,0x24,0x36,0xaf,0x4e,0xf5,0x9,0x3b,0xaa,0xef,0x1a,0x2a,0x27,0xd2,0xc1,0x7d,0x20,0x9d,0x96,0x60,0x23,0xb5,0xfd,0x8e,0x25,0xa9,0x99,0xf6,0x2f,0x7b,0x30,0x63,0x72,0x82,0xa8,0xb8,0xa1,0x49,0x55,0x6d,0x75,0xd8,0xc8,0x9c,0xff,0xf1,0x81,0x79,0xe9,0x78,0x40,0x93,0xb7,0x57,0xdd,0xd3,0x41,0xa3,0x4d,0xbd,0x33,0xbf,0xfe,0xe5,0xdb,0x5d,0xe8,0x7f,0xd1,0xd9,0x73,0x1b,0x6e,0xe3,0xf7,0x5c,0x5,0x4a,0x92,0x47,0x2b,0x8f,0x3d,0x9b,0x3e,0x62,0xd4,0x3f,0x54,0x38,0xc,0xe0,0xac,0xc7,0xdc,0x12,0xcd,0x39,0x50,0xfa,0x4b,0xb3,0x89,0x51,0x7,0xc2,0x88,0x10,0xa0,0xb2,0xd7,0xea,0xeb,0xd5,0x91,0xc3,0x56,0x1f,0xb4,0x34,0x64,0x6a,0x42,0xf9,0xcf,0xc4,0x4c,0x31,0x46,0x70,0x4,0x29,0x58,0x32,0xe,0x21,0x5b,0x9f,0x52,0xf3,0x3,0xed,0xce,0x9e,0x19,0xa6,0x76,0xbc,0x44,0x85,0xc5,0x1e,0x68,0x8b,0xf,0xd0,0x95,0x8,0xc0,0x5f,0xba,0xb6,0xec,0xb9,0xca,0x45,0x74,0x5a,0x8c,0x3c,0x90,0x6f,0x28,0x94,0x37,0x35,0x7c,0x2,0xa5,0xc9,0x7a,0x3a,0xf8,0x8d,0x16,0xad,0x22,0xe2,0x14,0xc6,0xc0,0xc8,0x55,0xf9,0xa2,0x25,0x9a,0x3,0x71,0xb,0x27,0xb0,0x4f,0x6e,0x53,0xdf,0x6b,0x77,0xf,0x13,0x8c,0x72,0xc9,0x2e,0x34,0x3b,0x19,0x7e,0xc4,0xb4,0xb3,0x32,0x56,0xcd,0xd3,0x8b,0xa4,0xc2,0x64,0xa,0xb2,0xbe,0x33,0xbc,0x1e,0xfb,0x65,0x29,0xd8,0x42,0xd4,0xde,0xf8,0x96,0x51,0x7b,0x9d,0xd5,0x21,0xab,0x86,0xb9,0x52,0x98,0x76,0xe6,0x68,0x8,0x82,0x94,0x6,0x95,0xad,0x62,0x46,0x54,0x24,0x3c,0xac,0x1d,0xd,0x2a,0x49,0x80,0x9c,0xa0,0xb8,0x7d,0x57,0x74,0x6d,0xe5,0xae,0xa7,0xb6,0x4c,0x7c,0xfa,0x23,0x28,0x60,0xf0,0x5b,0x43,0x48,0xf6,0xb5,0x14,0x7,0xf5,0xa8,0xcf,0x3a,0xf2,0xff,0xdc,0x20,0x7f,0xee,0xe3,0xf1,0x9b,0x7a,0x5f,0x31,0xf3,0x4d,0x97,0xbf,0x1a,0x2c,0x61,0xca,0xb1,0xe1,0x44,0x0,0x83,0x16,0x2,0x67,0x3e,0x3f,0x5d,0x17,0x75,0xc5,0x5c,0x66,0xd2,0x84,0x85,0xec,0x9e,0x2f,0x9,0x12,0x18,0xc7,0xd9,0xed,0x79,0x35,0x1,0xb7,0x81,0xea,0xe8,0x5a,0xeb,0x4e,0x47,0x9f,0xfe,0x92,0x22,0x36,0xd0,0x89,0xa6,0xc,0xbb,0xce,0x3d,0x88,0x4,0xaa,0x2b,0x6a,0xe,0x30,0xf7,0x78,0xc1,0x37,0x2d,0xef,0xc3,0x58,0x70,0xd7,0xaf,0x1c,0xe2,0x41,0xa9,0xe0,0x45,0xe9,0xfd,0xba,0xa1,0x90,0x59,0x8f,0x39,0x63,0x1f,0x6c,0x15,0xdd,0x6f,0x8a,0xda,0x5e,0x40,0x5,0x10,0x50,0xbd,0xcb,0xa3,0x73,0x91,0x69,0x1b,0x38,0xcc,0x4b,0x87,0x4a,0xd6,0x26,0xdb,0xe7,0x8e,0xf4,0xd1,0xa5,0x8d,0xfc,0x99,0x11,0x93,0xe4,0x79,0xbe,0x31,0x17,0xad,0x3b,0xc6,0x37,0x56,0xbd,0x44,0x69,0x3a,0xce,0x94,0x72,0x2d,0x8b,0x64,0x4b,0x22,0x3c,0xdd,0xb9,0x14,0x8a,0x53,0xf1,0x51,0xdc,0xe5,0x5d,0x9d,0x26,0xfc,0x63,0x98,0xe0,0x30,0x84,0x5b,0x5c,0x91,0x2b,0xd4,0xf6,0xc1,0xdb,0xca,0x75,0x16,0x4d,0x27,0xba,0x29,0x2f,0x81,0xbc,0x5f,0xa0,0xe4,0xc8,0xec,0x9e,0x90,0x1,0x33,0xcf,0x1d,0x10,0x20,0xd5,0x1c,0xa2,0xb0,0xde,0x74,0x95,0xc,0x1e,0x1f,0xb4,0xc7,0x8f,0x15,0xcc,0xa3,0x93,0x1a,0x47,0xfb,0xe8,0x19,0x5a,0xac,0xa7,0x4f,0x57,0x6f,0x73,0xc5,0xa6,0xf2,0xe2,0x48,0x59,0xa,0x41,0x9b,0x82,0x92,0xb8,0x7b,0xe9,0xe7,0x6d,0x9,0x87,0x77,0x99,0xd3,0x43,0xbb,0xcb,0x8d,0xa9,0x7a,0x42,0x54,0x21,0x49,0xe3,0x3f,0x66,0xcd,0xd9,0xe1,0xdf,0xc4,0x85,0xeb,0x45,0xd2,0x67,0x6e,0x5,0xee,0x58,0x96,0xda,0x36,0x2,0x11,0x7d,0xa8,0x70,0x4,0xa1,0x7,0xb5,0x3d,0x6b,0xb3,0x89,0x9a,0x2a,0xb2,0xf8,0xf7,0x28,0xe6,0xfd,0x71,0xc0,0x6a,0x3,0x5e,0xe,0x8e,0x25,0xf5,0xc3,0x78,0x50,0xd1,0xd0,0xed,0x88,0x6c,0xf9,0xab,0xef,0x61,0x1b,0x34,0x8,0x39,0xc9,0x68,0xa5,0x7c,0xb,0x76,0xfe,0x62,0x13,0x3e,0x4a,0x52,0x24,0xff,0xbf,0xaf,0xea,0x35,0xb1,0x23,0xa4,0xf4,0xd7,0x7e,0x86,0x4c,0x9c,0xb6,0x60,0x4e,0x7f,0x12,0x55,0xaa,0x6,0x80,0x65,0xfa,0x32,0xf0,0x83,0xd6,0x8c,0x2c,0xb7,0xc2,0x0,0x2e,0xd8,0x18,0x97,0x46,0xf,0xd,0xae,0x40,0xf3,0x9f,0x38,0xc6,0x60,0x8f,0xa0,0xc9,0xd7,0x36,0x52,0xff,0x61,0xb8,0x1a,0xba,0x37,0xe,0xb6,0x92,0x55,0xda,0xfc,0x46,0xd0,0x2d,0xdc,0xbd,0x56,0xaf,0x82,0xd1,0x25,0x7f,0x99,0x21,0x9e,0xfd,0xa6,0xcc,0x51,0xc2,0xc4,0x6a,0x57,0xb4,0x4b,0xf,0x23,0x7,0x75,0x76,0xcd,0x17,0x88,0x73,0xb,0xdb,0x6f,0xb0,0xb7,0x7a,0xc0,0x3f,0x1d,0x2a,0x30,0xf4,0x5f,0x2c,0x64,0xfe,0x27,0x48,0x78,0xf1,0xac,0x10,0x3,0xf2,0xb1,0x47,0x4c,0x7b,0xea,0xd8,0x24,0xf6,0xfb,0xcb,0x3e,0xf7,0x49,0x5b,0x35,0x9f,0x7e,0xe7,0xf5,0x90,0x2,0xc,0x86,0xe2,0x6c,0x9c,0x72,0x38,0xa8,0x50,0x20,0x66,0x42,0x91,0xa9,0xa4,0xbc,0x84,0x98,0x2e,0x4d,0x19,0x9,0xa3,0xb2,0xe1,0xaa,0x70,0x69,0x79,0x53,0x85,0xee,0x5,0xb3,0x7d,0x31,0xdd,0xe9,0xfa,0x96,0x43,0x9b,0xef,0x4a,0xec,0x5e,0xbf,0xca,0xa2,0x8,0xd4,0x8d,0x26,0x32,0xa,0x34,0x2f,0x6e,0x0,0xae,0x39,0x8c,0xb5,0xe5,0x65,0xce,0x1e,0x28,0x93,0xbb,0x3a,0x3b,0x6,0x63,0x87,0x12,0x40,0x4,0xd6,0x80,0x58,0x62,0x71,0xc1,0x59,0x13,0x1c,0xc3,0xd,0x16,0x9a,0x2b,0x81,0xe8,0xb9,0xcf,0x14,0x54,0x44,0x1,0xde,0x5a,0xc8,0x4f,0x1f,0x3c,0x95,0x6d,0xa7,0x77,0x8a,0xf0,0xdf,0xe3,0xd2,0x22,0x83,0x4e,0x97,0xe0,0x9d,0x15,0x89,0xf8,0xd5,0xa1,0xc7,0x5c,0x29,0xeb,0xc5,0x33,0xf3,0x7c,0xad,0xe4,0xe6,0x45,0xab,0x18,0x74,0xd3,0x5d,0x8b,0xa5,0x94,0xf9,0xbe,0x41,0xed,0x6b,0x8e,0x11,0xd9,0x1b,0x68,0x3d,0x67,0x7c,0x51,0xa8,0x43,0x67,0x81,0xdb,0x2f,0x2,0x24,0xab,0x6c,0x22,0xd3,0x2e,0xb8,0xe4,0x46,0x9f,0x1,0x48,0xf0,0xc9,0x44,0x5e,0x71,0x9e,0x38,0xac,0xc8,0x29,0x37,0x3e,0x84,0x49,0x4e,0xce,0xd4,0xe3,0xc1,0x76,0xe9,0x33,0x88,0x91,0x25,0xf5,0x8d,0xb5,0x4a,0xa9,0x94,0x8b,0xf9,0xdd,0xf1,0x58,0x3,0x60,0xdf,0x3a,0x3c,0xaf,0x32,0xcb,0xa5,0xb7,0x9,0xb,0x19,0x80,0x61,0xda,0x26,0x14,0x85,0xc0,0x35,0x5,0x8,0xfd,0xee,0x52,0xf,0xb2,0xb9,0x4f,0xc,0x9a,0xd2,0xa1,0xa,0x86,0xb6,0xd9,0x0,0x54,0x1f,0x4c,0x5d,0xad,0x87,0x97,0x8e,0x66,0x7a,0x42,0x5a,0xf7,0xe7,0xb3,0xd0,0xde,0xae,0x56,0xc6,0x57,0x6f,0xbc,0x98,0x78,0xf2,0xfc,0x6e,0x8c,0x62,0x92,0x1c,0x90,0xd1,0xca,0xf4,0x72,0xc7,0x50,0xfe,0xf6,0x5c,0x34,0x41,0xcc,0xd8,0x73,0x2a,0x65,0xbd,0x68,0x4,0xa0,0x12,0xb4,0x11,0x4d,0xfb,0x10,0x7b,0x17,0x23,0xcf,0x83,0xe8,0xf3,0x3d,0xe2,0x16,0x7f,0xd5,0x64,0x9c,0xa6,0x7e,0x28,0xed,0xa7,0x3f,0x8f,0x9d,0xf8,0xc5,0xc4,0xfa,0xbe,0xec,0x79,0x30,0x9b,0x1b,0x4b,0x45,0x6d,0xd6,0xe0,0xeb,0x63,0x1e,0x69,0x5f,0x2b,0x6,0x77,0x1d,0x21,0xe,0x74,0xb0,0x7d,0xdc,0x2c,0xc2,0xe1,0xb1,0x36,0x89,0x59,0x93,0x6b,0xaa,0xea,0x31,0x47,0xa4,0x20,0xff,0xba,0x27,0xef,0x70,0x95,0x99,0xc3,0x96,0xe5,0x6a,0x5b,0x75,0xa3,0x13,0xbf,0x40,0x7,0xbb,0x18,0x1a,0x53,0x2d,0x8a,0xe6,0x55,0x15,0xd7,0xa2,0x39,0x82,0xd,0xcd,0x3b,0x34,0x32,0x3a,0xa7,0xb,0x50,0xd7,0x68,0xf1,0x83,0xf9,0xd5,0x42,0xbd,0x9c,0xa1,0x2d,0x99,0x85,0xfd,0xe1,0x7e,0x80,0x3b,0xdc,0xc6,0xc9,0xeb,0x8c,0x36,0x46,0x41,0xc0,0xa4,0x3f,0x21,0x79,0x56,0x30,0x96,0xf8,0x40,0x4c,0xc1,0x4e,0xec,0x9,0x97,0xdb,0x2a,0xb0,0x26,0x2c,0xa,0x64,0xa3,0x89,0x6f,0x27,0xd3,0x59,0x74,0x4b,0xa0,0x6a,0x84,0x14,0x9a,0xfa,0x70,0x66,0xf4,0x67,0x5f,0x90,0xb4,0xa6,0xd6,0xce,0x5e,0xef,0xff,0xd8,0xbb,0x72,0x6e,0x52,0x4a,0x8f,0xa5,0x86,0x9f,0x17,0x5c,0x55,0x44,0xbe,0x8e,0x8,0xd1,0xda,0x92,0x2,0xa9,0xb1,0xba,0x4,0x47,0xe6,0xf5,0x7,0x5a,0x3d,0xc8,0x0,0xd,0x2e,0xd2,0x8d,0x1c,0x11,0x3,0x69,0x88,0xad,0xc3,0x1,0xbf,0x65,0x4d,0xe8,0xde,0x93,0x38,0x43,0x13,0xb6,0xf2,0x71,0xe4,0xf0,0x95,0xcc,0xcd,0xaf,0xe5,0x87,0x37,0xae,0x94,0x20,0x76,0x77,0x1e,0x6c,0xdd,0xfb,0xe0,0xea,0x35,0x2b,0x1f,0x8b,0xc7,0xf3,0x45,0x73,0x18,0x1a,0xa8,0x19,0xbc,0xb5,0x6d,0xc,0x60,0xd0,0xc4,0x22,0x7b,0x54,0xfe,0x49,0x3c,0xcf,0x7a,0xf6,0x58,0xd9,0x98,0xfc,0xc2,0x5,0x8a,0x33,0xc5,0xdf,0x1d,0x31,0xaa,0x82,0x25,0x5d,0xee,0x10,0xb3,0x5b,0x12,0xb7,0x1b,0xf,0x48,0x53,0x62,0xab,0x7d,0xcb,0x91,0xed,0x9e,0xe7,0x2f,0x9d,0x78,0x28,0xac,0xb2,0xf7,0xe2,0xa2,0x4f,0x39,0x51,0x81,0x63,0x9b,0xe9,0xca,0x3e,0xb9,0x75,0xb8,0x24,0xd4,0x29,0x15,0x7c,0x6,0x23,0x57,0x7f,0xe,0x6b,0xe3,0x61,0x16,0xd3,0x14,0x9b,0xbd,0x7,0x91,0x6c,0x9d,0xfc,0x17,0xee,0xc3,0x90,0x64,0x3e,0xd8,0x87,0x21,0xce,0xe1,0x88,0x96,0x77,0x13,0xbe,0x20,0xf9,0x5b,0xfb,0x76,0x4f,0xf7,0x37,0x8c,0x56,0xc9,0x32,0x4a,0x9a,0x2e,0xf1,0xf6,0x3b,0x81,0x7e,0x5c,0x6b,0x71,0x60,0xdf,0xbc,0xe7,0x8d,0x10,0x83,0x85,0x2b,0x16,0xf5,0xa,0x4e,0x62,0x46,0x34,0x3a,0xab,0x99,0x65,0xb7,0xba,0x8a,0x7f,0xb6,0x8,0x1a,0x74,0xde,0x3f,0xa6,0xb4,0xb5,0x1e,0x6d,0x25,0xbf,0x66,0x9,0x39,0xb0,0xed,0x51,0x42,0xb3,0xf0,0x6,0xd,0xe5,0xfd,0xc5,0xd9,0x6f,0xc,0x58,0x48,0xe2,0xf3,0xa0,0xeb,0x31,0x28,0x38,0x12,0xd1,0x43,0x4d,0xc7,0xa3,0x2d,0xdd,0x33,0x79,0xe9,0x11,0x61,0x27,0x3,0xd0,0xe8,0xfe,0x8b,0xe3,0x49,0x95,0xcc,0x67,0x73,0x4b,0x75,0x6e,0x2f,0x41,0xef,0x78,0xcd,0xc4,0xaf,0x44,0xf2,0x3c,0x70,0x9c,0xa8,0xbb,0xd7,0x2,0xda,0xae,0xb,0xad,0x1f,0x97,0xc1,0x19,0x23,0x30,0x80,0x18,0x52,0x5d,0x82,0x4c,0x57,0xdb,0x6a,0xc0,0xa9,0xf4,0xa4,0x24,0x8f,0x5f,0x69,0xd2,0xfa,0x7b,0x7a,0x47,0x22,0xc6,0x53,0x1,0x45,0xcb,0xb1,0x9e,0xa2,0x93,0x63,0xc2,0xf,0xd6,0xa1,0xdc,0x54,0xc8,0xb9,0x94,0xe0,0xf8,0x8e,0x55,0x15,0x5,0x40,0x9f,0x1b,0x89,0xe,0x5e,0x7d,0xd4,0x2c,0xe6,0x36,0x1c,0xca,0xe4,0xd5,0xb8,0xff,0x0,0xac,0x2a,0xcf,0x50,0x98,0x5a,0x29,0x7c,0x26,0x86,0x1d,0x68,0xaa,0x84,0x72,0xb2,0x3d,0xec,0xa5,0xa7,0x4,0xea,0x59,0x35,0x92,0x38,0x9e,0x71,0x5e,0x37,0x29,0xc8,0xac,0x1,0x9f,0x46,0xe4,0x44,0xc9,0xf0,0x48,0x6c,0xab,0x24,0x2,0xb8,0x2e,0xd3,0x22,0x43,0xa8,0x51,0x7c,0x2f,0xdb,0x81,0x67,0xdf,0x60,0x3,0x58,0x32,0xaf,0x3c,0x3a,0x94,0xa9,0x4a,0xb5,0xf1,0xdd,0xf9,0x8b,0x88,0x33,0xe9,0x76,0x8d,0xf5,0x25,0x91,0x4e,0x49,0x84,0x3e,0xc1,0xe3,0xd4,0xce,0xa,0xa1,0xd2,0x9a,0x0,0xd9,0xb6,0x86,0xf,0x52,0xee,0xfd,0xc,0x4f,0xb9,0xb2,0x85,0x14,0x26,0xda,0x8,0x5,0x35,0xc0,0x9,0xb7,0xa5,0xcb,0x61,0x80,0x19,0xb,0x6e,0xfc,0xf2,0x78,0x1c,0x92,0x62,0x8c,0xc6,0x56,0xae,0xde,0x98,0xbc,0x6f,0x57,0x5a,0x42,0x7a,0x66,0xd0,0xb3,0xe7,0xf7,0x5d,0x4c,0x1f,0x54,0x8e,0x97,0x87,0xad,0x7b,0x10,0xfb,0x4d,0x83,0xcf,0x23,0x17,0x4,0x68,0xbd,0x65,0x11,0xb4,0x12,0xa0,0x41,0x34,0x5c,0xf6,0x2a,0x73,0xd8,0xcc,0xf4,0xca,0xd1,0x90,0xfe,0x50,0xc7,0x72,0x4b,0x1b,0x9b,0x30,0xe0,0xd6,0x6d,0x45,0xc4,0xc5,0xf8,0x9d,0x79,0xec,0xbe,0xfa,0x28,0x7e,0xa6,0x9c,0x8f,0x3f,0xa7,0xed,0xe2,0x3d,0xf3,0xe8,0x64,0xd5,0x7f,0x16,0x47,0x31,0xea,0xaa,0xba,0xff,0x20,0xa4,0x36,0xb1,0xe1,0xc2,0x6b,0x93,0x59,0x89,0x74,0xe,0x21,0x1d,0x2c,0xdc,0x7d,0xb0,0x69,0x1e,0x63,0xeb,0x77,0x6,0x2b,0x5f,0x39,0xa2,0xd7,0x15,0x3b,0xcd,0xd,0x82,0x53,0x1a,0x18,0xbb,0x55,0xe6,0x8a,0x2d,0xa3,0x75,0x5b,0x6a,0x7,0x40,0xbf,0x13,0x95,0x70,0xef,0x27,0xe5,0x96,0xc3,0x99,0x99,0xb4,0x4d,0xa6,0x82,0x64,0x3e,0xca,0xe7,0xc1,0x4e,0x89,0xc7,0x36,0xcb,0x5d,0x1,0xa3,0x7a,0xe4,0xad,0x15,0x2c,0xa1,0xbb,0x94,0x7b,0xdd,0x49,0x2d,0xcc,0xd2,0xdb,0x61,0xac,0xab,0x2b,0x31,0x6,0x24,0x93,0xc,0xd6,0x6d,0x74,0xc0,0x10,0x68,0x50,0xaf,0x4c,0x71,0x6e,0x1c,0x38,0x14,0xbd,0xe6,0x85,0x3a,0xdf,0xd9,0x4a,0xd7,0x2e,0x40,0x52,0xec,0xee,0xfc,0x65,0x84,0x3f,0xc3,0xf1,0x60,0x25,0xd0,0xe0,0xed,0x18,0xb,0xb7,0xea,0x57,0x5c,0xaa,0xe9,0x7f,0x37,0x44,0xef,0x63,0x53,0x3c,0xe5,0xb1,0xfa,0xa9,0xb8,0x48,0x62,0x72,0x6b,0x83,0x9f,0xa7,0xbf,0x12,0x2,0x56,0x35,0x3b,0x4b,0xb3,0x23,0xb2,0x8a,0x59,0x7d,0x9d,0x17,0x19,0x8b,0x69,0x87,0x77,0xf9,0x75,0x34,0x2f,0x11,0x97,0x22,0xb5,0x1b,0x13,0xb9,0xd1,0xa4,0x29,0x3d,0x96,0xcf,0x80,0x58,0x8d,0xe1,0x45,0xf7,0x51,0xf4,0xa8,0x1e,0xf5,0x9e,0xf2,0xc6,0x2a,0x66,0xd,0x16,0xd8,0x7,0xf3,0x9a,0x30,0x81,0x79,0x43,0x9b,0xcd,0x8,0x42,0xda,0x6a,0x78,0x1d,0x20,0x21,0x1f,0x5b,0x9,0x9c,0xd5,0x7e,0xfe,0xae,0xa0,0x88,0x33,0x5,0xe,0x86,0xfb,0x8c,0xba,0xce,0xe3,0x92,0xf8,0xc4,0xeb,0x91,0x55,0x98,0x39,0xc9,0x27,0x4,0x54,0xd3,0x6c,0xbc,0x76,0x8e,0x4f,0xf,0xd4,0xa2,0x41,0xc5,0x1a,0x5f,0xc2,0xa,0x95,0x70,0x7c,0x26,0x73,0x0,0x8f,0xbe,0x90,0x46,0xf6,0x5a,0xa5,0xe2,0x5e,0xfd,0xff,0xb6,0xc8,0x6f,0x3,0xb0,0xf0,0x32,0x47,0xdc,0x67,0xe8,0x28,0xde,0xe9,0xef,0xe7,0x7a,0xd6,0x8d,0xa,0xb5,0x2c,0x5e,0x24,0x8,0x9f,0x60,0x41,0x7c,0xf0,0x44,0x58,0x20,0x3c,0xa3,0x5d,0xe6,0x1,0x1b,0x14,0x36,0x51,0xeb,0x9b,0x9c,0x1d,0x79,0xe2,0xfc,0xa4,0x8b,0xed,0x4b,0x25,0x9d,0x91,0x1c,0x93,0x31,0xd4,0x4a,0x6,0xf7,0x6d,0xfb,0xf1,0xd7,0xb9,0x7e,0x54,0xb2,0xfa,0xe,0x84,0xa9,0x96,0x7d,0xb7,0x59,0xc9,0x47,0x27,0xad,0xbb,0x29,0xba,0x82,0x4d,0x69,0x7b,0xb,0x13,0x83,0x32,0x22,0x5,0x66,0xaf,0xb3,0x8f,0x97,0x52,0x78,0x5b,0x42,0xca,0x81,0x88,0x99,0x63,0x53,0xd5,0xc,0x7,0x4f,0xdf,0x74,0x6c,0x67,0xd9,0x9a,0x3b,0x28,0xda,0x87,0xe0,0x15,0xdd,0xd0,0xf3,0xf,0x50,0xc1,0xcc,0xde,0xb4,0x55,0x70,0x1e,0xdc,0x62,0xb8,0x90,0x35,0x3,0x4e,0xe5,0x9e,0xce,0x6b,0x2f,0xac,0x39,0x2d,0x48,0x11,0x10,0x72,0x38,0x5a,0xea,0x73,0x49,0xfd,0xab,0xaa,0xc3,0xb1,0x0,0x26,0x3d,0x37,0xe8,0xf6,0xc2,0x56,0x1a,0x2e,0x98,0xae,0xc5,0xc7,0x75,0xc4,0x61,0x68,0xb0,0xd1,0xbd,0xd,0x19,0xff,0xa6,0x89,0x23,0x94,0xe1,0x12,0xa7,0x2b,0x85,0x4,0x45,0x21,0x1f,0xd8,0x57,0xee,0x18,0x2,0xc0,0xec,0x77,0x5f,0xf8,0x80,0x33,0xcd,0x6e,0x86,0xcf,0x6a,0xc6,0xd2,0x95,0x8e,0xbf,0x76,0xa0,0x16,0x4c,0x30,0x43,0x3a,0xf2,0x40,0xa5,0xf5,0x71,0x6f,0x2a,0x3f,0x7f,0x92,0xe4,0x8c,0x5c,0xbe,0x46,0x34,0x17,0xe3,0x64,0xa8,0x65,0xf9,0x9,0xf4,0xc8,0xa1,0xdb,0xfe,0x8a,0xa2,0xd3,0xb6,0x3e,0xbc,0xcb,0xc3,0x4,0x8b,0xad,0x17,0x81,0x7c,0x8d,0xec,0x7,0xfe,0xd3,0x80,0x74,0x2e,0xc8,0x97,0x31,0xde,0xf1,0x98,0x86,0x67,0x3,0xae,0x30,0xe9,0x4b,0xeb,0x66,0x5f,0xe7,0x27,0x9c,0x46,0xd9,0x22,0x5a,0x8a,0x3e,0xe1,0xe6,0x2b,0x91,0x6e,0x4c,0x7b,0x61,0x70,0xcf,0xac,0xf7,0x9d,0x0,0x93,0x95,0x3b,0x6,0xe5,0x1a,0x5e,0x72,0x56,0x24,0x2a,0xbb,0x89,0x75,0xa7,0xaa,0x9a,0x6f,0xa6,0x18,0xa,0x64,0xce,0x2f,0xb6,0xa4,0xa5,0xe,0x7d,0x35,0xaf,0x76,0x19,0x29,0xa0,0xfd,0x41,0x52,0xa3,0xe0,0x16,0x1d,0xf5,0xed,0xd5,0xc9,0x7f,0x1c,0x48,0x58,0xf2,0xe3,0xb0,0xfb,0x21,0x38,0x28,0x2,0xc1,0x53,0x5d,0xd7,0xb3,0x3d,0xcd,0x23,0x69,0xf9,0x1,0x71,0x37,0x13,0xc0,0xf8,0xee,0x9b,0xf3,0x59,0x85,0xdc,0x77,0x63,0x5b,0x65,0x7e,0x3f,0x51,0xff,0x68,0xdd,0xd4,0xbf,0x54,0xe2,0x2c,0x60,0x8c,0xb8,0xab,0xc7,0x12,0xca,0xbe,0x1b,0xbd,0xf,0x87,0xd1,0x9,0x33,0x20,0x90,0x8,0x42,0x4d,0x92,0x5c,0x47,0xcb,0x7a,0xd0,0xb9,0xe4,0xb4,0x34,0x9f,0x4f,0x79,0xc2,0xea,0x6b,0x6a,0x57,0x32,0xd6,0x43,0x11,0x55,0xdb,0xa1,0x8e,0xb2,0x83,0x73,0xd2,0x1f,0xc6,0xb1,0xcc,0x44,0xd8,0xa9,0x84,0xf0,0xe8,0x9e,0x45,0x5,0x15,0x50,0x8f,0xb,0x99,0x1e,0x4e,0x6d,0xc4,0x3c,0xf6,0x26,0xc,0xda,0xf4,0xc5,0xa8,0xef,0x10,0xbc,0x3a,0xdf,0x40,0x88,0x4a,0x39,0x6c,0x36,0x96,0xd,0x78,0xba,0x94,0x62,0xa2,0x2d,0xfc,0xb5,0xb7,0x14,0xfa,0x49,0x25,0x82,0x59,0xff,0x10,0x3f,0x56,0x48,0xa9,0xcd,0x60,0xfe,0x27,0x85,0x25,0xa8,0x91,0x29,0xd,0xca,0x45,0x63,0xd9,0x4f,0xb2,0x43,0x22,0xc9,0x30,0x1d,0x4e,0xba,0xe0,0x6,0xbe,0x1,0x62,0x39,0x53,0xce,0x5d,0x5b,0xf5,0xc8,0x2b,0xd4,0x90,0xbc,0x98,0xea,0xe9,0x52,0x88,0x17,0xec,0x94,0x44,0xf0,0x2f,0x28,0xe5,0x5f,0xa0,0x82,0xb5,0xaf,0x6b,0xc0,0xb3,0xfb,0x61,0xb8,0xd7,0xe7,0x6e,0x33,0x8f,0x9c,0x6d,0x2e,0xd8,0xd3,0xe4,0x75,0x47,0xbb,0x69,0x64,0x54,0xa1,0x68,0xd6,0xc4,0xaa,0x0,0xe1,0x78,0x6a,0xf,0x9d,0x93,0x19,0x7d,0xf3,0x3,0xed,0xa7,0x37,0xcf,0xbf,0xf9,0xdd,0xe,0x36,0x3b,0x23,0x1b,0x7,0xb1,0xd2,0x86,0x96,0x3c,0x2d,0x7e,0x35,0xef,0xf6,0xe6,0xcc,0x1a,0x71,0x9a,0x2c,0xe2,0xae,0x42,0x76,0x65,0x9,0xdc,0x4,0x70,0xd5,0x73,0xc1,0x20,0x55,0x3d,0x97,0x4b,0x12,0xb9,0xad,0x95,0xab,0xb0,0xf1,0x9f,0x31,0xa6,0x13,0x2a,0x7a,0xfa,0x51,0x81,0xb7,0xc,0x24,0xa5,0xa4,0x99,0xfc,0x18,0x8d,0xdf,0x9b,0x49,0x1f,0xc7,0xfd,0xee,0x5e,0xc6,0x8c,0x83,0x5c,0x92,0x89,0x5,0xb4,0x1e,0x77,0x26,0x50,0x8b,0xcb,0xdb,0x9e,0x41,0xc5,0x57,0xd0,0x80,0xa3,0xa,0xf2,0x38,0xe8,0x15,0x6f,0x40,0x7c,0x4d,0xbd,0x1c,0xd1,0x8,0x7f,0x2,0x8a,0x16,0x67,0x4a,0x3e,0x58,0xc3,0xb6,0x74,0x5a,0xac,0x6c,0xe3,0x32,0x7b,0x79,0xda,0x34,0x87,0xeb,0x4c,0xc2,0x14,0x3a,0xb,0x66,0x21,0xde,0x72,0xf4,0x11,0x8e,0x46,0x84,0xf7,0xa2,0xf8,0x81,0xac,0x55,0xbe,0x9a,0x7c,0x26,0xd2,0xff,0xd9,0x56,0x91,0xdf,0x2e,0xd3,0x45,0x19,0xbb,0x62,0xfc,0xb5,0xd,0x34,0xb9,0xa3,0x8c,0x63,0xc5,0x51,0x35,0xd4,0xca,0xc3,0x79,0xb4,0xb3,0x33,0x29,0x1e,0x3c,0x8b,0x14,0xce,0x75,0x6c,0xd8,0x8,0x70,0x48,0xb7,0x54,0x69,0x76,0x4,0x20,0xc,0xa5,0xfe,0x9d,0x22,0xc7,0xc1,0x52,0xcf,0x36,0x58,0x4a,0xf4,0xf6,0xe4,0x7d,0x9c,0x27,0xdb,0xe9,0x78,0x3d,0xc8,0xf8,0xf5,0x0,0x13,0xaf,0xf2,0x4f,0x44,0xb2,0xf1,0x67,0x2f,0x5c,0xf7,0x7b,0x4b,0x24,0xfd,0xa9,0xe2,0xb1,0xa0,0x50,0x7a,0x6a,0x73,0x9b,0x87,0xbf,0xa7,0xa,0x1a,0x4e,0x2d,0x23,0x53,0xab,0x3b,0xaa,0x92,0x41,0x65,0x85,0xf,0x1,0x93,0x71,0x9f,0x6f,0xe1,0x6d,0x2c,0x37,0x9,0x8f,0x3a,0xad,0x3,0xb,0xa1,0xc9,0xbc,0x31,0x25,0x8e,0xd7,0x98,0x40,0x95,0xf9,0x5d,0xef,0x49,0xec,0xb0,0x6,0xed,0x86,0xea,0xde,0x32,0x7e,0x15,0xe,0xc0,0x1f,0xeb,0x82,0x28,0x99,0x61,0x5b,0x83,0xd5,0x10,0x5a,0xc2,0x72,0x60,0x5,0x38,0x39,0x7,0x43,0x11,0x84,0xcd,0x66,0xe6,0xb6,0xb8,0x90,0x2b,0x1d,0x16,0x9e,0xe3,0x94,0xa2,0xd6,0xfb,0x8a,0xe0,0xdc,0xf3,0x89,0x4d,0x80,0x21,0xd1,0x3f,0x1c,0x4c,0xcb,0x74,0xa4,0x6e,0x96,0x57,0x17,0xcc,0xba,0x59,0xdd,0x2,0x47,0xda,0x12,0x8d,0x68,0x64,0x3e,0x6b,0x18,0x97,0xa6,0x88,0x5e,0xee,0x42,0xbd,0xfa,0x46,0xe5,0xe7,0xae,0xd0,0x77,0x1b,0xa8,0xe8,0x2a,0x5f,0xc4,0x7f,0xf0,0x30,0xc6,0x2e,0x28,0x20,0xbd,0x11,0x4a,0xcd,0x72,0xeb,0x99,0xe3,0xcf,0x58,0xa7,0x86,0xbb,0x37,0x83,0x9f,0xe7,0xfb,0x64,0x9a,0x21,0xc6,0xdc,0xd3,0xf1,0x96,0x2c,0x5c,0x5b,0xda,0xbe,0x25,0x3b,0x63,0x4c,0x2a,0x8c,0xe2,0x5a,0x56,0xdb,0x54,0xf6,0x13,0x8d,0xc1,0x30,0xaa,0x3c,0x36,0x10,0x7e,0xb9,0x93,0x75,0x3d,0xc9,0x43,0x6e,0x51,0xba,0x70,0x9e,0xe,0x80,0xe0,0x6a,0x7c,0xee,0x7d,0x45,0x8a,0xae,0xbc,0xcc,0xd4,0x44,0xf5,0xe5,0xc2,0xa1,0x68,0x74,0x48,0x50,0x95,0xbf,0x9c,0x85,0xd,0x46,0x4f,0x5e,0xa4,0x94,0x12,0xcb,0xc0,0x88,0x18,0xb3,0xab,0xa0,0x1e,0x5d,0xfc,0xef,0x1d,0x40,0x27,0xd2,0x1a,0x17,0x34,0xc8,0x97,0x6,0xb,0x19,0x73,0x92,0xb7,0xd9,0x1b,0xa5,0x7f,0x57,0xf2,0xc4,0x89,0x22,0x59,0x9,0xac,0xe8,0x6b,0xfe,0xea,0x8f,0xd6,0xd7,0xb5,0xff,0x9d,0x2d,0xb4,0x8e,0x3a,0x6c,0x6d,0x4,0x76,0xc7,0xe1,0xfa,0xf0,0x2f,0x31,0x5,0x91,0xdd,0xe9,0x5f,0x69,0x2,0x0,0xb2,0x3,0xa6,0xaf,0x77,0x16,0x7a,0xca,0xde,0x38,0x61,0x4e,0xe4,0x53,0x26,0xd5,0x60,0xec,0x42,0xc3,0x82,0xe6,0xd8,0x1f,0x90,0x29,0xdf,0xc5,0x7,0x2b,0xb0,0x98,0x3f,0x47,0xf4,0xa,0xa9,0x41,0x8,0xad,0x1,0x15,0x52,0x49,0x78,0xb1,0x67,0xd1,0x8b,0xf7,0x84,0xfd,0x35,0x87,0x62,0x32,0xb6,0xa8,0xed,0xf8,0xb8,0x55,0x23,0x4b,0x9b,0x79,0x81,0xf3,0xd0,0x24,0xa3,0x6f,0xa2,0x3e,0xce,0x33,0xf,0x66,0x1c,0x39,0x4d,0x65,0x14,0x71,0xf9,0x7b,0xc,0xf3,0x34,0xbb,0x9d,0x27,0xb1,0x4c,0xbd,0xdc,0x37,0xce,0xe3,0xb0,0x44,0x1e,0xf8,0xa7,0x1,0xee,0xc1,0xa8,0xb6,0x57,0x33,0x9e,0x0,0xd9,0x7b,0xdb,0x56,0x6f,0xd7,0x17,0xac,0x76,0xe9,0x12,0x6a,0xba,0xe,0xd1,0xd6,0x1b,0xa1,0x5e,0x7c,0x4b,0x51,0x40,0xff,0x9c,0xc7,0xad,0x30,0xa3,0xa5,0xb,0x36,0xd5,0x2a,0x6e,0x42,0x66,0x14,0x1a,0x8b,0xb9,0x45,0x97,0x9a,0xaa,0x5f,0x96,0x28,0x3a,0x54,0xfe,0x1f,0x86,0x94,0x95,0x3e,0x4d,0x5,0x9f,0x46,0x29,0x19,0x90,0xcd,0x71,0x62,0x93,0xd0,0x26,0x2d,0xc5,0xdd,0xe5,0xf9,0x4f,0x2c,0x78,0x68,0xc2,0xd3,0x80,0xcb,0x11,0x8,0x18,0x32,0xf1,0x63,0x6d,0xe7,0x83,0xd,0xfd,0x13,0x59,0xc9,0x31,0x41,0x7,0x23,0xf0,0xc8,0xde,0xab,0xc3,0x69,0xb5,0xec,0x47,0x53,0x6b,0x55,0x4e,0xf,0x61,0xcf,0x58,0xed,0xe4,0x8f,0x64,0xd2,0x1c,0x50,0xbc,0x88,0x9b,0xf7,0x22,0xfa,0x8e,0x2b,0x8d,0x3f,0xb7,0xe1,0x39,0x3,0x10,0xa0,0x38,0x72,0x7d,0xa2,0x6c,0x77,0xfb,0x4a,0xe0,0x89,0xd4,0x84,0x4,0xaf,0x7f,0x49,0xf2,0xda,0x5b,0x5a,0x67,0x2,0xe6,0x73,0x21,0x65,0xeb,0x91,0xbe,0x82,0xb3,0x43,0xe2,0x2f,0xf6,0x81,0xfc,0x74,0xe8,0x99,0xb4,0xc0,0xd8,0xae,0x75,0x35,0x25,0x60,0xbf,0x3b,0xa9,0x2e,0x7e,0x5d,0xf4,0xc,0xc6,0x16,0x3c,0xea,0xc4,0xf5,0x98,0xdf,0x20,0x8c,0xa,0xef,0x70,0xb8,0x7a,0x9,0x5c,0x6,0xa6,0x3d,0x48,0x8a,0xa4,0x52,0x92,0x1d,0xcc,0x85,0x87,0x24,0xca,0x79,0x15,0xb2,0xc8,0x6e,0x81,0xae,0xc7,0xd9,0x38,0x5c,0xf1,0x6f,0xb6,0x14,0xb4,0x39,0x0,0xb8,0x9c,0x5b,0xd4,0xf2,0x48,0xde,0x23,0xd2,0xb3,0x58,0xa1,0x8c,0xdf,0x2b,0x71,0x97,0x2f,0x90,0xf3,0xa8,0xc2,0x5f,0xcc,0xca,0x64,0x59,0xba,0x45,0x1,0x2d,0x9,0x7b,0x78,0xc3,0x19,0x86,0x7d,0x5,0xd5,0x61,0xbe,0xb9,0x74,0xce,0x31,0x13,0x24,0x3e,0xfa,0x51,0x22,0x6a,0xf0,0x29,0x46,0x76,0xff,0xa2,0x1e,0xd,0xfc,0xbf,0x49,0x42,0x75,0xe4,0xd6,0x2a,0xf8,0xf5,0xc5,0x30,0xf9,0x47,0x55,0x3b,0x91,0x70,0xe9,0xfb,0x9e,0xc,0x2,0x88,0xec,0x62,0x92,0x7c,0x36,0xa6,0x5e,0x2e,0x68,0x4c,0x9f,0xa7,0xaa,0xb2,0x8a,0x96,0x20,0x43,0x17,0x7,0xad,0xbc,0xef,0xa4,0x7e,0x67,0x77,0x5d,0x8b,0xe0,0xb,0xbd,0x73,0x3f,0xd3,0xe7,0xf4,0x98,0x4d,0x95,0xe1,0x44,0xe2,0x50,0xb1,0xc4,0xac,0x6,0xda,0x83,0x28,0x3c,0x4,0x3a,0x21,0x60,0xe,0xa0,0x37,0x82,0xbb,0xeb,0x6b,0xc0,0x10,0x26,0x9d,0xb5,0x34,0x35,0x8,0x6d,0x89,0x1c,0x4e,0xa,0xd8,0x8e,0x56,0x6c,0x7f,0xcf,0x57,0x1d,0x12,0xcd,0x3,0x18,0x94,0x25,0x8f,0xe6,0xb7,0xc1,0x1a,0x5a,0x4a,0xf,0xd0,0x54,0xc6,0x41,0x11,0x32,0x9b,0x63,0xa9,0x79,0x84,0xfe,0xd1,0xed,0xdc,0x2c,0x8d,0x40,0x99,0xee,0x93,0x1b,0x87,0xf6,0xdb,0xaf,0xc9,0x52,0x27,0xe5,0xcb,0x3d,0xfd,0x72,0xa3,0xea,0xe8,0x4b,0xa5,0x16,0x7a,0xdd,0x53,0x85,0xab,0x9a,0xf7,0xb0,0x4f,0xe3,0x65,0x80,0x1f,0xd7,0x15,0x66,0x33,0x69,0x2d,0x0,0xf9,0x12,0x36,0xd0,0x8a,0x7e,0x53,0x75,0xfa,0x3d,0x73,0x82,0x7f,0xe9,0xb5,0x17,0xce,0x50,0x19,0xa1,0x98,0x15,0xf,0x20,0xcf,0x69,0xfd,0x99,0x78,0x66,0x6f,0xd5,0x18,0x1f,0x9f,0x85,0xb2,0x90,0x27,0xb8,0x62,0xd9,0xc0,0x74,0xa4,0xdc,0xe4,0x1b,0xf8,0xc5,0xda,0xa8,0x8c,0xa0,0x9,0x52,0x31,0x8e,0x6b,0x6d,0xfe,0x63,0x9a,0xf4,0xe6,0x58,0x5a,0x48,0xd1,0x30,0x8b,0x77,0x45,0xd4,0x91,0x64,0x54,0x59,0xac,0xbf,0x3,0x5e,0xe3,0xe8,0x1e,0x5d,0xcb,0x83,0xf0,0x5b,0xd7,0xe7,0x88,0x51,0x5,0x4e,0x1d,0xc,0xfc,0xd6,0xc6,0xdf,0x37,0x2b,0x13,0xb,0xa6,0xb6,0xe2,0x81,0x8f,0xff,0x7,0x97,0x6,0x3e,0xed,0xc9,0x29,0xa3,0xad,0x3f,0xdd,0x33,0xc3,0x4d,0xc1,0x80,0x9b,0xa5,0x23,0x96,0x1,0xaf,0xa7,0xd,0x65,0x10,0x9d,0x89,0x22,0x7b,0x34,0xec,0x39,0x55,0xf1,0x43,0xe5,0x40,0x1c,0xaa,0x41,0x2a,0x46,0x72,0x9e,0xd2,0xb9,0xa2,0x6c,0xb3,0x47,0x2e,0x84,0x35,0xcd,0xf7,0x2f,0x79,0xbc,0xf6,0x6e,0xde,0xcc,0xa9,0x94,0x95,0xab,0xef,0xbd,0x28,0x61,0xca,0x4a,0x1a,0x14,0x3c,0x87,0xb1,0xba,0x32,0x4f,0x38,0xe,0x7a,0x57,0x26,0x4c,0x70,0x5f,0x25,0xe1,0x2c,0x8d,0x7d,0x93,0xb0,0xe0,0x67,0xd8,0x8,0xc2,0x3a,0xfb,0xbb,0x60,0x16,0xf5,0x71,0xae,0xeb,0x76,0xbe,0x21,0xc4,0xc8,0x92,0xc7,0xb4,0x3b,0xa,0x24,0xf2,0x42,0xee,0x11,0x56,0xea,0x49,0x4b,0x2,0x7c,0xdb,0xb7,0x4,0x44,0x86,0xf3,0x68,0xd3,0x5c,0x9c,0x6a,0x43,0x45,0x4d,0xd0,0x7c,0x27,0xa0,0x1f,0x86,0xf4,0x8e,0xa2,0x35,0xca,0xeb,0xd6,0x5a,0xee,0xf2,0x8a,0x96,0x9,0xf7,0x4c,0xab,0xb1,0xbe,0x9c,0xfb,0x41,0x31,0x36,0xb7,0xd3,0x48,0x56,0xe,0x21,0x47,0xe1,0x8f,0x37,0x3b,0xb6,0x39,0x9b,0x7e,0xe0,0xac,0x5d,0xc7,0x51,0x5b,0x7d,0x13,0xd4,0xfe,0x18,0x50,0xa4,0x2e,0x3,0x3c,0xd7,0x1d,0xf3,0x63,0xed,0x8d,0x7,0x11,0x83,0x10,0x28,0xe7,0xc3,0xd1,0xa1,0xb9,0x29,0x98,0x88,0xaf,0xcc,0x5,0x19,0x25,0x3d,0xf8,0xd2,0xf1,0xe8,0x60,0x2b,0x22,0x33,0xc9,0xf9,0x7f,0xa6,0xad,0xe5,0x75,0xde,0xc6,0xcd,0x73,0x30,0x91,0x82,0x70,0x2d,0x4a,0xbf,0x77,0x7a,0x59,0xa5,0xfa,0x6b,0x66,0x74,0x1e,0xff,0xda,0xb4,0x76,0xc8,0x12,0x3a,0x9f,0xa9,0xe4,0x4f,0x34,0x64,0xc1,0x85,0x6,0x93,0x87,0xe2,0xbb,0xba,0xd8,0x92,0xf0,0x40,0xd9,0xe3,0x57,0x1,0x0,0x69,0x1b,0xaa,0x8c,0x97,0x9d,0x42,0x5c,0x68,0xfc,0xb0,0x84,0x32,0x4,0x6f,0x6d,0xdf,0x6e,0xcb,0xc2,0x1a,0x7b,0x17,0xa7,0xb3,0x55,0xc,0x23,0x89,0x3e,0x4b,0xb8,0xd,0x81,0x2f,0xae,0xef,0x8b,0xb5,0x72,0xfd,0x44,0xb2,0xa8,0x6a,0x46,0xdd,0xf5,0x52,0x2a,0x99,0x67,0xc4,0x2c,0x65,0xc0,0x6c,0x78,0x3f,0x24,0x15,0xdc,0xa,0xbc,0xe6,0x9a,0xe9,0x90,0x58,0xea,0xf,0x5f,0xdb,0xc5,0x80,0x95,0xd5,0x38,0x4e,0x26,0xf6,0x14,0xec,0x9e,0xbd,0x49,0xce,0x2,0xcf,0x53,0xa3,0x5e,0x62,0xb,0x71,0x54,0x20,0x8,0x79,0x1c,0x94,0x16,0x61,0xc4,0x3,0x8c,0xaa,0x10,0x86,0x7b,0x8a,0xeb,0x0,0xf9,0xd4,0x87,0x73,0x29,0xcf,0x90,0x36,0xd9,0xf6,0x9f,0x81,0x60,0x4,0xa9,0x37,0xee,0x4c,0xec,0x61,0x58,0xe0,0x20,0x9b,0x41,0xde,0x25,0x5d,0x8d,0x39,0xe6,0xe1,0x2c,0x96,0x69,0x4b,0x7c,0x66,0x77,0xc8,0xab,0xf0,0x9a,0x7,0x94,0x92,0x3c,0x1,0xe2,0x1d,0x59,0x75,0x51,0x23,0x2d,0xbc,0x8e,0x72,0xa0,0xad,0x9d,0x68,0xa1,0x1f,0xd,0x63,0xc9,0x28,0xb1,0xa3,0xa2,0x9,0x7a,0x32,0xa8,0x71,0x1e,0x2e,0xa7,0xfa,0x46,0x55,0xa4,0xe7,0x11,0x1a,0xf2,0xea,0xd2,0xce,0x78,0x1b,0x4f,0x5f,0xf5,0xe4,0xb7,0xfc,0x26,0x3f,0x2f,0x5,0xc6,0x54,0x5a,0xd0,0xb4,0x3a,0xca,0x24,0x6e,0xfe,0x6,0x76,0x30,0x14,0xc7,0xff,0xe9,0x9c,0xf4,0x5e,0x82,0xdb,0x70,0x64,0x5c,0x62,0x79,0x38,0x56,0xf8,0x6f,0xda,0xd3,0xb8,0x53,0xe5,0x2b,0x67,0x8b,0xbf,0xac,0xc0,0x15,0xcd,0xb9,0x1c,0xba,0x8,0x80,0xd6,0xe,0x34,0x27,0x97,0xf,0x45,0x4a,0x95,0x5b,0x40,0xcc,0x7d,0xd7,0xbe,0xe3,0xb3,0x33,0x98,0x48,0x7e,0xc5,0xed,0x6c,0x6d,0x50,0x35,0xd1,0x44,0x16,0x52,0xdc,0xa6,0x89,0xb5,0x84,0x74,0xd5,0x18,0xc1,0xb6,0xcb,0x43,0xdf,0xae,0x83,0xf7,0xef,0x99,0x42,0x2,0x12,0x57,0x88,0xc,0x9e,0x19,0x49,0x6a,0xc3,0x3b,0xf1,0x21,0xb,0xdd,0xf3,0xc2,0xaf,0xe8,0x17,0xbb,0x3d,0xd8,0x47,0x8f,0x4d,0x3e,0x6b,0x31,0x91,0xa,0x7f,0xbd,0x93,0x65,0xa5,0x2a,0xfb,0xb2,0xb0,0x13,0xfd,0x4e,0x22,0x85,0x45,0xe3,0xc,0x23,0x4a,0x54,0xb5,0xd1,0x7c,0xe2,0x3b,0x99,0x39,0xb4,0x8d,0x35,0x11,0xd6,0x59,0x7f,0xc5,0x53,0xae,0x5f,0x3e,0xd5,0x2c,0x1,0x52,0xa6,0xfc,0x1a,0xa2,0x1d,0x7e,0x25,0x4f,0xd2,0x41,0x47,0xe9,0xd4,0x37,0xc8,0x8c,0xa0,0x84,0xf6,0xf5,0x4e,0x94,0xb,0xf0,0x88,0x58,0xec,0x33,0x34,0xf9,0x43,0xbc,0x9e,0xa9,0xb3,0x77,0xdc,0xaf,0xe7,0x7d,0xa4,0xcb,0xfb,0x72,0x2f,0x93,0x80,0x71,0x32,0xc4,0xcf,0xf8,0x69,0x5b,0xa7,0x75,0x78,0x48,0xbd,0x74,0xca,0xd8,0xb6,0x1c,0xfd,0x64,0x76,0x13,0x81,0x8f,0x5,0x61,0xef,0x1f,0xf1,0xbb,0x2b,0xd3,0xa3,0xe5,0xc1,0x12,0x2a,0x27,0x3f,0x7,0x1b,0xad,0xce,0x9a,0x8a,0x20,0x31,0x62,0x29,0xf3,0xea,0xfa,0xd0,0x6,0x6d,0x86,0x30,0xfe,0xb2,0x5e,0x6a,0x79,0x15,0xc0,0x18,0x6c,0xc9,0x6f,0xdd,0x3c,0x49,0x21,0x8b,0x57,0xe,0xa5,0xb1,0x89,0xb7,0xac,0xed,0x83,0x2d,0xba,0xf,0x36,0x66,0xe6,0x4d,0x9d,0xab,0x10,0x38,0xb9,0xb8,0x85,0xe0,0x4,0x91,0xc3,0x87,0x55,0x3,0xdb,0xe1,0xf2,0x42,0xda,0x90,0x9f,0x40,0x8e,0x95,0x19,0xa8,0x2,0x6b,0x3a,0x4c,0x97,0xd7,0xc7,0x82,0x5d,0xd9,0x4b,0xcc,0x9c,0xbf,0x16,0xee,0x24,0xf4,0x9,0x73,0x5c,0x60,0x51,0xa1,0x0,0xcd,0x14,0x63,0x1e,0x96,0xa,0x7b,0x56,0x22,0x44,0xdf,0xaa,0x68,0x46,0xb0,0x70,0xff,0x2e,0x67,0x65,0xc6,0x28,0x9b,0xf7,0x50,0xde,0x8,0x26,0x17,0x7a,0x3d,0xc2,0x6e,0xe8,0xd,0x92,0x5a,0x98,0xeb,0xbe,0xe4,0x93,0xbe,0x47,0xac,0x88,0x6e,0x34,0xc0,0xed,0xcb,0x44,0x83,0xcd,0x3c,0xc1,0x57,0xb,0xa9,0x70,0xee,0xa7,0x1f,0x26,0xab,0xb1,0x9e,0x71,0xd7,0x43,0x27,0xc6,0xd8,0xd1,0x6b,0xa6,0xa1,0x21,0x3b,0xc,0x2e,0x99,0x6,0xdc,0x67,0x7e,0xca,0x1a,0x62,0x5a,0xa5,0x46,0x7b,0x64,0x16,0x32,0x1e,0xb7,0xec,0x8f,0x30,0xd5,0xd3,0x40,0xdd,0x24,0x4a,0x58,0xe6,0xe4,0xf6,0x6f,0x8e,0x35,0xc9,0xfb,0x6a,0x2f,0xda,0xea,0xe7,0x12,0x1,0xbd,0xe0,0x5d,0x56,0xa0,0xe3,0x75,0x3d,0x4e,0xe5,0x69,0x59,0x36,0xef,0xbb,0xf0,0xa3,0xb2,0x42,0x68,0x78,0x61,0x89,0x95,0xad,0xb5,0x18,0x8,0x5c,0x3f,0x31,0x41,0xb9,0x29,0xb8,0x80,0x53,0x77,0x97,0x1d,0x13,0x81,0x63,0x8d,0x7d,0xf3,0x7f,0x3e,0x25,0x1b,0x9d,0x28,0xbf,0x11,0x19,0xb3,0xdb,0xae,0x23,0x37,0x9c,0xc5,0x8a,0x52,0x87,0xeb,0x4f,0xfd,0x5b,0xfe,0xa2,0x14,0xff,0x94,0xf8,0xcc,0x20,0x6c,0x7,0x1c,0xd2,0xd,0xf9,0x90,0x3a,0x8b,0x73,0x49,0x91,0xc7,0x2,0x48,0xd0,0x60,0x72,0x17,0x2a,0x2b,0x15,0x51,0x3,0x96,0xdf,0x74,0xf4,0xa4,0xaa,0x82,0x39,0xf,0x4,0x8c,0xf1,0x86,0xb0,0xc4,0xe9,0x98,0xf2,0xce,0xe1,0x9b,0x5f,0x92,0x33,0xc3,0x2d,0xe,0x5e,0xd9,0x66,0xb6,0x7c,0x84,0x45,0x5,0xde,0xa8,0x4b,0xcf,0x10,0x55,0xc8,0x0,0x9f,0x7a,0x76,0x2c,0x79,0xa,0x85,0xb4,0x9a,0x4c,0xfc,0x50,0xaf,0xe8,0x54,0xf7,0xf5,0xbc,0xc2,0x65,0x9,0xba,0xfa,0x38,0x4d,0xd6,0x6d,0xe2,0x22,0xd4,0x52,0x54,0x5c,0xc1,0x6d,0x36,0xb1,0xe,0x97,0xe5,0x9f,0xb3,0x24,0xdb,0xfa,0xc7,0x4b,0xff,0xe3,0x9b,0x87,0x18,0xe6,0x5d,0xba,0xa0,0xaf,0x8d,0xea,0x50,0x20,0x27,0xa6,0xc2,0x59,0x47,0x1f,0x30,0x56,0xf0,0x9e,0x26,0x2a,0xa7,0x28,0x8a,0x6f,0xf1,0xbd,0x4c,0xd6,0x40,0x4a,0x6c,0x2,0xc5,0xef,0x9,0x41,0xb5,0x3f,0x12,0x2d,0xc6,0xc,0xe2,0x72,0xfc,0x9c,0x16,0x0,0x92,0x1,0x39,0xf6,0xd2,0xc0,0xb0,0xa8,0x38,0x89,0x99,0xbe,0xdd,0x14,0x8,0x34,0x2c,0xe9,0xc3,0xe0,0xf9,0x71,0x3a,0x33,0x22,0xd8,0xe8,0x6e,0xb7,0xbc,0xf4,0x64,0xcf,0xd7,0xdc,0x62,0x21,0x80,0x93,0x61,0x3c,0x5b,0xae,0x66,0x6b,0x48,0xb4,0xeb,0x7a,0x77,0x65,0xf,0xee,0xcb,0xa5,0x67,0xd9,0x3,0x2b,0x8e,0xb8,0xf5,0x5e,0x25,0x75,0xd0,0x94,0x17,0x82,0x96,0xf3,0xaa,0xab,0xc9,0x83,0xe1,0x51,0xc8,0xf2,0x46,0x10,0x11,0x78,0xa,0xbb,0x9d,0x86,0x8c,0x53,0x4d,0x79,0xed,0xa1,0x95,0x23,0x15,0x7e,0x7c,0xce,0x7f,0xda,0xd3,0xb,0x6a,0x6,0xb6,0xa2,0x44,0x1d,0x32,0x98,0x2f,0x5a,0xa9,0x1c,0x90,0x3e,0xbf,0xfe,0x9a,0xa4,0x63,0xec,0x55,0xa3,0xb9,0x7b,0x57,0xcc,0xe4,0x43,0x3b,0x88,0x76,0xd5,0x3d,0x74,0xd1,0x7d,0x69,0x2e,0x35,0x4,0xcd,0x1b,0xad,0xf7,0x8b,0xf8,0x81,0x49,0xfb,0x1e,0x4e,0xca,0xd4,0x91,0x84,0xc4,0x29,0x5f,0x37,0xe7,0x5,0xfd,0x8f,0xac,0x58,0xdf,0x13,0xde,0x42,0xb2,0x4f,0x73,0x1a,0x60,0x45,0x31,0x19,0x68,0xd,0x85,0x7,0x70,0x76,0xb1,0x3e,0x18,0xa2,0x34,0xc9,0x38,0x59,0xb2,0x4b,0x66,0x35,0xc1,0x9b,0x7d,0x22,0x84,0x6b,0x44,0x2d,0x33,0xd2,0xb6,0x1b,0x85,0x5c,0xfe,0x5e,0xd3,0xea,0x52,0x92,0x29,0xf3,0x6c,0x97,0xef,0x3f,0x8b,0x54,0x53,0x9e,0x24,0xdb,0xf9,0xce,0xd4,0xc5,0x7a,0x19,0x42,0x28,0xb5,0x26,0x20,0x8e,0xb3,0x50,0xaf,0xeb,0xc7,0xe3,0x91,0x9f,0xe,0x3c,0xc0,0x12,0x1f,0x2f,0xda,0x13,0xad,0xbf,0xd1,0x7b,0x9a,0x3,0x11,0x10,0xbb,0xc8,0x80,0x1a,0xc3,0xac,0x9c,0x15,0x48,0xf4,0xe7,0x16,0x55,0xa3,0xa8,0x40,0x58,0x60,0x7c,0xca,0xa9,0xfd,0xed,0x47,0x56,0x5,0x4e,0x94,0x8d,0x9d,0xb7,0x74,0xe6,0xe8,0x62,0x6,0x88,0x78,0x96,0xdc,0x4c,0xb4,0xc4,0x82,0xa6,0x75,0x4d,0x5b,0x2e,0x46,0xec,0x30,0x69,0xc2,0xd6,0xee,0xd0,0xcb,0x8a,0xe4,0x4a,0xdd,0x68,0x61,0xa,0xe1,0x57,0x99,0xd5,0x39,0xd,0x1e,0x72,0xa7,0x7f,0xb,0xae,0x8,0xba,0x32,0x64,0xbc,0x86,0x95,0x25,0xbd,0xf7,0xf8,0x27,0xe9,0xf2,0x7e,0xcf,0x65,0xc,0x51,0x1,0x81,0x2a,0xfa,0xcc,0x77,0x5f,0xde,0xdf,0xe2,0x87,0x63,0xf6,0xa4,0xe0,0x6e,0x14,0x3b,0x7,0x36,0xc6,0x67,0xaa,0x73,0x4,0x79,0xf1,0x6d,0x1c,0x31,0x45,0x5d,0x2b,0xf0,0xb0,0xa0,0xe5,0x3a,0xbe,0x2c,0xab,0xfb,0xd8,0x71,0x89,0x43,0x93,0xb9,0x6f,0x41,0x70,0x1d,0x5a,0xa5,0x9,0x8f,0x6a,0xf5,0x3d,0xff,0x8c,0xd9,0x83,0x23,0xb8,0xcd,0xf,0x21,0xd7,0x17,0x98,0x49,0x0,0x2,0xa1,0x4f,0xfc,0x90,0x37,0x86,0x20,0xcf,0xe0,0x89,0x97,0x76,0x12,0xbf,0x21,0xf8,0x5a,0xfa,0x77,0x4e,0xf6,0xd2,0x15,0x9a,0xbc,0x6,0x90,0x6d,0x9c,0xfd,0x16,0xef,0xc2,0x91,0x65,0x3f,0xd9,0x61,0xde,0xbd,0xe6,0x8c,0x11,0x82,0x84,0x2a,0x17,0xf4,0xb,0x4f,0x63,0x47,0x35,0x36,0x8d,0x57,0xc8,0x33,0x4b,0x9b,0x2f,0xf0,0xf7,0x3a,0x80,0x7f,0x5d,0x6a,0x70,0xb4,0x1f,0x6c,0x24,0xbe,0x67,0x8,0x38,0xb1,0xec,0x50,0x43,0xb2,0xf1,0x7,0xc,0x3b,0xaa,0x98,0x64,0xb6,0xbb,0x8b,0x7e,0xb7,0x9,0x1b,0x75,0xdf,0x3e,0xa7,0xb5,0xd0,0x42,0x4c,0xc6,0xa2,0x2c,0xdc,0x32,0x78,0xe8,0x10,0x60,0x26,0x2,0xd1,0xe9,0xe4,0xfc,0xc4,0xd8,0x6e,0xd,0x59,0x49,0xe3,0xf2,0xa1,0xea,0x30,0x29,0x39,0x13,0xc5,0xae,0x45,0xf3,0x3d,0x71,0x9d,0xa9,0xba,0xd6,0x3,0xdb,0xaf,0xa,0xac,0x1e,0xff,0x8a,0xe2,0x48,0x94,0xcd,0x66,0x72,0x4a,0x74,0x6f,0x2e,0x40,0xee,0x79,0xcc,0xf5,0xa5,0x25,0x8e,0x5e,0x68,0xd3,0xfb,0x7a,0x7b,0x46,0x23,0xc7,0x52,0x0,0x44,0x96,0xc0,0x18,0x22,0x31,0x81,0x19,0x53,0x5c,0x83,0x4d,0x56,0xda,0x6b,0xc1,0xa8,0xf9,0x8f,0x54,0x14,0x4,0x41,0x9e,0x1a,0x88,0xf,0x5f,0x7c,0xd5,0x2d,0xe7,0x37,0xca,0xb0,0x9f,0xa3,0x92,0x62,0xc3,0xe,0xd7,0xa0,0xdd,0x55,0xc9,0xb8,0x95,0xe1,0x87,0x1c,0x69,0xab,0x85,0x73,0xb3,0x3c,0xed,0xa4,0xa6,0x5,0xeb,0x58,0x34,0x93,0x1d,0xcb,0xe5,0xd4,0xb9,0xfe,0x1,0xad,0x2b,0xce,0x51,0x99,0x5b,0x28,0x7d,0x27,0x6e,0x43,0xba,0x51,0x75,0x93,0xc9,0x3d,0x10,0x36,0xb9,0x7e,0x30,0xc1,0x3c,0xaa,0xf6,0x54,0x8d,0x13,0x5a,0xe2,0xdb,0x56,0x4c,0x63,0x8c,0x2a,0xbe,0xda,0x3b,0x25,0x2c,0x96,0x5b,0x5c,0xdc,0xc6,0xf1,0xd3,0x64,0xfb,0x21,0x9a,0x83,0x37,0xe7,0x9f,0xa7,0x58,0xbb,0x86,0x99,0xeb,0xcf,0xe3,0x4a,0x11,0x72,0xcd,0x28,0x2e,0xbd,0x20,0xd9,0xb7,0xa5,0x1b,0x19,0xb,0x92,0x73,0xc8,0x34,0x6,0x97,0xd2,0x27,0x17,0x1a,0xef,0xfc,0x40,0x1d,0xa0,0xab,0x5d,0x1e,0x88,0xc0,0xb3,0x18,0x94,0xa4,0xcb,0x12,0x46,0xd,0x5e,0x4f,0xbf,0x95,0x85,0x9c,0x74,0x68,0x50,0x48,0xe5,0xf5,0xa1,0xc2,0xcc,0xbc,0x44,0xd4,0x45,0x7d,0xae,0x8a,0x6a,0xe0,0xee,0x7c,0x9e,0x70,0x80,0xe,0x82,0xc3,0xd8,0xe6,0x60,0xd5,0x42,0xec,0xe4,0x4e,0x26,0x53,0xde,0xca,0x61,0x38,0x77,0xaf,0x7a,0x16,0xb2,0x0,0xa6,0x3,0x5f,0xe9,0x2,0x69,0x5,0x31,0xdd,0x91,0xfa,0xe1,0x2f,0xf0,0x4,0x6d,0xc7,0x76,0x8e,0xb4,0x6c,0x3a,0xff,0xb5,0x2d,0x9d,0x8f,0xea,0xd7,0xd6,0xe8,0xac,0xfe,0x6b,0x22,0x89,0x9,0x59,0x57,0x7f,0xc4,0xf2,0xf9,0x71,0xc,0x7b,0x4d,0x39,0x14,0x65,0xf,0x33,0x1c,0x66,0xa2,0x6f,0xce,0x3e,0xd0,0xf3,0xa3,0x24,0x9b,0x4b,0x81,0x79,0xb8,0xf8,0x23,0x55,0xb6,0x32,0xed,0xa8,0x35,0xfd,0x62,0x87,0x8b,0xd1,0x84,0xf7,0x78,0x49,0x67,0xb1,0x1,0xad,0x52,0x15,0xa9,0xa,0x8,0x41,0x3f,0x98,0xf4,0x47,0x7,0xc5,0xb0,0x2b,0x90,0x1f,0xdf,0x29,0x95,0x93,0x9b,0x6,0xaa,0xf1,0x76,0xc9,0x50,0x22,0x58,0x74,0xe3,0x1c,0x3d,0x0,0x8c,0x38,0x24,0x5c,0x40,0xdf,0x21,0x9a,0x7d,0x67,0x68,0x4a,0x2d,0x97,0xe7,0xe0,0x61,0x5,0x9e,0x80,0xd8,0xf7,0x91,0x37,0x59,0xe1,0xed,0x60,0xef,0x4d,0xa8,0x36,0x7a,0x8b,0x11,0x87,0x8d,0xab,0xc5,0x2,0x28,0xce,0x86,0x72,0xf8,0xd5,0xea,0x1,0xcb,0x25,0xb5,0x3b,0x5b,0xd1,0xc7,0x55,0xc6,0xfe,0x31,0x15,0x7,0x77,0x6f,0xff,0x4e,0x5e,0x79,0x1a,0xd3,0xcf,0xf3,0xeb,0x2e,0x4,0x27,0x3e,0xb6,0xfd,0xf4,0xe5,0x1f,0x2f,0xa9,0x70,0x7b,0x33,0xa3,0x8,0x10,0x1b,0xa5,0xe6,0x47,0x54,0xa6,0xfb,0x9c,0x69,0xa1,0xac,0x8f,0x73,0x2c,0xbd,0xb0,0xa2,0xc8,0x29,0xc,0x62,0xa0,0x1e,0xc4,0xec,0x49,0x7f,0x32,0x99,0xe2,0xb2,0x17,0x53,0xd0,0x45,0x51,0x34,0x6d,0x6c,0xe,0x44,0x26,0x96,0xf,0x35,0x81,0xd7,0xd6,0xbf,0xcd,0x7c,0x5a,0x41,0x4b,0x94,0x8a,0xbe,0x2a,0x66,0x52,0xe4,0xd2,0xb9,0xbb,0x9,0xb8,0x1d,0x14,0xcc,0xad,0xc1,0x71,0x65,0x83,0xda,0xf5,0x5f,0xe8,0x9d,0x6e,0xdb,0x57,0xf9,0x78,0x39,0x5d,0x63,0xa4,0x2b,0x92,0x64,0x7e,0xbc,0x90,0xb,0x23,0x84,0xfc,0x4f,0xb1,0x12,0xfa,0xb3,0x16,0xba,0xae,0xe9,0xf2,0xc3,0xa,0xdc,0x6a,0x30,0x4c,0x3f,0x46,0x8e,0x3c,0xd9,0x89,0xd,0x13,0x56,0x43,0x3,0xee,0x98,0xf0,0x20,0xc2,0x3a,0x48,0x6b,0x9f,0x18,0xd4,0x19,0x85,0x75,0x88,0xb4,0xdd,0xa7,0x82,0xf6,0xde,0xaf,0xca,0x42,0xc0,0xb7,0x56,0x91,0x1e,0x38,0x82,0x14,0xe9,0x18,0x79,0x92,0x6b,0x46,0x15,0xe1,0xbb,0x5d,0x2,0xa4,0x4b,0x64,0xd,0x13,0xf2,0x96,0x3b,0xa5,0x7c,0xde,0x7e,0xf3,0xca,0x72,0xb2,0x9,0xd3,0x4c,0xb7,0xcf,0x1f,0xab,0x74,0x73,0xbe,0x4,0xfb,0xd9,0xee,0xf4,0xe5,0x5a,0x39,0x62,0x8,0x95,0x6,0x0,0xae,0x93,0x70,0x8f,0xcb,0xe7,0xc3,0xb1,0xbf,0x2e,0x1c,0xe0,0x32,0x3f,0xf,0xfa,0x33,0x8d,0x9f,0xf1,0x5b,0xba,0x23,0x31,0x30,0x9b,0xe8,0xa0,0x3a,0xe3,0x8c,0xbc,0x35,0x68,0xd4,0xc7,0x36,0x75,0x83,0x88,0x60,0x78,0x40,0x5c,0xea,0x89,0xdd,0xcd,0x67,0x76,0x25,0x6e,0xb4,0xad,0xbd,0x97,0x54,0xc6,0xc8,0x42,0x26,0xa8,0x58,0xb6,0xfc,0x6c,0x94,0xe4,0xa2,0x86,0x55,0x6d,0x7b,0xe,0x66,0xcc,0x10,0x49,0xe2,0xf6,0xce,0xf0,0xeb,0xaa,0xc4,0x6a,0xfd,0x48,0x41,0x2a,0xc1,0x77,0xb9,0xf5,0x19,0x2d,0x3e,0x52,0x87,0x5f,0x2b,0x8e,0x28,0x9a,0x12,0x44,0x9c,0xa6,0xb5,0x5,0x9d,0xd7,0xd8,0x7,0xc9,0xd2,0x5e,0xef,0x45,0x2c,0x71,0x21,0xa1,0xa,0xda,0xec,0x57,0x7f,0xfe,0xff,0xc2,0xa7,0x43,0xd6,0x84,0xc0,0x4e,0x34,0x1b,0x27,0x16,0xe6,0x47,0x8a,0x53,0x24,0x59,0xd1,0x4d,0x3c,0x11,0x65,0x7d,0xb,0xd0,0x90,0x80,0xc5,0x1a,0x9e,0xc,0x8b,0xdb,0xf8,0x51,0xa9,0x63,0xb3,0x99,0x4f,0x61,0x50,0x3d,0x7a,0x85,0x29,0xaf,0x4a,0xd5,0x1d,0xdf,0xac,0xf9,0xa3,0x3,0x98,0xed,0x2f,0x1,0xf7,0x37,0xb8,0x69,0x20,0x22,0x81,0x6f,0xdc,0xb0,0x17,0x3a,0x9c,0x73,0x5c,0x35,0x2b,0xca,0xae,0x3,0x9d,0x44,0xe6,0x46,0xcb,0xf2,0x4a,0x6e,0xa9,0x26,0x0,0xba,0x2c,0xd1,0x20,0x41,0xaa,0x53,0x7e,0x2d,0xd9,0x83,0x65,0xdd,0x62,0x1,0x5a,0x30,0xad,0x3e,0x38,0x96,0xab,0x48,0xb7,0xf3,0xdf,0xfb,0x89,0x8a,0x31,0xeb,0x74,0x8f,0xf7,0x27,0x93,0x4c,0x4b,0x86,0x3c,0xc3,0xe1,0xd6,0xcc,0x8,0xa3,0xd0,0x98,0x2,0xdb,0xb4,0x84,0xd,0x50,0xec,0xff,0xe,0x4d,0xbb,0xb0,0x87,0x16,0x24,0xd8,0xa,0x7,0x37,0xc2,0xb,0xb5,0xa7,0xc9,0x63,0x82,0x1b,0x9,0x6c,0xfe,0xf0,0x7a,0x1e,0x90,0x60,0x8e,0xc4,0x54,0xac,0xdc,0x9a,0xbe,0x6d,0x55,0x58,0x40,0x78,0x64,0xd2,0xb1,0xe5,0xf5,0x5f,0x4e,0x1d,0x56,0x8c,0x95,0x85,0xaf,0x79,0x12,0xf9,0x4f,0x81,0xcd,0x21,0x15,0x6,0x6a,0xbf,0x67,0x13,0xb6,0x10,0xa2,0x43,0x36,0x5e,0xf4,0x28,0x71,0xda,0xce,0xf6,0xc8,0xd3,0x92,0xfc,0x52,0xc5,0x70,0x49,0x19,0x99,0x32,0xe2,0xd4,0x6f,0x47,0xc6,0xc7,0xfa,0x9f,0x7b,0xee,0xbc,0xf8,0x2a,0x7c,0xa4,0x9e,0x8d,0x3d,0xa5,0xef,0xe0,0x3f,0xf1,0xea,0x66,0xd7,0x7d,0x14,0x45,0x33,0xe8,0xa8,0xb8,0xfd,0x22,0xa6,0x34,0xb3,0xe3,0xc0,0x69,0x91,0x5b,0x8b,0x76,0xc,0x23,0x1f,0x2e,0xde,0x7f,0xb2,0x6b,0x1c,0x61,0xe9,0x75,0x4,0x29,0x5d,0x3b,0xa0,0xd5,0x17,0x39,0xcf,0xf,0x80,0x51,0x18,0x1a,0xb9,0x57,0xe4,0x88,0x2f,0xa1,0x77,0x59,0x68,0x5,0x42,0xbd,0x11,0x97,0x72,0xed,0x25,0xe7,0x94,0xc1,0x9b,0xda,0xf7,0xe,0xe5,0xc1,0x27,0x7d,0x89,0xa4,0x82,0xd,0xca,0x84,0x75,0x88,0x1e,0x42,0xe0,0x39,0xa7,0xee,0x56,0x6f,0xe2,0xf8,0xd7,0x38,0x9e,0xa,0x6e,0x8f,0x91,0x98,0x22,0xef,0xe8,0x68,0x72,0x45,0x67,0xd0,0x4f,0x95,0x2e,0x37,0x83,0x53,0x2b,0x13,0xec,0xf,0x32,0x2d,0x5f,0x7b,0x57,0xfe,0xa5,0xc6,0x79,0x9c,0x9a,0x9,0x94,0x6d,0x3,0x11,0xaf,0xad,0xbf,0x26,0xc7,0x7c,0x80,0xb2,0x23,0x66,0x93,0xa3,0xae,0x5b,0x48,0xf4,0xa9,0x14,0x1f,0xe9,0xaa,0x3c,0x74,0x7,0xac,0x20,0x10,0x7f,0xa6,0xf2,0xb9,0xea,0xfb,0xb,0x21,0x31,0x28,0xc0,0xdc,0xe4,0xfc,0x51,0x41,0x15,0x76,0x78,0x8,0xf0,0x60,0xf1,0xc9,0x1a,0x3e,0xde,0x54,0x5a,0xc8,0x2a,0xc4,0x34,0xba,0x36,0x77,0x6c,0x52,0xd4,0x61,0xf6,0x58,0x50,0xfa,0x92,0xe7,0x6a,0x7e,0xd5,0x8c,0xc3,0x1b,0xce,0xa2,0x6,0xb4,0x12,0xb7,0xeb,0x5d,0xb6,0xdd,0xb1,0x85,0x69,0x25,0x4e,0x55,0x9b,0x44,0xb0,0xd9,0x73,0xc2,0x3a,0x0,0xd8,0x8e,0x4b,0x1,0x99,0x29,0x3b,0x5e,0x63,0x62,0x5c,0x18,0x4a,0xdf,0x96,0x3d,0xbd,0xed,0xe3,0xcb,0x70,0x46,0x4d,0xc5,0xb8,0xcf,0xf9,0x8d,0xa0,0xd1,0xbb,0x87,0xa8,0xd2,0x16,0xdb,0x7a,0x8a,0x64,0x47,0x17,0x90,0x2f,0xff,0x35,0xcd,0xc,0x4c,0x97,0xe1,0x2,0x86,0x59,0x1c,0x81,0x49,0xd6,0x33,0x3f,0x65,0x30,0x43,0xcc,0xfd,0xd3,0x5,0xb5,0x19,0xe6,0xa1,0x1d,0xbe,0xbc,0xf5,0x8b,0x2c,0x40,0xf3,0xb3,0x71,0x4,0x9f,0x24,0xab,0x6b,0x9d,0xea,0xec,0xe4,0x79,0xd5,0x8e,0x9,0xb6,0x2f,0x5d,0x27,0xb,0x9c,0x63,0x42,0x7f,0xf3,0x47,0x5b,0x23,0x3f,0xa0,0x5e,0xe5,0x2,0x18,0x17,0x35,0x52,0xe8,0x98,0x9f,0x1e,0x7a,0xe1,0xff,0xa7,0x88,0xee,0x48,0x26,0x9e,0x92,0x1f,0x90,0x32,0xd7,0x49,0x5,0xf4,0x6e,0xf8,0xf2,0xd4,0xba,0x7d,0x57,0xb1,0xf9,0xd,0x87,0xaa,0x95,0x7e,0xb4,0x5a,0xca,0x44,0x24,0xae,0xb8,0x2a,0xb9,0x81,0x4e,0x6a,0x78,0x8,0x10,0x80,0x31,0x21,0x6,0x65,0xac,0xb0,0x8c,0x94,0x51,0x7b,0x58,0x41,0xc9,0x82,0x8b,0x9a,0x60,0x50,0xd6,0xf,0x4,0x4c,0xdc,0x77,0x6f,0x64,0xda,0x99,0x38,0x2b,0xd9,0x84,0xe3,0x16,0xde,0xd3,0xf0,0xc,0x53,0xc2,0xcf,0xdd,0xb7,0x56,0x73,0x1d,0xdf,0x61,0xbb,0x93,0x36,0x0,0x4d,0xe6,0x9d,0xcd,0x68,0x2c,0xaf,0x3a,0x2e,0x4b,0x12,0x13,0x71,0x3b,0x59,0xe9,0x70,0x4a,0xfe,0xa8,0xa9,0xc0,0xb2,0x3,0x25,0x3e,0x34,0xeb,0xf5,0xc1,0x55,0x19,0x2d,0x9b,0xad,0xc6,0xc4,0x76,0xc7,0x62,0x6b,0xb3,0xd2,0xbe,0xe,0x1a,0xfc,0xa5,0x8a,0x20,0x97,0xe2,0x11,0xa4,0x28,0x86,0x7,0x46,0x22,0x1c,0xdb,0x54,0xed,0x1b,0x1,0xc3,0xef,0x74,0x5c,0xfb,0x83,0x30,0xce,0x6d,0x85,0xcc,0x69,0xc5,0xd1,0x96,0x8d,0xbc,0x75,0xa3,0x15,0x4f,0x33,0x40,0x39,0xf1,0x43,0xa6,0xf6,0x72,0x6c,0x29,0x3c,0x7c,0x91,0xe7,0x8f,0x5f,0xbd,0x45,0x37,0x14,0xe0,0x67,0xab,0x66,0xfa,0xa,0xf7,0xcb,0xa2,0xd8,0xfd,0x89,0xa1,0xd0,0xb5,0x3d,0xbf,0xc8,0x51,0x96,0x19,0x3f,0x85,0x13,0xee,0x1f,0x7e,0x95,0x6c,0x41,0x12,0xe6,0xbc,0x5a,0x5,0xa3,0x4c,0x63,0xa,0x14,0xf5,0x91,0x3c,0xa2,0x7b,0xd9,0x79,0xf4,0xcd,0x75,0xb5,0xe,0xd4,0x4b,0xb0,0xc8,0x18,0xac,0x73,0x74,0xb9,0x3,0xfc,0xde,0xe9,0xf3,0xe2,0x5d,0x3e,0x65,0xf,0x92,0x1,0x7,0xa9,0x94,0x77,0x88,0xcc,0xe0,0xc4,0xb6,0xb8,0x29,0x1b,0xe7,0x35,0x38,0x8,0xfd,0x34,0x8a,0x98,0xf6,0x5c,0xbd,0x24,0x36,0x37,0x9c,0xef,0xa7,0x3d,0xe4,0x8b,0xbb,0x32,0x6f,0xd3,0xc0,0x31,0x72,0x84,0x8f,0x67,0x7f,0x47,0x5b,0xed,0x8e,0xda,0xca,0x60,0x71,0x22,0x69,0xb3,0xaa,0xba,0x90,0x53,0xc1,0xcf,0x45,0x21,0xaf,0x5f,0xb1,0xfb,0x6b,0x93,0xe3,0xa5,0x81,0x52,0x6a,0x7c,0x9,0x61,0xcb,0x17,0x4e,0xe5,0xf1,0xc9,0xf7,0xec,0xad,0xc3,0x6d,0xfa,0x4f,0x46,0x2d,0xc6,0x70,0xbe,0xf2,0x1e,0x2a,0x39,0x55,0x80,0x58,0x2c,0x89,0x2f,0x9d,0x15,0x43,0x9b,0xa1,0xb2,0x2,0x9a,0xd0,0xdf,0x0,0xce,0xd5,0x59,0xe8,0x42,0x2b,0x76,0x26,0xa6,0xd,0xdd,0xeb,0x50,0x78,0xf9,0xf8,0xc5,0xa0,0x44,0xd1,0x83,0xc7,0x49,0x33,0x1c,0x20,0x11,0xe1,0x40,0x8d,0x54,0x23,0x5e,0xd6,0x4a,0x3b,0x16,0x62,0x7a,0xc,0xd7,0x97,0x87,0xc2,0x1d,0x99,0xb,0x8c,0xdc,0xff,0x56,0xae,0x64,0xb4,0x9e,0x48,0x66,0x57,0x3a,0x7d,0x82,0x2e,0xa8,0x4d,0xd2,0x1a,0xd8,0xab,0xfe,0xa4,0x4,0x9f,0xea,0x28,0x6,0xf0,0x30,0xbf,0x6e,0x27,0x25,0x86,0x68,0xdb,0xb7,0x10,0x36,0x90,0x7f,0x50,0x39,0x27,0xc6,0xa2,0xf,0x91,0x48,0xea,0x4a,0xc7,0xfe,0x46,0x62,0xa5,0x2a,0xc,0xb6,0x20,0xdd,0x2c,0x4d,0xa6,0x5f,0x72,0x21,0xd5,0x8f,0x69,0xd1,0x6e,0xd,0x56,0x3c,0xa1,0x32,0x34,0x9a,0xa7,0x44,0xbb,0xff,0xd3,0xf7,0x85,0x86,0x3d,0xe7,0x78,0x83,0xfb,0x2b,0x9f,0x40,0x47,0x8a,0x30,0xcf,0xed,0xda,0xc0,0x4,0xaf,0xdc,0x94,0xe,0xd7,0xb8,0x88,0x1,0x5c,0xe0,0xf3,0x2,0x41,0xb7,0xbc,0x8b,0x1a,0x28,0xd4,0x6,0xb,0x3b,0xce,0x7,0xb9,0xab,0xc5,0x6f,0x8e,0x17,0x5,0x60,0xf2,0xfc,0x76,0x12,0x9c,0x6c,0x82,0xc8,0x58,0xa0,0xd0,0x96,0xb2,0x61,0x59,0x54,0x4c,0x74,0x68,0xde,0xbd,0xe9,0xf9,0x53,0x42,0x11,0x5a,0x80,0x99,0x89,0xa3,0x75,0x1e,0xf5,0x43,0x8d,0xc1,0x2d,0x19,0xa,0x66,0xb3,0x6b,0x1f,0xba,0x1c,0xae,0x4f,0x3a,0x52,0xf8,0x24,0x7d,0xd6,0xc2,0xfa,0xc4,0xdf,0x9e,0xf0,0x5e,0xc9,0x7c,0x45,0x15,0x95,0x3e,0xee,0xd8,0x63,0x4b,0xca,0xcb,0xf6,0x93,0x77,0xe2,0xb0,0xf4,0x26,0x70,0xa8,0x92,0x81,0x31,0xa9,0xe3,0xec,0x33,0xfd,0xe6,0x6a,0xdb,0x71,0x18,0x49,0x3f,0xe4,0xa4,0xb4,0xf1,0x2e,0xaa,0x38,0xbf,0xef,0xcc,0x65,0x9d,0x57,0x87,0x7a,0x0,0x2f,0x13,0x22,0xd2,0x73,0xbe,0x67,0x10,0x6d,0xe5,0x79,0x8,0x25,0x51,0x37,0xac,0xd9,0x1b,0x35,0xc3,0x3,0x8c,0x5d,0x14,0x16,0xb5,0x5b,0xe8,0x84,0x23,0xad,0x7b,0x55,0x64,0x9,0x4e,0xb1,0x1d,0x9b,0x7e,0xe1,0x29,0xeb,0x98,0xcd,0x97,0xa0,0x8d,0x74,0x9f,0xbb,0x5d,0x7,0xf3,0xde,0xf8,0x77,0xb0,0xfe,0xf,0xf2,0x64,0x38,0x9a,0x43,0xdd,0x94,0x2c,0x15,0x98,0x82,0xad,0x42,0xe4,0x70,0x14,0xf5,0xeb,0xe2,0x58,0x95,0x92,0x12,0x8,0x3f,0x1d,0xaa,0x35,0xef,0x54,0x4d,0xf9,0x29,0x51,0x69,0x96,0x75,0x48,0x57,0x25,0x1,0x2d,0x84,0xdf,0xbc,0x3,0xe6,0xe0,0x73,0xee,0x17,0x79,0x6b,0xd5,0xd7,0xc5,0x5c,0xbd,0x6,0xfa,0xc8,0x59,0x1c,0xe9,0xd9,0xd4,0x21,0x32,0x8e,0xd3,0x6e,0x65,0x93,0xd0,0x46,0xe,0x7d,0xd6,0x5a,0x6a,0x5,0xdc,0x88,0xc3,0x90,0x81,0x71,0x5b,0x4b,0x52,0xba,0xa6,0x9e,0x86,0x2b,0x3b,0x6f,0xc,0x2,0x72,0x8a,0x1a,0x8b,0xb3,0x60,0x44,0xa4,0x2e,0x20,0xb2,0x50,0xbe,0x4e,0xc0,0x4c,0xd,0x16,0x28,0xae,0x1b,0x8c,0x22,0x2a,0x80,0xe8,0x9d,0x10,0x4,0xaf,0xf6,0xb9,0x61,0xb4,0xd8,0x7c,0xce,0x68,0xcd,0x91,0x27,0xcc,0xa7,0xcb,0xff,0x13,0x5f,0x34,0x2f,0xe1,0x3e,0xca,0xa3,0x9,0xb8,0x40,0x7a,0xa2,0xf4,0x31,0x7b,0xe3,0x53,0x41,0x24,0x19,0x18,0x26,0x62,0x30,0xa5,0xec,0x47,0xc7,0x97,0x99,0xb1,0xa,0x3c,0x37,0xbf,0xc2,0xb5,0x83,0xf7,0xda,0xab,0xc1,0xfd,0xd2,0xa8,0x6c,0xa1,0x0,0xf0,0x1e,0x3d,0x6d,0xea,0x55,0x85,0x4f,0xb7,0x76,0x36,0xed,0x9b,0x78,0xfc,0x23,0x66,0xfb,0x33,0xac,0x49,0x45,0x1f,0x4a,0x39,0xb6,0x87,0xa9,0x7f,0xcf,0x63,0x9c,0xdb,0x67,0xc4,0xc6,0x8f,0xf1,0x56,0x3a,0x89,0xc9,0xb,0x7e,0xe5,0x5e,0xd1,0x11,0xe7,0xc5,0xc3,0xcb,0x56,0xfa,0xa1,0x26,0x99,0x0,0x72,0x8,0x24,0xb3,0x4c,0x6d,0x50,0xdc,0x68,0x74,0xc,0x10,0x8f,0x71,0xca,0x2d,0x37,0x38,0x1a,0x7d,0xc7,0xb7,0xb0,0x31,0x55,0xce,0xd0,0x88,0xa7,0xc1,0x67,0x9,0xb1,0xbd,0x30,0xbf,0x1d,0xf8,0x66,0x2a,0xdb,0x41,0xd7,0xdd,0xfb,0x95,0x52,0x78,0x9e,0xd6,0x22,0xa8,0x85,0xba,0x51,0x9b,0x75,0xe5,0x6b,0xb,0x81,0x97,0x5,0x96,0xae,0x61,0x45,0x57,0x27,0x3f,0xaf,0x1e,0xe,0x29,0x4a,0x83,0x9f,0xa3,0xbb,0x7e,0x54,0x77,0x6e,0xe6,0xad,0xa4,0xb5,0x4f,0x7f,0xf9,0x20,0x2b,0x63,0xf3,0x58,0x40,0x4b,0xf5,0xb6,0x17,0x4,0xf6,0xab,0xcc,0x39,0xf1,0xfc,0xdf,0x23,0x7c,0xed,0xe0,0xf2,0x98,0x79,0x5c,0x32,0xf0,0x4e,0x94,0xbc,0x19,0x2f,0x62,0xc9,0xb2,0xe2,0x47,0x3,0x80,0x15,0x1,0x64,0x3d,0x3c,0x5e,0x14,0x76,0xc6,0x5f,0x65,0xd1,0x87,0x86,0xef,0x9d,0x2c,0xa,0x11,0x1b,0xc4,0xda,0xee,0x7a,0x36,0x2,0xb4,0x82,0xe9,0xeb,0x59,0xe8,0x4d,0x44,0x9c,0xfd,0x91,0x21,0x35,0xd3,0x8a,0xa5,0xf,0xb8,0xcd,0x3e,0x8b,0x7,0xa9,0x28,0x69,0xd,0x33,0xf4,0x7b,0xc2,0x34,0x2e,0xec,0xc0,0x5b,0x73,0xd4,0xac,0x1f,0xe1,0x42,0xaa,0xe3,0x46,0xea,0xfe,0xb9,0xa2,0x93,0x5a,0x8c,0x3a,0x60,0x1c,0x6f,0x16,0xde,0x6c,0x89,0xd9,0x5d,0x43,0x6,0x13,0x53,0xbe,0xc8,0xa0,0x70,0x92,0x6a,0x18,0x3b,0xcf,0x48,0x84,0x49,0xd5,0x25,0xd8,0xe4,0x8d,0xf7,0xd2,0xa6,0x8e,0xff,0x9a,0x12,0x90,0xe7,0xf8,0x3f,0xb0,0x96,0x2c,0xba,0x47,0xb6,0xd7,0x3c,0xc5,0xe8,0xbb,0x4f,0x15,0xf3,0xac,0xa,0xe5,0xca,0xa3,0xbd,0x5c,0x38,0x95,0xb,0xd2,0x70,0xd0,0x5d,0x64,0xdc,0x1c,0xa7,0x7d,0xe2,0x19,0x61,0xb1,0x5,0xda,0xdd,0x10,0xaa,0x55,0x77,0x40,0x5a,0x4b,0xf4,0x97,0xcc,0xa6,0x3b,0xa8,0xae,0x0,0x3d,0xde,0x21,0x65,0x49,0x6d,0x1f,0x11,0x80,0xb2,0x4e,0x9c,0x91,0xa1,0x54,0x9d,0x23,0x31,0x5f,0xf5,0x14,0x8d,0x9f,0x9e,0x35,0x46,0xe,0x94,0x4d,0x22,0x12,0x9b,0xc6,0x7a,0x69,0x98,0xdb,0x2d,0x26,0xce,0xd6,0xee,0xf2,0x44,0x27,0x73,0x63,0xc9,0xd8,0x8b,0xc0,0x1a,0x3,0x13,0x39,0xfa,0x68,0x66,0xec,0x88,0x6,0xf6,0x18,0x52,0xc2,0x3a,0x4a,0xc,0x28,0xfb,0xc3,0xd5,0xa0,0xc8,0x62,0xbe,0xe7,0x4c,0x58,0x60,0x5e,0x45,0x4,0x6a,0xc4,0x53,0xe6,0xef,0x84,0x6f,0xd9,0x17,0x5b,0xb7,0x83,0x90,0xfc,0x29,0xf1,0x85,0x20,0x86,0x34,0xbc,0xea,0x32,0x8,0x1b,0xab,0x33,0x79,0x76,0xa9,0x67,0x7c,0xf0,0x41,0xeb,0x82,0xdf,0x8f,0xf,0xa4,0x74,0x42,0xf9,0xd1,0x50,0x51,0x6c,0x9,0xed,0x78,0x2a,0x6e,0xe0,0x9a,0xb5,0x89,0xb8,0x48,0xe9,0x24,0xfd,0x8a,0xf7,0x7f,0xe3,0x92,0xbf,0xcb,0xd3,0xa5,0x7e,0x3e,0x2e,0x6b,0xb4,0x30,0xa2,0x25,0x75,0x56,0xff,0x7,0xcd,0x1d,0x37,0xe1,0xcf,0xfe,0x93,0xd4,0x2b,0x87,0x1,0xe4,0x7b,0xb3,0x71,0x2,0x57,0xd,0xad,0x36,0x43,0x81,0xaf,0x59,0x99,0x16,0xc7,0x8e,0x8c,0x2f,0xc1,0x72,0x1e,0xb9,0xab,0xd,0xe2,0xcd,0xa4,0xba,0x5b,0x3f,0x92,0xc,0xd5,0x77,0xd7,0x5a,0x63,0xdb,0xff,0x38,0xb7,0x91,0x2b,0xbd,0x40,0xb1,0xd0,0x3b,0xc2,0xef,0xbc,0x48,0x12,0xf4,0x4c,0xf3,0x90,0xcb,0xa1,0x3c,0xaf,0xa9,0x7,0x3a,0xd9,0x26,0x62,0x4e,0x6a,0x18,0x1b,0xa0,0x7a,0xe5,0x1e,0x66,0xb6,0x2,0xdd,0xda,0x17,0xad,0x52,0x70,0x47,0x5d,0x99,0x32,0x41,0x9,0x93,0x4a,0x25,0x15,0x9c,0xc1,0x7d,0x6e,0x9f,0xdc,0x2a,0x21,0x16,0x87,0xb5,0x49,0x9b,0x96,0xa6,0x53,0x9a,0x24,0x36,0x58,0xf2,0x13,0x8a,0x98,0xfd,0x6f,0x61,0xeb,0x8f,0x1,0xf1,0x1f,0x55,0xc5,0x3d,0x4d,0xb,0x2f,0xfc,0xc4,0xc9,0xd1,0xe9,0xf5,0x43,0x20,0x74,0x64,0xce,0xdf,0x8c,0xc7,0x1d,0x4,0x14,0x3e,0xe8,0x83,0x68,0xde,0x10,0x5c,0xb0,0x84,0x97,0xfb,0x2e,0xf6,0x82,0x27,0x81,0x33,0xd2,0xa7,0xcf,0x65,0xb9,0xe0,0x4b,0x5f,0x67,0x59,0x42,0x3,0x6d,0xc3,0x54,0xe1,0xd8,0x88,0x8,0xa3,0x73,0x45,0xfe,0xd6,0x57,0x56,0x6b,0xe,0xea,0x7f,0x2d,0x69,0xbb,0xed,0x35,0xf,0x1c,0xac,0x34,0x7e,0x71,0xae,0x60,0x7b,0xf7,0x46,0xec,0x85,0xd4,0xa2,0x79,0x39,0x29,0x6c,0xb3,0x37,0xa5,0x22,0x72,0x51,0xf8,0x0,0xca,0x1a,0xe7,0x9d,0xb2,0x8e,0xbf,0x4f,0xee,0x23,0xfa,0x8d,0xf0,0x78,0xe4,0x95,0xb8,0xcc,0xaa,0x31,0x44,0x86,0xa8,0x5e,0x9e,0x11,0xc0,0x89,0x8b,0x28,0xc6,0x75,0x19,0xbe,0x30,0xe6,0xc8,0xf9,0x94,0xd3,0x2c,0x80,0x6,0xe3,0x7c,0xb4,0x76,0x5,0x50,0xa,0x8b,0xa6,0x5f,0xb4,0x90,0x76,0x2c,0xd8,0xf5,0xd3,0x5c,0x9b,0xd5,0x24,0xd9,0x4f,0x13,0xb1,0x68,0xf6,0xbf,0x7,0x3e,0xb3,0xa9,0x86,0x69,0xcf,0x5b,0x3f,0xde,0xc0,0xc9,0x73,0xbe,0xb9,0x39,0x23,0x14,0x36,0x81,0x1e,0xc4,0x7f,0x66,0xd2,0x2,0x7a,0x42,0xbd,0x5e,0x63,0x7c,0xe,0x2a,0x6,0xaf,0xf4,0x97,0x28,0xcd,0xcb,0x58,0xc5,0x3c,0x52,0x40,0xfe,0xfc,0xee,0x77,0x96,0x2d,0xd1,0xe3,0x72,0x37,0xc2,0xf2,0xff,0xa,0x19,0xa5,0xf8,0x45,0x4e,0xb8,0xfb,0x6d,0x25,0x56,0xfd,0x71,0x41,0x2e,0xf7,0xa3,0xe8,0xbb,0xaa,0x5a,0x70,0x60,0x79,0x91,0x8d,0xb5,0xad,0x0,0x10,0x44,0x27,0x29,0x59,0xa1,0x31,0xa0,0x98,0x4b,0x6f,0x8f,0x5,0xb,0x99,0x7b,0x95,0x65,0xeb,0x67,0x26,0x3d,0x3,0x85,0x30,0xa7,0x9,0x1,0xab,0xc3,0xb6,0x3b,0x2f,0x84,0xdd,0x92,0x4a,0x9f,0xf3,0x57,0xe5,0x43,0xe6,0xba,0xc,0xe7,0x8c,0xe0,0xd4,0x38,0x74,0x1f,0x4,0xca,0x15,0xe1,0x88,0x22,0x93,0x6b,0x51,0x89,0xdf,0x1a,0x50,0xc8,0x78,0x6a,0xf,0x32,0x33,0xd,0x49,0x1b,0x8e,0xc7,0x6c,0xec,0xbc,0xb2,0x9a,0x21,0x17,0x1c,0x94,0xe9,0x9e,0xa8,0xdc,0xf1,0x80,0xea,0xd6,0xf9,0x83,0x47,0x8a,0x2b,0xdb,0x35,0x16,0x46,0xc1,0x7e,0xae,0x64,0x9c,0x5d,0x1d,0xc6,0xb0,0x53,0xd7,0x8,0x4d,0xd0,0x18,0x87,0x62,0x6e,0x34,0x61,0x12,0x9d,0xac,0x82,0x54,0xe4,0x48,0xb7,0xf0,0x4c,0xef,0xed,0xa4,0xda,0x7d,0x11,0xa2,0xe2,0x20,0x55,0xce,0x75,0xfa,0x3a,0xcc,0x7e,0x78,0x70,0xed,0x41,0x1a,0x9d,0x22,0xbb,0xc9,0xb3,0x9f,0x8,0xf7,0xd6,0xeb,0x67,0xd3,0xcf,0xb7,0xab,0x34,0xca,0x71,0x96,0x8c,0x83,0xa1,0xc6,0x7c,0xc,0xb,0x8a,0xee,0x75,0x6b,0x33,0x1c,0x7a,0xdc,0xb2,0xa,0x6,0x8b,0x4,0xa6,0x43,0xdd,0x91,0x60,0xfa,0x6c,0x66,0x40,0x2e,0xe9,0xc3,0x25,0x6d,0x99,0x13,0x3e,0x1,0xea,0x20,0xce,0x5e,0xd0,0xb0,0x3a,0x2c,0xbe,0x2d,0x15,0xda,0xfe,0xec,0x9c,0x84,0x14,0xa5,0xb5,0x92,0xf1,0x38,0x24,0x18,0x0,0xc5,0xef,0xcc,0xd5,0x5d,0x16,0x1f,0xe,0xf4,0xc4,0x42,0x9b,0x90,0xd8,0x48,0xe3,0xfb,0xf0,0x4e,0xd,0xac,0xbf,0x4d,0x10,0x77,0x82,0x4a,0x47,0x64,0x98,0xc7,0x56,0x5b,0x49,0x23,0xc2,0xe7,0x89,0x4b,0xf5,0x2f,0x7,0xa2,0x94,0xd9,0x72,0x9,0x59,0xfc,0xb8,0x3b,0xae,0xba,0xdf,0x86,0x87,0xe5,0xaf,0xcd,0x7d,0xe4,0xde,0x6a,0x3c,0x3d,0x54,0x26,0x97,0xb1,0xaa,0xa0,0x7f,0x61,0x55,0xc1,0x8d,0xb9,0xf,0x39,0x52,0x50,0xe2,0x53,0xf6,0xff,0x27,0x46,0x2a,0x9a,0x8e,0x68,0x31,0x1e,0xb4,0x3,0x76,0x85,0x30,0xbc,0x12,0x93,0xd2,0xb6,0x88,0x4f,0xc0,0x79,0x8f,0x95,0x57,0x7b,0xe0,0xc8,0x6f,0x17,0xa4,0x5a,0xf9,0x11,0x58,0xfd,0x51,0x45,0x2,0x19,0x28,0xe1,0x37,0x81,0xdb,0xa7,0xd4,0xad,0x65,0xd7,0x32,0x62,0xe6,0xf8,0xbd,0xa8,0xe8,0x5,0x73,0x1b,0xcb,0x29,0xd1,0xa3,0x80,0x74,0xf3,0x3f,0xf2,0x6e,0x9e,0x63,0x5f,0x36,0x4c,0x69,0x1d,0x35,0x44,0x21,0xa9,0x2b,0x5c,0x46,0x81,0xe,0x28,0x92,0x4,0xf9,0x8,0x69,0x82,0x7b,0x56,0x5,0xf1,0xab,0x4d,0x12,0xb4,0x5b,0x74,0x1d,0x3,0xe2,0x86,0x2b,0xb5,0x6c,0xce,0x6e,0xe3,0xda,0x62,0xa2,0x19,0xc3,0x5c,0xa7,0xdf,0xf,0xbb,0x64,0x63,0xae,0x14,0xeb,0xc9,0xfe,0xe4,0xf5,0x4a,0x29,0x72,0x18,0x85,0x16,0x10,0xbe,0x83,0x60,0x9f,0xdb,0xf7,0xd3,0xa1,0xaf,0x3e,0xc,0xf0,0x22,0x2f,0x1f,0xea,0x23,0x9d,0x8f,0xe1,0x4b,0xaa,0x33,0x21,0x20,0x8b,0xf8,0xb0,0x2a,0xf3,0x9c,0xac,0x25,0x78,0xc4,0xd7,0x26,0x65,0x93,0x98,0x70,0x68,0x50,0x4c,0xfa,0x99,0xcd,0xdd,0x77,0x66,0x35,0x7e,0xa4,0xbd,0xad,0x87,0x44,0xd6,0xd8,0x52,0x36,0xb8,0x48,0xa6,0xec,0x7c,0x84,0xf4,0xb2,0x96,0x45,0x7d,0x6b,0x1e,0x76,0xdc,0x0,0x59,0xf2,0xe6,0xde,0xe0,0xfb,0xba,0xd4,0x7a,0xed,0x58,0x51,0x3a,0xd1,0x67,0xa9,0xe5,0x9,0x3d,0x2e,0x42,0x97,0x4f,0x3b,0x9e,0x38,0x8a,0x2,0x54,0x8c,0xb6,0xa5,0x15,0x8d,0xc7,0xc8,0x17,0xd9,0xc2,0x4e,0xff,0x55,0x3c,0x61,0x31,0xb1,0x1a,0xca,0xfc,0x47,0x6f,0xee,0xef,0xd2,0xb7,0x53,0xc6,0x94,0xd0,0x5e,0x24,0xb,0x37,0x6,0xf6,0x57,0x9a,0x43,0x34,0x49,0xc1,0x5d,0x2c,0x1,0x75,0x6d,0x1b,0xc0,0x80,0x90,0xd5,0xa,0x8e,0x1c,0x9b,0xcb,0xe8,0x41,0xb9,0x73,0xa3,0x89,0x5f,0x71,0x40,0x2d,0x6a,0x95,0x39,0xbf,0x5a,0xc5,0xd,0xcf,0xbc,0xe9,0xb3,0x13,0x88,0xfd,0x3f,0x11,0xe7,0x27,0xa8,0x79,0x30,0x32,0x91,0x7f,0xcc,0xa0,0x7,0x43,0xe5,0xa,0x25,0x4c,0x52,0xb3,0xd7,0x7a,0xe4,0x3d,0x9f,0x3f,0xb2,0x8b,0x33,0x17,0xd0,0x5f,0x79,0xc3,0x55,0xa8,0x59,0x38,0xd3,0x2a,0x7,0x54,0xa0,0xfa,0x1c,0xa4,0x1b,0x78,0x23,0x49,0xd4,0x47,0x41,0xef,0xd2,0x31,0xce,0x8a,0xa6,0x82,0xf0,0xf3,0x48,0x92,0xd,0xf6,0x8e,0x5e,0xea,0x35,0x32,0xff,0x45,0xba,0x98,0xaf,0xb5,0x71,0xda,0xa9,0xe1,0x7b,0xa2,0xcd,0xfd,0x74,0x29,0x95,0x86,0x77,0x34,0xc2,0xc9,0xfe,0x6f,0x5d,0xa1,0x73,0x7e,0x4e,0xbb,0x72,0xcc,0xde,0xb0,0x1a,0xfb,0x62,0x70,0x15,0x87,0x89,0x3,0x67,0xe9,0x19,0xf7,0xbd,0x2d,0xd5,0xa5,0xe3,0xc7,0x14,0x2c,0x21,0x39,0x1,0x1d,0xab,0xc8,0x9c,0x8c,0x26,0x37,0x64,0x2f,0xf5,0xec,0xfc,0xd6,0x0,0x6b,0x80,0x36,0xf8,0xb4,0x58,0x6c,0x7f,0x13,0xc6,0x1e,0x6a,0xcf,0x69,0xdb,0x3a,0x4f,0x27,0x8d,0x51,0x8,0xa3,0xb7,0x8f,0xb1,0xaa,0xeb,0x85,0x2b,0xbc,0x9,0x30,0x60,0xe0,0x4b,0x9b,0xad,0x16,0x3e,0xbf,0xbe,0x83,0xe6,0x2,0x97,0xc5,0x81,0x53,0x5,0xdd,0xe7,0xf4,0x44,0xdc,0x96,0x99,0x46,0x88,0x93,0x1f,0xae,0x4,0x6d,0x3c,0x4a,0x91,0xd1,0xc1,0x84,0x5b,0xdf,0x4d,0xca,0x9a,0xb9,0x10,0xe8,0x22,0xf2,0xf,0x75,0x5a,0x66,0x57,0xa7,0x6,0xcb,0x12,0x65,0x18,0x90,0xc,0x7d,0x50,0x24,0x42,0xd9,0xac,0x6e,0x40,0xb6,0x76,0xf9,0x28,0x61,0x63,0xc0,0x2e,0x9d,0xf1,0x56,0xd8,0xe,0x20,0x11,0x7c,0x3b,0xc4,0x68,0xee,0xb,0x94,0x5c,0x9e,0xed,0xb8,0xe2,0xc2,0xef,0x16,0xfd,0xd9,0x3f,0x65,0x91,0xbc,0x9a,0x15,0xd2,0x9c,0x6d,0x90,0x6,0x5a,0xf8,0x21,0xbf,0xf6,0x4e,0x77,0xfa,0xe0,0xcf,0x20,0x86,0x12,0x76,0x97,0x89,0x80,0x3a,0xf7,0xf0,0x70,0x6a,0x5d,0x7f,0xc8,0x57,0x8d,0x36,0x2f,0x9b,0x4b,0x33,0xb,0xf4,0x17,0x2a,0x35,0x47,0x63,0x4f,0xe6,0xbd,0xde,0x61,0x84,0x82,0x11,0x8c,0x75,0x1b,0x9,0xb7,0xb5,0xa7,0x3e,0xdf,0x64,0x98,0xaa,0x3b,0x7e,0x8b,0xbb,0xb6,0x43,0x50,0xec,0xb1,0xc,0x7,0xf1,0xb2,0x24,0x6c,0x1f,0xb4,0x38,0x8,0x67,0xbe,0xea,0xa1,0xf2,0xe3,0x13,0x39,0x29,0x30,0xd8,0xc4,0xfc,0xe4,0x49,0x59,0xd,0x6e,0x60,0x10,0xe8,0x78,0xe9,0xd1,0x2,0x26,0xc6,0x4c,0x42,0xd0,0x32,0xdc,0x2c,0xa2,0x2e,0x6f,0x74,0x4a,0xcc,0x79,0xee,0x40,0x48,0xe2,0x8a,0xff,0x72,0x66,0xcd,0x94,0xdb,0x3,0xd6,0xba,0x1e,0xac,0xa,0xaf,0xf3,0x45,0xae,0xc5,0xa9,0x9d,0x71,0x3d,0x56,0x4d,0x83,0x5c,0xa8,0xc1,0x6b,0xda,0x22,0x18,0xc0,0x96,0x53,0x19,0x81,0x31,0x23,0x46,0x7b,0x7a,0x44,0x0,0x52,0xc7,0x8e,0x25,0xa5,0xf5,0xfb,0xd3,0x68,0x5e,0x55,0xdd,0xa0,0xd7,0xe1,0x95,0xb8,0xc9,0xa3,0x9f,0xb0,0xca,0xe,0xc3,0x62,0x92,0x7c,0x5f,0xf,0x88,0x37,0xe7,0x2d,0xd5,0x14,0x54,0x8f,0xf9,0x1a,0x9e,0x41,0x4,0x99,0x51,0xce,0x2b,0x27,0x7d,0x28,0x5b,0xd4,0xe5,0xcb,0x1d,0xad,0x1,0xfe,0xb9,0x5,0xa6,0xa4,0xed,0x93,0x34,0x58,0xeb,0xab,0x69,0x1c,0x87,0x3c,0xb3,0x73,0x85,0xae,0xa8,0xa0,0x3d,0x91,0xca,0x4d,0xf2,0x6b,0x19,0x63,0x4f,0xd8,0x27,0x6,0x3b,0xb7,0x3,0x1f,0x67,0x7b,0xe4,0x1a,0xa1,0x46,0x5c,0x53,0x71,0x16,0xac,0xdc,0xdb,0x5a,0x3e,0xa5,0xbb,0xe3,0xcc,0xaa,0xc,0x62,0xda,0xd6,0x5b,0xd4,0x76,0x93,0xd,0x41,0xb0,0x2a,0xbc,0xb6,0x90,0xfe,0x39,0x13,0xf5,0xbd,0x49,0xc3,0xee,0xd1,0x3a,0xf0,0x1e,0x8e,0x0,0x60,0xea,0xfc,0x6e,0xfd,0xc5,0xa,0x2e,0x3c,0x4c,0x54,0xc4,0x75,0x65,0x42,0x21,0xe8,0xf4,0xc8,0xd0,0x15,0x3f,0x1c,0x5,0x8d,0xc6,0xcf,0xde,0x24,0x14,0x92,0x4b,0x40,0x8,0x98,0x33,0x2b,0x20,0x9e,0xdd,0x7c,0x6f,0x9d,0xc0,0xa7,0x52,0x9a,0x97,0xb4,0x48,0x17,0x86,0x8b,0x99,0xf3,0x12,0x37,0x59,0x9b,0x25,0xff,0xd7,0x72,0x44,0x9,0xa2,0xd9,0x89,0x2c,0x68,0xeb,0x7e,0x6a,0xf,0x56,0x57,0x35,0x7f,0x1d,0xad,0x34,0xe,0xba,0xec,0xed,0x84,0xf6,0x47,0x61,0x7a,0x70,0xaf,0xb1,0x85,0x11,0x5d,0x69,0xdf,0xe9,0x82,0x80,0x32,0x83,0x26,0x2f,0xf7,0x96,0xfa,0x4a,0x5e,0xb8,0xe1,0xce,0x64,0xd3,0xa6,0x55,0xe0,0x6c,0xc2,0x43,0x2,0x66,0x58,0x9f,0x10,0xa9,0x5f,0x45,0x87,0xab,0x30,0x18,0xbf,0xc7,0x74,0x8a,0x29,0xc1,0x88,0x2d,0x81,0x95,0xd2,0xc9,0xf8,0x31,0xe7,0x51,0xb,0x77,0x4,0x7d,0xb5,0x7,0xe2,0xb2,0x36,0x28,0x6d,0x78,0x38,0xd5,0xa3,0xcb,0x1b,0xf9,0x1,0x73,0x50,0xa4,0x23,0xef,0x22,0xbe,0x4e,0xb3,0x8f,0xe6,0x9c,0xb9,0xcd,0xe5,0x94,0xf1,0x79,0xfb,0x8c,0x61,0xa6,0x29,0xf,0xb5,0x23,0xde,0x2f,0x4e,0xa5,0x5c,0x71,0x22,0xd6,0x8c,0x6a,0x35,0x93,0x7c,0x53,0x3a,0x24,0xc5,0xa1,0xc,0x92,0x4b,0xe9,0x49,0xc4,0xfd,0x45,0x85,0x3e,0xe4,0x7b,0x80,0xf8,0x28,0x9c,0x43,0x44,0x89,0x33,0xcc,0xee,0xd9,0xc3,0xd2,0x6d,0xe,0x55,0x3f,0xa2,0x31,0x37,0x99,0xa4,0x47,0xb8,0xfc,0xd0,0xf4,0x86,0x88,0x19,0x2b,0xd7,0x5,0x8,0x38,0xcd,0x4,0xba,0xa8,0xc6,0x6c,0x8d,0x14,0x6,0x7,0xac,0xdf,0x97,0xd,0xd4,0xbb,0x8b,0x2,0x5f,0xe3,0xf0,0x1,0x42,0xb4,0xbf,0x57,0x4f,0x77,0x6b,0xdd,0xbe,0xea,0xfa,0x50,0x41,0x12,0x59,0x83,0x9a,0x8a,0xa0,0x63,0xf1,0xff,0x75,0x11,0x9f,0x6f,0x81,0xcb,0x5b,0xa3,0xd3,0x95,0xb1,0x62,0x5a,0x4c,0x39,0x51,0xfb,0x27,0x7e,0xd5,0xc1,0xf9,0xc7,0xdc,0x9d,0xf3,0x5d,0xca,0x7f,0x76,0x1d,0xf6,0x40,0x8e,0xc2,0x2e,0x1a,0x9,0x65,0xb0,0x68,0x1c,0xb9,0x1f,0xad,0x25,0x73,0xab,0x91,0x82,0x32,0xaa,0xe0,0xef,0x30,0xfe,0xe5,0x69,0xd8,0x72,0x1b,0x46,0x16,0x96,0x3d,0xed,0xdb,0x60,0x48,0xc9,0xc8,0xf5,0x90,0x74,0xe1,0xb3,0xf7,0x79,0x3,0x2c,0x10,0x21,0xd1,0x70,0xbd,0x64,0x13,0x6e,0xe6,0x7a,0xb,0x26,0x52,0x4a,0x3c,0xe7,0xa7,0xb7,0xf2,0x2d,0xa9,0x3b,0xbc,0xec,0xcf,0x66,0x9e,0x54,0x84,0xae,0x78,0x56,0x67,0xa,0x4d,0xb2,0x1e,0x98,0x7d,0xe2,0x2a,0xe8,0x9b,0xce,0x94,0x34,0xaf,0xda,0x18,0x36,0xc0,0x0,0x8f,0x5e,0x17,0x15,0xb6,0x58,0xeb,0x87,0x20,0x3e,0x98,0x77,0x58,0x31,0x2f,0xce,0xaa,0x7,0x99,0x40,0xe2,0x42,0xcf,0xf6,0x4e,0x6a,0xad,0x22,0x4,0xbe,0x28,0xd5,0x24,0x45,0xae,0x57,0x7a,0x29,0xdd,0x87,0x61,0xd9,0x66,0x5,0x5e,0x34,0xa9,0x3a,0x3c,0x92,0xaf,0x4c,0xb3,0xf7,0xdb,0xff,0x8d,0x8e,0x35,0xef,0x70,0x8b,0xf3,0x23,0x97,0x48,0x4f,0x82,0x38,0xc7,0xe5,0xd2,0xc8,0xc,0xa7,0xd4,0x9c,0x6,0xdf,0xb0,0x80,0x9,0x54,0xe8,0xfb,0xa,0x49,0xbf,0xb4,0x83,0x12,0x20,0xdc,0xe,0x3,0x33,0xc6,0xf,0xb1,0xa3,0xcd,0x67,0x86,0x1f,0xd,0x68,0xfa,0xf4,0x7e,0x1a,0x94,0x64,0x8a,0xc0,0x50,0xa8,0xd8,0x9e,0xba,0x69,0x51,0x5c,0x44,0x7c,0x60,0xd6,0xb5,0xe1,0xf1,0x5b,0x4a,0x19,0x52,0x88,0x91,0x81,0xab,0x7d,0x16,0xfd,0x4b,0x85,0xc9,0x25,0x11,0x2,0x6e,0xbb,0x63,0x17,0xb2,0x14,0xa6,0x47,0x32,0x5a,0xf0,0x2c,0x75,0xde,0xca,0xf2,0xcc,0xd7,0x96,0xf8,0x56,0xc1,0x74,0x4d,0x1d,0x9d,0x36,0xe6,0xd0,0x6b,0x43,0xc2,0xc3,0xfe,0x9b,0x7f,0xea,0xb8,0xfc,0x2e,0x78,0xa0,0x9a,0x89,0x39,0xa1,0xeb,0xe4,0x3b,0xf5,0xee,0x62,0xd3,0x79,0x10,0x41,0x37,0xec,0xac,0xbc,0xf9,0x26,0xa2,0x30,0xb7,0xe7,0xc4,0x6d,0x95,0x5f,0x8f,0x72,0x8,0x27,0x1b,0x2a,0xda,0x7b,0xb6,0x6f,0x18,0x65,0xed,0x71,0x0,0x2d,0x59,0x3f,0xa4,0xd1,0x13,0x3d,0xcb,0xb,0x84,0x55,0x1c,0x1e,0xbd,0x53,0xe0,0x8c,0x2b,0xa5,0x73,0x5d,0x6c,0x1,0x46,0xb9,0x15,0x93,0x76,0xe9,0x21,0xe3,0x90,0xc5,0x9f,0xc,0x21,0xd8,0x33,0x17,0xf1,0xab,0x5f,0x72,0x54,0xdb,0x1c,0x52,0xa3,0x5e,0xc8,0x94,0x36,0xef,0x71,0x38,0x80,0xb9,0x34,0x2e,0x1,0xee,0x48,0xdc,0xb8,0x59,0x47,0x4e,0xf4,0x39,0x3e,0xbe,0xa4,0x93,0xb1,0x6,0x99,0x43,0xf8,0xe1,0x55,0x85,0xfd,0xc5,0x3a,0xd9,0xe4,0xfb,0x89,0xad,0x81,0x28,0x73,0x10,0xaf,0x4a,0x4c,0xdf,0x42,0xbb,0xd5,0xc7,0x79,0x7b,0x69,0xf0,0x11,0xaa,0x56,0x64,0xf5,0xb0,0x45,0x75,0x78,0x8d,0x9e,0x22,0x7f,0xc2,0xc9,0x3f,0x7c,0xea,0xa2,0xd1,0x7a,0xf6,0xc6,0xa9,0x70,0x24,0x6f,0x3c,0x2d,0xdd,0xf7,0xe7,0xfe,0x16,0xa,0x32,0x2a,0x87,0x97,0xc3,0xa0,0xae,0xde,0x26,0xb6,0x27,0x1f,0xcc,0xe8,0x8,0x82,0x8c,0x1e,0xfc,0x12,0xe2,0x6c,0xe0,0xa1,0xba,0x84,0x2,0xb7,0x20,0x8e,0x86,0x2c,0x44,0x31,0xbc,0xa8,0x3,0x5a,0x15,0xcd,0x18,0x74,0xd0,0x62,0xc4,0x61,0x3d,0x8b,0x60,0xb,0x67,0x53,0xbf,0xf3,0x98,0x83,0x4d,0x92,0x66,0xf,0xa5,0x14,0xec,0xd6,0xe,0x58,0x9d,0xd7,0x4f,0xff,0xed,0x88,0xb5,0xb4,0x8a,0xce,0x9c,0x9,0x40,0xeb,0x6b,0x3b,0x35,0x1d,0xa6,0x90,0x9b,0x13,0x6e,0x19,0x2f,0x5b,0x76,0x7,0x6d,0x51,0x7e,0x4,0xc0,0xd,0xac,0x5c,0xb2,0x91,0xc1,0x46,0xf9,0x29,0xe3,0x1b,0xda,0x9a,0x41,0x37,0xd4,0x50,0x8f,0xca,0x57,0x9f,0x0,0xe5,0xe9,0xb3,0xe6,0x95,0x1a,0x2b,0x5,0xd3,0x63,0xcf,0x30,0x77,0xcb,0x68,0x6a,0x23,0x5d,0xfa,0x96,0x25,0x65,0xa7,0xd2,0x49,0xf2,0x7d,0xbd,0x4b,0x19,0x1f,0x17,0x8a,0x26,0x7d,0xfa,0x45,0xdc,0xae,0xd4,0xf8,0x6f,0x90,0xb1,0x8c,0x0,0xb4,0xa8,0xd0,0xcc,0x53,0xad,0x16,0xf1,0xeb,0xe4,0xc6,0xa1,0x1b,0x6b,0x6c,0xed,0x89,0x12,0xc,0x54,0x7b,0x1d,0xbb,0xd5,0x6d,0x61,0xec,0x63,0xc1,0x24,0xba,0xf6,0x7,0x9d,0xb,0x1,0x27,0x49,0x8e,0xa4,0x42,0xa,0xfe,0x74,0x59,0x66,0x8d,0x47,0xa9,0x39,0xb7,0xd7,0x5d,0x4b,0xd9,0x4a,0x72,0xbd,0x99,0x8b,0xfb,0xe3,0x73,0xc2,0xd2,0xf5,0x96,0x5f,0x43,0x7f,0x67,0xa2,0x88,0xab,0xb2,0x3a,0x71,0x78,0x69,0x93,0xa3,0x25,0xfc,0xf7,0xbf,0x2f,0x84,0x9c,0x97,0x29,0x6a,0xcb,0xd8,0x2a,0x77,0x10,0xe5,0x2d,0x20,0x3,0xff,0xa0,0x31,0x3c,0x2e,0x44,0xa5,0x80,0xee,0x2c,0x92,0x48,0x60,0xc5,0xf3,0xbe,0x15,0x6e,0x3e,0x9b,0xdf,0x5c,0xc9,0xdd,0xb8,0xe1,0xe0,0x82,0xc8,0xaa,0x1a,0x83,0xb9,0xd,0x5b,0x5a,0x33,0x41,0xf0,0xd6,0xcd,0xc7,0x18,0x6,0x32,0xa6,0xea,0xde,0x68,0x5e,0x35,0x37,0x85,0x34,0x91,0x98,0x40,0x21,0x4d,0xfd,0xe9,0xf,0x56,0x79,0xd3,0x64,0x11,0xe2,0x57,0xdb,0x75,0xf4,0xb5,0xd1,0xef,0x28,0xa7,0x1e,0xe8,0xf2,0x30,0x1c,0x87,0xaf,0x8,0x70,0xc3,0x3d,0x9e,0x76,0x3f,0x9a,0x36,0x22,0x65,0x7e,0x4f,0x86,0x50,0xe6,0xbc,0xc0,0xb3,0xca,0x2,0xb0,0x55,0x5,0x81,0x9f,0xda,0xcf,0x8f,0x62,0x14,0x7c,0xac,0x4e,0xb6,0xc4,0xe7,0x13,0x94,0x58,0x95,0x9,0xf9,0x4,0x38,0x51,0x2b,0xe,0x7a,0x52,0x23,0x46,0xce,0x4c,0x3b,0xcf,0x8,0x87,0xa1,0x1b,0x8d,0x70,0x81,0xe0,0xb,0xf2,0xdf,0x8c,0x78,0x22,0xc4,0x9b,0x3d,0xd2,0xfd,0x94,0x8a,0x6b,0xf,0xa2,0x3c,0xe5,0x47,0xe7,0x6a,0x53,0xeb,0x2b,0x90,0x4a,0xd5,0x2e,0x56,0x86,0x32,0xed,0xea,0x27,0x9d,0x62,0x40,0x77,0x6d,0x7c,0xc3,0xa0,0xfb,0x91,0xc,0x9f,0x99,0x37,0xa,0xe9,0x16,0x52,0x7e,0x5a,0x28,0x26,0xb7,0x85,0x79,0xab,0xa6,0x96,0x63,0xaa,0x14,0x6,0x68,0xc2,0x23,0xba,0xa8,0xa9,0x2,0x71,0x39,0xa3,0x7a,0x15,0x25,0xac,0xf1,0x4d,0x5e,0xaf,0xec,0x1a,0x11,0xf9,0xe1,0xd9,0xc5,0x73,0x10,0x44,0x54,0xfe,0xef,0xbc,0xf7,0x2d,0x34,0x24,0xe,0xcd,0x5f,0x51,0xdb,0xbf,0x31,0xc1,0x2f,0x65,0xf5,0xd,0x7d,0x3b,0x1f,0xcc,0xf4,0xe2,0x97,0xff,0x55,0x89,0xd0,0x7b,0x6f,0x57,0x69,0x72,0x33,0x5d,0xf3,0x64,0xd1,0xd8,0xb3,0x58,0xee,0x20,0x6c,0x80,0xb4,0xa7,0xcb,0x1e,0xc6,0xb2,0x17,0xb1,0x3,0x8b,0xdd,0x5,0x3f,0x2c,0x9c,0x4,0x4e,0x41,0x9e,0x50,0x4b,0xc7,0x76,0xdc,0xb5,0xe8,0xb8,0x38,0x93,0x43,0x75,0xce,0xe6,0x67,0x66,0x5b,0x3e,0xda,0x4f,0x1d,0x59,0xd7,0xad,0x82,0xbe,0x8f,0x7f,0xde,0x13,0xca,0xbd,0xc0,0x48,0xd4,0xa5,0x88,0xfc,0xe4,0x92,0x49,0x9,0x19,0x5c,0x83,0x7,0x95,0x12,0x42,0x61,0xc8,0x30,0xfa,0x2a,0x0,0xd6,0xf8,0xc9,0xa4,0xe3,0x1c,0xb0,0x36,0xd3,0x4c,0x84,0x46,0x35,0x60,0x3a,0x9a,0x1,0x74,0xb6,0x98,0x6e,0xae,0x21,0xf0,0xb9,0xbb,0x18,0xf6,0x45,0x29,0x8e,0xaf,0x9,0xe6,0xc9,0xa0,0xbe,0x5f,0x3b,0x96,0x8,0xd1,0x73,0xd3,0x5e,0x67,0xdf,0xfb,0x3c,0xb3,0x95,0x2f,0xb9,0x44,0xb5,0xd4,0x3f,0xc6,0xeb,0xb8,0x4c,0x16,0xf0,0x48,0xf7,0x94,0xcf,0xa5,0x38,0xab,0xad,0x3,0x3e,0xdd,0x22,0x66,0x4a,0x6e,0x1c,0x1f,0xa4,0x7e,0xe1,0x1a,0x62,0xb2,0x6,0xd9,0xde,0x13,0xa9,0x56,0x74,0x43,0x59,0x9d,0x36,0x45,0xd,0x97,0x4e,0x21,0x11,0x98,0xc5,0x79,0x6a,0x9b,0xd8,0x2e,0x25,0x12,0x83,0xb1,0x4d,0x9f,0x92,0xa2,0x57,0x9e,0x20,0x32,0x5c,0xf6,0x17,0x8e,0x9c,0xf9,0x6b,0x65,0xef,0x8b,0x5,0xf5,0x1b,0x51,0xc1,0x39,0x49,0xf,0x2b,0xf8,0xc0,0xcd,0xd5,0xed,0xf1,0x47,0x24,0x70,0x60,0xca,0xdb,0x88,0xc3,0x19,0x0,0x10,0x3a,0xec,0x87,0x6c,0xda,0x14,0x58,0xb4,0x80,0x93,0xff,0x2a,0xf2,0x86,0x23,0x85,0x37,0xd6,0xa3,0xcb,0x61,0xbd,0xe4,0x4f,0x5b,0x63,0x5d,0x46,0x7,0x69,0xc7,0x50,0xe5,0xdc,0x8c,0xc,0xa7,0x77,0x41,0xfa,0xd2,0x53,0x52,0x6f,0xa,0xee,0x7b,0x29,0x6d,0xbf,0xe9,0x31,0xb,0x18,0xa8,0x30,0x7a,0x75,0xaa,0x64,0x7f,0xf3,0x42,0xe8,0x81,0xd0,0xa6,0x7d,0x3d,0x2d,0x68,0xb7,0x33,0xa1,0x26,0x76,0x55,0xfc,0x4,0xce,0x1e,0xe3,0x99,0xb6,0x8a,0xbb,0x4b,0xea,0x27,0xfe,0x89,0xf4,0x7c,0xe0,0x91,0xbc,0xc8,0xae,0x35,0x40,0x82,0xac,0x5a,0x9a,0x15,0xc4,0x8d,0x8f,0x2c,0xc2,0x71,0x1d,0xba,0x34,0xe2,0xcc,0xfd,0x90,0xd7,0x28,0x84,0x2,0xe7,0x78,0xb0,0x72,0x1,0x54,0xe,0xe5,0xc8,0x31,0xda,0xfe,0x18,0x42,0xb6,0x9b,0xbd,0x32,0xf5,0xbb,0x4a,0xb7,0x21,0x7d,0xdf,0x6,0x98,0xd1,0x69,0x50,0xdd,0xc7,0xe8,0x7,0xa1,0x35,0x51,0xb0,0xae,0xa7,0x1d,0xd0,0xd7,0x57,0x4d,0x7a,0x58,0xef,0x70,0xaa,0x11,0x8,0xbc,0x6c,0x14,0x2c,0xd3,0x30,0xd,0x12,0x60,0x44,0x68,0xc1,0x9a,0xf9,0x46,0xa3,0xa5,0x36,0xab,0x52,0x3c,0x2e,0x90,0x92,0x80,0x19,0xf8,0x43,0xbf,0x8d,0x1c,0x59,0xac,0x9c,0x91,0x64,0x77,0xcb,0x96,0x2b,0x20,0xd6,0x95,0x3,0x4b,0x38,0x93,0x1f,0x2f,0x40,0x99,0xcd,0x86,0xd5,0xc4,0x34,0x1e,0xe,0x17,0xff,0xe3,0xdb,0xc3,0x6e,0x7e,0x2a,0x49,0x47,0x37,0xcf,0x5f,0xce,0xf6,0x25,0x1,0xe1,0x6b,0x65,0xf7,0x15,0xfb,0xb,0x85,0x9,0x48,0x53,0x6d,0xeb,0x5e,0xc9,0x67,0x6f,0xc5,0xad,0xd8,0x55,0x41,0xea,0xb3,0xfc,0x24,0xf1,0x9d,0x39,0x8b,0x2d,0x88,0xd4,0x62,0x89,0xe2,0x8e,0xba,0x56,0x1a,0x71,0x6a,0xa4,0x7b,0x8f,0xe6,0x4c,0xfd,0x5,0x3f,0xe7,0xb1,0x74,0x3e,0xa6,0x16,0x4,0x61,0x5c,0x5d,0x63,0x27,0x75,0xe0,0xa9,0x2,0x82,0xd2,0xdc,0xf4,0x4f,0x79,0x72,0xfa,0x87,0xf0,0xc6,0xb2,0x9f,0xee,0x84,0xb8,0x97,0xed,0x29,0xe4,0x45,0xb5,0x5b,0x78,0x28,0xaf,0x10,0xc0,0xa,0xf2,0x33,0x73,0xa8,0xde,0x3d,0xb9,0x66,0x23,0xbe,0x76,0xe9,0xc,0x0,0x5a,0xf,0x7c,0xf3,0xc2,0xec,0x3a,0x8a,0x26,0xd9,0x9e,0x22,0x81,0x83,0xca,0xb4,0x13,0x7f,0xcc,0x8c,0x4e,0x3b,0xa0,0x1b,0x94,0x54,0xa2,0x8d,0x8b,0x83,0x1e,0xb2,0xe9,0x6e,0xd1,0x48,0x3a,0x40,0x6c,0xfb,0x4,0x25,0x18,0x94,0x20,0x3c,0x44,0x58,0xc7,0x39,0x82,0x65,0x7f,0x70,0x52,0x35,0x8f,0xff,0xf8,0x79,0x1d,0x86,0x98,0xc0,0xef,0x89,0x2f,0x41,0xf9,0xf5,0x78,0xf7,0x55,0xb0,0x2e,0x62,0x93,0x9,0x9f,0x95,0xb3,0xdd,0x1a,0x30,0xd6,0x9e,0x6a,0xe0,0xcd,0xf2,0x19,0xd3,0x3d,0xad,0x23,0x43,0xc9,0xdf,0x4d,0xde,0xe6,0x29,0xd,0x1f,0x6f,0x77,0xe7,0x56,0x46,0x61,0x2,0xcb,0xd7,0xeb,0xf3,0x36,0x1c,0x3f,0x26,0xae,0xe5,0xec,0xfd,0x7,0x37,0xb1,0x68,0x63,0x2b,0xbb,0x10,0x8,0x3,0xbd,0xfe,0x5f,0x4c,0xbe,0xe3,0x84,0x71,0xb9,0xb4,0x97,0x6b,0x34,0xa5,0xa8,0xba,0xd0,0x31,0x14,0x7a,0xb8,0x6,0xdc,0xf4,0x51,0x67,0x2a,0x81,0xfa,0xaa,0xf,0x4b,0xc8,0x5d,0x49,0x2c,0x75,0x74,0x16,0x5c,0x3e,0x8e,0x17,0x2d,0x99,0xcf,0xce,0xa7,0xd5,0x64,0x42,0x59,0x53,0x8c,0x92,0xa6,0x32,0x7e,0x4a,0xfc,0xca,0xa1,0xa3,0x11,0xa0,0x5,0xc,0xd4,0xb5,0xd9,0x69,0x7d,0x9b,0xc2,0xed,0x47,0xf0,0x85,0x76,0xc3,0x4f,0xe1,0x60,0x21,0x45,0x7b,0xbc,0x33,0x8a,0x7c,0x66,0xa4,0x88,0x13,0x3b,0x9c,0xe4,0x57,0xa9,0xa,0xe2,0xab,0xe,0xa2,0xb6,0xf1,0xea,0xdb,0x12,0xc4,0x72,0x28,0x54,0x27,0x5e,0x96,0x24,0xc1,0x91,0x15,0xb,0x4e,0x5b,0x1b,0xf6,0x80,0xe8,0x38,0xda,0x22,0x50,0x73,0x87,0x0,0xcc,0x1,0x9d,0x6d,0x90,0xac,0xc5,0xbf,0x9a,0xee,0xc6,0xb7,0xd2,0x5a,0xd8,0xaf,0x84,0x43,0xcc,0xea,0x50,0xc6,0x3b,0xca,0xab,0x40,0xb9,0x94,0xc7,0x33,0x69,0x8f,0xd0,0x76,0x99,0xb6,0xdf,0xc1,0x20,0x44,0xe9,0x77,0xae,0xc,0xac,0x21,0x18,0xa0,0x60,0xdb,0x1,0x9e,0x65,0x1d,0xcd,0x79,0xa6,0xa1,0x6c,0xd6,0x29,0xb,0x3c,0x26,0x37,0x88,0xeb,0xb0,0xda,0x47,0xd4,0xd2,0x7c,0x41,0xa2,0x5d,0x19,0x35,0x11,0x63,0x6d,0xfc,0xce,0x32,0xe0,0xed,0xdd,0x28,0xe1,0x5f,0x4d,0x23,0x89,0x68,0xf1,0xe3,0xe2,0x49,0x3a,0x72,0xe8,0x31,0x5e,0x6e,0xe7,0xba,0x6,0x15,0xe4,0xa7,0x51,0x5a,0xb2,0xaa,0x92,0x8e,0x38,0x5b,0xf,0x1f,0xb5,0xa4,0xf7,0xbc,0x66,0x7f,0x6f,0x45,0x86,0x14,0x1a,0x90,0xf4,0x7a,0x8a,0x64,0x2e,0xbe,0x46,0x36,0x70,0x54,0x87,0xbf,0xa9,0xdc,0xb4,0x1e,0xc2,0x9b,0x30,0x24,0x1c,0x22,0x39,0x78,0x16,0xb8,0x2f,0x9a,0x93,0xf8,0x13,0xa5,0x6b,0x27,0xcb,0xff,0xec,0x80,0x55,0x8d,0xf9,0x5c,0xfa,0x48,0xc0,0x96,0x4e,0x74,0x67,0xd7,0x4f,0x5,0xa,0xd5,0x1b,0x0,0x8c,0x3d,0x97,0xfe,0xa3,0xf3,0x73,0xd8,0x8,0x3e,0x85,0xad,0x2c,0x2d,0x10,0x75,0x91,0x4,0x56,0x12,0x9c,0xe6,0xc9,0xf5,0xc4,0x34,0x95,0x58,0x81,0xf6,0x8b,0x3,0x9f,0xee,0xc3,0xb7,0xaf,0xd9,0x2,0x42,0x52,0x17,0xc8,0x4c,0xde,0x59,0x9,0x2a,0x83,0x7b,0xb1,0x61,0x4b,0x9d,0xb3,0x82,0xef,0xa8,0x57,0xfb,0x7d,0x98,0x7,0xcf,0xd,0x7e,0x2b,0x71,0xd1,0x4a,0x3f,0xfd,0xd3,0x25,0xe5,0x6a,0xbb,0xf2,0xf0,0x53,0xbd,0xe,0x62,0xc5,0xda,0x7c,0x93,0xbc,0xd5,0xcb,0x2a,0x4e,0xe3,0x7d,0xa4,0x6,0xa6,0x2b,0x12,0xaa,0x8e,0x49,0xc6,0xe0,0x5a,0xcc,0x31,0xc0,0xa1,0x4a,0xb3,0x9e,0xcd,0x39,0x63,0x85,0x3d,0x82,0xe1,0xba,0xd0,0x4d,0xde,0xd8,0x76,0x4b,0xa8,0x57,0x13,0x3f,0x1b,0x69,0x6a,0xd1,0xb,0x94,0x6f,0x17,0xc7,0x73,0xac,0xab,0x66,0xdc,0x23,0x1,0x36,0x2c,0xe8,0x43,0x30,0x78,0xe2,0x3b,0x54,0x64,0xed,0xb0,0xc,0x1f,0xee,0xad,0x5b,0x50,0x67,0xf6,0xc4,0x38,0xea,0xe7,0xd7,0x22,0xeb,0x55,0x47,0x29,0x83,0x62,0xfb,0xe9,0x8c,0x1e,0x10,0x9a,0xfe,0x70,0x80,0x6e,0x24,0xb4,0x4c,0x3c,0x7a,0x5e,0x8d,0xb5,0xb8,0xa0,0x98,0x84,0x32,0x51,0x5,0x15,0xbf,0xae,0xfd,0xb6,0x6c,0x75,0x65,0x4f,0x99,0xf2,0x19,0xaf,0x61,0x2d,0xc1,0xf5,0xe6,0x8a,0x5f,0x87,0xf3,0x56,0xf0,0x42,0xa3,0xd6,0xbe,0x14,0xc8,0x91,0x3a,0x2e,0x16,0x28,0x33,0x72,0x1c,0xb2,0x25,0x90,0xa9,0xf9,0x79,0xd2,0x2,0x34,0x8f,0xa7,0x26,0x27,0x1a,0x7f,0x9b,0xe,0x5c,0x18,0xca,0x9c,0x44,0x7e,0x6d,0xdd,0x45,0xf,0x0,0xdf,0x11,0xa,0x86,0x37,0x9d,0xf4,0xa5,0xd3,0x8,0x48,0x58,0x1d,0xc2,0x46,0xd4,0x53,0x3,0x20,0x89,0x71,0xbb,0x6b,0x96,0xec,0xc3,0xff,0xce,0x3e,0x9f,0x52,0x8b,0xfc,0x81,0x9,0x95,0xe4,0xc9,0xbd,0xdb,0x40,0x35,0xf7,0xd9,0x2f,0xef,0x60,0xb1,0xf8,0xfa,0x59,0xb7,0x4,0x68,0xcf,0x41,0x97,0xb9,0x88,0xe5,0xa2,0x5d,0xf1,0x77,0x92,0xd,0xc5,0x7,0x74,0x21,0x7b,0x3f,0x12,0xeb,0x0,0x24,0xc2,0x98,0x6c,0x41,0x67,0xe8,0x2f,0x61,0x90,0x6d,0xfb,0xa7,0x5,0xdc,0x42,0xb,0xb3,0x8a,0x7,0x1d,0x32,0xdd,0x7b,0xef,0x8b,0x6a,0x74,0x7d,0xc7,0xa,0xd,0x8d,0x97,0xa0,0x82,0x35,0xaa,0x70,0xcb,0xd2,0x66,0xb6,0xce,0xf6,0x9,0xea,0xd7,0xc8,0xba,0x9e,0xb2,0x1b,0x40,0x23,0x9c,0x79,0x7f,0xec,0x71,0x88,0xe6,0xf4,0x4a,0x48,0x5a,0xc3,0x22,0x99,0x65,0x57,0xc6,0x83,0x76,0x46,0x4b,0xbe,0xad,0x11,0x4c,0xf1,0xfa,0xc,0x4f,0xd9,0x91,0xe2,0x49,0xc5,0xf5,0x9a,0x43,0x17,0x5c,0xf,0x1e,0xee,0xc4,0xd4,0xcd,0x25,0x39,0x1,0x19,0xb4,0xa4,0xf0,0x93,0x9d,0xed,0x15,0x85,0x14,0x2c,0xff,0xdb,0x3b,0xb1,0xbf,0x2d,0xcf,0x21,0xd1,0x5f,0xd3,0x92,0x89,0xb7,0x31,0x84,0x13,0xbd,0xb5,0x1f,0x77,0x2,0x8f,0x9b,0x30,0x69,0x26,0xfe,0x2b,0x47,0xe3,0x51,0xf7,0x52,0xe,0xb8,0x53,0x38,0x54,0x60,0x8c,0xc0,0xab,0xb0,0x7e,0xa1,0x55,0x3c,0x96,0x27,0xdf,0xe5,0x3d,0x6b,0xae,0xe4,0x7c,0xcc,0xde,0xbb,0x86,0x87,0xb9,0xfd,0xaf,0x3a,0x73,0xd8,0x58,0x8,0x6,0x2e,0x95,0xa3,0xa8,0x20,0x5d,0x2a,0x1c,0x68,0x45,0x34,0x5e,0x62,0x4d,0x37,0xf3,0x3e,0x9f,0x6f,0x81,0xa2,0xf2,0x75,0xca,0x1a,0xd0,0x28,0xe9,0xa9,0x72,0x4,0xe7,0x63,0xbc,0xf9,0x64,0xac,0x33,0xd6,0xda,0x80,0xd5,0xa6,0x29,0x18,0x36,0xe0,0x50,0xfc,0x3,0x44,0xf8,0x5b,0x59,0x10,0x6e,0xc9,0xa5,0x16,0x56,0x94,0xe1,0x7a,0xc1,0x4e,0x8e,0x78,0xe6,0xe0,0xe8,0x75,0xd9,0x82,0x5,0xba,0x23,0x51,0x2b,0x7,0x90,0x6f,0x4e,0x73,0xff,0x4b,0x57,0x2f,0x33,0xac,0x52,0xe9,0xe,0x14,0x1b,0x39,0x5e,0xe4,0x94,0x93,0x12,0x76,0xed,0xf3,0xab,0x84,0xe2,0x44,0x2a,0x92,0x9e,0x13,0x9c,0x3e,0xdb,0x45,0x9,0xf8,0x62,0xf4,0xfe,0xd8,0xb6,0x71,0x5b,0xbd,0xf5,0x1,0x8b,0xa6,0x99,0x72,0xb8,0x56,0xc6,0x48,0x28,0xa2,0xb4,0x26,0xb5,0x8d,0x42,0x66,0x74,0x4,0x1c,0x8c,0x3d,0x2d,0xa,0x69,0xa0,0xbc,0x80,0x98,0x5d,0x77,0x54,0x4d,0xc5,0x8e,0x87,0x96,0x6c,0x5c,0xda,0x3,0x8,0x40,0xd0,0x7b,0x63,0x68,0xd6,0x95,0x34,0x27,0xd5,0x88,0xef,0x1a,0xd2,0xdf,0xfc,0x0,0x5f,0xce,0xc3,0xd1,0xbb,0x5a,0x7f,0x11,0xd3,0x6d,0xb7,0x9f,0x3a,0xc,0x41,0xea,0x91,0xc1,0x64,0x20,0xa3,0x36,0x22,0x47,0x1e,0x1f,0x7d,0x37,0x55,0xe5,0x7c,0x46,0xf2,0xa4,0xa5,0xcc,0xbe,0xf,0x29,0x32,0x38,0xe7,0xf9,0xcd,0x59,0x15,0x21,0x97,0xa1,0xca,0xc8,0x7a,0xcb,0x6e,0x67,0xbf,0xde,0xb2,0x2,0x16,0xf0,0xa9,0x86,0x2c,0x9b,0xee,0x1d,0xa8,0x24,0x8a,0xb,0x4a,0x2e,0x10,0xd7,0x58,0xe1,0x17,0xd,0xcf,0xe3,0x78,0x50,0xf7,0x8f,0x3c,0xc2,0x61,0x89,0xc0,0x65,0xc9,0xdd,0x9a,0x81,0xb0,0x79,0xaf,0x19,0x43,0x3f,0x4c,0x35,0xfd,0x4f,0xaa,0xfa,0x7e,0x60,0x25,0x30,0x70,0x9d,0xeb,0x83,0x53,0xb1,0x49,0x3b,0x18,0xec,0x6b,0xa7,0x6a,0xf6,0x6,0xfb,0xc7,0xae,0xd4,0xf1,0x85,0xad,0xdc,0xb9,0x31,0xb3,0xc4,0x41,0x86,0x9,0x2f,0x95,0x3,0xfe,0xf,0x6e,0x85,0x7c,0x51,0x2,0xf6,0xac,0x4a,0x15,0xb3,0x5c,0x73,0x1a,0x4,0xe5,0x81,0x2c,0xb2,0x6b,0xc9,0x69,0xe4,0xdd,0x65,0xa5,0x1e,0xc4,0x5b,0xa0,0xd8,0x8,0xbc,0x63,0x64,0xa9,0x13,0xec,0xce,0xf9,0xe3,0xf2,0x4d,0x2e,0x75,0x1f,0x82,0x11,0x17,0xb9,0x84,0x67,0x98,0xdc,0xf0,0xd4,0xa6,0xa8,0x39,0xb,0xf7,0x25,0x28,0x18,0xed,0x24,0x9a,0x88,0xe6,0x4c,0xad,0x34,0x26,0x27,0x8c,0xff,0xb7,0x2d,0xf4,0x9b,0xab,0x22,0x7f,0xc3,0xd0,0x21,0x62,0x94,0x9f,0x77,0x6f,0x57,0x4b,0xfd,0x9e,0xca,0xda,0x70,0x61,0x32,0x79,0xa3,0xba,0xaa,0x80,0x43,0xd1,0xdf,0x55,0x31,0xbf,0x4f,0xa1,0xeb,0x7b,0x83,0xf3,0xb5,0x91,0x42,0x7a,0x6c,0x19,0x71,0xdb,0x7,0x5e,0xf5,0xe1,0xd9,0xe7,0xfc,0xbd,0xd3,0x7d,0xea,0x5f,0x56,0x3d,0xd6,0x60,0xae,0xe2,0xe,0x3a,0x29,0x45,0x90,0x48,0x3c,0x99,0x3f,0x8d,0x5,0x53,0x8b,0xb1,0xa2,0x12,0x8a,0xc0,0xcf,0x10,0xde,0xc5,0x49,0xf8,0x52,0x3b,0x66,0x36,0xb6,0x1d,0xcd,0xfb,0x40,0x68,0xe9,0xe8,0xd5,0xb0,0x54,0xc1,0x93,0xd7,0x59,0x23,0xc,0x30,0x1,0xf1,0x50,0x9d,0x44,0x33,0x4e,0xc6,0x5a,0x2b,0x6,0x72,0x6a,0x1c,0xc7,0x87,0x97,0xd2,0xd,0x89,0x1b,0x9c,0xcc,0xef,0x46,0xbe,0x74,0xa4,0x8e,0x58,0x76,0x47,0x2a,0x6d,0x92,0x3e,0xb8,0x5d,0xc2,0xa,0xc8,0xbb,0xee,0xb4,0x14,0x8f,0xfa,0x38,0x16,0xe0,0x20,0xaf,0x7e,0x37,0x35,0x96,0x78,0xcb,0xa7,0x0,0x6d,0xcb,0x24,0xb,0x62,0x7c,0x9d,0xf9,0x54,0xca,0x13,0xb1,0x11,0x9c,0xa5,0x1d,0x39,0xfe,0x71,0x57,0xed,0x7b,0x86,0x77,0x16,0xfd,0x4,0x29,0x7a,0x8e,0xd4,0x32,0x8a,0x35,0x56,0xd,0x67,0xfa,0x69,0x6f,0xc1,0xfc,0x1f,0xe0,0xa4,0x88,0xac,0xde,0xdd,0x66,0xbc,0x23,0xd8,0xa0,0x70,0xc4,0x1b,0x1c,0xd1,0x6b,0x94,0xb6,0x81,0x9b,0x5f,0xf4,0x87,0xcf,0x55,0x8c,0xe3,0xd3,0x5a,0x7,0xbb,0xa8,0x59,0x1a,0xec,0xe7,0xd0,0x41,0x73,0x8f,0x5d,0x50,0x60,0x95,0x5c,0xe2,0xf0,0x9e,0x34,0xd5,0x4c,0x5e,0x3b,0xa9,0xa7,0x2d,0x49,0xc7,0x37,0xd9,0x93,0x3,0xfb,0x8b,0xcd,0xe9,0x3a,0x2,0xf,0x17,0x2f,0x33,0x85,0xe6,0xb2,0xa2,0x8,0x19,0x4a,0x1,0xdb,0xc2,0xd2,0xf8,0x2e,0x45,0xae,0x18,0xd6,0x9a,0x76,0x42,0x51,0x3d,0xe8,0x30,0x44,0xe1,0x47,0xf5,0x14,0x61,0x9,0xa3,0x7f,0x26,0x8d,0x99,0xa1,0x9f,0x84,0xc5,0xab,0x5,0x92,0x27,0x1e,0x4e,0xce,0x65,0xb5,0x83,0x38,0x10,0x91,0x90,0xad,0xc8,0x2c,0xb9,0xeb,0xaf,0x7d,0x2b,0xf3,0xc9,0xda,0x6a,0xf2,0xb8,0xb7,0x68,0xa6,0xbd,0x31,0x80,0x2a,0x43,0x12,0x64,0xbf,0xff,0xef,0xaa,0x75,0xf1,0x63,0xe4,0xb4,0x97,0x3e,0xc6,0xc,0xdc,0x21,0x5b,0x74,0x48,0x79,0x89,0x28,0xe5,0x3c,0x4b,0x36,0xbe,0x22,0x53,0x7e,0xa,0x6c,0xf7,0x82,0x40,0x6e,0x98,0x58,0xd7,0x6,0x4f,0x4d,0xee,0x0,0xb3,0xdf,0x78,0xf6,0x20,0xe,0x3f,0x52,0x15,0xea,0x46,0xc0,0x25,0xba,0x72,0xb0,0xc3,0x96,0xcc,0xb8,0x95,0x6c,0x87,0xa3,0x45,0x1f,0xeb,0xc6,0xe0,0x6f,0xa8,0xe6,0x17,0xea,0x7c,0x20,0x82,0x5b,0xc5,0x8c,0x34,0xd,0x80,0x9a,0xb5,0x5a,0xfc,0x68,0xc,0xed,0xf3,0xfa,0x40,0x8d,0x8a,0xa,0x10,0x27,0x5,0xb2,0x2d,0xf7,0x4c,0x55,0xe1,0x31,0x49,0x71,0x8e,0x6d,0x50,0x4f,0x3d,0x19,0x35,0x9c,0xc7,0xa4,0x1b,0xfe,0xf8,0x6b,0xf6,0xf,0x61,0x73,0xcd,0xcf,0xdd,0x44,0xa5,0x1e,0xe2,0xd0,0x41,0x4,0xf1,0xc1,0xcc,0x39,0x2a,0x96,0xcb,0x76,0x7d,0x8b,0xc8,0x5e,0x16,0x65,0xce,0x42,0x72,0x1d,0xc4,0x90,0xdb,0x88,0x99,0x69,0x43,0x53,0x4a,0xa2,0xbe,0x86,0x9e,0x33,0x23,0x77,0x14,0x1a,0x6a,0x92,0x2,0x93,0xab,0x78,0x5c,0xbc,0x36,0x38,0xaa,0x48,0xa6,0x56,0xd8,0x54,0x15,0xe,0x30,0xb6,0x3,0x94,0x3a,0x32,0x98,0xf0,0x85,0x8,0x1c,0xb7,0xee,0xa1,0x79,0xac,0xc0,0x64,0xd6,0x70,0xd5,0x89,0x3f,0xd4,0xbf,0xd3,0xe7,0xb,0x47,0x2c,0x37,0xf9,0x26,0xd2,0xbb,0x11,0xa0,0x58,0x62,0xba,0xec,0x29,0x63,0xfb,0x4b,0x59,0x3c,0x1,0x0,0x3e,0x7a,0x28,0xbd,0xf4,0x5f,0xdf,0x8f,0x81,0xa9,0x12,0x24,0x2f,0xa7,0xda,0xad,0x9b,0xef,0xc2,0xb3,0xd9,0xe5,0xca,0xb0,0x74,0xb9,0x18,0xe8,0x6,0x25,0x75,0xf2,0x4d,0x9d,0x57,0xaf,0x6e,0x2e,0xf5,0x83,0x60,0xe4,0x3b,0x7e,0xe3,0x2b,0xb4,0x51,0x5d,0x7,0x52,0x21,0xae,0x9f,0xb1,0x67,0xd7,0x7b,0x84,0xc3,0x7f,0xdc,0xde,0x97,0xe9,0x4e,0x22,0x91,0xd1,0x13,0x66,0xfd,0x46,0xc9,0x9,0xff,0x76,0x70,0x78,0xe5,0x49,0x12,0x95,0x2a,0xb3,0xc1,0xbb,0x97,0x0,0xff,0xde,0xe3,0x6f,0xdb,0xc7,0xbf,0xa3,0x3c,0xc2,0x79,0x9e,0x84,0x8b,0xa9,0xce,0x74,0x4,0x3,0x82,0xe6,0x7d,0x63,0x3b,0x14,0x72,0xd4,0xba,0x2,0xe,0x83,0xc,0xae,0x4b,0xd5,0x99,0x68,0xf2,0x64,0x6e,0x48,0x26,0xe1,0xcb,0x2d,0x65,0x91,0x1b,0x36,0x9,0xe2,0x28,0xc6,0x56,0xd8,0xb8,0x32,0x24,0xb6,0x25,0x1d,0xd2,0xf6,0xe4,0x94,0x8c,0x1c,0xad,0xbd,0x9a,0xf9,0x30,0x2c,0x10,0x8,0xcd,0xe7,0xc4,0xdd,0x55,0x1e,0x17,0x6,0xfc,0xcc,0x4a,0x93,0x98,0xd0,0x40,0xeb,0xf3,0xf8,0x46,0x5,0xa4,0xb7,0x45,0x18,0x7f,0x8a,0x42,0x4f,0x6c,0x90,0xcf,0x5e,0x53,0x41,0x2b,0xca,0xef,0x81,0x43,0xfd,0x27,0xf,0xaa,0x9c,0xd1,0x7a,0x1,0x51,0xf4,0xb0,0x33,0xa6,0xb2,0xd7,0x8e,0x8f,0xed,0xa7,0xc5,0x75,0xec,0xd6,0x62,0x34,0x35,0x5c,0x2e,0x9f,0xb9,0xa2,0xa8,0x77,0x69,0x5d,0xc9,0x85,0xb1,0x7,0x31,0x5a,0x58,0xea,0x5b,0xfe,0xf7,0x2f,0x4e,0x22,0x92,0x86,0x60,0x39,0x16,0xbc,0xb,0x7e,0x8d,0x38,0xb4,0x1a,0x9b,0xda,0xbe,0x80,0x47,0xc8,0x71,0x87,0x9d,0x5f,0x73,0xe8,0xc0,0x67,0x1f,0xac,0x52,0xf1,0x19,0x50,0xf5,0x59,0x4d,0xa,0x11,0x20,0xe9,0x3f,0x89,0xd3,0xaf,0xdc,0xa5,0x6d,0xdf,0x3a,0x6a,0xee,0xf0,0xb5,0xa0,0xe0,0xd,0x7b,0x13,0xc3,0x21,0xd9,0xab,0x88,0x7c,0xfb,0x37,0xfa,0x66,0x96,0x6b,0x57,0x3e,0x44,0x61,0x15,0x3d,0x4c,0x29,0xa1,0x23,0x54,0xc8,0xf,0x80,0xa6,0x1c,0x8a,0x77,0x86,0xe7,0xc,0xf5,0xd8,0x8b,0x7f,0x25,0xc3,0x9c,0x3a,0xd5,0xfa,0x93,0x8d,0x6c,0x8,0xa5,0x3b,0xe2,0x40,0xe0,0x6d,0x54,0xec,0x2c,0x97,0x4d,0xd2,0x29,0x51,0x81,0x35,0xea,0xed,0x20,0x9a,0x65,0x47,0x70,0x6a,0x7b,0xc4,0xa7,0xfc,0x96,0xb,0x98,0x9e,0x30,0xd,0xee,0x11,0x55,0x79,0x5d,0x2f,0x21,0xb0,0x82,0x7e,0xac,0xa1,0x91,0x64,0xad,0x13,0x1,0x6f,0xc5,0x24,0xbd,0xaf,0xae,0x5,0x76,0x3e,0xa4,0x7d,0x12,0x22,0xab,0xf6,0x4a,0x59,0xa8,0xeb,0x1d,0x16,0xfe,0xe6,0xde,0xc2,0x74,0x17,0x43,0x53,0xf9,0xe8,0xbb,0xf0,0x2a,0x33,0x23,0x9,0xca,0x58,0x56,0xdc,0xb8,0x36,0xc6,0x28,0x62,0xf2,0xa,0x7a,0x3c,0x18,0xcb,0xf3,0xe5,0x90,0xf8,0x52,0x8e,0xd7,0x7c,0x68,0x50,0x6e,0x75,0x34,0x5a,0xf4,0x63,0xd6,0xdf,0xb4,0x5f,0xe9,0x27,0x6b,0x87,0xb3,0xa0,0xcc,0x19,0xc1,0xb5,0x10,0xb6,0x4,0x8c,0xda,0x2,0x38,0x2b,0x9b,0x3,0x49,0x46,0x99,0x57,0x4c,0xc0,0x71,0xdb,0xb2,0xef,0xbf,0x3f,0x94,0x44,0x72,0xc9,0xe1,0x60,0x61,0x5c,0x39,0xdd,0x48,0x1a,0x5e,0xd0,0xaa,0x85,0xb9,0x88,0x78,0xd9,0x14,0xcd,0xba,0xc7,0x4f,0xd3,0xa2,0x8f,0xfb,0xe3,0x95,0x4e,0xe,0x1e,0x5b,0x84,0x0,0x92,0x15,0x45,0x66,0xcf,0x37,0xfd,0x2d,0x7,0xd1,0xff,0xce,0xa3,0xe4,0x1b,0xb7,0x31,0xd4,0x4b,0x83,0x41,0x32,0x67,0x3d,0x9d,0x6,0x73,0xb1,0x9f,0x69,0xa9,0x26,0xf7,0xbe,0xbc,0x1f,0xf1,0x42,0x2e,0x89,0xa3,0x5,0xea,0xc5,0xac,0xb2,0x53,0x37,0x9a,0x4,0xdd,0x7f,0xdf,0x52,0x6b,0xd3,0xf7,0x30,0xbf,0x99,0x23,0xb5,0x48,0xb9,0xd8,0x33,0xca,0xe7,0xb4,0x40,0x1a,0xfc,0x44,0xfb,0x98,0xc3,0xa9,0x34,0xa7,0xa1,0xf,0x32,0xd1,0x2e,0x6a,0x46,0x62,0x10,0x13,0xa8,0x72,0xed,0x16,0x6e,0xbe,0xa,0xd5,0xd2,0x1f,0xa5,0x5a,0x78,0x4f,0x55,0x91,0x3a,0x49,0x1,0x9b,0x42,0x2d,0x1d,0x94,0xc9,0x75,0x66,0x97,0xd4,0x22,0x29,0x1e,0x8f,0xbd,0x41,0x93,0x9e,0xae,0x5b,0x92,0x2c,0x3e,0x50,0xfa,0x1b,0x82,0x90,0xf5,0x67,0x69,0xe3,0x87,0x9,0xf9,0x17,0x5d,0xcd,0x35,0x45,0x3,0x27,0xf4,0xcc,0xc1,0xd9,0xe1,0xfd,0x4b,0x28,0x7c,0x6c,0xc6,0xd7,0x84,0xcf,0x15,0xc,0x1c,0x36,0xe0,0x8b,0x60,0xd6,0x18,0x54,0xb8,0x8c,0x9f,0xf3,0x26,0xfe,0x8a,0x2f,0x89,0x3b,0xda,0xaf,0xc7,0x6d,0xb1,0xe8,0x43,0x57,0x6f,0x51,0x4a,0xb,0x65,0xcb,0x5c,0xe9,0xd0,0x80,0x0,0xab,0x7b,0x4d,0xf6,0xde,0x5f,0x5e,0x63,0x6,0xe2,0x77,0x25,0x61,0xb3,0xe5,0x3d,0x7,0x14,0xa4,0x3c,0x76,0x79,0xa6,0x68,0x73,0xff,0x4e,0xe4,0x8d,0xdc,0xaa,0x71,0x31,0x21,0x64,0xbb,0x3f,0xad,0x2a,0x7a,0x59,0xf0,0x8,0xc2,0x12,0xef,0x95,0xba,0x86,0xb7,0x47,0xe6,0x2b,0xf2,0x85,0xf8,0x70,0xec,0x9d,0xb0,0xc4,0xa2,0x39,0x4c,0x8e,0xa0,0x56,0x96,0x19,0xc8,0x81,0x83,0x20,0xce,0x7d,0x11,0xb6,0x38,0xee,0xc0,0xf1,0x9c,0xdb,0x24,0x88,0xe,0xeb,0x74,0xbc,0x7e,0xd,0x58,0x2,0x9f,0xb2,0x4b,0xa0,0x84,0x62,0x38,0xcc,0xe1,0xc7,0x48,0x8f,0xc1,0x30,0xcd,0x5b,0x7,0xa5,0x7c,0xe2,0xab,0x13,0x2a,0xa7,0xbd,0x92,0x7d,0xdb,0x4f,0x2b,0xca,0xd4,0xdd,0x67,0xaa,0xad,0x2d,0x37,0x0,0x22,0x95,0xa,0xd0,0x6b,0x72,0xc6,0x16,0x6e,0x56,0xa9,0x4a,0x77,0x68,0x1a,0x3e,0x12,0xbb,0xe0,0x83,0x3c,0xd9,0xdf,0x4c,0xd1,0x28,0x46,0x54,0xea,0xe8,0xfa,0x63,0x82,0x39,0xc5,0xf7,0x66,0x23,0xd6,0xe6,0xeb,0x1e,0xd,0xb1,0xec,0x51,0x5a,0xac,0xef,0x79,0x31,0x42,0xe9,0x65,0x55,0x3a,0xe3,0xb7,0xfc,0xaf,0xbe,0x4e,0x64,0x74,0x6d,0x85,0x99,0xa1,0xb9,0x14,0x4,0x50,0x33,0x3d,0x4d,0xb5,0x25,0xb4,0x8c,0x5f,0x7b,0x9b,0x11,0x1f,0x8d,0x6f,0x81,0x71,0xff,0x73,0x32,0x29,0x17,0x91,0x24,0xb3,0x1d,0x15,0xbf,0xd7,0xa2,0x2f,0x3b,0x90,0xc9,0x86,0x5e,0x8b,0xe7,0x43,0xf1,0x57,0xf2,0xae,0x18,0xf3,0x98,0xf4,0xc0,0x2c,0x60,0xb,0x10,0xde,0x1,0xf5,0x9c,0x36,0x87,0x7f,0x45,0x9d,0xcb,0xe,0x44,0xdc,0x6c,0x7e,0x1b,0x26,0x27,0x19,0x5d,0xf,0x9a,0xd3,0x78,0xf8,0xa8,0xa6,0x8e,0x35,0x3,0x8,0x80,0xfd,0x8a,0xbc,0xc8,0xe5,0x94,0xfe,0xc2,0xed,0x97,0x53,0x9e,0x3f,0xcf,0x21,0x2,0x52,0xd5,0x6a,0xba,0x70,0x88,0x49,0x9,0xd2,0xa4,0x47,0xc3,0x1c,0x59,0xc4,0xc,0x93,0x76,0x7a,0x20,0x75,0x6,0x89,0xb8,0x96,0x40,0xf0,0x5c,0xa3,0xe4,0x58,0xfb,0xf9,0xb0,0xce,0x69,0x5,0xb6,0xf6,0x34,0x41,0xda,0x61,0xee,0x2e,0xd8,0xa2,0xa4,0xac,0x31,0x9d,0xc6,0x41,0xfe,0x67,0x15,0x6f,0x43,0xd4,0x2b,0xa,0x37,0xbb,0xf,0x13,0x6b,0x77,0xe8,0x16,0xad,0x4a,0x50,0x5f,0x7d,0x1a,0xa0,0xd0,0xd7,0x56,0x32,0xa9,0xb7,0xef,0xc0,0xa6,0x0,0x6e,0xd6,0xda,0x57,0xd8,0x7a,0x9f,0x1,0x4d,0xbc,0x26,0xb0,0xba,0x9c,0xf2,0x35,0x1f,0xf9,0xb1,0x45,0xcf,0xe2,0xdd,0x36,0xfc,0x12,0x82,0xc,0x6c,0xe6,0xf0,0x62,0xf1,0xc9,0x6,0x22,0x30,0x40,0x58,0xc8,0x79,0x69,0x4e,0x2d,0xe4,0xf8,0xc4,0xdc,0x19,0x33,0x10,0x9,0x81,0xca,0xc3,0xd2,0x28,0x18,0x9e,0x47,0x4c,0x4,0x94,0x3f,0x27,0x2c,0x92,0xd1,0x70,0x63,0x91,0xcc,0xab,0x5e,0x96,0x9b,0xb8,0x44,0x1b,0x8a,0x87,0x95,0xff,0x1e,0x3b,0x55,0x97,0x29,0xf3,0xdb,0x7e,0x48,0x5,0xae,0xd5,0x85,0x20,0x64,0xe7,0x72,0x66,0x3,0x5a,0x5b,0x39,0x73,0x11,0xa1,0x38,0x2,0xb6,0xe0,0xe1,0x88,0xfa,0x4b,0x6d,0x76,0x7c,0xa3,0xbd,0x89,0x1d,0x51,0x65,0xd3,0xe5,0x8e,0x8c,0x3e,0x8f,0x2a,0x23,0xfb,0x9a,0xf6,0x46,0x52,0xb4,0xed,0xc2,0x68,0xdf,0xaa,0x59,0xec,0x60,0xce,0x4f,0xe,0x6a,0x54,0x93,0x1c,0xa5,0x53,0x49,0x8b,0xa7,0x3c,0x14,0xb3,0xcb,0x78,0x86,0x25,0xcd,0x84,0x21,0x8d,0x99,0xde,0xc5,0xf4,0x3d,0xeb,0x5d,0x7,0x7b,0x8,0x71,0xb9,0xb,0xee,0xbe,0x3a,0x24,0x61,0x74,0x34,0xd9,0xaf,0xc7,0x17,0xf5,0xd,0x7f,0x5c,0xa8,0x2f,0xe3,0x2e,0xb2,0x42,0xbf,0x83,0xea,0x90,0xb5,0xc1,0xe9,0x98,0xfd,0x75,0xf7,0x80,0x2d,0xea,0x65,0x43,0xf9,0x6f,0x92,0x63,0x2,0xe9,0x10,0x3d,0x6e,0x9a,0xc0,0x26,0x79,0xdf,0x30,0x1f,0x76,0x68,0x89,0xed,0x40,0xde,0x7,0xa5,0x5,0x88,0xb1,0x9,0xc9,0x72,0xa8,0x37,0xcc,0xb4,0x64,0xd0,0xf,0x8,0xc5,0x7f,0x80,0xa2,0x95,0x8f,0x9e,0x21,0x42,0x19,0x73,0xee,0x7d,0x7b,0xd5,0xe8,0xb,0xf4,0xb0,0x9c,0xb8,0xca,0xc4,0x55,0x67,0x9b,0x49,0x44,0x74,0x81,0x48,0xf6,0xe4,0x8a,0x20,0xc1,0x58,0x4a,0x4b,0xe0,0x93,0xdb,0x41,0x98,0xf7,0xc7,0x4e,0x13,0xaf,0xbc,0x4d,0xe,0xf8,0xf3,0x1b,0x3,0x3b,0x27,0x91,0xf2,0xa6,0xb6,0x1c,0xd,0x5e,0x15,0xcf,0xd6,0xc6,0xec,0x2f,0xbd,0xb3,0x39,0x5d,0xd3,0x23,0xcd,0x87,0x17,0xef,0x9f,0xd9,0xfd,0x2e,0x16,0x0,0x75,0x1d,0xb7,0x6b,0x32,0x99,0x8d,0xb5,0x8b,0x90,0xd1,0xbf,0x11,0x86,0x33,0x3a,0x51,0xba,0xc,0xc2,0x8e,0x62,0x56,0x45,0x29,0xfc,0x24,0x50,0xf5,0x53,0xe1,0x69,0x3f,0xe7,0xdd,0xce,0x7e,0xe6,0xac,0xa3,0x7c,0xb2,0xa9,0x25,0x94,0x3e,0x57,0xa,0x5a,0xda,0x71,0xa1,0x97,0x2c,0x4,0x85,0x84,0xb9,0xdc,0x38,0xad,0xff,0xbb,0x35,0x4f,0x60,0x5c,0x6d,0x9d,0x3c,0xf1,0x28,0x5f,0x22,0xaa,0x36,0x47,0x6a,0x1e,0x6,0x70,0xab,0xeb,0xfb,0xbe,0x61,0xe5,0x77,0xf0,0xa0,0x83,0x2a,0xd2,0x18,0xc8,0xe2,0x34,0x1a,0x2b,0x46,0x1,0xfe,0x52,0xd4,0x31,0xae,0x66,0xa4,0xd7,0x82,0xd8,0x78,0xe3,0x96,0x54,0x7a,0x8c,0x4c,0xc3,0x12,0x5b,0x59,0xfa,0x14,0xa7,0xcb,0x6c,0x47,0xe1,0xe,0x21,0x48,0x56,0xb7,0xd3,0x7e,0xe0,0x39,0x9b,0x3b,0xb6,0x8f,0x37,0x13,0xd4,0x5b,0x7d,0xc7,0x51,0xac,0x5d,0x3c,0xd7,0x2e,0x3,0x50,0xa4,0xfe,0x18,0xa0,0x1f,0x7c,0x27,0x4d,0xd0,0x43,0x45,0xeb,0xd6,0x35,0xca,0x8e,0xa2,0x86,0xf4,0xf7,0x4c,0x96,0x9,0xf2,0x8a,0x5a,0xee,0x31,0x36,0xfb,0x41,0xbe,0x9c,0xab,0xb1,0x75,0xde,0xad,0xe5,0x7f,0xa6,0xc9,0xf9,0x70,0x2d,0x91,0x82,0x73,0x30,0xc6,0xcd,0xfa,0x6b,0x59,0xa5,0x77,0x7a,0x4a,0xbf,0x76,0xc8,0xda,0xb4,0x1e,0xff,0x66,0x74,0x11,0x83,0x8d,0x7,0x63,0xed,0x1d,0xf3,0xb9,0x29,0xd1,0xa1,0xe7,0xc3,0x10,0x28,0x25,0x3d,0x5,0x19,0xaf,0xcc,0x98,0x88,0x22,0x33,0x60,0x2b,0xf1,0xe8,0xf8,0xd2,0x4,0x6f,0x84,0x32,0xfc,0xb0,0x5c,0x68,0x7b,0x17,0xc2,0x1a,0x6e,0xcb,0x6d,0xdf,0x3e,0x4b,0x23,0x89,0x55,0xc,0xa7,0xb3,0x8b,0xb5,0xae,0xef,0x81,0x2f,0xb8,0xd,0x34,0x64,0xe4,0x4f,0x9f,0xa9,0x12,0x3a,0xbb,0xba,0x87,0xe2,0x6,0x93,0xc1,0x85,0x57,0x1,0xd9,0xe3,0xf0,0x40,0xd8,0x92,0x9d,0x42,0x8c,0x97,0x1b,0xaa,0x0,0x69,0x38,0x4e,0x95,0xd5,0xc5,0x80,0x5f,0xdb,0x49,0xce,0x9e,0xbd,0x14,0xec,0x26,0xf6,0xb,0x71,0x5e,0x62,0x53,0xa3,0x2,0xcf,0x16,0x61,0x1c,0x94,0x8,0x79,0x54,0x20,0x46,0xdd,0xa8,0x6a,0x44,0xb2,0x72,0xfd,0x2c,0x65,0x67,0xc4,0x2a,0x99,0xf5,0x52,0xdc,0xa,0x24,0x15,0x78,0x3f,0xc0,0x6c,0xea,0xf,0x90,0x58,0x9a,0xe9,0xbc,0xe6,0x9e,0xb3,0x4a,0xa1,0x85,0x63,0x39,0xcd,0xe0,0xc6,0x49,0x8e,0xc0,0x31,0xcc,0x5a,0x6,0xa4,0x7d,0xe3,0xaa,0x12,0x2b,0xa6,0xbc,0x93,0x7c,0xda,0x4e,0x2a,0xcb,0xd5,0xdc,0x66,0xab,0xac,0x2c,0x36,0x1,0x23,0x94,0xb,0xd1,0x6a,0x73,0xc7,0x17,0x6f,0x57,0xa8,0x4b,0x76,0x69,0x1b,0x3f,0x13,0xba,0xe1,0x82,0x3d,0xd8,0xde,0x4d,0xd0,0x29,0x47,0x55,0xeb,0xe9,0xfb,0x62,0x83,0x38,0xc4,0xf6,0x67,0x22,0xd7,0xe7,0xea,0x1f,0xc,0xb0,0xed,0x50,0x5b,0xad,0xee,0x78,0x30,0x43,0xe8,0x64,0x54,0x3b,0xe2,0xb6,0xfd,0xae,0xbf,0x4f,0x65,0x75,0x6c,0x84,0x98,0xa0,0xb8,0x15,0x5,0x51,0x32,0x3c,0x4c,0xb4,0x24,0xb5,0x8d,0x5e,0x7a,0x9a,0x10,0x1e,0x8c,0x6e,0x80,0x70,0xfe,0x72,0x33,0x28,0x16,0x90,0x25,0xb2,0x1c,0x14,0xbe,0xd6,0xa3,0x2e,0x3a,0x91,0xc8,0x87,0x5f,0x8a,0xe6,0x42,0xf0,0x56,0xf3,0xaf,0x19,0xf2,0x99,0xf5,0xc1,0x2d,0x61,0xa,0x11,0xdf,0x0,0xf4,0x9d,0x37,0x86,0x7e,0x44,0x9c,0xca,0xf,0x45,0xdd,0x6d,0x7f,0x1a,0x27,0x26,0x18,0x5c,0xe,0x9b,0xd2,0x79,0xf9,0xa9,0xa7,0x8f,0x34,0x2,0x9,0x81,0xfc,0x8b,0xbd,0xc9,0xe4,0x95,0xff,0xc3,0xec,0x96,0x52,0x9f,0x3e,0xce,0x20,0x3,0x53,0xd4,0x6b,0xbb,0x71,0x89,0x48,0x8,0xd3,0xa5,0x46,0xc2,0x1d,0x58,0xc5,0xd,0x92,0x77,0x7b,0x21,0x74,0x7,0x88,0xb9,0x97,0x41,0xf1,0x5d,0xa2,0xe5,0x59,0xfa,0xf8,0xb1,0xcf,0x68,0x4,0xb7,0xf7,0x35,0x40,0xdb,0x60,0xef,0x2f,0xd9,0x5d,0x5b,0x53,0xce,0x62,0x39,0xbe,0x1,0x98,0xea,0x90,0xbc,0x2b,0xd4,0xf5,0xc8,0x44,0xf0,0xec,0x94,0x88,0x17,0xe9,0x52,0xb5,0xaf,0xa0,0x82,0xe5,0x5f,0x2f,0x28,0xa9,0xcd,0x56,0x48,0x10,0x3f,0x59,0xff,0x91,0x29,0x25,0xa8,0x27,0x85,0x60,0xfe,0xb2,0x43,0xd9,0x4f,0x45,0x63,0xd,0xca,0xe0,0x6,0x4e,0xba,0x30,0x1d,0x22,0xc9,0x3,0xed,0x7d,0xf3,0x93,0x19,0xf,0x9d,0xe,0x36,0xf9,0xdd,0xcf,0xbf,0xa7,0x37,0x86,0x96,0xb1,0xd2,0x1b,0x7,0x3b,0x23,0xe6,0xcc,0xef,0xf6,0x7e,0x35,0x3c,0x2d,0xd7,0xe7,0x61,0xb8,0xb3,0xfb,0x6b,0xc0,0xd8,0xd3,0x6d,0x2e,0x8f,0x9c,0x6e,0x33,0x54,0xa1,0x69,0x64,0x47,0xbb,0xe4,0x75,0x78,0x6a,0x0,0xe1,0xc4,0xaa,0x68,0xd6,0xc,0x24,0x81,0xb7,0xfa,0x51,0x2a,0x7a,0xdf,0x9b,0x18,0x8d,0x99,0xfc,0xa5,0xa4,0xc6,0x8c,0xee,0x5e,0xc7,0xfd,0x49,0x1f,0x1e,0x77,0x5,0xb4,0x92,0x89,0x83,0x5c,0x42,0x76,0xe2,0xae,0x9a,0x2c,0x1a,0x71,0x73,0xc1,0x70,0xd5,0xdc,0x4,0x65,0x9,0xb9,0xad,0x4b,0x12,0x3d,0x97,0x20,0x55,0xa6,0x13,0x9f,0x31,0xb0,0xf1,0x95,0xab,0x6c,0xe3,0x5a,0xac,0xb6,0x74,0x58,0xc3,0xeb,0x4c,0x34,0x87,0x79,0xda,0x32,0x7b,0xde,0x72,0x66,0x21,0x3a,0xb,0xc2,0x14,0xa2,0xf8,0x84,0xf7,0x8e,0x46,0xf4,0x11,0x41,0xc5,0xdb,0x9e,0x8b,0xcb,0x26,0x50,0x38,0xe8,0xa,0xf2,0x80,0xa3,0x57,0xd0,0x1c,0xd1,0x4d,0xbd,0x40,0x7c,0x15,0x6f,0x4a,0x3e,0x16,0x67,0x2,0x8a,0x8,0x7f,0xd9,0x1e,0x91,0xb7,0xd,0x9b,0x66,0x97,0xf6,0x1d,0xe4,0xc9,0x9a,0x6e,0x34,0xd2,0x8d,0x2b,0xc4,0xeb,0x82,0x9c,0x7d,0x19,0xb4,0x2a,0xf3,0x51,0xf1,0x7c,0x45,0xfd,0x3d,0x86,0x5c,0xc3,0x38,0x40,0x90,0x24,0xfb,0xfc,0x31,0x8b,0x74,0x56,0x61,0x7b,0x6a,0xd5,0xb6,0xed,0x87,0x1a,0x89,0x8f,0x21,0x1c,0xff,0x0,0x44,0x68,0x4c,0x3e,0x30,0xa1,0x93,0x6f,0xbd,0xb0,0x80,0x75,0xbc,0x2,0x10,0x7e,0xd4,0x35,0xac,0xbe,0xbf,0x14,0x67,0x2f,0xb5,0x6c,0x3,0x33,0xba,0xe7,0x5b,0x48,0xb9,0xfa,0xc,0x7,0xef,0xf7,0xcf,0xd3,0x65,0x6,0x52,0x42,0xe8,0xf9,0xaa,0xe1,0x3b,0x22,0x32,0x18,0xdb,0x49,0x47,0xcd,0xa9,0x27,0xd7,0x39,0x73,0xe3,0x1b,0x6b,0x2d,0x9,0xda,0xe2,0xf4,0x81,0xe9,0x43,0x9f,0xc6,0x6d,0x79,0x41,0x7f,0x64,0x25,0x4b,0xe5,0x72,0xc7,0xce,0xa5,0x4e,0xf8,0x36,0x7a,0x96,0xa2,0xb1,0xdd,0x8,0xd0,0xa4,0x1,0xa7,0x15,0x9d,0xcb,0x13,0x29,0x3a,0x8a,0x12,0x58,0x57,0x88,0x46,0x5d,0xd1,0x60,0xca,0xa3,0xfe,0xae,0x2e,0x85,0x55,0x63,0xd8,0xf0,0x71,0x70,0x4d,0x28,0xcc,0x59,0xb,0x4f,0xc1,0xbb,0x94,0xa8,0x99,0x69,0xc8,0x5,0xdc,0xab,0xd6,0x5e,0xc2,0xb3,0x9e,0xea,0xf2,0x84,0x5f,0x1f,0xf,0x4a,0x95,0x11,0x83,0x4,0x54,0x77,0xde,0x26,0xec,0x3c,0x16,0xc0,0xee,0xdf,0xb2,0xf5,0xa,0xa6,0x20,0xc5,0x5a,0x92,0x50,0x23,0x76,0x2c,0x8c,0x17,0x62,0xa0,0x8e,0x78,0xb8,0x37,0xe6,0xaf,0xad,0xe,0xe0,0x53,0x3f,0x98,0x85,0x23,0xcc,0xe3,0x8a,0x94,0x75,0x11,0xbc,0x22,0xfb,0x59,0xf9,0x74,0x4d,0xf5,0xd1,0x16,0x99,0xbf,0x5,0x93,0x6e,0x9f,0xfe,0x15,0xec,0xc1,0x92,0x66,0x3c,0xda,0x62,0xdd,0xbe,0xe5,0x8f,0x12,0x81,0x87,0x29,0x14,0xf7,0x8,0x4c,0x60,0x44,0x36,0x35,0x8e,0x54,0xcb,0x30,0x48,0x98,0x2c,0xf3,0xf4,0x39,0x83,0x7c,0x5e,0x69,0x73,0xb7,0x1c,0x6f,0x27,0xbd,0x64,0xb,0x3b,0xb2,0xef,0x53,0x40,0xb1,0xf2,0x4,0xf,0x38,0xa9,0x9b,0x67,0xb5,0xb8,0x88,0x7d,0xb4,0xa,0x18,0x76,0xdc,0x3d,0xa4,0xb6,0xd3,0x41,0x4f,0xc5,0xa1,0x2f,0xdf,0x31,0x7b,0xeb,0x13,0x63,0x25,0x1,0xd2,0xea,0xe7,0xff,0xc7,0xdb,0x6d,0xe,0x5a,0x4a,0xe0,0xf1,0xa2,0xe9,0x33,0x2a,0x3a,0x10,0xc6,0xad,0x46,0xf0,0x3e,0x72,0x9e,0xaa,0xb9,0xd5,0x0,0xd8,0xac,0x9,0xaf,0x1d,0xfc,0x89,0xe1,0x4b,0x97,0xce,0x65,0x71,0x49,0x77,0x6c,0x2d,0x43,0xed,0x7a,0xcf,0xf6,0xa6,0x26,0x8d,0x5d,0x6b,0xd0,0xf8,0x79,0x78,0x45,0x20,0xc4,0x51,0x3,0x47,0x95,0xc3,0x1b,0x21,0x32,0x82,0x1a,0x50,0x5f,0x80,0x4e,0x55,0xd9,0x68,0xc2,0xab,0xfa,0x8c,0x57,0x17,0x7,0x42,0x9d,0x19,0x8b,0xc,0x5c,0x7f,0xd6,0x2e,0xe4,0x34,0xc9,0xb3,0x9c,0xa0,0x91,0x61,0xc0,0xd,0xd4,0xa3,0xde,0x56,0xca,0xbb,0x96,0xe2,0x84,0x1f,0x6a,0xa8,0x86,0x70,0xb0,0x3f,0xee,0xa7,0xa5,0x6,0xe8,0x5b,0x37,0x90,0x1e,0xc8,0xe6,0xd7,0xba,0xfd,0x2,0xae,0x28,0xcd,0x52,0x9a,0x58,0x2b,0x7e,0x24,0xf1,0xdc,0x25,0xce,0xea,0xc,0x56,0xa2,0x8f,0xa9,0x26,0xe1,0xaf,0x5e,0xa3,0x35,0x69,0xcb,0x12,0x8c,0xc5,0x7d,0x44,0xc9,0xd3,0xfc,0x13,0xb5,0x21,0x45,0xa4,0xba,0xb3,0x9,0xc4,0xc3,0x43,0x59,0x6e,0x4c,0xfb,0x64,0xbe,0x5,0x1c,0xa8,0x78,0x0,0x38,0xc7,0x24,0x19,0x6,0x74,0x50,0x7c,0xd5,0x8e,0xed,0x52,0xb7,0xb1,0x22,0xbf,0x46,0x28,0x3a,0x84,0x86,0x94,0xd,0xec,0x57,0xab,0x99,0x8,0x4d,0xb8,0x88,0x85,0x70,0x63,0xdf,0x82,0x3f,0x34,0xc2,0x81,0x17,0x5f,0x2c,0x87,0xb,0x3b,0x54,0x8d,0xd9,0x92,0xc1,0xd0,0x20,0xa,0x1a,0x3,0xeb,0xf7,0xcf,0xd7,0x7a,0x6a,0x3e,0x5d,0x53,0x23,0xdb,0x4b,0xda,0xe2,0x31,0x15,0xf5,0x7f,0x71,0xe3,0x1,0xef,0x1f,0x91,0x1d,0x5c,0x47,0x79,0xff,0x4a,0xdd,0x73,0x7b,0xd1,0xb9,0xcc,0x41,0x55,0xfe,0xa7,0xe8,0x30,0xe5,0x89,0x2d,0x9f,0x39,0x9c,0xc0,0x76,0x9d,0xf6,0x9a,0xae,0x42,0xe,0x65,0x7e,0xb0,0x6f,0x9b,0xf2,0x58,0xe9,0x11,0x2b,0xf3,0xa5,0x60,0x2a,0xb2,0x2,0x10,0x75,0x48,0x49,0x77,0x33,0x61,0xf4,0xbd,0x16,0x96,0xc6,0xc8,0xe0,0x5b,0x6d,0x66,0xee,0x93,0xe4,0xd2,0xa6,0x8b,0xfa,0x90,0xac,0x83,0xf9,0x3d,0xf0,0x51,0xa1,0x4f,0x6c,0x3c,0xbb,0x4,0xd4,0x1e,0xe6,0x27,0x67,0xbc,0xca,0x29,0xad,0x72,0x37,0xaa,0x62,0xfd,0x18,0x14,0x4e,0x1b,0x68,0xe7,0xd6,0xf8,0x2e,0x9e,0x32,0xcd,0x8a,0x36,0x95,0x97,0xde,0xa0,0x7,0x6b,0xd8,0x98,0x5a,0x2f,0xb4,0xf,0x80,0x40,0xb6,0xa6,0xa0,0xa8,0x35,0x99,0xc2,0x45,0xfa,0x63,0x11,0x6b,0x47,0xd0,0x2f,0xe,0x33,0xbf,0xb,0x17,0x6f,0x73,0xec,0x12,0xa9,0x4e,0x54,0x5b,0x79,0x1e,0xa4,0xd4,0xd3,0x52,0x36,0xad,0xb3,0xeb,0xc4,0xa2,0x4,0x6a,0xd2,0xde,0x53,0xdc,0x7e,0x9b,0x5,0x49,0xb8,0x22,0xb4,0xbe,0x98,0xf6,0x31,0x1b,0xfd,0xb5,0x41,0xcb,0xe6,0xd9,0x32,0xf8,0x16,0x86,0x8,0x68,0xe2,0xf4,0x66,0xf5,0xcd,0x2,0x26,0x34,0x44,0x5c,0xcc,0x7d,0x6d,0x4a,0x29,0xe0,0xfc,0xc0,0xd8,0x1d,0x37,0x14,0xd,0x85,0xce,0xc7,0xd6,0x2c,0x1c,0x9a,0x43,0x48,0x0,0x90,0x3b,0x23,0x28,0x96,0xd5,0x74,0x67,0x95,0xc8,0xaf,0x5a,0x92,0x9f,0xbc,0x40,0x1f,0x8e,0x83,0x91,0xfb,0x1a,0x3f,0x51,0x93,0x2d,0xf7,0xdf,0x7a,0x4c,0x1,0xaa,0xd1,0x81,0x24,0x60,0xe3,0x76,0x62,0x7,0x5e,0x5f,0x3d,0x77,0x15,0xa5,0x3c,0x6,0xb2,0xe4,0xe5,0x8c,0xfe,0x4f,0x69,0x72,0x78,0xa7,0xb9,0x8d,0x19,0x55,0x61,0xd7,0xe1,0x8a,0x88,0x3a,0x8b,0x2e,0x27,0xff,0x9e,0xf2,0x42,0x56,0xb0,0xe9,0xc6,0x6c,0xdb,0xae,0x5d,0xe8,0x64,0xca,0x4b,0xa,0x6e,0x50,0x97,0x18,0xa1,0x57,0x4d,0x8f,0xa3,0x38,0x10,0xb7,0xcf,0x7c,0x82,0x21,0xc9,0x80,0x25,0x89,0x9d,0xda,0xc1,0xf0,0x39,0xef,0x59,0x3,0x7f,0xc,0x75,0xbd,0xf,0xea,0xba,0x3e,0x20,0x65,0x70,0x30,0xdd,0xab,0xc3,0x13,0xf1,0x9,0x7b,0x58,0xac,0x2b,0xe7,0x2a,0xb6,0x46,0xbb,0x87,0xee,0x94,0xb1,0xc5,0xed,0x9c,0xf9,0x71,0xf3,0x84,0xef,0x28,0xa7,0x81,0x3b,0xad,0x50,0xa1,0xc0,0x2b,0xd2,0xff,0xac,0x58,0x2,0xe4,0xbb,0x1d,0xf2,0xdd,0xb4,0xaa,0x4b,0x2f,0x82,0x1c,0xc5,0x67,0xc7,0x4a,0x73,0xcb,0xb,0xb0,0x6a,0xf5,0xe,0x76,0xa6,0x12,0xcd,0xca,0x7,0xbd,0x42,0x60,0x57,0x4d,0x5c,0xe3,0x80,0xdb,0xb1,0x2c,0xbf,0xb9,0x17,0x2a,0xc9,0x36,0x72,0x5e,0x7a,0x8,0x6,0x97,0xa5,0x59,0x8b,0x86,0xb6,0x43,0x8a,0x34,0x26,0x48,0xe2,0x3,0x9a,0x88,0x89,0x22,0x51,0x19,0x83,0x5a,0x35,0x5,0x8c,0xd1,0x6d,0x7e,0x8f,0xcc,0x3a,0x31,0xd9,0xc1,0xf9,0xe5,0x53,0x30,0x64,0x74,0xde,0xcf,0x9c,0xd7,0xd,0x14,0x4,0x2e,0xed,0x7f,0x71,0xfb,0x9f,0x11,0xe1,0xf,0x45,0xd5,0x2d,0x5d,0x1b,0x3f,0xec,0xd4,0xc2,0xb7,0xdf,0x75,0xa9,0xf0,0x5b,0x4f,0x77,0x49,0x52,0x13,0x7d,0xd3,0x44,0xf1,0xf8,0x93,0x78,0xce,0x0,0x4c,0xa0,0x94,0x87,0xeb,0x3e,0xe6,0x92,0x37,0x91,0x23,0xab,0xfd,0x25,0x1f,0xc,0xbc,0x24,0x6e,0x61,0xbe,0x70,0x6b,0xe7,0x56,0xfc,0x95,0xc8,0x98,0x18,0xb3,0x63,0x55,0xee,0xc6,0x47,0x46,0x7b,0x1e,0xfa,0x6f,0x3d,0x79,0xf7,0x8d,0xa2,0x9e,0xaf,0x5f,0xfe,0x33,0xea,0x9d,0xe0,0x68,0xf4,0x85,0xa8,0xdc,0xc4,0xb2,0x69,0x29,0x39,0x7c,0xa3,0x27,0xb5,0x32,0x62,0x41,0xe8,0x10,0xda,0xa,0x20,0xf6,0xd8,0xe9,0x84,0xc3,0x3c,0x90,0x16,0xf3,0x6c,0xa4,0x66,0x15,0x40,0x1a,0xba,0x21,0x54,0x96,0xb8,0x4e,0x8e,0x1,0xd0,0x99,0x9b,0x38,0xd6,0x65,0x9,0xae,0xf9,0x5f,0xb0,0x9f,0xf6,0xe8,0x9,0x6d,0xc0,0x5e,0x87,0x25,0x85,0x8,0x31,0x89,0xad,0x6a,0xe5,0xc3,0x79,0xef,0x12,0xe3,0x82,0x69,0x90,0xbd,0xee,0x1a,0x40,0xa6,0x1e,0xa1,0xc2,0x99,0xf3,0x6e,0xfd,0xfb,0x55,0x68,0x8b,0x74,0x30,0x1c,0x38,0x4a,0x49,0xf2,0x28,0xb7,0x4c,0x34,0xe4,0x50,0x8f,0x88,0x45,0xff,0x0,0x22,0x15,0xf,0xcb,0x60,0x13,0x5b,0xc1,0x18,0x77,0x47,0xce,0x93,0x2f,0x3c,0xcd,0x8e,0x78,0x73,0x44,0xd5,0xe7,0x1b,0xc9,0xc4,0xf4,0x1,0xc8,0x76,0x64,0xa,0xa0,0x41,0xd8,0xca,0xaf,0x3d,0x33,0xb9,0xdd,0x53,0xa3,0x4d,0x7,0x97,0x6f,0x1f,0x59,0x7d,0xae,0x96,0x9b,0x83,0xbb,0xa7,0x11,0x72,0x26,0x36,0x9c,0x8d,0xde,0x95,0x4f,0x56,0x46,0x6c,0xba,0xd1,0x3a,0x8c,0x42,0xe,0xe2,0xd6,0xc5,0xa9,0x7c,0xa4,0xd0,0x75,0xd3,0x61,0x80,0xf5,0x9d,0x37,0xeb,0xb2,0x19,0xd,0x35,0xb,0x10,0x51,0x3f,0x91,0x6,0xb3,0x8a,0xda,0x5a,0xf1,0x21,0x17,0xac,0x84,0x5,0x4,0x39,0x5c,0xb8,0x2d,0x7f,0x3b,0xe9,0xbf,0x67,0x5d,0x4e,0xfe,0x66,0x2c,0x23,0xfc,0x32,0x29,0xa5,0x14,0xbe,0xd7,0x86,0xf0,0x2b,0x6b,0x7b,0x3e,0xe1,0x65,0xf7,0x70,0x20,0x3,0xaa,0x52,0x98,0x48,0xb5,0xcf,0xe0,0xdc,0xed,0x1d,0xbc,0x71,0xa8,0xdf,0xa2,0x2a,0xb6,0xc7,0xea,0x9e,0xf8,0x63,0x16,0xd4,0xfa,0xc,0xcc,0x43,0x92,0xdb,0xd9,0x7a,0x94,0x27,0x4b,0xec,0x62,0xb4,0x9a,0xab,0xc6,0x81,0x7e,0xd2,0x54,0xb1,0x2e,0xe6,0x24,0x57,0x2,0x58,0x51,0x7c,0x85,0x6e,0x4a,0xac,0xf6,0x2,0x2f,0x9,0x86,0x41,0xf,0xfe,0x3,0x95,0xc9,0x6b,0xb2,0x2c,0x65,0xdd,0xe4,0x69,0x73,0x5c,0xb3,0x15,0x81,0xe5,0x4,0x1a,0x13,0xa9,0x64,0x63,0xe3,0xf9,0xce,0xec,0x5b,0xc4,0x1e,0xa5,0xbc,0x8,0xd8,0xa0,0x98,0x67,0x84,0xb9,0xa6,0xd4,0xf0,0xdc,0x75,0x2e,0x4d,0xf2,0x17,0x11,0x82,0x1f,0xe6,0x88,0x9a,0x24,0x26,0x34,0xad,0x4c,0xf7,0xb,0x39,0xa8,0xed,0x18,0x28,0x25,0xd0,0xc3,0x7f,0x22,0x9f,0x94,0x62,0x21,0xb7,0xff,0x8c,0x27,0xab,0x9b,0xf4,0x2d,0x79,0x32,0x61,0x70,0x80,0xaa,0xba,0xa3,0x4b,0x57,0x6f,0x77,0xda,0xca,0x9e,0xfd,0xf3,0x83,0x7b,0xeb,0x7a,0x42,0x91,0xb5,0x55,0xdf,0xd1,0x43,0xa1,0x4f,0xbf,0x31,0xbd,0xfc,0xe7,0xd9,0x5f,0xea,0x7d,0xd3,0xdb,0x71,0x19,0x6c,0xe1,0xf5,0x5e,0x7,0x48,0x90,0x45,0x29,0x8d,0x3f,0x99,0x3c,0x60,0xd6,0x3d,0x56,0x3a,0xe,0xe2,0xae,0xc5,0xde,0x10,0xcf,0x3b,0x52,0xf8,0x49,0xb1,0x8b,0x53,0x5,0xc0,0x8a,0x12,0xa2,0xb0,0xd5,0xe8,0xe9,0xd7,0x93,0xc1,0x54,0x1d,0xb6,0x36,0x66,0x68,0x40,0xfb,0xcd,0xc6,0x4e,0x33,0x44,0x72,0x6,0x2b,0x5a,0x30,0xc,0x23,0x59,0x9d,0x50,0xf1,0x1,0xef,0xcc,0x9c,0x1b,0xa4,0x74,0xbe,0x46,0x87,0xc7,0x1c,0x6a,0x89,0xd,0xd2,0x97,0xa,0xc2,0x5d,0xb8,0xb4,0xee,0xbb,0xc8,0x47,0x76,0x58,0x8e,0x3e,0x92,0x6d,0x2a,0x96,0x35,0x37,0x7e,0x0,0xa7,0xcb,0x78,0x38,0xfa,0x8f,0x14,0xaf,0x20,0xe0,0x16,0x64,0x62,0x6a,0xf7,0x5b,0x0,0x87,0x38,0xa1,0xd3,0xa9,0x85,0x12,0xed,0xcc,0xf1,0x7d,0xc9,0xd5,0xad,0xb1,0x2e,0xd0,0x6b,0x8c,0x96,0x99,0xbb,0xdc,0x66,0x16,0x11,0x90,0xf4,0x6f,0x71,0x29,0x6,0x60,0xc6,0xa8,0x10,0x1c,0x91,0x1e,0xbc,0x59,0xc7,0x8b,0x7a,0xe0,0x76,0x7c,0x5a,0x34,0xf3,0xd9,0x3f,0x77,0x83,0x9,0x24,0x1b,0xf0,0x3a,0xd4,0x44,0xca,0xaa,0x20,0x36,0xa4,0x37,0xf,0xc0,0xe4,0xf6,0x86,0x9e,0xe,0xbf,0xaf,0x88,0xeb,0x22,0x3e,0x2,0x1a,0xdf,0xf5,0xd6,0xcf,0x47,0xc,0x5,0x14,0xee,0xde,0x58,0x81,0x8a,0xc2,0x52,0xf9,0xe1,0xea,0x54,0x17,0xb6,0xa5,0x57,0xa,0x6d,0x98,0x50,0x5d,0x7e,0x82,0xdd,0x4c,0x41,0x53,0x39,0xd8,0xfd,0x93,0x51,0xef,0x35,0x1d,0xb8,0x8e,0xc3,0x68,0x13,0x43,0xe6,0xa2,0x21,0xb4,0xa0,0xc5,0x9c,0x9d,0xff,0xb5,0xd7,0x67,0xfe,0xc4,0x70,0x26,0x27,0x4e,0x3c,0x8d,0xab,0xb0,0xba,0x65,0x7b,0x4f,0xdb,0x97,0xa3,0x15,0x23,0x48,0x4a,0xf8,0x49,0xec,0xe5,0x3d,0x5c,0x30,0x80,0x94,0x72,0x2b,0x4,0xae,0x19,0x6c,0x9f,0x2a,0xa6,0x8,0x89,0xc8,0xac,0x92,0x55,0xda,0x63,0x95,0x8f,0x4d,0x61,0xfa,0xd2,0x75,0xd,0xbe,0x40,0xe3,0xb,0x42,0xe7,0x4b,0x5f,0x18,0x3,0x32,0xfb,0x2d,0x9b,0xc1,0xbd,0xce,0xb7,0x7f,0xcd,0x28,0x78,0xfc,0xe2,0xa7,0xb2,0xf2,0x1f,0x69,0x1,0xd1,0x33,0xcb,0xb9,0x9a,0x6e,0xe9,0x25,0xe8,0x74,0x84,0x79,0x45,0x2c,0x56,0x73,0x7,0x2f,0x5e,0x3b,0xb3,0x31,0x46,0x83,0x44,0xcb,0xed,0x57,0xc1,0x3c,0xcd,0xac,0x47,0xbe,0x93,0xc0,0x34,0x6e,0x88,0xd7,0x71,0x9e,0xb1,0xd8,0xc6,0x27,0x43,0xee,0x70,0xa9,0xb,0xab,0x26,0x1f,0xa7,0x67,0xdc,0x6,0x99,0x62,0x1a,0xca,0x7e,0xa1,0xa6,0x6b,0xd1,0x2e,0xc,0x3b,0x21,0x30,0x8f,0xec,0xb7,0xdd,0x40,0xd3,0xd5,0x7b,0x46,0xa5,0x5a,0x1e,0x32,0x16,0x64,0x6a,0xfb,0xc9,0x35,0xe7,0xea,0xda,0x2f,0xe6,0x58,0x4a,0x24,0x8e,0x6f,0xf6,0xe4,0xe5,0x4e,0x3d,0x75,0xef,0x36,0x59,0x69,0xe0,0xbd,0x1,0x12,0xe3,0xa0,0x56,0x5d,0xb5,0xad,0x95,0x89,0x3f,0x5c,0x8,0x18,0xb2,0xa3,0xf0,0xbb,0x61,0x78,0x68,0x42,0x81,0x13,0x1d,0x97,0xf3,0x7d,0x8d,0x63,0x29,0xb9,0x41,0x31,0x77,0x53,0x80,0xb8,0xae,0xdb,0xb3,0x19,0xc5,0x9c,0x37,0x23,0x1b,0x25,0x3e,0x7f,0x11,0xbf,0x28,0x9d,0x94,0xff,0x14,0xa2,0x6c,0x20,0xcc,0xf8,0xeb,0x87,0x52,0x8a,0xfe,0x5b,0xfd,0x4f,0xc7,0x91,0x49,0x73,0x60,0xd0,0x48,0x2,0xd,0xd2,0x1c,0x7,0x8b,0x3a,0x90,0xf9,0xa4,0xf4,0x74,0xdf,0xf,0x39,0x82,0xaa,0x2b,0x2a,0x17,0x72,0x96,0x3,0x51,0x15,0x9b,0xe1,0xce,0xf2,0xc3,0x33,0x92,0x5f,0x86,0xf1,0x8c,0x4,0x98,0xe9,0xc4,0xb0,0xa8,0xde,0x5,0x45,0x55,0x10,0xcf,0x4b,0xd9,0x5e,0xe,0x2d,0x84,0x7c,0xb6,0x66,0x4c,0x9a,0xb4,0x85,0xe8,0xaf,0x50,0xfc,0x7a,0x9f,0x0,0xc8,0xa,0x79,0x2c,0x76,0xd6,0x4d,0x38,0xfa,0xd4,0x22,0xe2,0x6d,0xbc,0xf5,0xf7,0x54,0xba,0x9,0x65,0xc2,0xd6,0x70,0x9f,0xb0,0xd9,0xc7,0x26,0x42,0xef,0x71,0xa8,0xa,0xaa,0x27,0x1e,0xa6,0x82,0x45,0xca,0xec,0x56,0xc0,0x3d,0xcc,0xad,0x46,0xbf,0x92,0xc1,0x35,0x6f,0x89,0x31,0x8e,0xed,0xb6,0xdc,0x41,0xd2,0xd4,0x7a,0x47,0xa4,0x5b,0x1f,0x33,0x17,0x65,0x66,0xdd,0x7,0x98,0x63,0x1b,0xcb,0x7f,0xa0,0xa7,0x6a,0xd0,0x2f,0xd,0x3a,0x20,0xe4,0x4f,0x3c,0x74,0xee,0x37,0x58,0x68,0xe1,0xbc,0x0,0x13,0xe2,0xa1,0x57,0x5c,0x6b,0xfa,0xc8,0x34,0xe6,0xeb,0xdb,0x2e,0xe7,0x59,0x4b,0x25,0x8f,0x6e,0xf7,0xe5,0x80,0x12,0x1c,0x96,0xf2,0x7c,0x8c,0x62,0x28,0xb8,0x40,0x30,0x76,0x52,0x81,0xb9,0xb4,0xac,0x94,0x88,0x3e,0x5d,0x9,0x19,0xb3,0xa2,0xf1,0xba,0x60,0x79,0x69,0x43,0x95,0xfe,0x15,0xa3,0x6d,0x21,0xcd,0xf9,0xea,0x86,0x53,0x8b,0xff,0x5a,0xfc,0x4e,0xaf,0xda,0xb2,0x18,0xc4,0x9d,0x36,0x22,0x1a,0x24,0x3f,0x7e,0x10,0xbe,0x29,0x9c,0xa5,0xf5,0x75,0xde,0xe,0x38,0x83,0xab,0x2a,0x2b,0x16,0x73,0x97,0x2,0x50,0x14,0xc6,0x90,0x48,0x72,0x61,0xd1,0x49,0x3,0xc,0xd3,0x1d,0x6,0x8a,0x3b,0x91,0xf8,0xa9,0xdf,0x4,0x44,0x54,0x11,0xce,0x4a,0xd8,0x5f,0xf,0x2c,0x85,0x7d,0xb7,0x67,0x9a,0xe0,0xcf,0xf3,0xc2,0x32,0x93,0x5e,0x87,0xf0,0x8d,0x5,0x99,0xe8,0xc5,0xb1,0xd7,0x4c,0x39,0xfb,0xd5,0x23,0xe3,0x6c,0xbd,0xf4,0xf6,0x55,0xbb,0x8,0x64,0xc3,0x4d,0x9b,0xb5,0x84,0xe9,0xae,0x51,0xfd,0x7b,0x9e,0x1,0xc9,0xb,0x78,0x2d,0x77,0x77,0x5a,0xa3,0x48,0x6c,0x8a,0xd0,0x24,0x9,0x2f,0xa0,0x67,0x29,0xd8,0x25,0xb3,0xef,0x4d,0x94,0xa,0x43,0xfb,0xc2,0x4f,0x55,0x7a,0x95,0x33,0xa7,0xc3,0x22,0x3c,0x35,0x8f,0x42,0x45,0xc5,0xdf,0xe8,0xca,0x7d,0xe2,0x38,0x83,0x9a,0x2e,0xfe,0x86,0xbe,0x41,0xa2,0x9f,0x80,0xf2,0xd6,0xfa,0x53,0x8,0x6b,0xd4,0x31,0x37,0xa4,0x39,0xc0,0xae,0xbc,0x2,0x0,0x12,0x8b,0x6a,0xd1,0x2d,0x1f,0x8e,0xcb,0x3e,0xe,0x3,0xf6,0xe5,0x59,0x4,0xb9,0xb2,0x44,0x7,0x91,0xd9,0xaa,0x1,0x8d,0xbd,0xd2,0xb,0x5f,0x14,0x47,0x56,0xa6,0x8c,0x9c,0x85,0x6d,0x71,0x49,0x51,0xfc,0xec,0xb8,0xdb,0xd5,0xa5,0x5d,0xcd,0x5c,0x64,0xb7,0x93,0x73,0xf9,0xf7,0x65,0x87,0x69,0x99,0x17,0x9b,0xda,0xc1,0xff,0x79,0xcc,0x5b,0xf5,0xfd,0x57,0x3f,0x4a,0xc7,0xd3,0x78,0x21,0x6e,0xb6,0x63,0xf,0xab,0x19,0xbf,0x1a,0x46,0xf0,0x1b,0x70,0x1c,0x28,0xc4,0x88,0xe3,0xf8,0x36,0xe9,0x1d,0x74,0xde,0x6f,0x97,0xad,0x75,0x23,0xe6,0xac,0x34,0x84,0x96,0xf3,0xce,0xcf,0xf1,0xb5,0xe7,0x72,0x3b,0x90,0x10,0x40,0x4e,0x66,0xdd,0xeb,0xe0,0x68,0x15,0x62,0x54,0x20,0xd,0x7c,0x16,0x2a,0x5,0x7f,0xbb,0x76,0xd7,0x27,0xc9,0xea,0xba,0x3d,0x82,0x52,0x98,0x60,0xa1,0xe1,0x3a,0x4c,0xaf,0x2b,0xf4,0xb1,0x2c,0xe4,0x7b,0x9e,0x92,0xc8,0x9d,0xee,0x61,0x50,0x7e,0xa8,0x18,0xb4,0x4b,0xc,0xb0,0x13,0x11,0x58,0x26,0x81,0xed,0x5e,0x1e,0xdc,0xa9,0x32,0x89,0x6,0xc6,0x30,0xc9,0xcf,0xc7,0x5a,0xf6,0xad,0x2a,0x95,0xc,0x7e,0x4,0x28,0xbf,0x40,0x61,0x5c,0xd0,0x64,0x78,0x0,0x1c,0x83,0x7d,0xc6,0x21,0x3b,0x34,0x16,0x71,0xcb,0xbb,0xbc,0x3d,0x59,0xc2,0xdc,0x84,0xab,0xcd,0x6b,0x5,0xbd,0xb1,0x3c,0xb3,0x11,0xf4,0x6a,0x26,0xd7,0x4d,0xdb,0xd1,0xf7,0x99,0x5e,0x74,0x92,0xda,0x2e,0xa4,0x89,0xb6,0x5d,0x97,0x79,0xe9,0x67,0x7,0x8d,0x9b,0x9,0x9a,0xa2,0x6d,0x49,0x5b,0x2b,0x33,0xa3,0x12,0x2,0x25,0x46,0x8f,0x93,0xaf,0xb7,0x72,0x58,0x7b,0x62,0xea,0xa1,0xa8,0xb9,0x43,0x73,0xf5,0x2c,0x27,0x6f,0xff,0x54,0x4c,0x47,0xf9,0xba,0x1b,0x8,0xfa,0xa7,0xc0,0x35,0xfd,0xf0,0xd3,0x2f,0x70,0xe1,0xec,0xfe,0x94,0x75,0x50,0x3e,0xfc,0x42,0x98,0xb0,0x15,0x23,0x6e,0xc5,0xbe,0xee,0x4b,0xf,0x8c,0x19,0xd,0x68,0x31,0x30,0x52,0x18,0x7a,0xca,0x53,0x69,0xdd,0x8b,0x8a,0xe3,0x91,0x20,0x6,0x1d,0x17,0xc8,0xd6,0xe2,0x76,0x3a,0xe,0xb8,0x8e,0xe5,0xe7,0x55,0xe4,0x41,0x48,0x90,0xf1,0x9d,0x2d,0x39,0xdf,0x86,0xa9,0x3,0xb4,0xc1,0x32,0x87,0xb,0xa5,0x24,0x65,0x1,0x3f,0xf8,0x77,0xce,0x38,0x22,0xe0,0xcc,0x57,0x7f,0xd8,0xa0,0x13,0xed,0x4e,0xa6,0xef,0x4a,0xe6,0xf2,0xb5,0xae,0x9f,0x56,0x80,0x36,0x6c,0x10,0x63,0x1a,0xd2,0x60,0x85,0xd5,0x51,0x4f,0xa,0x1f,0x5f,0xb2,0xc4,0xac,0x7c,0x9e,0x66,0x14,0x37,0xc3,0x44,0x88,0x45,0xd9,0x29,0xd4,0xe8,0x81,0xfb,0xde,0xaa,0x82,0xf3,0x96,0x1e,0x9c,0xeb,0x92,0x55,0xda,0xfc,0x46,0xd0,0x2d,0xdc,0xbd,0x56,0xaf,0x82,0xd1,0x25,0x7f,0x99,0xc6,0x60,0x8f,0xa0,0xc9,0xd7,0x36,0x52,0xff,0x61,0xb8,0x1a,0xba,0x37,0xe,0xb6,0x76,0xcd,0x17,0x88,0x73,0xb,0xdb,0x6f,0xb0,0xb7,0x7a,0xc0,0x3f,0x1d,0x2a,0x30,0x21,0x9e,0xfd,0xa6,0xcc,0x51,0xc2,0xc4,0x6a,0x57,0xb4,0x4b,0xf,0x23,0x7,0x75,0x7b,0xea,0xd8,0x24,0xf6,0xfb,0xcb,0x3e,0xf7,0x49,0x5b,0x35,0x9f,0x7e,0xe7,0xf5,0xf4,0x5f,0x2c,0x64,0xfe,0x27,0x48,0x78,0xf1,0xac,0x10,0x3,0xf2,0xb1,0x47,0x4c,0xa4,0xbc,0x84,0x98,0x2e,0x4d,0x19,0x9,0xa3,0xb2,0xe1,0xaa,0x70,0x69,0x79,0x53,0x90,0x2,0xc,0x86,0xe2,0x6c,0x9c,0x72,0x38,0xa8,0x50,0x20,0x66,0x42,0x91,0xa9,0xbf,0xca,0xa2,0x8,0xd4,0x8d,0x26,0x32,0xa,0x34,0x2f,0x6e,0x0,0xae,0x39,0x8c,0x85,0xee,0x5,0xb3,0x7d,0x31,0xdd,0xe9,0xfa,0x96,0x43,0x9b,0xef,0x4a,0xec,0x5e,0xd6,0x80,0x58,0x62,0x71,0xc1,0x59,0x13,0x1c,0xc3,0xd,0x16,0x9a,0x2b,0x81,0xe8,0xb5,0xe5,0x65,0xce,0x1e,0x28,0x93,0xbb,0x3a,0x3b,0x6,0x63,0x87,0x12,0x40,0x4,0x8a,0xf0,0xdf,0xe3,0xd2,0x22,0x83,0x4e,0x97,0xe0,0x9d,0x15,0x89,0xf8,0xd5,0xa1,0xb9,0xcf,0x14,0x54,0x44,0x1,0xde,0x5a,0xc8,0x4f,0x1f,0x3c,0x95,0x6d,0xa7,0x77,0x5d,0x8b,0xa5,0x94,0xf9,0xbe,0x41,0xed,0x6b,0x8e,0x11,0xd9,0x1b,0x68,0x3d,0x67,0xc7,0x5c,0x29,0xeb,0xc5,0x33,0xf3,0x7c,0xad,0xe4,0xe6,0x45,0xab,0x18,0x74,0xd3,0xf0,0x56,0xb9,0x96,0xff,0xe1,0x0,0x64,0xc9,0x57,0x8e,0x2c,0x8c,0x1,0x38,0x80,0xa4,0x63,0xec,0xca,0x70,0xe6,0x1b,0xea,0x8b,0x60,0x99,0xb4,0xe7,0x13,0x49,0xaf,0x17,0xa8,0xcb,0x90,0xfa,0x67,0xf4,0xf2,0x5c,0x61,0x82,0x7d,0x39,0x15,0x31,0x43,0x40,0xfb,0x21,0xbe,0x45,0x3d,0xed,0x59,0x86,0x81,0x4c,0xf6,0x9,0x2b,0x1c,0x6,0xc2,0x69,0x1a,0x52,0xc8,0x11,0x7e,0x4e,0xc7,0x9a,0x26,0x35,0xc4,0x87,0x71,0x7a,0x4d,0xdc,0xee,0x12,0xc0,0xcd,0xfd,0x8,0xc1,0x7f,0x6d,0x3,0xa9,0x48,0xd1,0xc3,0xa6,0x34,0x3a,0xb0,0xd4,0x5a,0xaa,0x44,0xe,0x9e,0x66,0x16,0x50,0x74,0xa7,0x9f,0x92,0x8a,0xb2,0xae,0x18,0x7b,0x2f,0x3f,0x95,0x84,0xd7,0x9c,0x46,0x5f,0x4f,0x65,0xb3,0xd8,0x33,0x85,0x4b,0x7,0xeb,0xdf,0xcc,0xa0,0x75,0xad,0xd9,0x7c,0xda,0x68,0x89,0xfc,0x94,0x3e,0xe2,0xbb,0x10,0x4,0x3c,0x2,0x19,0x58,0x36,0x98,0xf,0xba,0x83,0xd3,0x53,0xf8,0x28,0x1e,0xa5,0x8d,0xc,0xd,0x30,0x55,0xb1,0x24,0x76,0x32,0xe0,0xb6,0x6e,0x54,0x47,0xf7,0x6f,0x25,0x2a,0xf5,0x3b,0x20,0xac,0x1d,0xb7,0xde,0x8f,0xf9,0x22,0x62,0x72,0x37,0xe8,0x6c,0xfe,0x79,0x29,0xa,0xa3,0x5b,0x91,0x41,0xbc,0xc6,0xe9,0xd5,0xe4,0x14,0xb5,0x78,0xa1,0xd6,0xab,0x23,0xbf,0xce,0xe3,0x97,0xf1,0x6a,0x1f,0xdd,0xf3,0x5,0xc5,0x4a,0x9b,0xd2,0xd0,0x73,0x9d,0x2e,0x42,0xe5,0x6b,0xbd,0x93,0xa2,0xcf,0x88,0x77,0xdb,0x5d,0xb8,0x27,0xef,0x2d,0x5e,0xb,0x51,0xe,0x23,0xda,0x31,0x15,0xf3,0xa9,0x5d,0x70,0x56,0xd9,0x1e,0x50,0xa1,0x5c,0xca,0x96,0x34,0xed,0x73,0x3a,0x82,0xbb,0x36,0x2c,0x3,0xec,0x4a,0xde,0xba,0x5b,0x45,0x4c,0xf6,0x3b,0x3c,0xbc,0xa6,0x91,0xb3,0x4,0x9b,0x41,0xfa,0xe3,0x57,0x87,0xff,0xc7,0x38,0xdb,0xe6,0xf9,0x8b,0xaf,0x83,0x2a,0x71,0x12,0xad,0x48,0x4e,0xdd,0x40,0xb9,0xd7,0xc5,0x7b,0x79,0x6b,0xf2,0x13,0xa8,0x54,0x66,0xf7,0xb2,0x47,0x77,0x7a,0x8f,0x9c,0x20,0x7d,0xc0,0xcb,0x3d,0x7e,0xe8,0xa0,0xd3,0x78,0xf4,0xc4,0xab,0x72,0x26,0x6d,0x3e,0x2f,0xdf,0xf5,0xe5,0xfc,0x14,0x8,0x30,0x28,0x85,0x95,0xc1,0xa2,0xac,0xdc,0x24,0xb4,0x25,0x1d,0xce,0xea,0xa,0x80,0x8e,0x1c,0xfe,0x10,0xe0,0x6e,0xe2,0xa3,0xb8,0x86,0x0,0xb5,0x22,0x8c,0x84,0x2e,0x46,0x33,0xbe,0xaa,0x1,0x58,0x17,0xcf,0x1a,0x76,0xd2,0x60,0xc6,0x63,0x3f,0x89,0x62,0x9,0x65,0x51,0xbd,0xf1,0x9a,0x81,0x4f,0x90,0x64,0xd,0xa7,0x16,0xee,0xd4,0xc,0x5a,0x9f,0xd5,0x4d,0xfd,0xef,0x8a,0xb7,0xb6,0x88,0xcc,0x9e,0xb,0x42,0xe9,0x69,0x39,0x37,0x1f,0xa4,0x92,0x99,0x11,0x6c,0x1b,0x2d,0x59,0x74,0x5,0x6f,0x53,0x7c,0x6,0xc2,0xf,0xae,0x5e,0xb0,0x93,0xc3,0x44,0xfb,0x2b,0xe1,0x19,0xd8,0x98,0x43,0x35,0xd6,0x52,0x8d,0xc8,0x55,0x9d,0x2,0xe7,0xeb,0xb1,0xe4,0x97,0x18,0x29,0x7,0xd1,0x61,0xcd,0x32,0x75,0xc9,0x6a,0x68,0x21,0x5f,0xf8,0x94,0x27,0x67,0xa5,0xd0,0x4b,0xf0,0x7f,0xbf,0x49,0xcd,0xcb,0xc3,0x5e,0xf2,0xa9,0x2e,0x91,0x8,0x7a,0x0,0x2c,0xbb,0x44,0x65,0x58,0xd4,0x60,0x7c,0x4,0x18,0x87,0x79,0xc2,0x25,0x3f,0x30,0x12,0x75,0xcf,0xbf,0xb8,0x39,0x5d,0xc6,0xd8,0x80,0xaf,0xc9,0x6f,0x1,0xb9,0xb5,0x38,0xb7,0x15,0xf0,0x6e,0x22,0xd3,0x49,0xdf,0xd5,0xf3,0x9d,0x5a,0x70,0x96,0xde,0x2a,0xa0,0x8d,0xb2,0x59,0x93,0x7d,0xed,0x63,0x3,0x89,0x9f,0xd,0x9e,0xa6,0x69,0x4d,0x5f,0x2f,0x37,0xa7,0x16,0x6,0x21,0x42,0x8b,0x97,0xab,0xb3,0x76,0x5c,0x7f,0x66,0xee,0xa5,0xac,0xbd,0x47,0x77,0xf1,0x28,0x23,0x6b,0xfb,0x50,0x48,0x43,0xfd,0xbe,0x1f,0xc,0xfe,0xa3,0xc4,0x31,0xf9,0xf4,0xd7,0x2b,0x74,0xe5,0xe8,0xfa,0x90,0x71,0x54,0x3a,0xf8,0x46,0x9c,0xb4,0x11,0x27,0x6a,0xc1,0xba,0xea,0x4f,0xb,0x88,0x1d,0x9,0x6c,0x35,0x34,0x56,0x1c,0x7e,0xce,0x57,0x6d,0xd9,0x8f,0x8e,0xe7,0x95,0x24,0x2,0x19,0x13,0xcc,0xd2,0xe6,0x72,0x3e,0xa,0xbc,0x8a,0xe1,0xe3,0x51,0xe0,0x45,0x4c,0x94,0xf5,0x99,0x29,0x3d,0xdb,0x82,0xad,0x7,0xb0,0xc5,0x36,0x83,0xf,0xa1,0x20,0x61,0x5,0x3b,0xfc,0x73,0xca,0x3c,0x26,0xe4,0xc8,0x53,0x7b,0xdc,0xa4,0x17,0xe9,0x4a,0xa2,0xeb,0x4e,0xe2,0xf6,0xb1,0xaa,0x9b,0x52,0x84,0x32,0x68,0x14,0x67,0x1e,0xd6,0x64,0x81,0xd1,0x55,0x4b,0xe,0x1b,0x5b,0xb6,0xc0,0xa8,0x78,0x9a,0x62,0x10,0x33,0xc7,0x40,0x8c,0x41,0xdd,0x2d,0xd0,0xec,0x85,0xff,0xda,0xae,0x86,0xf7,0x92,0x1a,0x98,0xef,0x80,0x47,0xc8,0xee,0x54,0xc2,0x3f,0xce,0xaf,0x44,0xbd,0x90,0xc3,0x37,0x6d,0x8b,0xd4,0x72,0x9d,0xb2,0xdb,0xc5,0x24,0x40,0xed,0x73,0xaa,0x8,0xa8,0x25,0x1c,0xa4,0x64,0xdf,0x5,0x9a,0x61,0x19,0xc9,0x7d,0xa2,0xa5,0x68,0xd2,0x2d,0xf,0x38,0x22,0x33,0x8c,0xef,0xb4,0xde,0x43,0xd0,0xd6,0x78,0x45,0xa6,0x59,0x1d,0x31,0x15,0x67,0x69,0xf8,0xca,0x36,0xe4,0xe9,0xd9,0x2c,0xe5,0x5b,0x49,0x27,0x8d,0x6c,0xf5,0xe7,0xe6,0x4d,0x3e,0x76,0xec,0x35,0x5a,0x6a,0xe3,0xbe,0x2,0x11,0xe0,0xa3,0x55,0x5e,0xb6,0xae,0x96,0x8a,0x3c,0x5f,0xb,0x1b,0xb1,0xa0,0xf3,0xb8,0x62,0x7b,0x6b,0x41,0x82,0x10,0x1e,0x94,0xf0,0x7e,0x8e,0x60,0x2a,0xba,0x42,0x32,0x74,0x50,0x83,0xbb,0xad,0xd8,0xb0,0x1a,0xc6,0x9f,0x34,0x20,0x18,0x26,0x3d,0x7c,0x12,0xbc,0x2b,0x9e,0x97,0xfc,0x17,0xa1,0x6f,0x23,0xcf,0xfb,0xe8,0x84,0x51,0x89,0xfd,0x58,0xfe,0x4c,0xc4,0x92,0x4a,0x70,0x63,0xd3,0x4b,0x1,0xe,0xd1,0x1f,0x4,0x88,0x39,0x93,0xfa,0xa7,0xf7,0x77,0xdc,0xc,0x3a,0x81,0xa9,0x28,0x29,0x14,0x71,0x95,0x0,0x52,0x16,0x98,0xe2,0xcd,0xf1,0xc0,0x30,0x91,0x5c,0x85,0xf2,0x8f,0x7,0x9b,0xea,0xc7,0xb3,0xab,0xdd,0x6,0x46,0x56,0x13,0xcc,0x48,0xda,0x5d,0xd,0x2e,0x87,0x7f,0xb5,0x65,0x4f,0x99,0xb7,0x86,0xeb,0xac,0x53,0xff,0x79,0x9c,0x3,0xcb,0x9,0x7a,0x2f,0x75,0xd5,0x4e,0x3b,0xf9,0xd7,0x21,0xe1,0x6e,0xbf,0xf6,0xf4,0x57,0xb9,0xa,0x66,0xc1,0x4e,0xe8,0x7,0x28,0x41,0x5f,0xbe,0xda,0x77,0xe9,0x30,0x92,0x32,0xbf,0x86,0x3e,0x1a,0xdd,0x52,0x74,0xce,0x58,0xa5,0x54,0x35,0xde,0x27,0xa,0x59,0xad,0xf7,0x11,0xa9,0x16,0x75,0x2e,0x44,0xd9,0x4a,0x4c,0xe2,0xdf,0x3c,0xc3,0x87,0xab,0x8f,0xfd,0xfe,0x45,0x9f,0x0,0xfb,0x83,0x53,0xe7,0x38,0x3f,0xf2,0x48,0xb7,0x95,0xa2,0xb8,0x7c,0xd7,0xa4,0xec,0x76,0xaf,0xc0,0xf0,0x79,0x24,0x98,0x8b,0x7a,0x39,0xcf,0xc4,0xf3,0x62,0x50,0xac,0x7e,0x73,0x43,0xb6,0x7f,0xc1,0xd3,0xbd,0x17,0xf6,0x6f,0x7d,0x18,0x8a,0x84,0xe,0x6a,0xe4,0x14,0xfa,0xb0,0x20,0xd8,0xa8,0xee,0xca,0x19,0x21,0x2c,0x34,0xc,0x10,0xa6,0xc5,0x91,0x81,0x2b,0x3a,0x69,0x22,0xf8,0xe1,0xf1,0xdb,0xd,0x66,0x8d,0x3b,0xf5,0xb9,0x55,0x61,0x72,0x1e,0xcb,0x13,0x67,0xc2,0x64,0xd6,0x37,0x42,0x2a,0x80,0x5c,0x5,0xae,0xba,0x82,0xbc,0xa7,0xe6,0x88,0x26,0xb1,0x4,0x3d,0x6d,0xed,0x46,0x96,0xa0,0x1b,0x33,0xb2,0xb3,0x8e,0xeb,0xf,0x9a,0xc8,0x8c,0x5e,0x8,0xd0,0xea,0xf9,0x49,0xd1,0x9b,0x94,0x4b,0x85,0x9e,0x12,0xa3,0x9,0x60,0x31,0x47,0x9c,0xdc,0xcc,0x89,0x56,0xd2,0x40,0xc7,0x97,0xb4,0x1d,0xe5,0x2f,0xff,0x2,0x78,0x57,0x6b,0x5a,0xaa,0xb,0xc6,0x1f,0x68,0x15,0x9d,0x1,0x70,0x5d,0x29,0x4f,0xd4,0xa1,0x63,0x4d,0xbb,0x7b,0xf4,0x25,0x6c,0x6e,0xcd,0x23,0x90,0xfc,0x5b,0xd5,0x3,0x2d,0x1c,0x71,0x36,0xc9,0x65,0xe3,0x6,0x99,0x51,0x93,0xe0,0xb5,0xef,0x70,0x5d,0xa4,0x4f,0x6b,0x8d,0xd7,0x23,0xe,0x28,0xa7,0x60,0x2e,0xdf,0x22,0xb4,0xe8,0x4a,0x93,0xd,0x44,0xfc,0xc5,0x48,0x52,0x7d,0x92,0x34,0xa0,0xc4,0x25,0x3b,0x32,0x88,0x45,0x42,0xc2,0xd8,0xef,0xcd,0x7a,0xe5,0x3f,0x84,0x9d,0x29,0xf9,0x81,0xb9,0x46,0xa5,0x98,0x87,0xf5,0xd1,0xfd,0x54,0xf,0x6c,0xd3,0x36,0x30,0xa3,0x3e,0xc7,0xa9,0xbb,0x5,0x7,0x15,0x8c,0x6d,0xd6,0x2a,0x18,0x89,0xcc,0x39,0x9,0x4,0xf1,0xe2,0x5e,0x3,0xbe,0xb5,0x43,0x0,0x96,0xde,0xad,0x6,0x8a,0xba,0xd5,0xc,0x58,0x13,0x40,0x51,0xa1,0x8b,0x9b,0x82,0x6a,0x76,0x4e,0x56,0xfb,0xeb,0xbf,0xdc,0xd2,0xa2,0x5a,0xca,0x5b,0x63,0xb0,0x94,0x74,0xfe,0xf0,0x62,0x80,0x6e,0x9e,0x10,0x9c,0xdd,0xc6,0xf8,0x7e,0xcb,0x5c,0xf2,0xfa,0x50,0x38,0x4d,0xc0,0xd4,0x7f,0x26,0x69,0xb1,0x64,0x8,0xac,0x1e,0xb8,0x1d,0x41,0xf7,0x1c,0x77,0x1b,0x2f,0xc3,0x8f,0xe4,0xff,0x31,0xee,0x1a,0x73,0xd9,0x68,0x90,0xaa,0x72,0x24,0xe1,0xab,0x33,0x83,0x91,0xf4,0xc9,0xc8,0xf6,0xb2,0xe0,0x75,0x3c,0x97,0x17,0x47,0x49,0x61,0xda,0xec,0xe7,0x6f,0x12,0x65,0x53,0x27,0xa,0x7b,0x11,0x2d,0x2,0x78,0xbc,0x71,0xd0,0x20,0xce,0xed,0xbd,0x3a,0x85,0x55,0x9f,0x67,0xa6,0xe6,0x3d,0x4b,0xa8,0x2c,0xf3,0xb6,0x2b,0xe3,0x7c,0x99,0x95,0xcf,0x9a,0xe9,0x66,0x57,0x79,0xaf,0x1f,0xb3,0x4c,0xb,0xb7,0x14,0x16,0x5f,0x21,0x86,0xea,0x59,0x19,0xdb,0xae,0x35,0x8e,0x1,0xc1,0x37,0xf4,0xf2,0xfa,0x67,0xcb,0x90,0x17,0xa8,0x31,0x43,0x39,0x15,0x82,0x7d,0x5c,0x61,0xed,0x59,0x45,0x3d,0x21,0xbe,0x40,0xfb,0x1c,0x6,0x9,0x2b,0x4c,0xf6,0x86,0x81,0x0,0x64,0xff,0xe1,0xb9,0x96,0xf0,0x56,0x38,0x80,0x8c,0x1,0x8e,0x2c,0xc9,0x57,0x1b,0xea,0x70,0xe6,0xec,0xca,0xa4,0x63,0x49,0xaf,0xe7,0x13,0x99,0xb4,0x8b,0x60,0xaa,0x44,0xd4,0x5a,0x3a,0xb0,0xa6,0x34,0xa7,0x9f,0x50,0x74,0x66,0x16,0xe,0x9e,0x2f,0x3f,0x18,0x7b,0xb2,0xae,0x92,0x8a,0x4f,0x65,0x46,0x5f,0xd7,0x9c,0x95,0x84,0x7e,0x4e,0xc8,0x11,0x1a,0x52,0xc2,0x69,0x71,0x7a,0xc4,0x87,0x26,0x35,0xc7,0x9a,0xfd,0x8,0xc0,0xcd,0xee,0x12,0x4d,0xdc,0xd1,0xc3,0xa9,0x48,0x6d,0x3,0xc1,0x7f,0xa5,0x8d,0x28,0x1e,0x53,0xf8,0x83,0xd3,0x76,0x32,0xb1,0x24,0x30,0x55,0xc,0xd,0x6f,0x25,0x47,0xf7,0x6e,0x54,0xe0,0xb6,0xb7,0xde,0xac,0x1d,0x3b,0x20,0x2a,0xf5,0xeb,0xdf,0x4b,0x7,0x33,0x85,0xb3,0xd8,0xda,0x68,0xd9,0x7c,0x75,0xad,0xcc,0xa0,0x10,0x4,0xe2,0xbb,0x94,0x3e,0x89,0xfc,0xf,0xba,0x36,0x98,0x19,0x58,0x3c,0x2,0xc5,0x4a,0xf3,0x5,0x1f,0xdd,0xf1,0x6a,0x42,0xe5,0x9d,0x2e,0xd0,0x73,0x9b,0xd2,0x77,0xdb,0xcf,0x88,0x93,0xa2,0x6b,0xbd,0xb,0x51,0x2d,0x5e,0x27,0xef,0x5d,0xb8,0xe8,0x6c,0x72,0x37,0x22,0x62,0x8f,0xf9,0x91,0x41,0xa3,0x5b,0x29,0xa,0xfe,0x79,0xb5,0x78,0xe4,0x14,0xe9,0xd5,0xbc,0xc6,0xe3,0x97,0xbf,0xce,0xab,0x23,0xa1,0xd6,0x44,0x83,0xc,0x2a,0x90,0x6,0xfb,0xa,0x6b,0x80,0x79,0x54,0x7,0xf3,0xa9,0x4f,0x10,0xb6,0x59,0x76,0x1f,0x1,0xe0,0x84,0x29,0xb7,0x6e,0xcc,0x6c,0xe1,0xd8,0x60,0xa0,0x1b,0xc1,0x5e,0xa5,0xdd,0xd,0xb9,0x66,0x61,0xac,0x16,0xe9,0xcb,0xfc,0xe6,0xf7,0x48,0x2b,0x70,0x1a,0x87,0x14,0x12,0xbc,0x81,0x62,0x9d,0xd9,0xf5,0xd1,0xa3,0xad,0x3c,0xe,0xf2,0x20,0x2d,0x1d,0xe8,0x21,0x9f,0x8d,0xe3,0x49,0xa8,0x31,0x23,0x22,0x89,0xfa,0xb2,0x28,0xf1,0x9e,0xae,0x27,0x7a,0xc6,0xd5,0x24,0x67,0x91,0x9a,0x72,0x6a,0x52,0x4e,0xf8,0x9b,0xcf,0xdf,0x75,0x64,0x37,0x7c,0xa6,0xbf,0xaf,0x85,0x46,0xd4,0xda,0x50,0x34,0xba,0x4a,0xa4,0xee,0x7e,0x86,0xf6,0xb0,0x94,0x47,0x7f,0x69,0x1c,0x74,0xde,0x2,0x5b,0xf0,0xe4,0xdc,0xe2,0xf9,0xb8,0xd6,0x78,0xef,0x5a,0x53,0x38,0xd3,0x65,0xab,0xe7,0xb,0x3f,0x2c,0x40,0x95,0x4d,0x39,0x9c,0x3a,0x88,0x0,0x56,0x8e,0xb4,0xa7,0x17,0x8f,0xc5,0xca,0x15,0xdb,0xc0,0x4c,0xfd,0x57,0x3e,0x63,0x33,0xb3,0x18,0xc8,0xfe,0x45,0x6d,0xec,0xed,0xd0,0xb5,0x51,0xc4,0x96,0xd2,0x5c,0x26,0x9,0x35,0x4,0xf4,0x55,0x98,0x41,0x36,0x4b,0xc3,0x5f,0x2e,0x3,0x77,0x6f,0x19,0xc2,0x82,0x92,0xd7,0x8,0x8c,0x1e,0x99,0xc9,0xea,0x43,0xbb,0x71,0xa1,0x8b,0x5d,0x73,0x42,0x2f,0x68,0x97,0x3b,0xbd,0x58,0xc7,0xf,0xcd,0xbe,0xeb,0xb1,0x11,0x8a,0xff,0x3d,0x13,0xe5,0x25,0xaa,0x7b,0x32,0x30,0x93,0x7d,0xce,0xa2,0x5,0xed,0x4b,0xa4,0x8b,0xe2,0xfc,0x1d,0x79,0xd4,0x4a,0x93,0x31,0x91,0x1c,0x25,0x9d,0xb9,0x7e,0xf1,0xd7,0x6d,0xfb,0x6,0xf7,0x96,0x7d,0x84,0xa9,0xfa,0xe,0x54,0xb2,0xa,0xb5,0xd6,0x8d,0xe7,0x7a,0xe9,0xef,0x41,0x7c,0x9f,0x60,0x24,0x8,0x2c,0x5e,0x5d,0xe6,0x3c,0xa3,0x58,0x20,0xf0,0x44,0x9b,0x9c,0x51,0xeb,0x14,0x36,0x1,0x1b,0xdf,0x74,0x7,0x4f,0xd5,0xc,0x63,0x53,0xda,0x87,0x3b,0x28,0xd9,0x9a,0x6c,0x67,0x50,0xc1,0xf3,0xf,0xdd,0xd0,0xe0,0x15,0xdc,0x62,0x70,0x1e,0xb4,0x55,0xcc,0xde,0xbb,0x29,0x27,0xad,0xc9,0x47,0xb7,0x59,0x13,0x83,0x7b,0xb,0x4d,0x69,0xba,0x82,0x8f,0x97,0xaf,0xb3,0x5,0x66,0x32,0x22,0x88,0x99,0xca,0x81,0x5b,0x42,0x52,0x78,0xae,0xc5,0x2e,0x98,0x56,0x1a,0xf6,0xc2,0xd1,0xbd,0x68,0xb0,0xc4,0x61,0xc7,0x75,0x94,0xe1,0x89,0x23,0xff,0xa6,0xd,0x19,0x21,0x1f,0x4,0x45,0x2b,0x85,0x12,0xa7,0x9e,0xce,0x4e,0xe5,0x35,0x3,0xb8,0x90,0x11,0x10,0x2d,0x48,0xac,0x39,0x6b,0x2f,0xfd,0xab,0x73,0x49,0x5a,0xea,0x72,0x38,0x37,0xe8,0x26,0x3d,0xb1,0x0,0xaa,0xc3,0x92,0xe4,0x3f,0x7f,0x6f,0x2a,0xf5,0x71,0xe3,0x64,0x34,0x17,0xbe,0x46,0x8c,0x5c,0xa1,0xdb,0xf4,0xc8,0xf9,0x9,0xa8,0x65,0xbc,0xcb,0xb6,0x3e,0xa2,0xd3,0xfe,0x8a,0xec,0x77,0x2,0xc0,0xee,0x18,0xd8,0x57,0x86,0xcf,0xcd,0x6e,0x80,0x33,0x5f,0xf8,0x76,0xa0,0x8e,0xbf,0xd2,0x95,0x6a,0xc6,0x40,0xa5,0x3a,0xf2,0x30,0x43,0x16,0x4c,0xb3,0x9e,0x67,0x8c,0xa8,0x4e,0x14,0xe0,0xcd,0xeb,0x64,0xa3,0xed,0x1c,0xe1,0x77,0x2b,0x89,0x50,0xce,0x87,0x3f,0x6,0x8b,0x91,0xbe,0x51,0xf7,0x63,0x7,0xe6,0xf8,0xf1,0x4b,0x86,0x81,0x1,0x1b,0x2c,0xe,0xb9,0x26,0xfc,0x47,0x5e,0xea,0x3a,0x42,0x7a,0x85,0x66,0x5b,0x44,0x36,0x12,0x3e,0x97,0xcc,0xaf,0x10,0xf5,0xf3,0x60,0xfd,0x4,0x6a,0x78,0xc6,0xc4,0xd6,0x4f,0xae,0x15,0xe9,0xdb,0x4a,0xf,0xfa,0xca,0xc7,0x32,0x21,0x9d,0xc0,0x7d,0x76,0x80,0xc3,0x55,0x1d,0x6e,0xc5,0x49,0x79,0x16,0xcf,0x9b,0xd0,0x83,0x92,0x62,0x48,0x58,0x41,0xa9,0xb5,0x8d,0x95,0x38,0x28,0x7c,0x1f,0x11,0x61,0x99,0x9,0x98,0xa0,0x73,0x57,0xb7,0x3d,0x33,0xa1,0x43,0xad,0x5d,0xd3,0x5f,0x1e,0x5,0x3b,0xbd,0x8,0x9f,0x31,0x39,0x93,0xfb,0x8e,0x3,0x17,0xbc,0xe5,0xaa,0x72,0xa7,0xcb,0x6f,0xdd,0x7b,0xde,0x82,0x34,0xdf,0xb4,0xd8,0xec,0x0,0x4c,0x27,0x3c,0xf2,0x2d,0xd9,0xb0,0x1a,0xab,0x53,0x69,0xb1,0xe7,0x22,0x68,0xf0,0x40,0x52,0x37,0xa,0xb,0x35,0x71,0x23,0xb6,0xff,0x54,0xd4,0x84,0x8a,0xa2,0x19,0x2f,0x24,0xac,0xd1,0xa6,0x90,0xe4,0xc9,0xb8,0xd2,0xee,0xc1,0xbb,0x7f,0xb2,0x13,0xe3,0xd,0x2e,0x7e,0xf9,0x46,0x96,0x5c,0xa4,0x65,0x25,0xfe,0x88,0x6b,0xef,0x30,0x75,0xe8,0x20,0xbf,0x5a,0x56,0xc,0x59,0x2a,0xa5,0x94,0xba,0x6c,0xdc,0x70,0x8f,0xc8,0x74,0xd7,0xd5,0x9c,0xe2,0x45,0x29,0x9a,0xda,0x18,0x6d,0xf6,0x4d,0xc2,0x2,0xf4,0x7e,0x78,0x70,0xed,0x41,0x1a,0x9d,0x22,0xbb,0xc9,0xb3,0x9f,0x8,0xf7,0xd6,0xeb,0x67,0xd3,0xcf,0xb7,0xab,0x34,0xca,0x71,0x96,0x8c,0x83,0xa1,0xc6,0x7c,0xc,0xb,0x8a,0xee,0x75,0x6b,0x33,0x1c,0x7a,0xdc,0xb2,0xa,0x6,0x8b,0x4,0xa6,0x43,0xdd,0x91,0x60,0xfa,0x6c,0x66,0x40,0x2e,0xe9,0xc3,0x25,0x6d,0x99,0x13,0x3e,0x1,0xea,0x20,0xce,0x5e,0xd0,0xb0,0x3a,0x2c,0xbe,0x2d,0x15,0xda,0xfe,0xec,0x9c,0x84,0x14,0xa5,0xb5,0x92,0xf1,0x38,0x24,0x18,0x0,0xc5,0xef,0xcc,0xd5,0x5d,0x16,0x1f,0xe,0xf4,0xc4,0x42,0x9b,0x90,0xd8,0x48,0xe3,0xfb,0xf0,0x4e,0xd,0xac,0xbf,0x4d,0x10,0x77,0x82,0x4a,0x47,0x64,0x98,0xc7,0x56,0x5b,0x49,0x23,0xc2,0xe7,0x89,0x4b,0xf5,0x2f,0x7,0xa2,0x94,0xd9,0x72,0x9,0x59,0xfc,0xb8,0x3b,0xae,0xba,0xdf,0x86,0x87,0xe5,0xaf,0xcd,0x7d,0xe4,0xde,0x6a,0x3c,0x3d,0x54,0x26,0x97,0xb1,0xaa,0xa0,0x7f,0x61,0x55,0xc1,0x8d,0xb9,0xf,0x39,0x52,0x50,0xe2,0x53,0xf6,0xff,0x27,0x46,0x2a,0x9a,0x8e,0x68,0x31,0x1e,0xb4,0x3,0x76,0x85,0x30,0xbc,0x12,0x93,0xd2,0xb6,0x88,0x4f,0xc0,0x79,0x8f,0x95,0x57,0x7b,0xe0,0xc8,0x6f,0x17,0xa4,0x5a,0xf9,0x11,0x58,0xfd,0x51,0x45,0x2,0x19,0x28,0xe1,0x37,0x81,0xdb,0xa7,0xd4,0xad,0x65,0xd7,0x32,0x62,0xe6,0xf8,0xbd,0xa8,0xe8,0x5,0x73,0x1b,0xcb,0x29,0xd1,0xa3,0x80,0x74,0xf3,0x3f,0xf2,0x6e,0x9e,0x63,0x5f,0x36,0x4c,0x69,0x1d,0x35,0x44,0x21,0xa9,0x2b,0x5c,0x10,0xd7,0x58,0x7e,0xc4,0x52,0xaf,0x5e,0x3f,0xd4,0x2d,0x0,0x53,0xa7,0xfd,0x1b,0x44,0xe2,0xd,0x22,0x4b,0x55,0xb4,0xd0,0x7d,0xe3,0x3a,0x98,0x38,0xb5,0x8c,0x34,0xf4,0x4f,0x95,0xa,0xf1,0x89,0x59,0xed,0x32,0x35,0xf8,0x42,0xbd,0x9f,0xa8,0xb2,0xa3,0x1c,0x7f,0x24,0x4e,0xd3,0x40,0x46,0xe8,0xd5,0x36,0xc9,0x8d,0xa1,0x85,0xf7,0xf9,0x68,0x5a,0xa6,0x74,0x79,0x49,0xbc,0x75,0xcb,0xd9,0xb7,0x1d,0xfc,0x65,0x77,0x76,0xdd,0xae,0xe6,0x7c,0xa5,0xca,0xfa,0x73,0x2e,0x92,0x81,0x70,0x33,0xc5,0xce,0x26,0x3e,0x6,0x1a,0xac,0xcf,0x9b,0x8b,0x21,0x30,0x63,0x28,0xf2,0xeb,0xfb,0xd1,0x12,0x80,0x8e,0x4,0x60,0xee,0x1e,0xf0,0xba,0x2a,0xd2,0xa2,0xe4,0xc0,0x13,0x2b,0x3d,0x48,0x20,0x8a,0x56,0xf,0xa4,0xb0,0x88,0xb6,0xad,0xec,0x82,0x2c,0xbb,0xe,0x7,0x6c,0x87,0x31,0xff,0xb3,0x5f,0x6b,0x78,0x14,0xc1,0x19,0x6d,0xc8,0x6e,0xdc,0x54,0x2,0xda,0xe0,0xf3,0x43,0xdb,0x91,0x9e,0x41,0x8f,0x94,0x18,0xa9,0x3,0x6a,0x37,0x67,0xe7,0x4c,0x9c,0xaa,0x11,0x39,0xb8,0xb9,0x84,0xe1,0x5,0x90,0xc2,0x86,0x8,0x72,0x5d,0x61,0x50,0xa0,0x1,0xcc,0x15,0x62,0x1f,0x97,0xb,0x7a,0x57,0x23,0x3b,0x4d,0x96,0xd6,0xc6,0x83,0x5c,0xd8,0x4a,0xcd,0x9d,0xbe,0x17,0xef,0x25,0xf5,0xdf,0x9,0x27,0x16,0x7b,0x3c,0xc3,0x6f,0xe9,0xc,0x93,0x5b,0x99,0xea,0xbf,0xe5,0x45,0xde,0xab,0x69,0x47,0xb1,0x71,0xfe,0x2f,0x66,0x64,0xc7,0x29,0x9a,0xf6,0x51,0x14,0xb2,0x5d,0x72,0x1b,0x5,0xe4,0x80,0x2d,0xb3,0x6a,0xc8,0x68,0xe5,0xdc,0x64,0x40,0x87,0x8,0x2e,0x94,0x2,0xff,0xe,0x6f,0x84,0x7d,0x50,0x3,0xf7,0xad,0x4b,0xf3,0x4c,0x2f,0x74,0x1e,0x83,0x10,0x16,0xb8,0x85,0x66,0x99,0xdd,0xf1,0xd5,0xa7,0xa4,0x1f,0xc5,0x5a,0xa1,0xd9,0x9,0xbd,0x62,0x65,0xa8,0x12,0xed,0xcf,0xf8,0xe2,0x26,0x8d,0xfe,0xb6,0x2c,0xf5,0x9a,0xaa,0x23,0x7e,0xc2,0xd1,0x20,0x63,0x95,0x9e,0xa9,0x38,0xa,0xf6,0x24,0x29,0x19,0xec,0x25,0x9b,0x89,0xe7,0x4d,0xac,0x35,0x27,0x42,0xd0,0xde,0x54,0x30,0xbe,0x4e,0xa0,0xea,0x7a,0x82,0xf2,0xb4,0x90,0x43,0x7b,0x76,0x6e,0x56,0x4a,0xfc,0x9f,0xcb,0xdb,0x71,0x60,0x33,0x78,0xa2,0xbb,0xab,0x81,0x57,0x3c,0xd7,0x61,0xaf,0xe3,0xf,0x3b,0x28,0x44,0x91,0x49,0x3d,0x98,0x3e,0x8c,0x6d,0x18,0x70,0xda,0x6,0x5f,0xf4,0xe0,0xd8,0xe6,0xfd,0xbc,0xd2,0x7c,0xeb,0x5e,0x67,0x37,0xb7,0x1c,0xcc,0xfa,0x41,0x69,0xe8,0xe9,0xd4,0xb1,0x55,0xc0,0x92,0xd6,0x4,0x52,0x8a,0xb0,0xa3,0x13,0x8b,0xc1,0xce,0x11,0xdf,0xc4,0x48,0xf9,0x53,0x3a,0x6b,0x1d,0xc6,0x86,0x96,0xd3,0xc,0x88,0x1a,0x9d,0xcd,0xee,0x47,0xbf,0x75,0xa5,0x58,0x22,0xd,0x31,0x0,0xf0,0x51,0x9c,0x45,0x32,0x4f,0xc7,0x5b,0x2a,0x7,0x73,0x15,0x8e,0xfb,0x39,0x17,0xe1,0x21,0xae,0x7f,0x36,0x34,0x97,0x79,0xca,0xa6,0x1,0x8f,0x59,0x77,0x46,0x2b,0x6c,0x93,0x3f,0xb9,0x5c,0xc3,0xb,0xc9,0xba,0xef,0xb5,0xf8,0xd5,0x2c,0xc7,0xe3,0x5,0x5f,0xab,0x86,0xa0,0x2f,0xe8,0xa6,0x57,0xaa,0x3c,0x60,0xc2,0x1b,0x85,0xcc,0x74,0x4d,0xc0,0xda,0xf5,0x1a,0xbc,0x28,0x4c,0xad,0xb3,0xba,0x0,0xcd,0xca,0x4a,0x50,0x67,0x45,0xf2,0x6d,0xb7,0xc,0x15,0xa1,0x71,0x9,0x31,0xce,0x2d,0x10,0xf,0x7d,0x59,0x75,0xdc,0x87,0xe4,0x5b,0xbe,0xb8,0x2b,0xb6,0x4f,0x21,0x33,0x8d,0x8f,0x9d,0x4,0xe5,0x5e,0xa2,0x90,0x1,0x44,0xb1,0x81,0x8c,0x79,0x6a,0xd6,0x8b,0x36,0x3d,0xcb,0x88,0x1e,0x56,0x25,0x8e,0x2,0x32,0x5d,0x84,0xd0,0x9b,0xc8,0xd9,0x29,0x3,0x13,0xa,0xe2,0xfe,0xc6,0xde,0x73,0x63,0x37,0x54,0x5a,0x2a,0xd2,0x42,0xd3,0xeb,0x38,0x1c,0xfc,0x76,0x78,0xea,0x8,0xe6,0x16,0x98,0x14,0x55,0x4e,0x70,0xf6,0x43,0xd4,0x7a,0x72,0xd8,0xb0,0xc5,0x48,0x5c,0xf7,0xae,0xe1,0x39,0xec,0x80,0x24,0x96,0x30,0x95,0xc9,0x7f,0x94,0xff,0x93,0xa7,0x4b,0x7,0x6c,0x77,0xb9,0x66,0x92,0xfb,0x51,0xe0,0x18,0x22,0xfa,0xac,0x69,0x23,0xbb,0xb,0x19,0x7c,0x41,0x40,0x7e,0x3a,0x68,0xfd,0xb4,0x1f,0x9f,0xcf,0xc1,0xe9,0x52,0x64,0x6f,0xe7,0x9a,0xed,0xdb,0xaf,0x82,0xf3,0x99,0xa5,0x8a,0xf0,0x34,0xf9,0x58,0xa8,0x46,0x65,0x35,0xb2,0xd,0xdd,0x17,0xef,0x2e,0x6e,0xb5,0xc3,0x20,0xa4,0x7b,0x3e,0xa3,0x6b,0xf4,0x11,0x1d,0x47,0x12,0x61,0xee,0xdf,0xf1,0x27,0x97,0x3b,0xc4,0x83,0x3f,0x9c,0x9e,0xd7,0xa9,0xe,0x62,0xd1,0x91,0x53,0x26,0xbd,0x6,0x89,0x49,0xbf,0x32,0x34,0x3c,0xa1,0xd,0x56,0xd1,0x6e,0xf7,0x85,0xff,0xd3,0x44,0xbb,0x9a,0xa7,0x2b,0x9f,0x83,0xfb,0xe7,0x78,0x86,0x3d,0xda,0xc0,0xcf,0xed,0x8a,0x30,0x40,0x47,0xc6,0xa2,0x39,0x27,0x7f,0x50,0x36,0x90,0xfe,0x46,0x4a,0xc7,0x48,0xea,0xf,0x91,0xdd,0x2c,0xb6,0x20,0x2a,0xc,0x62,0xa5,0x8f,0x69,0x21,0xd5,0x5f,0x72,0x4d,0xa6,0x6c,0x82,0x12,0x9c,0xfc,0x76,0x60,0xf2,0x61,0x59,0x96,0xb2,0xa0,0xd0,0xc8,0x58,0xe9,0xf9,0xde,0xbd,0x74,0x68,0x54,0x4c,0x89,0xa3,0x80,0x99,0x11,0x5a,0x53,0x42,0xb8,0x88,0xe,0xd7,0xdc,0x94,0x4,0xaf,0xb7,0xbc,0x2,0x41,0xe0,0xf3,0x1,0x5c,0x3b,0xce,0x6,0xb,0x28,0xd4,0x8b,0x1a,0x17,0x5,0x6f,0x8e,0xab,0xc5,0x7,0xb9,0x63,0x4b,0xee,0xd8,0x95,0x3e,0x45,0x15,0xb0,0xf4,0x77,0xe2,0xf6,0x93,0xca,0xcb,0xa9,0xe3,0x81,0x31,0xa8,0x92,0x26,0x70,0x71,0x18,0x6a,0xdb,0xfd,0xe6,0xec,0x33,0x2d,0x19,0x8d,0xc1,0xf5,0x43,0x75,0x1e,0x1c,0xae,0x1f,0xba,0xb3,0x6b,0xa,0x66,0xd6,0xc2,0x24,0x7d,0x52,0xf8,0x4f,0x3a,0xc9,0x7c,0xf0,0x5e,0xdf,0x9e,0xfa,0xc4,0x3,0x8c,0x35,0xc3,0xd9,0x1b,0x37,0xac,0x84,0x23,0x5b,0xe8,0x16,0xb5,0x5d,0x14,0xb1,0x1d,0x9,0x4e,0x55,0x64,0xad,0x7b,0xcd,0x97,0xeb,0x98,0xe1,0x29,0x9b,0x7e,0x2e,0xaa,0xb4,0xf1,0xe4,0xa4,0x49,0x3f,0x57,0x87,0x65,0x9d,0xef,0xcc,0x38,0xbf,0x73,0xbe,0x22,0xd2,0x2f,0x13,0x7a,0x0,0x25,0x51,0x79,0x8,0x6d,0xe5,0x67,0x10,0xae,0x69,0xe6,0xc0,0x7a,0xec,0x11,0xe0,0x81,0x6a,0x93,0xbe,0xed,0x19,0x43,0xa5,0xfa,0x5c,0xb3,0x9c,0xf5,0xeb,0xa,0x6e,0xc3,0x5d,0x84,0x26,0x86,0xb,0x32,0x8a,0x4a,0xf1,0x2b,0xb4,0x4f,0x37,0xe7,0x53,0x8c,0x8b,0x46,0xfc,0x3,0x21,0x16,0xc,0x1d,0xa2,0xc1,0x9a,0xf0,0x6d,0xfe,0xf8,0x56,0x6b,0x88,0x77,0x33,0x1f,0x3b,0x49,0x47,0xd6,0xe4,0x18,0xca,0xc7,0xf7,0x2,0xcb,0x75,0x67,0x9,0xa3,0x42,0xdb,0xc9,0xc8,0x63,0x10,0x58,0xc2,0x1b,0x74,0x44,0xcd,0x90,0x2c,0x3f,0xce,0x8d,0x7b,0x70,0x98,0x80,0xb8,0xa4,0x12,0x71,0x25,0x35,0x9f,0x8e,0xdd,0x96,0x4c,0x55,0x45,0x6f,0xac,0x3e,0x30,0xba,0xde,0x50,0xa0,0x4e,0x4,0x94,0x6c,0x1c,0x5a,0x7e,0xad,0x95,0x83,0xf6,0x9e,0x34,0xe8,0xb1,0x1a,0xe,0x36,0x8,0x13,0x52,0x3c,0x92,0x5,0xb0,0xb9,0xd2,0x39,0x8f,0x41,0xd,0xe1,0xd5,0xc6,0xaa,0x7f,0xa7,0xd3,0x76,0xd0,0x62,0xea,0xbc,0x64,0x5e,0x4d,0xfd,0x65,0x2f,0x20,0xff,0x31,0x2a,0xa6,0x17,0xbd,0xd4,0x89,0xd9,0x59,0xf2,0x22,0x14,0xaf,0x87,0x6,0x7,0x3a,0x5f,0xbb,0x2e,0x7c,0x38,0xb6,0xcc,0xe3,0xdf,0xee,0x1e,0xbf,0x72,0xab,0xdc,0xa1,0x29,0xb5,0xc4,0xe9,0x9d,0x85,0xf3,0x28,0x68,0x78,0x3d,0xe2,0x66,0xf4,0x73,0x23,0x0,0xa9,0x51,0x9b,0x4b,0x61,0xb7,0x99,0xa8,0xc5,0x82,0x7d,0xd1,0x57,0xb2,0x2d,0xe5,0x27,0x54,0x1,0x5b,0xfb,0x60,0x15,0xd7,0xf9,0xf,0xcf,0x40,0x91,0xd8,0xda,0x79,0x97,0x24,0x48,0xef,0x8c,0x2a,0xc5,0xea,0x83,0x9d,0x7c,0x18,0xb5,0x2b,0xf2,0x50,0xf0,0x7d,0x44,0xfc,0xd8,0x1f,0x90,0xb6,0xc,0x9a,0x67,0x96,0xf7,0x1c,0xe5,0xc8,0x9b,0x6f,0x35,0xd3,0x6b,0xd4,0xb7,0xec,0x86,0x1b,0x88,0x8e,0x20,0x1d,0xfe,0x1,0x45,0x69,0x4d,0x3f,0x3c,0x87,0x5d,0xc2,0x39,0x41,0x91,0x25,0xfa,0xfd,0x30,0x8a,0x75,0x57,0x60,0x7a,0xbe,0x15,0x66,0x2e,0xb4,0x6d,0x2,0x32,0xbb,0xe6,0x5a,0x49,0xb8,0xfb,0xd,0x6,0x31,0xa0,0x92,0x6e,0xbc,0xb1,0x81,0x74,0xbd,0x3,0x11,0x7f,0xd5,0x34,0xad,0xbf,0xda,0x48,0x46,0xcc,0xa8,0x26,0xd6,0x38,0x72,0xe2,0x1a,0x6a,0x2c,0x8,0xdb,0xe3,0xee,0xf6,0xce,0xd2,0x64,0x7,0x53,0x43,0xe9,0xf8,0xab,0xe0,0x3a,0x23,0x33,0x19,0xcf,0xa4,0x4f,0xf9,0x37,0x7b,0x97,0xa3,0xb0,0xdc,0x9,0xd1,0xa5,0x0,0xa6,0x14,0xf5,0x80,0xe8,0x42,0x9e,0xc7,0x6c,0x78,0x40,0x7e,0x65,0x24,0x4a,0xe4,0x73,0xc6,0xff,0xaf,0x2f,0x84,0x54,0x62,0xd9,0xf1,0x70,0x71,0x4c,0x29,0xcd,0x58,0xa,0x4e,0x9c,0xca,0x12,0x28,0x3b,0x8b,0x13,0x59,0x56,0x89,0x47,0x5c,0xd0,0x61,0xcb,0xa2,0xf3,0x85,0x5e,0x1e,0xe,0x4b,0x94,0x10,0x82,0x5,0x55,0x76,0xdf,0x27,0xed,0x3d,0xc0,0xba,0x95,0xa9,0x98,0x68,0xc9,0x4,0xdd,0xaa,0xd7,0x5f,0xc3,0xb2,0x9f,0xeb,0x8d,0x16,0x63,0xa1,0x8f,0x79,0xb9,0x36,0xe7,0xae,0xac,0xf,0xe1,0x52,0x3e,0x99,0x17,0xc1,0xef,0xde,0xb3,0xf4,0xb,0xa7,0x21,0xc4,0x5b,0x93,0x51,0x22,0x77,0x2d,0x58,0x75,0x8c,0x67,0x43,0xa5,0xff,0xb,0x26,0x0,0x8f,0x48,0x6,0xf7,0xa,0x9c,0xc0,0x62,0xbb,0x25,0x6c,0xd4,0xed,0x60,0x7a,0x55,0xba,0x1c,0x88,0xec,0xd,0x13,0x1a,0xa0,0x6d,0x6a,0xea,0xf0,0xc7,0xe5,0x52,0xcd,0x17,0xac,0xb5,0x1,0xd1,0xa9,0x91,0x6e,0x8d,0xb0,0xaf,0xdd,0xf9,0xd5,0x7c,0x27,0x44,0xfb,0x1e,0x18,0x8b,0x16,0xef,0x81,0x93,0x2d,0x2f,0x3d,0xa4,0x45,0xfe,0x2,0x30,0xa1,0xe4,0x11,0x21,0x2c,0xd9,0xca,0x76,0x2b,0x96,0x9d,0x6b,0x28,0xbe,0xf6,0x85,0x2e,0xa2,0x92,0xfd,0x24,0x70,0x3b,0x68,0x79,0x89,0xa3,0xb3,0xaa,0x42,0x5e,0x66,0x7e,0xd3,0xc3,0x97,0xf4,0xfa,0x8a,0x72,0xe2,0x73,0x4b,0x98,0xbc,0x5c,0xd6,0xd8,0x4a,0xa8,0x46,0xb6,0x38,0xb4,0xf5,0xee,0xd0,0x56,0xe3,0x74,0xda,0xd2,0x78,0x10,0x65,0xe8,0xfc,0x57,0xe,0x41,0x99,0x4c,0x20,0x84,0x36,0x90,0x35,0x69,0xdf,0x34,0x5f,0x33,0x7,0xeb,0xa7,0xcc,0xd7,0x19,0xc6,0x32,0x5b,0xf1,0x40,0xb8,0x82,0x5a,0xc,0xc9,0x83,0x1b,0xab,0xb9,0xdc,0xe1,0xe0,0xde,0x9a,0xc8,0x5d,0x14,0xbf,0x3f,0x6f,0x61,0x49,0xf2,0xc4,0xcf,0x47,0x3a,0x4d,0x7b,0xf,0x22,0x53,0x39,0x5,0x2a,0x50,0x94,0x59,0xf8,0x8,0xe6,0xc5,0x95,0x12,0xad,0x7d,0xb7,0x4f,0x8e,0xce,0x15,0x63,0x80,0x4,0xdb,0x9e,0x3,0xcb,0x54,0xb1,0xbd,0xe7,0xb2,0xc1,0x4e,0x7f,0x51,0x87,0x37,0x9b,0x64,0x23,0x9f,0x3c,0x3e,0x77,0x9,0xae,0xc2,0x71,0x31,0xf3,0x86,0x1d,0xa6,0x29,0xe9,0x1f,0xf,0x9,0x1,0x9c,0x30,0x6b,0xec,0x53,0xca,0xb8,0xc2,0xee,0x79,0x86,0xa7,0x9a,0x16,0xa2,0xbe,0xc6,0xda,0x45,0xbb,0x0,0xe7,0xfd,0xf2,0xd0,0xb7,0xd,0x7d,0x7a,0xfb,0x9f,0x4,0x1a,0x42,0x6d,0xb,0xad,0xc3,0x7b,0x77,0xfa,0x75,0xd7,0x32,0xac,0xe0,0x11,0x8b,0x1d,0x17,0x31,0x5f,0x98,0xb2,0x54,0x1c,0xe8,0x62,0x4f,0x70,0x9b,0x51,0xbf,0x2f,0xa1,0xc1,0x4b,0x5d,0xcf,0x5c,0x64,0xab,0x8f,0x9d,0xed,0xf5,0x65,0xd4,0xc4,0xe3,0x80,0x49,0x55,0x69,0x71,0xb4,0x9e,0xbd,0xa4,0x2c,0x67,0x6e,0x7f,0x85,0xb5,0x33,0xea,0xe1,0xa9,0x39,0x92,0x8a,0x81,0x3f,0x7c,0xdd,0xce,0x3c,0x61,0x6,0xf3,0x3b,0x36,0x15,0xe9,0xb6,0x27,0x2a,0x38,0x52,0xb3,0x96,0xf8,0x3a,0x84,0x5e,0x76,0xd3,0xe5,0xa8,0x3,0x78,0x28,0x8d,0xc9,0x4a,0xdf,0xcb,0xae,0xf7,0xf6,0x94,0xde,0xbc,0xc,0x95,0xaf,0x1b,0x4d,0x4c,0x25,0x57,0xe6,0xc0,0xdb,0xd1,0xe,0x10,0x24,0xb0,0xfc,0xc8,0x7e,0x48,0x23,0x21,0x93,0x22,0x87,0x8e,0x56,0x37,0x5b,0xeb,0xff,0x19,0x40,0x6f,0xc5,0x72,0x7,0xf4,0x41,0xcd,0x63,0xe2,0xa3,0xc7,0xf9,0x3e,0xb1,0x8,0xfe,0xe4,0x26,0xa,0x91,0xb9,0x1e,0x66,0xd5,0x2b,0x88,0x60,0x29,0x8c,0x20,0x34,0x73,0x68,0x59,0x90,0x46,0xf0,0xaa,0xd6,0xa5,0xdc,0x14,0xa6,0x43,0x13,0x97,0x89,0xcc,0xd9,0x99,0x74,0x2,0x6a,0xba,0x58,0xa0,0xd2,0xf1,0x5,0x82,0x4e,0x83,0x1f,0xef,0x12,0x2e,0x47,0x3d,0x18,0x6c,0x44,0x35,0x50,0xd8,0x5a,0x2d}; unsigned char table_s2[] = {0xab,0xd,0xb5,0xc8,0x9d,0xed,0x11,0x50,0x63,0x8b,0x83,0x79,0x12,0x7c,0x8d,0x23,0xa1,0xeb,0x4c,0xe6,0xd2,0x53,0x7b,0x62,0xf0,0x14,0x28,0xae,0x9e,0xaf,0xb6,0x8c,0xc6,0xb3,0x85,0x40,0x94,0x6d,0x32,0x58,0xf7,0xf8,0x86,0xb1,0xdd,0xdb,0xfc,0x37,0x5b,0xa4,0xee,0x46,0x27,0x1a,0x41,0x93,0x89,0xdf,0x3,0x5a,0x59,0x87,0x60,0xd5,0xe5,0xb7,0xc1,0x3c,0xce,0x1f,0xc2,0x6f,0x36,0x9,0x5f,0xe0,0x10,0x52,0x4a,0x61,0x4b,0xe7,0x42,0xbe,0xa0,0xde,0x2d,0xa9,0x91,0x21,0xfe,0x39,0xb9,0x26,0x68,0xbb,0x25,0xec,0x4f,0x97,0xa,0x4e,0xfb,0x81,0x49,0x5c,0x67,0xc7,0x1c,0x17,0xb8,0xa7,0x16,0xad,0xf9,0x69,0xe4,0x3e,0x0,0xd9,0xac,0x3d,0x2e,0x47,0xd1,0x74,0x1d,0x54,0x7,0x9b,0xd3,0x56,0x29,0xdc,0xa6,0xc9,0x33,0x9c,0x2a,0xfd,0x72,0xf5,0xb,0x7d,0x22,0x80,0x96,0x4,0x3f,0xe9,0x2f,0x34,0x65,0x84,0x38,0xa3,0x2b,0xe1,0x24,0xc4,0x7f,0x57,0xc0,0xb4,0xea,0xca,0x45,0x99,0x90,0x75,0xbc,0x71,0xb0,0xf6,0x1b,0xcb,0x9f,0x6,0xff,0x98,0x20,0xd4,0xfa,0x9a,0xd0,0x8a,0x18,0x70,0xb2,0x5e,0x13,0x3a,0xe3,0x35,0x5d,0x1e,0xd8,0xd6,0xda,0x51,0x2,0x66,0x8,0xd7,0xcf,0xf1,0x30,0x2c,0x6b,0x95,0xaa,0xf2,0xba,0xc3,0xef,0x78,0xc,0x8f,0xa2,0x4d,0x44,0x43,0x7a,0x77,0x15,0xa8,0xc5,0xf3,0x5,0xf4,0xe,0xf,0x55,0x48,0xbf,0xe2,0xbd,0x92,0x7e,0x6c,0xcd,0x82,0x31,0x3b,0xcc,0x19,0x6e,0x6a,0x1,0x76,0x73,0x64,0xe8,0x8e,0xa5,0x88,0x28,0xef,0x30,0x80,0xaa,0x79,0x37,0xa8,0xaf,0x53,0xf6,0x5a,0xb8,0x3c,0xcf,0xb1,0xf1,0x4e,0x18,0x27,0x70,0x5b,0x43,0x1,0x2d,0xd0,0xa6,0xf4,0x7e,0xd3,0xe,0xdf,0x56,0x3f,0x2c,0xbd,0x45,0xc,0x65,0xc0,0x78,0xe8,0xbc,0x7,0xc8,0x11,0x2f,0xf5,0xd6,0x76,0x4d,0x58,0xb6,0xa9,0x6,0xd,0x86,0x5e,0xfd,0x34,0x90,0xea,0x5f,0x1b,0xbf,0x39,0x5,0xe1,0x9d,0xa7,0xbe,0x8f,0xf7,0x5d,0xfa,0xb0,0x73,0x6a,0x42,0xc3,0x68,0x92,0x9a,0x72,0x32,0x9c,0x6d,0x3,0xd9,0xa4,0x1c,0xba,0x41,0x0,0xfc,0x8c,0x4b,0x12,0xce,0x98,0xc4,0x71,0x96,0x48,0x57,0xff,0xb5,0x4a,0x82,0x50,0xb,0x36,0xa0,0x97,0xe9,0xe6,0x26,0xed,0xca,0xcc,0x51,0x94,0xa2,0xd7,0x49,0x23,0x7c,0x85,0x5c,0xb3,0x9e,0x1d,0x66,0x6b,0x52,0x55,0xe3,0xbb,0x84,0x7a,0x69,0xfe,0xd2,0xab,0xc6,0x19,0x77,0x13,0x3d,0x21,0xe0,0xde,0xf,0x4c,0x24,0xf2,0x40,0xcb,0xc7,0xc9,0x75,0x62,0x67,0x10,0x99,0xb4,0x9f,0xf9,0x2a,0x20,0x93,0xdc,0x7b,0x7f,0x8,0xdd,0xf3,0xae,0x59,0x44,0x7d,0x6f,0x83,0xac,0xe2,0xd4,0xb9,0x4,0x1e,0x1f,0xe5,0x14,0xb2,0x29,0x95,0x74,0xd5,0x35,0xf0,0x3a,0x15,0x87,0x91,0x33,0x25,0x3e,0xf8,0x2e,0xec,0x3b,0x8d,0x22,0x6c,0x1a,0xe4,0x63,0x47,0xc2,0x8a,0x16,0xd8,0xb7,0xcd,0x38,0x61,0x9,0x9b,0xc1,0x2b,0x2,0x4f,0xa3,0x89,0xee,0x17,0x8e,0x8b,0xeb,0xc5,0x31,0x60,0xad,0x64,0x81,0xda,0xa,0xe7,0xa1,0xa5,0xd1,0x46,0x6e,0x88,0x54,0xdb,0xfb,0x83,0x21,0x7,0x95,0xea,0x3c,0x37,0x2c,0x87,0x66,0xa0,0x3b,0xe2,0x28,0xc7,0x27,0x98,0x4,0x55,0xd0,0xdf,0x2a,0xca,0xa5,0x9f,0x30,0xfe,0x29,0xf6,0x71,0x7e,0x8,0x5,0x9c,0x9b,0xfc,0xd7,0x23,0x99,0xf9,0x89,0xd3,0x73,0x1b,0x5d,0xb1,0x39,0x10,0x54,0x7c,0xb7,0xc3,0xc9,0xe9,0x9a,0x46,0x76,0x93,0x72,0xbf,0xf5,0xb3,0xc8,0x18,0x96,0x68,0xf1,0xa9,0xc0,0xb9,0x7b,0xec,0x8c,0xf,0x4e,0xa1,0x40,0x47,0x74,0x79,0x36,0xe0,0x1d,0x5e,0xd5,0xdb,0x52,0xd9,0x65,0x1,0xd4,0xb,0xf2,0xcc,0x2f,0x33,0x81,0xce,0x38,0x32,0x1a,0xcf,0x69,0x6d,0x75,0x2,0x67,0x70,0x8d,0xeb,0x8b,0xa6,0xab,0x16,0xf0,0xc6,0xf7,0x6,0xc,0xd,0x4b,0x56,0xe1,0xbc,0x91,0xbe,0x6f,0x7d,0xe8,0xa2,0xe5,0x4f,0x50,0xd1,0x61,0x78,0x17,0xf3,0xad,0x2b,0xac,0x9d,0x8f,0xb5,0xe,0xa8,0xcb,0xb6,0xee,0x9e,0x53,0x12,0x88,0x60,0x7a,0x80,0x7f,0x11,0x20,0x8e,0xa7,0x58,0x45,0xed,0x19,0x24,0x90,0x42,0xdc,0x8a,0x59,0x0,0x84,0x5a,0xd6,0x63,0xb0,0xc5,0x43,0x86,0x6e,0x97,0x5b,0x31,0xfb,0xf4,0xb2,0x85,0xd8,0xde,0x34,0xff,0xe4,0x48,0xbd,0x41,0xdd,0xa3,0xaa,0x2e,0x22,0x92,0x3a,0xfd,0x25,0xba,0xb8,0x6b,0xb4,0xe6,0x3f,0xc2,0x1c,0xcd,0x6c,0xc1,0xa,0x35,0xe3,0x5c,0x51,0x13,0x62,0x49,0xae,0x15,0x6a,0xfa,0x3d,0xe7,0xda,0x3,0x3e,0xaf,0x44,0x2d,0x77,0xd2,0x57,0x1e,0xef,0x26,0x94,0x4c,0x4d,0x9,0x82,0xf8,0x5f,0x4a,0xc4,0x64,0x14,0x1f,0xa4,0xbb,0x47,0xbb,0x4e,0xe2,0x28,0xac,0xa5,0xdb,0xfb,0x3c,0x94,0x24,0x6d,0xbe,0xbc,0x23,0xc4,0x39,0xe0,0xb2,0xc7,0x6a,0xcb,0x1a,0x5a,0xe5,0x33,0xc,0x4f,0x64,0x15,0x57,0xfc,0x6c,0x13,0xa8,0x5,0xdc,0xe1,0x3b,0x2b,0x42,0xa9,0x38,0x18,0x51,0xd4,0x71,0x4a,0x92,0x20,0xe9,0xfe,0x84,0xf,0x4b,0x62,0xc2,0x4c,0x59,0xbd,0xa2,0x19,0x12,0x49,0xe3,0xa4,0xee,0x7e,0x67,0xd7,0x56,0x2d,0xab,0xf5,0x11,0xb3,0x89,0x9b,0xaa,0xb0,0xcd,0xae,0x8,0x14,0x55,0x98,0xe8,0x86,0x7c,0x66,0x8e,0x88,0x26,0x17,0x79,0xeb,0x43,0x5e,0xa1,0x44,0x96,0x22,0x1f,0x6,0x5f,0x8c,0xda,0x65,0xd0,0x5c,0x82,0x80,0x45,0xc3,0xb6,0x37,0x5d,0x91,0x68,0x83,0xb4,0xf2,0xfd,0xf9,0x32,0xd8,0xde,0xaf,0xf7,0x6e,0x90,0xea,0x7d,0xbf,0xc6,0xa7,0x48,0x9,0x8a,0x7f,0x72,0x41,0x46,0x58,0x1b,0xe6,0x30,0xdf,0x54,0xdd,0xd3,0xd,0xd2,0x7,0x63,0x35,0x29,0xca,0xf4,0x34,0x3e,0xc8,0x87,0x6b,0x6f,0xc9,0x1c,0x76,0x61,0x4,0x73,0xa0,0x8d,0xed,0x8b,0xc0,0xf6,0x10,0xad,0xb,0xa,0x0,0xf1,0xba,0xe7,0x50,0x4d,0x7b,0x69,0xb8,0x97,0x93,0x1,0x27,0x85,0x2a,0x31,0x3a,0xec,0x3d,0xa6,0x60,0x81,0x21,0xc1,0x2e,0xe4,0xd6,0x53,0x2,0x9e,0xa3,0xcc,0x2c,0xd9,0x2f,0xf8,0x36,0x99,0xe,0x78,0x77,0xf0,0xfa,0x9d,0x9a,0x3,0xff,0x9f,0x25,0xd1,0x1d,0x75,0xd5,0x8f,0x16,0x3f,0xb7,0x5b,0xc5,0xb1,0x7a,0x52,0x40,0x9c,0xef,0xcf,0xb9,0x74,0x95,0x70,0x1e,0xce,0xb5,0xf3,0x6c,0xca,0x72,0xf,0x5a,0x2a,0xd6,0x97,0xa4,0x4c,0x44,0xbe,0xd5,0xbb,0x4a,0xe4,0x66,0x2c,0x8b,0x21,0x15,0x94,0xbc,0xa5,0x37,0xd3,0xef,0x69,0x59,0x68,0x71,0x4b,0x1,0x74,0x42,0x87,0x53,0xaa,0xf5,0x9f,0x30,0x3f,0x41,0x76,0x1a,0x1c,0x3b,0xf0,0x9c,0x63,0x29,0x81,0xe0,0xdd,0x86,0x54,0x4e,0x18,0xc4,0x9d,0x9e,0x40,0xa7,0x12,0x22,0x70,0x6,0xfb,0x9,0xd8,0x5,0xa8,0xf1,0xce,0x98,0x27,0xd7,0x95,0x8d,0xa6,0x8c,0x20,0x85,0x79,0x67,0x19,0xea,0x6e,0x56,0xe6,0x39,0xfe,0x7e,0xe1,0xaf,0x7c,0xe2,0x2b,0x88,0x50,0xcd,0x89,0x3c,0x46,0x8e,0x9b,0xa0,0x0,0xdb,0xd0,0x7f,0x60,0xd1,0x6a,0x3e,0xae,0x23,0xf9,0xc7,0x1e,0x6b,0xfa,0xe9,0x80,0x16,0xb3,0xda,0x93,0xc0,0x5c,0x14,0x91,0xee,0x1b,0x61,0xe,0xf4,0x5b,0xed,0x3a,0xb5,0x32,0xcc,0xba,0xe5,0x47,0x51,0xc3,0xf8,0x2e,0xe8,0xf3,0xa2,0x43,0xff,0x64,0xec,0x26,0xe3,0x3,0xb8,0x90,0x7,0x73,0x2d,0xd,0x82,0x5e,0x57,0xb2,0x7b,0xb6,0x77,0x31,0xdc,0xc,0x58,0xc1,0x38,0x5f,0xe7,0x13,0x3d,0x5d,0x17,0x4d,0xdf,0xb7,0x75,0x99,0xd4,0xfd,0x24,0xf2,0x9a,0xd9,0x1f,0x11,0x1d,0x96,0xc5,0xa1,0xcf,0x10,0x8,0x36,0xf7,0xeb,0xac,0x52,0x6d,0x35,0x7d,0x4,0x28,0xbf,0xcb,0x48,0x65,0x8a,0x83,0x84,0xbd,0xb0,0xd2,0x6f,0x2,0x34,0xc2,0x33,0xc9,0xc8,0x92,0x8f,0x78,0x25,0x7a,0x55,0xb9,0xab,0xa,0x45,0xf6,0xfc,0xb,0xde,0xa9,0xad,0xc6,0xb1,0xb4,0xa3,0x2f,0x49,0x62,0x4f,0xad,0x6a,0xb5,0x5,0x2f,0xfc,0xb2,0x2d,0x2a,0xd6,0x73,0xdf,0x3d,0xb9,0x4a,0x34,0x74,0xcb,0x9d,0xa2,0xf5,0xde,0xc6,0x84,0xa8,0x55,0x23,0x71,0xfb,0x56,0x8b,0x5a,0xd3,0xba,0xa9,0x38,0xc0,0x89,0xe0,0x45,0xfd,0x6d,0x39,0x82,0x4d,0x94,0xaa,0x70,0x53,0xf3,0xc8,0xdd,0x33,0x2c,0x83,0x88,0x3,0xdb,0x78,0xb1,0x15,0x6f,0xda,0x9e,0x3a,0xbc,0x80,0x64,0x18,0x22,0x3b,0xa,0x72,0xd8,0x7f,0x35,0xf6,0xef,0xc7,0x46,0xed,0x17,0x1f,0xf7,0xb7,0x19,0xe8,0x86,0x5c,0x21,0x99,0x3f,0xc4,0x85,0x79,0x9,0xce,0x97,0x4b,0x1d,0x41,0xf4,0x13,0xcd,0xd2,0x7a,0x30,0xcf,0x7,0xd5,0x8e,0xb3,0x25,0x12,0x6c,0x63,0xa3,0x68,0x4f,0x49,0xd4,0x11,0x27,0x52,0xcc,0xa6,0xf9,0x0,0xd9,0x36,0x1b,0x98,0xe3,0xee,0xd7,0xd0,0x66,0x3e,0x1,0xff,0xec,0x7b,0x57,0x2e,0x43,0x9c,0xf2,0x96,0xb8,0xa4,0x65,0x5b,0x8a,0xc9,0xa1,0x77,0xc5,0x4e,0x42,0x4c,0xf0,0xe7,0xe2,0x95,0x1c,0x31,0x1a,0x7c,0xaf,0xa5,0x16,0x59,0xfe,0xfa,0x8d,0x58,0x76,0x2b,0xdc,0xc1,0xf8,0xea,0x6,0x29,0x67,0x51,0x3c,0x81,0x9b,0x9a,0x60,0x91,0x37,0xac,0x10,0xf1,0x50,0xb0,0x75,0xbf,0x90,0x2,0x14,0xb6,0xa0,0xbb,0x7d,0xab,0x69,0xbe,0x8,0xa7,0xe9,0x9f,0x61,0xe6,0xc2,0x47,0xf,0x93,0x5d,0x32,0x48,0xbd,0xe4,0x8c,0x1e,0x44,0xae,0x87,0xca,0x26,0xc,0x6b,0x92,0xb,0xe,0x6e,0x40,0xb4,0xe5,0x28,0xe1,0x4,0x5f,0x8f,0x62,0x24,0x20,0x54,0xc3,0xeb,0xd,0xd1,0x5e,0x7e,0x94,0x36,0x10,0x82,0xfd,0x2b,0x20,0x3b,0x90,0x71,0xb7,0x2c,0xf5,0x3f,0xd0,0x30,0x8f,0x13,0x42,0xc7,0xc8,0x3d,0xdd,0xb2,0x88,0x27,0xe9,0x3e,0xe1,0x66,0x69,0x1f,0x12,0x8b,0x8c,0xeb,0xc0,0x34,0x8e,0xee,0x9e,0xc4,0x64,0xc,0x4a,0xa6,0x2e,0x7,0x43,0x6b,0xa0,0xd4,0xde,0xfe,0x8d,0x51,0x61,0x84,0x65,0xa8,0xe2,0xa4,0xdf,0xf,0x81,0x7f,0xe6,0xbe,0xd7,0xae,0x6c,0xfb,0x9b,0x18,0x59,0xb6,0x57,0x50,0x63,0x6e,0x21,0xf7,0xa,0x49,0xc2,0xcc,0x45,0xce,0x72,0x16,0xc3,0x1c,0xe5,0xdb,0x38,0x24,0x96,0xd9,0x2f,0x25,0xd,0xd8,0x7e,0x7a,0x62,0x15,0x70,0x67,0x9a,0xfc,0x9c,0xb1,0xbc,0x1,0xe7,0xd1,0xe0,0x11,0x1b,0x1a,0x5c,0x41,0xf6,0xab,0x86,0xa9,0x78,0x6a,0xff,0xb5,0xf2,0x58,0x47,0xc6,0x76,0x6f,0x0,0xe4,0xba,0x3c,0xbb,0x8a,0x98,0xa2,0x19,0xbf,0xdc,0xa1,0xf9,0x89,0x44,0x5,0x9f,0x77,0x6d,0x97,0x68,0x6,0x37,0x99,0xb0,0x4f,0x52,0xfa,0xe,0x33,0x87,0x55,0xcb,0x9d,0x4e,0x17,0x93,0x4d,0xc1,0x74,0xa7,0xd2,0x54,0x91,0x79,0x80,0x4c,0x26,0xec,0xe3,0xa5,0x92,0xcf,0xc9,0x23,0xe8,0xf3,0x5f,0xaa,0x56,0xca,0xb4,0xbd,0x39,0x35,0x85,0x2d,0xea,0x32,0xad,0xaf,0x7c,0xa3,0xf1,0x28,0xd5,0xb,0xda,0x7b,0xd6,0x1d,0x22,0xf4,0x4b,0x46,0x4,0x75,0x5e,0xb9,0x2,0x7d,0xed,0x2a,0xf0,0xcd,0x14,0x29,0xb8,0x53,0x3a,0x60,0xc5,0x40,0x9,0xf8,0x31,0x83,0x5b,0x5a,0x1e,0x95,0xef,0x48,0x5d,0xd3,0x73,0x3,0x8,0xb3,0xac,0x8c,0x70,0x85,0x29,0xe3,0x67,0x6e,0x10,0x30,0xf7,0x5f,0xef,0xa6,0x75,0x77,0xe8,0xf,0xf2,0x2b,0x79,0xc,0xa1,0x0,0xd1,0x91,0x2e,0xf8,0xc7,0x84,0xaf,0xde,0x9c,0x37,0xa7,0xd8,0x63,0xce,0x17,0x2a,0xf0,0xe0,0x89,0x62,0xf3,0xd3,0x9a,0x1f,0xba,0x81,0x59,0xeb,0x22,0x35,0x4f,0xc4,0x80,0xa9,0x9,0x87,0x92,0x76,0x69,0xd2,0xd9,0x82,0x28,0x6f,0x25,0xb5,0xac,0x1c,0x9d,0xe6,0x60,0x3e,0xda,0x78,0x42,0x50,0x61,0x7b,0x6,0x65,0xc3,0xdf,0x9e,0x53,0x23,0x4d,0xb7,0xad,0x45,0x43,0xed,0xdc,0xb2,0x20,0x88,0x95,0x6a,0x8f,0x5d,0xe9,0xd4,0xcd,0x94,0x47,0x11,0xae,0x1b,0x97,0x49,0x4b,0x8e,0x8,0x7d,0xfc,0x96,0x5a,0xa3,0x48,0x7f,0x39,0x36,0x32,0xf9,0x13,0x15,0x64,0x3c,0xa5,0x5b,0x21,0xb6,0x74,0xd,0x6c,0x83,0xc2,0x41,0xb4,0xb9,0x8a,0x8d,0x93,0xd0,0x2d,0xfb,0x14,0x9f,0x16,0x18,0xc6,0x19,0xcc,0xa8,0xfe,0xe2,0x1,0x3f,0xff,0xf5,0x3,0x4c,0xa0,0xa4,0x2,0xd7,0xbd,0xaa,0xcf,0xb8,0x6b,0x46,0x26,0x40,0xb,0x3d,0xdb,0x66,0xc0,0xc1,0xcb,0x3a,0x71,0x2c,0x9b,0x86,0xb0,0xa2,0x73,0x5c,0x58,0xca,0xec,0x4e,0xe1,0xfa,0xf1,0x27,0xf6,0x6d,0xab,0x4a,0xea,0xa,0xe5,0x2f,0x1d,0x98,0xc9,0x55,0x68,0x7,0xe7,0x12,0xe4,0x33,0xfd,0x52,0xc5,0xb3,0xbc,0x3b,0x31,0x56,0x51,0xc8,0x34,0x54,0xee,0x1a,0xd6,0xbe,0x1e,0x44,0xdd,0xf4,0x7c,0x90,0xe,0x7a,0xb1,0x99,0x8b,0x57,0x24,0x4,0x72,0xbf,0x5e,0xbb,0xd5,0x5,0x7e,0x38,0x1,0xa7,0x1f,0x62,0x37,0x47,0xbb,0xfa,0xc9,0x21,0x29,0xd3,0xb8,0xd6,0x27,0x89,0xb,0x41,0xe6,0x4c,0x78,0xf9,0xd1,0xc8,0x5a,0xbe,0x82,0x4,0x34,0x5,0x1c,0x26,0x6c,0x19,0x2f,0xea,0x3e,0xc7,0x98,0xf2,0x5d,0x52,0x2c,0x1b,0x77,0x71,0x56,0x9d,0xf1,0xe,0x44,0xec,0x8d,0xb0,0xeb,0x39,0x23,0x75,0xa9,0xf0,0xf3,0x2d,0xca,0x7f,0x4f,0x1d,0x6b,0x96,0x64,0xb5,0x68,0xc5,0x9c,0xa3,0xf5,0x4a,0xba,0xf8,0xe0,0xcb,0xe1,0x4d,0xe8,0x14,0xa,0x74,0x87,0x3,0x3b,0x8b,0x54,0x93,0x13,0x8c,0xc2,0x11,0x8f,0x46,0xe5,0x3d,0xa0,0xe4,0x51,0x2b,0xe3,0xf6,0xcd,0x6d,0xb6,0xbd,0x12,0xd,0xbc,0x7,0x53,0xc3,0x4e,0x94,0xaa,0x73,0x6,0x97,0x84,0xed,0x7b,0xde,0xb7,0xfe,0xad,0x31,0x79,0xfc,0x83,0x76,0xc,0x63,0x99,0x36,0x80,0x57,0xd8,0x5f,0xa1,0xd7,0x88,0x2a,0x3c,0xae,0x95,0x43,0x85,0x9e,0xcf,0x2e,0x92,0x9,0x81,0x4b,0x8e,0x6e,0xd5,0xfd,0x6a,0x1e,0x40,0x60,0xef,0x33,0x3a,0xdf,0x16,0xdb,0x1a,0x5c,0xb1,0x61,0x35,0xac,0x55,0x32,0x8a,0x7e,0x50,0x30,0x7a,0x20,0xb2,0xda,0x18,0xf4,0xb9,0x90,0x49,0x9f,0xf7,0xb4,0x72,0x7c,0x70,0xfb,0xa8,0xcc,0xa2,0x7d,0x65,0x5b,0x9a,0x86,0xc1,0x3f,0x0,0x58,0x10,0x69,0x45,0xd2,0xa6,0x25,0x8,0xe7,0xee,0xe9,0xd0,0xdd,0xbf,0x2,0x6f,0x59,0xaf,0x5e,0xa4,0xa5,0xff,0xe2,0x15,0x48,0x17,0x38,0xd4,0xc6,0x67,0x28,0x9b,0x91,0x66,0xb3,0xc4,0xc0,0xab,0xdc,0xd9,0xce,0x42,0x24,0xf,0x22,0xf4,0x33,0xec,0x5c,0x76,0xa5,0xeb,0x74,0x73,0x8f,0x2a,0x86,0x64,0xe0,0x13,0x6d,0x2d,0x92,0xc4,0xfb,0xac,0x87,0x9f,0xdd,0xf1,0xc,0x7a,0x28,0xa2,0xf,0xd2,0x3,0x8a,0xe3,0xf0,0x61,0x99,0xd0,0xb9,0x1c,0xa4,0x34,0x60,0xdb,0x14,0xcd,0xf3,0x29,0xa,0xaa,0x91,0x84,0x6a,0x75,0xda,0xd1,0x5a,0x82,0x21,0xe8,0x4c,0x36,0x83,0xc7,0x63,0xe5,0xd9,0x3d,0x41,0x7b,0x62,0x53,0x2b,0x81,0x26,0x6c,0xaf,0xb6,0x9e,0x1f,0xb4,0x4e,0x46,0xae,0xee,0x40,0xb1,0xdf,0x5,0x78,0xc0,0x66,0x9d,0xdc,0x20,0x50,0x97,0xce,0x12,0x44,0x18,0xad,0x4a,0x94,0x8b,0x23,0x69,0x96,0x5e,0x8c,0xd7,0xea,0x7c,0x4b,0x35,0x3a,0xfa,0x31,0x16,0x10,0x8d,0x48,0x7e,0xb,0x95,0xff,0xa0,0x59,0x80,0x6f,0x42,0xc1,0xba,0xb7,0x8e,0x89,0x3f,0x67,0x58,0xa6,0xb5,0x22,0xe,0x77,0x1a,0xc5,0xab,0xcf,0xe1,0xfd,0x3c,0x2,0xd3,0x90,0xf8,0x2e,0x9c,0x17,0x1b,0x15,0xa9,0xbe,0xbb,0xcc,0x45,0x68,0x43,0x25,0xf6,0xfc,0x4f,0x0,0xa7,0xa3,0xd4,0x1,0x2f,0x72,0x85,0x98,0xa1,0xb3,0x5f,0x70,0x3e,0x8,0x65,0xd8,0xc2,0xc3,0x39,0xc8,0x6e,0xf5,0x49,0xa8,0x9,0xe9,0x2c,0xe6,0xc9,0x5b,0x4d,0xef,0xf9,0xe2,0x24,0xf2,0x30,0xe7,0x51,0xfe,0xb0,0xc6,0x38,0xbf,0x9b,0x1e,0x56,0xca,0x4,0x6b,0x11,0xe4,0xbd,0xd5,0x47,0x1d,0xf7,0xde,0x93,0x7f,0x55,0x32,0xcb,0x52,0x57,0x37,0x19,0xed,0xbc,0x71,0xb8,0x5d,0x6,0xd6,0x3b,0x7d,0x79,0xd,0x9a,0xb2,0x54,0x88,0x7,0x27,0x31,0x93,0xb5,0x27,0x58,0x8e,0x85,0x9e,0x35,0xd4,0x12,0x89,0x50,0x9a,0x75,0x95,0x2a,0xb6,0xe7,0x62,0x6d,0x98,0x78,0x17,0x2d,0x82,0x4c,0x9b,0x44,0xc3,0xcc,0xba,0xb7,0x2e,0x29,0x4e,0x65,0x91,0x2b,0x4b,0x3b,0x61,0xc1,0xa9,0xef,0x3,0x8b,0xa2,0xe6,0xce,0x5,0x71,0x7b,0x5b,0x28,0xf4,0xc4,0x21,0xc0,0xd,0x47,0x1,0x7a,0xaa,0x24,0xda,0x43,0x1b,0x72,0xb,0xc9,0x5e,0x3e,0xbd,0xfc,0x13,0xf2,0xf5,0xc6,0xcb,0x84,0x52,0xaf,0xec,0x67,0x69,0xe0,0x6b,0xd7,0xb3,0x66,0xb9,0x40,0x7e,0x9d,0x81,0x33,0x7c,0x8a,0x80,0xa8,0x7d,0xdb,0xdf,0xc7,0xb0,0xd5,0xc2,0x3f,0x59,0x39,0x14,0x19,0xa4,0x42,0x74,0x45,0xb4,0xbe,0xbf,0xf9,0xe4,0x53,0xe,0x23,0xc,0xdd,0xcf,0x5a,0x10,0x57,0xfd,0xe2,0x63,0xd3,0xca,0xa5,0x41,0x1f,0x99,0x1e,0x2f,0x3d,0x7,0xbc,0x1a,0x79,0x4,0x5c,0x2c,0xe1,0xa0,0x3a,0xd2,0xc8,0x32,0xcd,0xa3,0x92,0x3c,0x15,0xea,0xf7,0x5f,0xab,0x96,0x22,0xf0,0x6e,0x38,0xeb,0xb2,0x36,0xe8,0x64,0xd1,0x2,0x77,0xf1,0x34,0xdc,0x25,0xe9,0x83,0x49,0x46,0x0,0x37,0x6a,0x6c,0x86,0x4d,0x56,0xfa,0xf,0xf3,0x6f,0x11,0x18,0x9c,0x90,0x20,0x88,0x4f,0x97,0x8,0xa,0xd9,0x6,0x54,0x8d,0x70,0xae,0x7f,0xde,0x73,0xb8,0x87,0x51,0xee,0xe3,0xa1,0xd0,0xfb,0x1c,0xa7,0xd8,0x48,0x8f,0x55,0x68,0xb1,0x8c,0x1d,0xf6,0x9f,0xc5,0x60,0xe5,0xac,0x5d,0x94,0x26,0xfe,0xff,0xbb,0x30,0x4a,0xed,0xf8,0x76,0xd6,0xa6,0xad,0x16,0x9,0x66,0x9a,0x6f,0xc3,0x9,0x8d,0x84,0xfa,0xda,0x1d,0xb5,0x5,0x4c,0x9f,0x9d,0x2,0xe5,0x18,0xc1,0x93,0xe6,0x4b,0xea,0x3b,0x7b,0xc4,0x12,0x2d,0x6e,0x45,0x34,0x76,0xdd,0x4d,0x32,0x89,0x24,0xfd,0xc0,0x1a,0xa,0x63,0x88,0x19,0x39,0x70,0xf5,0x50,0x6b,0xb3,0x1,0xc8,0xdf,0xa5,0x2e,0x6a,0x43,0xe3,0x6d,0x78,0x9c,0x83,0x38,0x33,0x68,0xc2,0x85,0xcf,0x5f,0x46,0xf6,0x77,0xc,0x8a,0xd4,0x30,0x92,0xa8,0xba,0x8b,0x91,0xec,0x8f,0x29,0x35,0x74,0xb9,0xc9,0xa7,0x5d,0x47,0xaf,0xa9,0x7,0x36,0x58,0xca,0x62,0x7f,0x80,0x65,0xb7,0x3,0x3e,0x27,0x7e,0xad,0xfb,0x44,0xf1,0x7d,0xa3,0xa1,0x64,0xe2,0x97,0x16,0x7c,0xb0,0x49,0xa2,0x95,0xd3,0xdc,0xd8,0x13,0xf9,0xff,0x8e,0xd6,0x4f,0xb1,0xcb,0x5c,0x9e,0xe7,0x86,0x69,0x28,0xab,0x5e,0x53,0x60,0x67,0x79,0x3a,0xc7,0x11,0xfe,0x75,0xfc,0xf2,0x2c,0xf3,0x26,0x42,0x14,0x8,0xeb,0xd5,0x15,0x1f,0xe9,0xa6,0x4a,0x4e,0xe8,0x3d,0x57,0x40,0x25,0x52,0x81,0xac,0xcc,0xaa,0xe1,0xd7,0x31,0x8c,0x2a,0x2b,0x21,0xd0,0x9b,0xc6,0x71,0x6c,0x5a,0x48,0x99,0xb6,0xb2,0x20,0x6,0xa4,0xb,0x10,0x1b,0xcd,0x1c,0x87,0x41,0xa0,0x0,0xe0,0xf,0xc5,0xf7,0x72,0x23,0xbf,0x82,0xed,0xd,0xf8,0xe,0xd9,0x17,0xb8,0x2f,0x59,0x56,0xd1,0xdb,0xbc,0xbb,0x22,0xde,0xbe,0x4,0xf0,0x3c,0x54,0xf4,0xae,0x37,0x1e,0x96,0x7a,0xe4,0x90,0x5b,0x73,0x61,0xbd,0xce,0xee,0x98,0x55,0xb4,0x51,0x3f,0xef,0x94,0xd2,0x2b,0x8d,0x35,0x48,0x1d,0x6d,0x91,0xd0,0xe3,0xb,0x3,0xf9,0x92,0xfc,0xd,0xa3,0x21,0x6b,0xcc,0x66,0x52,0xd3,0xfb,0xe2,0x70,0x94,0xa8,0x2e,0x1e,0x2f,0x36,0xc,0x46,0x33,0x5,0xc0,0x14,0xed,0xb2,0xd8,0x77,0x78,0x6,0x31,0x5d,0x5b,0x7c,0xb7,0xdb,0x24,0x6e,0xc6,0xa7,0x9a,0xc1,0x13,0x9,0x5f,0x83,0xda,0xd9,0x7,0xe0,0x55,0x65,0x37,0x41,0xbc,0x4e,0x9f,0x42,0xef,0xb6,0x89,0xdf,0x60,0x90,0xd2,0xca,0xe1,0xcb,0x67,0xc2,0x3e,0x20,0x5e,0xad,0x29,0x11,0xa1,0x7e,0xb9,0x39,0xa6,0xe8,0x3b,0xa5,0x6c,0xcf,0x17,0x8a,0xce,0x7b,0x1,0xc9,0xdc,0xe7,0x47,0x9c,0x97,0x38,0x27,0x96,0x2d,0x79,0xe9,0x64,0xbe,0x80,0x59,0x2c,0xbd,0xae,0xc7,0x51,0xf4,0x9d,0xd4,0x87,0x1b,0x53,0xd6,0xa9,0x5c,0x26,0x49,0xb3,0x1c,0xaa,0x7d,0xf2,0x75,0x8b,0xfd,0xa2,0x0,0x16,0x84,0xbf,0x69,0xaf,0xb4,0xe5,0x4,0xb8,0x23,0xab,0x61,0xa4,0x44,0xff,0xd7,0x40,0x34,0x6a,0x4a,0xc5,0x19,0x10,0xf5,0x3c,0xf1,0x30,0x76,0x9b,0x4b,0x1f,0x86,0x7f,0x18,0xa0,0x54,0x7a,0x1a,0x50,0xa,0x98,0xf0,0x32,0xde,0x93,0xba,0x63,0xb5,0xdd,0x9e,0x58,0x56,0x5a,0xd1,0x82,0xe6,0x88,0x57,0x4f,0x71,0xb0,0xac,0xeb,0x15,0x2a,0x72,0x3a,0x43,0x6f,0xf8,0x8c,0xf,0x22,0xcd,0xc4,0xc3,0xfa,0xf7,0x95,0x28,0x45,0x73,0x85,0x74,0x8e,0x8f,0xd5,0xc8,0x3f,0x62,0x3d,0x12,0xfe,0xec,0x4d,0x2,0xb1,0xbb,0x4c,0x99,0xee,0xea,0x81,0xf6,0xf3,0xe4,0x68,0xe,0x25,0x8,0xfa,0x3d,0xe2,0x52,0x78,0xab,0xe5,0x7a,0x7d,0x81,0x24,0x88,0x6a,0xee,0x1d,0x63,0x23,0x9c,0xca,0xf5,0xa2,0x89,0x91,0xd3,0xff,0x2,0x74,0x26,0xac,0x1,0xdc,0xd,0x84,0xed,0xfe,0x6f,0x97,0xde,0xb7,0x12,0xaa,0x3a,0x6e,0xd5,0x1a,0xc3,0xfd,0x27,0x4,0xa4,0x9f,0x8a,0x64,0x7b,0xd4,0xdf,0x54,0x8c,0x2f,0xe6,0x42,0x38,0x8d,0xc9,0x6d,0xeb,0xd7,0x33,0x4f,0x75,0x6c,0x5d,0x25,0x8f,0x28,0x62,0xa1,0xb8,0x90,0x11,0xba,0x40,0x48,0xa0,0xe0,0x4e,0xbf,0xd1,0xb,0x76,0xce,0x68,0x93,0xd2,0x2e,0x5e,0x99,0xc0,0x1c,0x4a,0x16,0xa3,0x44,0x9a,0x85,0x2d,0x67,0x98,0x50,0x82,0xd9,0xe4,0x72,0x45,0x3b,0x34,0xf4,0x3f,0x18,0x1e,0x83,0x46,0x70,0x5,0x9b,0xf1,0xae,0x57,0x8e,0x61,0x4c,0xcf,0xb4,0xb9,0x80,0x87,0x31,0x69,0x56,0xa8,0xbb,0x2c,0x0,0x79,0x14,0xcb,0xa5,0xc1,0xef,0xf3,0x32,0xc,0xdd,0x9e,0xf6,0x20,0x92,0x19,0x15,0x1b,0xa7,0xb0,0xb5,0xc2,0x4b,0x66,0x4d,0x2b,0xf8,0xf2,0x41,0xe,0xa9,0xad,0xda,0xf,0x21,0x7c,0x8b,0x96,0xaf,0xbd,0x51,0x7e,0x30,0x6,0x6b,0xd6,0xcc,0xcd,0x37,0xc6,0x60,0xfb,0x47,0xa6,0x7,0xe7,0x22,0xe8,0xc7,0x55,0x43,0xe1,0xf7,0xec,0x2a,0xfc,0x3e,0xe9,0x5f,0xf0,0xbe,0xc8,0x36,0xb1,0x95,0x10,0x58,0xc4,0xa,0x65,0x1f,0xea,0xb3,0xdb,0x49,0x13,0xf9,0xd0,0x9d,0x71,0x5b,0x3c,0xc5,0x5c,0x59,0x39,0x17,0xe3,0xb2,0x7f,0xb6,0x53,0x8,0xd8,0x35,0x73,0x77,0x3,0x94,0xbc,0x5a,0x86,0x9,0x29,0x3f,0x9d,0xbb,0x29,0x56,0x80,0x8b,0x90,0x3b,0xda,0x1c,0x87,0x5e,0x94,0x7b,0x9b,0x24,0xb8,0xe9,0x6c,0x63,0x96,0x76,0x19,0x23,0x8c,0x42,0x95,0x4a,0xcd,0xc2,0xb4,0xb9,0x20,0x27,0x40,0x6b,0x9f,0x25,0x45,0x35,0x6f,0xcf,0xa7,0xe1,0xd,0x85,0xac,0xe8,0xc0,0xb,0x7f,0x75,0x55,0x26,0xfa,0xca,0x2f,0xce,0x3,0x49,0xf,0x74,0xa4,0x2a,0xd4,0x4d,0x15,0x7c,0x5,0xc7,0x50,0x30,0xb3,0xf2,0x1d,0xfc,0xfb,0xc8,0xc5,0x8a,0x5c,0xa1,0xe2,0x69,0x67,0xee,0x65,0xd9,0xbd,0x68,0xb7,0x4e,0x70,0x93,0x8f,0x3d,0x72,0x84,0x8e,0xa6,0x73,0xd5,0xd1,0xc9,0xbe,0xdb,0xcc,0x31,0x57,0x37,0x1a,0x17,0xaa,0x4c,0x7a,0x4b,0xba,0xb0,0xb1,0xf7,0xea,0x5d,0x0,0x2d,0x2,0xd3,0xc1,0x54,0x1e,0x59,0xf3,0xec,0x6d,0xdd,0xc4,0xab,0x4f,0x11,0x97,0x10,0x21,0x33,0x9,0xb2,0x14,0x77,0xa,0x52,0x22,0xef,0xae,0x34,0xdc,0xc6,0x3c,0xc3,0xad,0x9c,0x32,0x1b,0xe4,0xf9,0x51,0xa5,0x98,0x2c,0xfe,0x60,0x36,0xe5,0xbc,0x38,0xe6,0x6a,0xdf,0xc,0x79,0xff,0x3a,0xd2,0x2b,0xe7,0x8d,0x47,0x48,0xe,0x39,0x64,0x62,0x88,0x43,0x58,0xf4,0x1,0xfd,0x61,0x1f,0x16,0x92,0x9e,0x2e,0x86,0x41,0x99,0x6,0x4,0xd7,0x8,0x5a,0x83,0x7e,0xa0,0x71,0xd0,0x7d,0xb6,0x89,0x5f,0xe0,0xed,0xaf,0xde,0xf5,0x12,0xa9,0xd6,0x46,0x81,0x5b,0x66,0xbf,0x82,0x13,0xf8,0x91,0xcb,0x6e,0xeb,0xa2,0x53,0x9a,0x28,0xf0,0xf1,0xb5,0x3e,0x44,0xe3,0xf6,0x78,0xd8,0xa8,0xa3,0x18,0x7,0xef,0x13,0xe6,0x4a,0x80,0x4,0xd,0x73,0x53,0x94,0x3c,0x8c,0xc5,0x16,0x14,0x8b,0x6c,0x91,0x48,0x1a,0x6f,0xc2,0x63,0xb2,0xf2,0x4d,0x9b,0xa4,0xe7,0xcc,0xbd,0xff,0x54,0xc4,0xbb,0x0,0xad,0x74,0x49,0x93,0x83,0xea,0x1,0x90,0xb0,0xf9,0x7c,0xd9,0xe2,0x3a,0x88,0x41,0x56,0x2c,0xa7,0xe3,0xca,0x6a,0xe4,0xf1,0x15,0xa,0xb1,0xba,0xe1,0x4b,0xc,0x46,0xd6,0xcf,0x7f,0xfe,0x85,0x3,0x5d,0xb9,0x1b,0x21,0x33,0x2,0x18,0x65,0x6,0xa0,0xbc,0xfd,0x30,0x40,0x2e,0xd4,0xce,0x26,0x20,0x8e,0xbf,0xd1,0x43,0xeb,0xf6,0x9,0xec,0x3e,0x8a,0xb7,0xae,0xf7,0x24,0x72,0xcd,0x78,0xf4,0x2a,0x28,0xed,0x6b,0x1e,0x9f,0xf5,0x39,0xc0,0x2b,0x1c,0x5a,0x55,0x51,0x9a,0x70,0x76,0x7,0x5f,0xc6,0x38,0x42,0xd5,0x17,0x6e,0xf,0xe0,0xa1,0x22,0xd7,0xda,0xe9,0xee,0xf0,0xb3,0x4e,0x98,0x77,0xfc,0x75,0x7b,0xa5,0x7a,0xaf,0xcb,0x9d,0x81,0x62,0x5c,0x9c,0x96,0x60,0x2f,0xc3,0xc7,0x61,0xb4,0xde,0xc9,0xac,0xdb,0x8,0x25,0x45,0x23,0x68,0x5e,0xb8,0x5,0xa3,0xa2,0xa8,0x59,0x12,0x4f,0xf8,0xe5,0xd3,0xc1,0x10,0x3f,0x3b,0xa9,0x8f,0x2d,0x82,0x99,0x92,0x44,0x95,0xe,0xc8,0x29,0x89,0x69,0x86,0x4c,0x7e,0xfb,0xaa,0x36,0xb,0x64,0x84,0x71,0x87,0x50,0x9e,0x31,0xa6,0xd0,0xdf,0x58,0x52,0x35,0x32,0xab,0x57,0x37,0x8d,0x79,0xb5,0xdd,0x7d,0x27,0xbe,0x97,0x1f,0xf3,0x6d,0x19,0xd2,0xfa,0xe8,0x34,0x47,0x67,0x11,0xdc,0x3d,0xd8,0xb6,0x66,0x1d,0x5b,0x89,0x2f,0x97,0xea,0xbf,0xcf,0x33,0x72,0x41,0xa9,0xa1,0x5b,0x30,0x5e,0xaf,0x1,0x83,0xc9,0x6e,0xc4,0xf0,0x71,0x59,0x40,0xd2,0x36,0xa,0x8c,0xbc,0x8d,0x94,0xae,0xe4,0x91,0xa7,0x62,0xb6,0x4f,0x10,0x7a,0xd5,0xda,0xa4,0x93,0xff,0xf9,0xde,0x15,0x79,0x86,0xcc,0x64,0x5,0x38,0x63,0xb1,0xab,0xfd,0x21,0x78,0x7b,0xa5,0x42,0xf7,0xc7,0x95,0xe3,0x1e,0xec,0x3d,0xe0,0x4d,0x14,0x2b,0x7d,0xc2,0x32,0x70,0x68,0x43,0x69,0xc5,0x60,0x9c,0x82,0xfc,0xf,0x8b,0xb3,0x3,0xdc,0x1b,0x9b,0x4,0x4a,0x99,0x7,0xce,0x6d,0xb5,0x28,0x6c,0xd9,0xa3,0x6b,0x7e,0x45,0xe5,0x3e,0x35,0x9a,0x85,0x34,0x8f,0xdb,0x4b,0xc6,0x1c,0x22,0xfb,0x8e,0x1f,0xc,0x65,0xf3,0x56,0x3f,0x76,0x25,0xb9,0xf1,0x74,0xb,0xfe,0x84,0xeb,0x11,0xbe,0x8,0xdf,0x50,0xd7,0x29,0x5f,0x0,0xa2,0xb4,0x26,0x1d,0xcb,0xd,0x16,0x47,0xa6,0x1a,0x81,0x9,0xc3,0x6,0xe6,0x5d,0x75,0xe2,0x96,0xc8,0xe8,0x67,0xbb,0xb2,0x57,0x9e,0x53,0x92,0xd4,0x39,0xe9,0xbd,0x24,0xdd,0xba,0x2,0xf6,0xd8,0xb8,0xf2,0xa8,0x3a,0x52,0x90,0x7c,0x31,0x18,0xc1,0x17,0x7f,0x3c,0xfa,0xf4,0xf8,0x73,0x20,0x44,0x2a,0xf5,0xed,0xd3,0x12,0xe,0x49,0xb7,0x88,0xd0,0x98,0xe1,0xcd,0x5a,0x2e,0xad,0x80,0x6f,0x66,0x61,0x58,0x55,0x37,0x8a,0xe7,0xd1,0x27,0xd6,0x2c,0x2d,0x77,0x6a,0x9d,0xc0,0x9f,0xb0,0x5c,0x4e,0xef,0xa0,0x13,0x19,0xee,0x3b,0x4c,0x48,0x23,0x54,0x51,0x46,0xca,0xac,0x87,0xaa,0x76,0xb1,0x6e,0xde,0xf4,0x27,0x69,0xf6,0xf1,0xd,0xa8,0x4,0xe6,0x62,0x91,0xef,0xaf,0x10,0x46,0x79,0x2e,0x5,0x1d,0x5f,0x73,0x8e,0xf8,0xaa,0x20,0x8d,0x50,0x81,0x8,0x61,0x72,0xe3,0x1b,0x52,0x3b,0x9e,0x26,0xb6,0xe2,0x59,0x96,0x4f,0x71,0xab,0x88,0x28,0x13,0x6,0xe8,0xf7,0x58,0x53,0xd8,0x0,0xa3,0x6a,0xce,0xb4,0x1,0x45,0xe1,0x67,0x5b,0xbf,0xc3,0xf9,0xe0,0xd1,0xa9,0x3,0xa4,0xee,0x2d,0x34,0x1c,0x9d,0x36,0xcc,0xc4,0x2c,0x6c,0xc2,0x33,0x5d,0x87,0xfa,0x42,0xe4,0x1f,0x5e,0xa2,0xd2,0x15,0x4c,0x90,0xc6,0x9a,0x2f,0xc8,0x16,0x9,0xa1,0xeb,0x14,0xdc,0xe,0x55,0x68,0xfe,0xc9,0xb7,0xb8,0x78,0xb3,0x94,0x92,0xf,0xca,0xfc,0x89,0x17,0x7d,0x22,0xdb,0x2,0xed,0xc0,0x43,0x38,0x35,0xc,0xb,0xbd,0xe5,0xda,0x24,0x37,0xa0,0x8c,0xf5,0x98,0x47,0x29,0x4d,0x63,0x7f,0xbe,0x80,0x51,0x12,0x7a,0xac,0x1e,0x95,0x99,0x97,0x2b,0x3c,0x39,0x4e,0xc7,0xea,0xc1,0xa7,0x74,0x7e,0xcd,0x82,0x25,0x21,0x56,0x83,0xad,0xf0,0x7,0x1a,0x23,0x31,0xdd,0xf2,0xbc,0x8a,0xe7,0x5a,0x40,0x41,0xbb,0x4a,0xec,0x77,0xcb,0x2a,0x8b,0x6b,0xae,0x64,0x4b,0xd9,0xcf,0x6d,0x7b,0x60,0xa6,0x70,0xb2,0x65,0xd3,0x7c,0x32,0x44,0xba,0x3d,0x19,0x9c,0xd4,0x48,0x86,0xe9,0x93,0x66,0x3f,0x57,0xc5,0x9f,0x75,0x5c,0x11,0xfd,0xd7,0xb0,0x49,0xd0,0xd5,0xb5,0x9b,0x6f,0x3e,0xf3,0x3a,0xdf,0x84,0x54,0xb9,0xff,0xfb,0x8f,0x18,0x30,0xd6,0xa,0x85,0xa5,0x17,0xb5,0x93,0x1,0x7e,0xa8,0xa3,0xb8,0x13,0xf2,0x34,0xaf,0x76,0xbc,0x53,0xb3,0xc,0x90,0xc1,0x44,0x4b,0xbe,0x5e,0x31,0xb,0xa4,0x6a,0xbd,0x62,0xe5,0xea,0x9c,0x91,0x8,0xf,0x68,0x43,0xb7,0xd,0x6d,0x1d,0x47,0xe7,0x8f,0xc9,0x25,0xad,0x84,0xc0,0xe8,0x23,0x57,0x5d,0x7d,0xe,0xd2,0xe2,0x7,0xe6,0x2b,0x61,0x27,0x5c,0x8c,0x2,0xfc,0x65,0x3d,0x54,0x2d,0xef,0x78,0x18,0x9b,0xda,0x35,0xd4,0xd3,0xe0,0xed,0xa2,0x74,0x89,0xca,0x41,0x4f,0xc6,0x4d,0xf1,0x95,0x40,0x9f,0x66,0x58,0xbb,0xa7,0x15,0x5a,0xac,0xa6,0x8e,0x5b,0xfd,0xf9,0xe1,0x96,0xf3,0xe4,0x19,0x7f,0x1f,0x32,0x3f,0x82,0x64,0x52,0x63,0x92,0x98,0x99,0xdf,0xc2,0x75,0x28,0x5,0x2a,0xfb,0xe9,0x7c,0x36,0x71,0xdb,0xc4,0x45,0xf5,0xec,0x83,0x67,0x39,0xbf,0x38,0x9,0x1b,0x21,0x9a,0x3c,0x5f,0x22,0x7a,0xa,0xc7,0x86,0x1c,0xf4,0xee,0x14,0xeb,0x85,0xb4,0x1a,0x33,0xcc,0xd1,0x79,0x8d,0xb0,0x4,0xd6,0x48,0x1e,0xcd,0x94,0x10,0xce,0x42,0xf7,0x24,0x51,0xd7,0x12,0xfa,0x3,0xcf,0xa5,0x6f,0x60,0x26,0x11,0x4c,0x4a,0xa0,0x6b,0x70,0xdc,0x29,0xd5,0x49,0x37,0x3e,0xba,0xb6,0x6,0xae,0x69,0xb1,0x2e,0x2c,0xff,0x20,0x72,0xab,0x56,0x88,0x59,0xf8,0x55,0x9e,0xa1,0x77,0xc8,0xc5,0x87,0xf6,0xdd,0x3a,0x81,0xfe,0x6e,0xa9,0x73,0x4e,0x97,0xaa,0x3b,0xd0,0xb9,0xe3,0x46,0xc3,0x8a,0x7b,0xb2,0x0,0xd8,0xd9,0x9d,0x16,0x6c,0xcb,0xde,0x50,0xf0,0x80,0x8b,0x30,0x2f,0x34,0xc8,0x3d,0x91,0x5b,0xdf,0xd6,0xa8,0x88,0x4f,0xe7,0x57,0x1e,0xcd,0xcf,0x50,0xb7,0x4a,0x93,0xc1,0xb4,0x19,0xb8,0x69,0x29,0x96,0x40,0x7f,0x3c,0x17,0x66,0x24,0x8f,0x1f,0x60,0xdb,0x76,0xaf,0x92,0x48,0x58,0x31,0xda,0x4b,0x6b,0x22,0xa7,0x2,0x39,0xe1,0x53,0x9a,0x8d,0xf7,0x7c,0x38,0x11,0xb1,0x3f,0x2a,0xce,0xd1,0x6a,0x61,0x3a,0x90,0xd7,0x9d,0xd,0x14,0xa4,0x25,0x5e,0xd8,0x86,0x62,0xc0,0xfa,0xe8,0xd9,0xc3,0xbe,0xdd,0x7b,0x67,0x26,0xeb,0x9b,0xf5,0xf,0x15,0xfd,0xfb,0x55,0x64,0xa,0x98,0x30,0x2d,0xd2,0x37,0xe5,0x51,0x6c,0x75,0x2c,0xff,0xa9,0x16,0xa3,0x2f,0xf1,0xf3,0x36,0xb0,0xc5,0x44,0x2e,0xe2,0x1b,0xf0,0xc7,0x81,0x8e,0x8a,0x41,0xab,0xad,0xdc,0x84,0x1d,0xe3,0x99,0xe,0xcc,0xb5,0xd4,0x3b,0x7a,0xf9,0xc,0x1,0x32,0x35,0x2b,0x68,0x95,0x43,0xac,0x27,0xae,0xa0,0x7e,0xa1,0x74,0x10,0x46,0x5a,0xb9,0x87,0x47,0x4d,0xbb,0xf4,0x18,0x1c,0xba,0x6f,0x5,0x12,0x77,0x0,0xd3,0xfe,0x9e,0xf8,0xb3,0x85,0x63,0xde,0x78,0x79,0x73,0x82,0xc9,0x94,0x23,0x3e,0x8,0x1a,0xcb,0xe4,0xe0,0x72,0x54,0xf6,0x59,0x42,0x49,0x9f,0x4e,0xd5,0x13,0xf2,0x52,0xb2,0x5d,0x97,0xa5,0x20,0x71,0xed,0xd0,0xbf,0x5f,0xaa,0x5c,0x8b,0x45,0xea,0x7d,0xb,0x4,0x83,0x89,0xee,0xe9,0x70,0x8c,0xec,0x56,0xa2,0x6e,0x6,0xa6,0xfc,0x65,0x4c,0xc4,0x28,0xb6,0xc2,0x9,0x21,0x33,0xef,0x9c,0xbc,0xca,0x7,0xe6,0x3,0x6d,0xbd,0xc6,0x80,0x5b,0xfd,0x45,0x38,0x6d,0x1d,0xe1,0xa0,0x93,0x7b,0x73,0x89,0xe2,0x8c,0x7d,0xd3,0x51,0x1b,0xbc,0x16,0x22,0xa3,0x8b,0x92,0x0,0xe4,0xd8,0x5e,0x6e,0x5f,0x46,0x7c,0x36,0x43,0x75,0xb0,0x64,0x9d,0xc2,0xa8,0x7,0x8,0x76,0x41,0x2d,0x2b,0xc,0xc7,0xab,0x54,0x1e,0xb6,0xd7,0xea,0xb1,0x63,0x79,0x2f,0xf3,0xaa,0xa9,0x77,0x90,0x25,0x15,0x47,0x31,0xcc,0x3e,0xef,0x32,0x9f,0xc6,0xf9,0xaf,0x10,0xe0,0xa2,0xba,0x91,0xbb,0x17,0xb2,0x4e,0x50,0x2e,0xdd,0x59,0x61,0xd1,0xe,0xc9,0x49,0xd6,0x98,0x4b,0xd5,0x1c,0xbf,0x67,0xfa,0xbe,0xb,0x71,0xb9,0xac,0x97,0x37,0xec,0xe7,0x48,0x57,0xe6,0x5d,0x9,0x99,0x14,0xce,0xf0,0x29,0x5c,0xcd,0xde,0xb7,0x21,0x84,0xed,0xa4,0xf7,0x6b,0x23,0xa6,0xd9,0x2c,0x56,0x39,0xc3,0x6c,0xda,0xd,0x82,0x5,0xfb,0x8d,0xd2,0x70,0x66,0xf4,0xcf,0x19,0xdf,0xc4,0x95,0x74,0xc8,0x53,0xdb,0x11,0xd4,0x34,0x8f,0xa7,0x30,0x44,0x1a,0x3a,0xb5,0x69,0x60,0x85,0x4c,0x81,0x40,0x6,0xeb,0x3b,0x6f,0xf6,0xf,0x68,0xd0,0x24,0xa,0x6a,0x20,0x7a,0xe8,0x80,0x42,0xae,0xe3,0xca,0x13,0xc5,0xad,0xee,0x28,0x26,0x2a,0xa1,0xf2,0x96,0xf8,0x27,0x3f,0x1,0xc0,0xdc,0x9b,0x65,0x5a,0x2,0x4a,0x33,0x1f,0x88,0xfc,0x7f,0x52,0xbd,0xb4,0xb3,0x8a,0x87,0xe5,0x58,0x35,0x3,0xf5,0x4,0xfe,0xff,0xa5,0xb8,0x4f,0x12,0x4d,0x62,0x8e,0x9c,0x3d,0x72,0xc1,0xcb,0x3c,0xe9,0x9e,0x9a,0xf1,0x86,0x83,0x94,0x18,0x7e,0x55,0x78,0xc0,0x7,0xd8,0x68,0x42,0x91,0xdf,0x40,0x47,0xbb,0x1e,0xb2,0x50,0xd4,0x27,0x59,0x19,0xa6,0xf0,0xcf,0x98,0xb3,0xab,0xe9,0xc5,0x38,0x4e,0x1c,0x96,0x3b,0xe6,0x37,0xbe,0xd7,0xc4,0x55,0xad,0xe4,0x8d,0x28,0x90,0x0,0x54,0xef,0x20,0xf9,0xc7,0x1d,0x3e,0x9e,0xa5,0xb0,0x5e,0x41,0xee,0xe5,0x6e,0xb6,0x15,0xdc,0x78,0x2,0xb7,0xf3,0x57,0xd1,0xed,0x9,0x75,0x4f,0x56,0x67,0x1f,0xb5,0x12,0x58,0x9b,0x82,0xaa,0x2b,0x80,0x7a,0x72,0x9a,0xda,0x74,0x85,0xeb,0x31,0x4c,0xf4,0x52,0xa9,0xe8,0x14,0x64,0xa3,0xfa,0x26,0x70,0x2c,0x99,0x7e,0xa0,0xbf,0x17,0x5d,0xa2,0x6a,0xb8,0xe3,0xde,0x48,0x7f,0x1,0xe,0xce,0x5,0x22,0x24,0xb9,0x7c,0x4a,0x3f,0xa1,0xcb,0x94,0x6d,0xb4,0x5b,0x76,0xf5,0x8e,0x83,0xba,0xbd,0xb,0x53,0x6c,0x92,0x81,0x16,0x3a,0x43,0x2e,0xf1,0x9f,0xfb,0xd5,0xc9,0x8,0x36,0xe7,0xa4,0xcc,0x1a,0xa8,0x23,0x2f,0x21,0x9d,0x8a,0x8f,0xf8,0x71,0x5c,0x77,0x11,0xc2,0xc8,0x7b,0x34,0x93,0x97,0xe0,0x35,0x1b,0x46,0xb1,0xac,0x95,0x87,0x6b,0x44,0xa,0x3c,0x51,0xec,0xf6,0xf7,0xd,0xfc,0x5a,0xc1,0x7d,0x9c,0x3d,0xdd,0x18,0xd2,0xfd,0x6f,0x79,0xdb,0xcd,0xd6,0x10,0xc6,0x4,0xd3,0x65,0xca,0x84,0xf2,0xc,0x8b,0xaf,0x2a,0x62,0xfe,0x30,0x5f,0x25,0xd0,0x89,0xe1,0x73,0x29,0xc3,0xea,0xa7,0x4b,0x61,0x6,0xff,0x66,0x63,0x3,0x2d,0xd9,0x88,0x45,0x8c,0x69,0x32,0xe2,0xf,0x49,0x4d,0x39,0xae,0x86,0x60,0xbc,0x33,0x13,0xc8,0x6a,0x4c,0xde,0xa1,0x77,0x7c,0x67,0xcc,0x2d,0xeb,0x70,0xa9,0x63,0x8c,0x6c,0xd3,0x4f,0x1e,0x9b,0x94,0x61,0x81,0xee,0xd4,0x7b,0xb5,0x62,0xbd,0x3a,0x35,0x43,0x4e,0xd7,0xd0,0xb7,0x9c,0x68,0xd2,0xb2,0xc2,0x98,0x38,0x50,0x16,0xfa,0x72,0x5b,0x1f,0x37,0xfc,0x88,0x82,0xa2,0xd1,0xd,0x3d,0xd8,0x39,0xf4,0xbe,0xf8,0x83,0x53,0xdd,0x23,0xba,0xe2,0x8b,0xf2,0x30,0xa7,0xc7,0x44,0x5,0xea,0xb,0xc,0x3f,0x32,0x7d,0xab,0x56,0x15,0x9e,0x90,0x19,0x92,0x2e,0x4a,0x9f,0x40,0xb9,0x87,0x64,0x78,0xca,0x85,0x73,0x79,0x51,0x84,0x22,0x26,0x3e,0x49,0x2c,0x3b,0xc6,0xa0,0xc0,0xed,0xe0,0x5d,0xbb,0x8d,0xbc,0x4d,0x47,0x46,0x0,0x1d,0xaa,0xf7,0xda,0xf5,0x24,0x36,0xa3,0xe9,0xae,0x4,0x1b,0x9a,0x2a,0x33,0x5c,0xb8,0xe6,0x60,0xe7,0xd6,0xc4,0xfe,0x45,0xe3,0x80,0xfd,0xa5,0xd5,0x18,0x59,0xc3,0x2b,0x31,0xcb,0x34,0x5a,0x6b,0xc5,0xec,0x13,0xe,0xa6,0x52,0x6f,0xdb,0x9,0x97,0xc1,0x12,0x4b,0xcf,0x11,0x9d,0x28,0xfb,0x8e,0x8,0xcd,0x25,0xdc,0x10,0x7a,0xb0,0xbf,0xf9,0xce,0x93,0x95,0x7f,0xb4,0xaf,0x3,0xf6,0xa,0x96,0xe8,0xe1,0x65,0x69,0xd9,0x71,0xb6,0x6e,0xf1,0xf3,0x20,0xff,0xad,0x74,0x89,0x57,0x86,0x27,0x8a,0x41,0x7e,0xa8,0x17,0x1a,0x58,0x29,0x2,0xe5,0x5e,0x21,0xb1,0x76,0xac,0x91,0x48,0x75,0xe4,0xf,0x66,0x3c,0x99,0x1c,0x55,0xa4,0x6d,0xdf,0x7,0x6,0x42,0xc9,0xb3,0x14,0x1,0x8f,0x2f,0x5f,0x54,0xef,0xf0,0xee,0x12,0xe7,0x4b,0x81,0x5,0xc,0x72,0x52,0x95,0x3d,0x8d,0xc4,0x17,0x15,0x8a,0x6d,0x90,0x49,0x1b,0x6e,0xc3,0x62,0xb3,0xf3,0x4c,0x9a,0xa5,0xe6,0xcd,0xbc,0xfe,0x55,0xc5,0xba,0x1,0xac,0x75,0x48,0x92,0x82,0xeb,0x0,0x91,0xb1,0xf8,0x7d,0xd8,0xe3,0x3b,0x89,0x40,0x57,0x2d,0xa6,0xe2,0xcb,0x6b,0xe5,0xf0,0x14,0xb,0xb0,0xbb,0xe0,0x4a,0xd,0x47,0xd7,0xce,0x7e,0xff,0x84,0x2,0x5c,0xb8,0x1a,0x20,0x32,0x3,0x19,0x64,0x7,0xa1,0xbd,0xfc,0x31,0x41,0x2f,0xd5,0xcf,0x27,0x21,0x8f,0xbe,0xd0,0x42,0xea,0xf7,0x8,0xed,0x3f,0x8b,0xb6,0xaf,0xf6,0x25,0x73,0xcc,0x79,0xf5,0x2b,0x29,0xec,0x6a,0x1f,0x9e,0xf4,0x38,0xc1,0x2a,0x1d,0x5b,0x54,0x50,0x9b,0x71,0x77,0x6,0x5e,0xc7,0x39,0x43,0xd4,0x16,0x6f,0xe,0xe1,0xa0,0x23,0xd6,0xdb,0xe8,0xef,0xf1,0xb2,0x4f,0x99,0x76,0xfd,0x74,0x7a,0xa4,0x7b,0xae,0xca,0x9c,0x80,0x63,0x5d,0x9d,0x97,0x61,0x2e,0xc2,0xc6,0x60,0xb5,0xdf,0xc8,0xad,0xda,0x9,0x24,0x44,0x22,0x69,0x5f,0xb9,0x4,0xa2,0xa3,0xa9,0x58,0x13,0x4e,0xf9,0xe4,0xd2,0xc0,0x11,0x3e,0x3a,0xa8,0x8e,0x2c,0x83,0x98,0x93,0x45,0x94,0xf,0xc9,0x28,0x88,0x68,0x87,0x4d,0x7f,0xfa,0xab,0x37,0xa,0x65,0x85,0x70,0x86,0x51,0x9f,0x30,0xa7,0xd1,0xde,0x59,0x53,0x34,0x33,0xaa,0x56,0x36,0x8c,0x78,0xb4,0xdc,0x7c,0x26,0xbf,0x96,0x1e,0xf2,0x6c,0x18,0xd3,0xfb,0xe9,0x35,0x46,0x66,0x10,0xdd,0x3c,0xd9,0xb7,0x67,0x1c,0x5a,0xa7,0x1,0xb9,0xc4,0x91,0xe1,0x1d,0x5c,0x6f,0x87,0x8f,0x75,0x1e,0x70,0x81,0x2f,0xad,0xe7,0x40,0xea,0xde,0x5f,0x77,0x6e,0xfc,0x18,0x24,0xa2,0x92,0xa3,0xba,0x80,0xca,0xbf,0x89,0x4c,0x98,0x61,0x3e,0x54,0xfb,0xf4,0x8a,0xbd,0xd1,0xd7,0xf0,0x3b,0x57,0xa8,0xe2,0x4a,0x2b,0x16,0x4d,0x9f,0x85,0xd3,0xf,0x56,0x55,0x8b,0x6c,0xd9,0xe9,0xbb,0xcd,0x30,0xc2,0x13,0xce,0x63,0x3a,0x5,0x53,0xec,0x1c,0x5e,0x46,0x6d,0x47,0xeb,0x4e,0xb2,0xac,0xd2,0x21,0xa5,0x9d,0x2d,0xf2,0x35,0xb5,0x2a,0x64,0xb7,0x29,0xe0,0x43,0x9b,0x6,0x42,0xf7,0x8d,0x45,0x50,0x6b,0xcb,0x10,0x1b,0xb4,0xab,0x1a,0xa1,0xf5,0x65,0xe8,0x32,0xc,0xd5,0xa0,0x31,0x22,0x4b,0xdd,0x78,0x11,0x58,0xb,0x97,0xdf,0x5a,0x25,0xd0,0xaa,0xc5,0x3f,0x90,0x26,0xf1,0x7e,0xf9,0x7,0x71,0x2e,0x8c,0x9a,0x8,0x33,0xe5,0x23,0x38,0x69,0x88,0x34,0xaf,0x27,0xed,0x28,0xc8,0x73,0x5b,0xcc,0xb8,0xe6,0xc6,0x49,0x95,0x9c,0x79,0xb0,0x7d,0xbc,0xfa,0x17,0xc7,0x93,0xa,0xf3,0x94,0x2c,0xd8,0xf6,0x96,0xdc,0x86,0x14,0x7c,0xbe,0x52,0x1f,0x36,0xef,0x39,0x51,0x12,0xd4,0xda,0xd6,0x5d,0xe,0x6a,0x4,0xdb,0xc3,0xfd,0x3c,0x20,0x67,0x99,0xa6,0xfe,0xb6,0xcf,0xe3,0x74,0x0,0x83,0xae,0x41,0x48,0x4f,0x76,0x7b,0x19,0xa4,0xc9,0xff,0x9,0xf8,0x2,0x3,0x59,0x44,0xb3,0xee,0xb1,0x9e,0x72,0x60,0xc1,0x8e,0x3d,0x37,0xc0,0x15,0x62,0x66,0xd,0x7a,0x7f,0x68,0xe4,0x82,0xa9,0x84,0x28,0xef,0x30,0x80,0xaa,0x79,0x37,0xa8,0xaf,0x53,0xf6,0x5a,0xb8,0x3c,0xcf,0xb1,0xf1,0x4e,0x18,0x27,0x70,0x5b,0x43,0x1,0x2d,0xd0,0xa6,0xf4,0x7e,0xd3,0xe,0xdf,0x56,0x3f,0x2c,0xbd,0x45,0xc,0x65,0xc0,0x78,0xe8,0xbc,0x7,0xc8,0x11,0x2f,0xf5,0xd6,0x76,0x4d,0x58,0xb6,0xa9,0x6,0xd,0x86,0x5e,0xfd,0x34,0x90,0xea,0x5f,0x1b,0xbf,0x39,0x5,0xe1,0x9d,0xa7,0xbe,0x8f,0xf7,0x5d,0xfa,0xb0,0x73,0x6a,0x42,0xc3,0x68,0x92,0x9a,0x72,0x32,0x9c,0x6d,0x3,0xd9,0xa4,0x1c,0xba,0x41,0x0,0xfc,0x8c,0x4b,0x12,0xce,0x98,0xc4,0x71,0x96,0x48,0x57,0xff,0xb5,0x4a,0x82,0x50,0xb,0x36,0xa0,0x97,0xe9,0xe6,0x26,0xed,0xca,0xcc,0x51,0x94,0xa2,0xd7,0x49,0x23,0x7c,0x85,0x5c,0xb3,0x9e,0x1d,0x66,0x6b,0x52,0x55,0xe3,0xbb,0x84,0x7a,0x69,0xfe,0xd2,0xab,0xc6,0x19,0x77,0x13,0x3d,0x21,0xe0,0xde,0xf,0x4c,0x24,0xf2,0x40,0xcb,0xc7,0xc9,0x75,0x62,0x67,0x10,0x99,0xb4,0x9f,0xf9,0x2a,0x20,0x93,0xdc,0x7b,0x7f,0x8,0xdd,0xf3,0xae,0x59,0x44,0x7d,0x6f,0x83,0xac,0xe2,0xd4,0xb9,0x4,0x1e,0x1f,0xe5,0x14,0xb2,0x29,0x95,0x74,0xd5,0x35,0xf0,0x3a,0x15,0x87,0x91,0x33,0x25,0x3e,0xf8,0x2e,0xec,0x3b,0x8d,0x22,0x6c,0x1a,0xe4,0x63,0x47,0xc2,0x8a,0x16,0xd8,0xb7,0xcd,0x38,0x61,0x9,0x9b,0xc1,0x2b,0x2,0x4f,0xa3,0x89,0xee,0x17,0x8e,0x8b,0xeb,0xc5,0x31,0x60,0xad,0x64,0x81,0xda,0xa,0xe7,0xa1,0xa5,0xd1,0x46,0x6e,0x88,0x54,0xdb,0xfb,0x6c,0xce,0xe8,0x7a,0x5,0xd3,0xd8,0xc3,0x68,0x89,0x4f,0xd4,0xd,0xc7,0x28,0xc8,0x77,0xeb,0xba,0x3f,0x30,0xc5,0x25,0x4a,0x70,0xdf,0x11,0xc6,0x19,0x9e,0x91,0xe7,0xea,0x73,0x74,0x13,0x38,0xcc,0x76,0x16,0x66,0x3c,0x9c,0xf4,0xb2,0x5e,0xd6,0xff,0xbb,0x93,0x58,0x2c,0x26,0x6,0x75,0xa9,0x99,0x7c,0x9d,0x50,0x1a,0x5c,0x27,0xf7,0x79,0x87,0x1e,0x46,0x2f,0x56,0x94,0x3,0x63,0xe0,0xa1,0x4e,0xaf,0xa8,0x9b,0x96,0xd9,0xf,0xf2,0xb1,0x3a,0x34,0xbd,0x36,0x8a,0xee,0x3b,0xe4,0x1d,0x23,0xc0,0xdc,0x6e,0x21,0xd7,0xdd,0xf5,0x20,0x86,0x82,0x9a,0xed,0x88,0x9f,0x62,0x4,0x64,0x49,0x44,0xf9,0x1f,0x29,0x18,0xe9,0xe3,0xe2,0xa4,0xb9,0xe,0x53,0x7e,0x51,0x80,0x92,0x7,0x4d,0xa,0xa0,0xbf,0x3e,0x8e,0x97,0xf8,0x1c,0x42,0xc4,0x43,0x72,0x60,0x5a,0xe1,0x47,0x24,0x59,0x1,0x71,0xbc,0xfd,0x67,0x8f,0x95,0x6f,0x90,0xfe,0xcf,0x61,0x48,0xb7,0xaa,0x2,0xf6,0xcb,0x7f,0xad,0x33,0x65,0xb6,0xef,0x6b,0xb5,0x39,0x8c,0x5f,0x2a,0xac,0x69,0x81,0x78,0xb4,0xde,0x14,0x1b,0x5d,0x6a,0x37,0x31,0xdb,0x10,0xb,0xa7,0x52,0xae,0x32,0x4c,0x45,0xc1,0xcd,0x7d,0xd5,0x12,0xca,0x55,0x57,0x84,0x5b,0x9,0xd0,0x2d,0xf3,0x22,0x83,0x2e,0xe5,0xda,0xc,0xb3,0xbe,0xfc,0x8d,0xa6,0x41,0xfa,0x85,0x15,0xd2,0x8,0x35,0xec,0xd1,0x40,0xab,0xc2,0x98,0x3d,0xb8,0xf1,0x0,0xc9,0x7b,0xa3,0xa2,0xe6,0x6d,0x17,0xb0,0xa5,0x2b,0x8b,0xfb,0xf0,0x4b,0x54,0x29,0xd5,0x20,0x8c,0x46,0xc2,0xcb,0xb5,0x95,0x52,0xfa,0x4a,0x3,0xd0,0xd2,0x4d,0xaa,0x57,0x8e,0xdc,0xa9,0x4,0xa5,0x74,0x34,0x8b,0x5d,0x62,0x21,0xa,0x7b,0x39,0x92,0x2,0x7d,0xc6,0x6b,0xb2,0x8f,0x55,0x45,0x2c,0xc7,0x56,0x76,0x3f,0xba,0x1f,0x24,0xfc,0x4e,0x87,0x90,0xea,0x61,0x25,0xc,0xac,0x22,0x37,0xd3,0xcc,0x77,0x7c,0x27,0x8d,0xca,0x80,0x10,0x9,0xb9,0x38,0x43,0xc5,0x9b,0x7f,0xdd,0xe7,0xf5,0xc4,0xde,0xa3,0xc0,0x66,0x7a,0x3b,0xf6,0x86,0xe8,0x12,0x8,0xe0,0xe6,0x48,0x79,0x17,0x85,0x2d,0x30,0xcf,0x2a,0xf8,0x4c,0x71,0x68,0x31,0xe2,0xb4,0xb,0xbe,0x32,0xec,0xee,0x2b,0xad,0xd8,0x59,0x33,0xff,0x6,0xed,0xda,0x9c,0x93,0x97,0x5c,0xb6,0xb0,0xc1,0x99,0x0,0xfe,0x84,0x13,0xd1,0xa8,0xc9,0x26,0x67,0xe4,0x11,0x1c,0x2f,0x28,0x36,0x75,0x88,0x5e,0xb1,0x3a,0xb3,0xbd,0x63,0xbc,0x69,0xd,0x5b,0x47,0xa4,0x9a,0x5a,0x50,0xa6,0xe9,0x5,0x1,0xa7,0x72,0x18,0xf,0x6a,0x1d,0xce,0xe3,0x83,0xe5,0xae,0x98,0x7e,0xc3,0x65,0x64,0x6e,0x9f,0xd4,0x89,0x3e,0x23,0x15,0x7,0xd6,0xf9,0xfd,0x6f,0x49,0xeb,0x44,0x5f,0x54,0x82,0x53,0xc8,0xe,0xef,0x4f,0xaf,0x40,0x8a,0xb8,0x3d,0x6c,0xf0,0xcd,0xa2,0x42,0xb7,0x41,0x96,0x58,0xf7,0x60,0x16,0x19,0x9e,0x94,0xf3,0xf4,0x6d,0x91,0xf1,0x4b,0xbf,0x73,0x1b,0xbb,0xe1,0x78,0x51,0xd9,0x35,0xab,0xdf,0x14,0x3c,0x2e,0xf2,0x81,0xa1,0xd7,0x1a,0xfb,0x1e,0x70,0xa0,0xdb,0x9d,0xc8,0x6e,0xd6,0xab,0xfe,0x8e,0x72,0x33,0x0,0xe8,0xe0,0x1a,0x71,0x1f,0xee,0x40,0xc2,0x88,0x2f,0x85,0xb1,0x30,0x18,0x1,0x93,0x77,0x4b,0xcd,0xfd,0xcc,0xd5,0xef,0xa5,0xd0,0xe6,0x23,0xf7,0xe,0x51,0x3b,0x94,0x9b,0xe5,0xd2,0xbe,0xb8,0x9f,0x54,0x38,0xc7,0x8d,0x25,0x44,0x79,0x22,0xf0,0xea,0xbc,0x60,0x39,0x3a,0xe4,0x3,0xb6,0x86,0xd4,0xa2,0x5f,0xad,0x7c,0xa1,0xc,0x55,0x6a,0x3c,0x83,0x73,0x31,0x29,0x2,0x28,0x84,0x21,0xdd,0xc3,0xbd,0x4e,0xca,0xf2,0x42,0x9d,0x5a,0xda,0x45,0xb,0xd8,0x46,0x8f,0x2c,0xf4,0x69,0x2d,0x98,0xe2,0x2a,0x3f,0x4,0xa4,0x7f,0x74,0xdb,0xc4,0x75,0xce,0x9a,0xa,0x87,0x5d,0x63,0xba,0xcf,0x5e,0x4d,0x24,0xb2,0x17,0x7e,0x37,0x64,0xf8,0xb0,0x35,0x4a,0xbf,0xc5,0xaa,0x50,0xff,0x49,0x9e,0x11,0x96,0x68,0x1e,0x41,0xe3,0xf5,0x67,0x5c,0x8a,0x4c,0x57,0x6,0xe7,0x5b,0xc0,0x48,0x82,0x47,0xa7,0x1c,0x34,0xa3,0xd7,0x89,0xa9,0x26,0xfa,0xf3,0x16,0xdf,0x12,0xd3,0x95,0x78,0xa8,0xfc,0x65,0x9c,0xfb,0x43,0xb7,0x99,0xf9,0xb3,0xe9,0x7b,0x13,0xd1,0x3d,0x70,0x59,0x80,0x56,0x3e,0x7d,0xbb,0xb5,0xb9,0x32,0x61,0x5,0x6b,0xb4,0xac,0x92,0x53,0x4f,0x8,0xf6,0xc9,0x91,0xd9,0xa0,0x8c,0x1b,0x6f,0xec,0xc1,0x2e,0x27,0x20,0x19,0x14,0x76,0xcb,0xa6,0x90,0x66,0x97,0x6d,0x6c,0x36,0x2b,0xdc,0x81,0xde,0xf1,0x1d,0xf,0xae,0xe1,0x52,0x58,0xaf,0x7a,0xd,0x9,0x62,0x15,0x10,0x7,0x8b,0xed,0xc6,0xeb,0x21,0xe6,0x39,0x89,0xa3,0x70,0x3e,0xa1,0xa6,0x5a,0xff,0x53,0xb1,0x35,0xc6,0xb8,0xf8,0x47,0x11,0x2e,0x79,0x52,0x4a,0x8,0x24,0xd9,0xaf,0xfd,0x77,0xda,0x7,0xd6,0x5f,0x36,0x25,0xb4,0x4c,0x5,0x6c,0xc9,0x71,0xe1,0xb5,0xe,0xc1,0x18,0x26,0xfc,0xdf,0x7f,0x44,0x51,0xbf,0xa0,0xf,0x4,0x8f,0x57,0xf4,0x3d,0x99,0xe3,0x56,0x12,0xb6,0x30,0xc,0xe8,0x94,0xae,0xb7,0x86,0xfe,0x54,0xf3,0xb9,0x7a,0x63,0x4b,0xca,0x61,0x9b,0x93,0x7b,0x3b,0x95,0x64,0xa,0xd0,0xad,0x15,0xb3,0x48,0x9,0xf5,0x85,0x42,0x1b,0xc7,0x91,0xcd,0x78,0x9f,0x41,0x5e,0xf6,0xbc,0x43,0x8b,0x59,0x2,0x3f,0xa9,0x9e,0xe0,0xef,0x2f,0xe4,0xc3,0xc5,0x58,0x9d,0xab,0xde,0x40,0x2a,0x75,0x8c,0x55,0xba,0x97,0x14,0x6f,0x62,0x5b,0x5c,0xea,0xb2,0x8d,0x73,0x60,0xf7,0xdb,0xa2,0xcf,0x10,0x7e,0x1a,0x34,0x28,0xe9,0xd7,0x6,0x45,0x2d,0xfb,0x49,0xc2,0xce,0xc0,0x7c,0x6b,0x6e,0x19,0x90,0xbd,0x96,0xf0,0x23,0x29,0x9a,0xd5,0x72,0x76,0x1,0xd4,0xfa,0xa7,0x50,0x4d,0x74,0x66,0x8a,0xa5,0xeb,0xdd,0xb0,0xd,0x17,0x16,0xec,0x1d,0xbb,0x20,0x9c,0x7d,0xdc,0x3c,0xf9,0x33,0x1c,0x8e,0x98,0x3a,0x2c,0x37,0xf1,0x27,0xe5,0x32,0x84,0x2b,0x65,0x13,0xed,0x6a,0x4e,0xcb,0x83,0x1f,0xd1,0xbe,0xc4,0x31,0x68,0x0,0x92,0xc8,0x22,0xb,0x46,0xaa,0x80,0xe7,0x1e,0x87,0x82,0xe2,0xcc,0x38,0x69,0xa4,0x6d,0x88,0xd3,0x3,0xee,0xa8,0xac,0xd8,0x4f,0x67,0x81,0x5d,0xd2,0xf2,0xe9,0x4b,0x6d,0xff,0x80,0x56,0x5d,0x46,0xed,0xc,0xca,0x51,0x88,0x42,0xad,0x4d,0xf2,0x6e,0x3f,0xba,0xb5,0x40,0xa0,0xcf,0xf5,0x5a,0x94,0x43,0x9c,0x1b,0x14,0x62,0x6f,0xf6,0xf1,0x96,0xbd,0x49,0xf3,0x93,0xe3,0xb9,0x19,0x71,0x37,0xdb,0x53,0x7a,0x3e,0x16,0xdd,0xa9,0xa3,0x83,0xf0,0x2c,0x1c,0xf9,0x18,0xd5,0x9f,0xd9,0xa2,0x72,0xfc,0x2,0x9b,0xc3,0xaa,0xd3,0x11,0x86,0xe6,0x65,0x24,0xcb,0x2a,0x2d,0x1e,0x13,0x5c,0x8a,0x77,0x34,0xbf,0xb1,0x38,0xb3,0xf,0x6b,0xbe,0x61,0x98,0xa6,0x45,0x59,0xeb,0xa4,0x52,0x58,0x70,0xa5,0x3,0x7,0x1f,0x68,0xd,0x1a,0xe7,0x81,0xe1,0xcc,0xc1,0x7c,0x9a,0xac,0x9d,0x6c,0x66,0x67,0x21,0x3c,0x8b,0xd6,0xfb,0xd4,0x5,0x17,0x82,0xc8,0x8f,0x25,0x3a,0xbb,0xb,0x12,0x7d,0x99,0xc7,0x41,0xc6,0xf7,0xe5,0xdf,0x64,0xc2,0xa1,0xdc,0x84,0xf4,0x39,0x78,0xe2,0xa,0x10,0xea,0x15,0x7b,0x4a,0xe4,0xcd,0x32,0x2f,0x87,0x73,0x4e,0xfa,0x28,0xb6,0xe0,0x33,0x6a,0xee,0x30,0xbc,0x9,0xda,0xaf,0x29,0xec,0x4,0xfd,0x31,0x5b,0x91,0x9e,0xd8,0xef,0xb2,0xb4,0x5e,0x95,0x8e,0x22,0xd7,0x2b,0xb7,0xc9,0xc0,0x44,0x48,0xf8,0x50,0x97,0x4f,0xd0,0xd2,0x1,0xde,0x8c,0x55,0xa8,0x76,0xa7,0x6,0xab,0x60,0x5f,0x89,0x36,0x3b,0x79,0x8,0x23,0xc4,0x7f,0x0,0x90,0x57,0x8d,0xb0,0x69,0x54,0xc5,0x2e,0x47,0x1d,0xb8,0x3d,0x74,0x85,0x4c,0xfe,0x26,0x27,0x63,0xe8,0x92,0x35,0x20,0xae,0xe,0x7e,0x75,0xce,0xd1,0x8e,0x72,0x87,0x2b,0xe1,0x65,0x6c,0x12,0x32,0xf5,0x5d,0xed,0xa4,0x77,0x75,0xea,0xd,0xf0,0x29,0x7b,0xe,0xa3,0x2,0xd3,0x93,0x2c,0xfa,0xc5,0x86,0xad,0xdc,0x9e,0x35,0xa5,0xda,0x61,0xcc,0x15,0x28,0xf2,0xe2,0x8b,0x60,0xf1,0xd1,0x98,0x1d,0xb8,0x83,0x5b,0xe9,0x20,0x37,0x4d,0xc6,0x82,0xab,0xb,0x85,0x90,0x74,0x6b,0xd0,0xdb,0x80,0x2a,0x6d,0x27,0xb7,0xae,0x1e,0x9f,0xe4,0x62,0x3c,0xd8,0x7a,0x40,0x52,0x63,0x79,0x4,0x67,0xc1,0xdd,0x9c,0x51,0x21,0x4f,0xb5,0xaf,0x47,0x41,0xef,0xde,0xb0,0x22,0x8a,0x97,0x68,0x8d,0x5f,0xeb,0xd6,0xcf,0x96,0x45,0x13,0xac,0x19,0x95,0x4b,0x49,0x8c,0xa,0x7f,0xfe,0x94,0x58,0xa1,0x4a,0x7d,0x3b,0x34,0x30,0xfb,0x11,0x17,0x66,0x3e,0xa7,0x59,0x23,0xb4,0x76,0xf,0x6e,0x81,0xc0,0x43,0xb6,0xbb,0x88,0x8f,0x91,0xd2,0x2f,0xf9,0x16,0x9d,0x14,0x1a,0xc4,0x1b,0xce,0xaa,0xfc,0xe0,0x3,0x3d,0xfd,0xf7,0x1,0x4e,0xa2,0xa6,0x0,0xd5,0xbf,0xa8,0xcd,0xba,0x69,0x44,0x24,0x42,0x9,0x3f,0xd9,0x64,0xc2,0xc3,0xc9,0x38,0x73,0x2e,0x99,0x84,0xb2,0xa0,0x71,0x5e,0x5a,0xc8,0xee,0x4c,0xe3,0xf8,0xf3,0x25,0xf4,0x6f,0xa9,0x48,0xe8,0x8,0xe7,0x2d,0x1f,0x9a,0xcb,0x57,0x6a,0x5,0xe5,0x10,0xe6,0x31,0xff,0x50,0xc7,0xb1,0xbe,0x39,0x33,0x54,0x53,0xca,0x36,0x56,0xec,0x18,0xd4,0xbc,0x1c,0x46,0xdf,0xf6,0x7e,0x92,0xc,0x78,0xb3,0x9b,0x89,0x55,0x26,0x6,0x70,0xbd,0x5c,0xb9,0xd7,0x7,0x7c,0x3a,0xfa,0x3b,0x87,0x55,0xc6,0x13,0xdc,0x89,0xb8,0xc7,0x67,0xc9,0xbc,0x82,0x28,0x44,0xaf,0xdf,0x77,0xd4,0x5,0x49,0xf6,0x7d,0x7,0xd9,0xca,0xf9,0xe1,0x8,0x29,0x4,0xae,0xd8,0x65,0xad,0x63,0xc2,0x23,0x61,0x7f,0x1f,0x7e,0x2,0x7c,0x79,0xcf,0x15,0x60,0xf5,0x4b,0xa7,0x58,0x11,0x2a,0x9d,0x39,0xc,0x56,0xa3,0x12,0xbf,0x69,0x9a,0x6a,0x7b,0x2d,0x27,0x34,0xcb,0x99,0xf4,0x3e,0x80,0xe,0xd1,0x90,0x78,0xe6,0xe4,0x76,0xa0,0x6e,0xf3,0x2b,0x33,0x41,0x3c,0x3d,0x4a,0x83,0x73,0x50,0xa6,0x42,0x1b,0xb4,0xb,0x96,0x18,0x48,0x3,0xe8,0x47,0x5d,0xcd,0xaa,0x86,0x16,0xbd,0x62,0xfb,0xbb,0x32,0x6f,0xfe,0xe7,0x8f,0x1d,0xff,0xb7,0xa4,0xd,0x5f,0xd7,0x52,0x94,0x6c,0x71,0xc8,0xb2,0x25,0x6d,0xec,0xd6,0xa5,0x35,0xa1,0xd2,0xc0,0x46,0x40,0x1c,0x20,0xbe,0x4f,0xee,0xb9,0xf0,0xea,0xba,0xd0,0x38,0x3f,0x8a,0x2e,0xf,0x21,0x8c,0xb6,0x5c,0x43,0xd5,0xf2,0x68,0x4d,0xf7,0xb1,0x57,0xd3,0xfc,0xda,0xc5,0xfd,0x8e,0x66,0xab,0xe3,0x17,0x88,0x72,0x92,0xac,0x3a,0x1,0x8d,0xc1,0x85,0x24,0xf8,0xf1,0xef,0x59,0x97,0x64,0xce,0x8b,0x75,0x9b,0x5b,0x51,0xa,0x37,0x0,0xde,0xc3,0x81,0x7a,0x9e,0xeb,0xe0,0x2c,0x9c,0x1e,0x9f,0xa9,0x6,0xe2,0xcc,0x70,0x5e,0x26,0xb5,0x5a,0x9,0xc4,0xed,0xdd,0xa2,0x1a,0x91,0x84,0xb0,0x22,0x4e,0x2f,0x10,0x98,0x45,0xe9,0xe5,0x4c,0x74,0x95,0x93,0x54,0xdb,0x36,0xa8,0x30,0x31,0x19,0x6b,0xb3,0x53,0x14,0x43,0x84,0x5b,0xeb,0xc1,0x12,0x5c,0xc3,0xc4,0x38,0x9d,0x31,0xd3,0x57,0xa4,0xda,0x9a,0x25,0x73,0x4c,0x1b,0x30,0x28,0x6a,0x46,0xbb,0xcd,0x9f,0x15,0xb8,0x65,0xb4,0x3d,0x54,0x47,0xd6,0x2e,0x67,0xe,0xab,0x13,0x83,0xd7,0x6c,0xa3,0x7a,0x44,0x9e,0xbd,0x1d,0x26,0x33,0xdd,0xc2,0x6d,0x66,0xed,0x35,0x96,0x5f,0xfb,0x81,0x34,0x70,0xd4,0x52,0x6e,0x8a,0xf6,0xcc,0xd5,0xe4,0x9c,0x36,0x91,0xdb,0x18,0x1,0x29,0xa8,0x3,0xf9,0xf1,0x19,0x59,0xf7,0x6,0x68,0xb2,0xcf,0x77,0xd1,0x2a,0x6b,0x97,0xe7,0x20,0x79,0xa5,0xf3,0xaf,0x1a,0xfd,0x23,0x3c,0x94,0xde,0x21,0xe9,0x3b,0x60,0x5d,0xcb,0xfc,0x82,0x8d,0x4d,0x86,0xa1,0xa7,0x3a,0xff,0xc9,0xbc,0x22,0x48,0x17,0xee,0x37,0xd8,0xf5,0x76,0xd,0x0,0x39,0x3e,0x88,0xd0,0xef,0x11,0x2,0x95,0xb9,0xc0,0xad,0x72,0x1c,0x78,0x56,0x4a,0x8b,0xb5,0x64,0x27,0x4f,0x99,0x2b,0xa0,0xac,0xa2,0x1e,0x9,0xc,0x7b,0xf2,0xdf,0xf4,0x92,0x41,0x4b,0xf8,0xb7,0x10,0x14,0x63,0xb6,0x98,0xc5,0x32,0x2f,0x16,0x4,0xe8,0xc7,0x89,0xbf,0xd2,0x6f,0x75,0x74,0x8e,0x7f,0xd9,0x42,0xfe,0x1f,0xbe,0x5e,0x9b,0x51,0x7e,0xec,0xfa,0x58,0x4e,0x55,0x93,0x45,0x87,0x50,0xe6,0x49,0x7,0x71,0x8f,0x8,0x2c,0xa9,0xe1,0x7d,0xb3,0xdc,0xa6,0x53,0xa,0x62,0xf0,0xaa,0x40,0x69,0x24,0xc8,0xe2,0x85,0x7c,0xe5,0xe0,0x80,0xae,0x5a,0xb,0xc6,0xf,0xea,0xb1,0x61,0x8c,0xca,0xce,0xba,0x2d,0x5,0xe3,0x3f,0xb0,0x90,0xc2,0x60,0x46,0xd4,0xab,0x7d,0x76,0x6d,0xc6,0x27,0xe1,0x7a,0xa3,0x69,0x86,0x66,0xd9,0x45,0x14,0x91,0x9e,0x6b,0x8b,0xe4,0xde,0x71,0xbf,0x68,0xb7,0x30,0x3f,0x49,0x44,0xdd,0xda,0xbd,0x96,0x62,0xd8,0xb8,0xc8,0x92,0x32,0x5a,0x1c,0xf0,0x78,0x51,0x15,0x3d,0xf6,0x82,0x88,0xa8,0xdb,0x7,0x37,0xd2,0x33,0xfe,0xb4,0xf2,0x89,0x59,0xd7,0x29,0xb0,0xe8,0x81,0xf8,0x3a,0xad,0xcd,0x4e,0xf,0xe0,0x1,0x6,0x35,0x38,0x77,0xa1,0x5c,0x1f,0x94,0x9a,0x13,0x98,0x24,0x40,0x95,0x4a,0xb3,0x8d,0x6e,0x72,0xc0,0x8f,0x79,0x73,0x5b,0x8e,0x28,0x2c,0x34,0x43,0x26,0x31,0xcc,0xaa,0xca,0xe7,0xea,0x57,0xb1,0x87,0xb6,0x47,0x4d,0x4c,0xa,0x17,0xa0,0xfd,0xd0,0xff,0x2e,0x3c,0xa9,0xe3,0xa4,0xe,0x11,0x90,0x20,0x39,0x56,0xb2,0xec,0x6a,0xed,0xdc,0xce,0xf4,0x4f,0xe9,0x8a,0xf7,0xaf,0xdf,0x12,0x53,0xc9,0x21,0x3b,0xc1,0x3e,0x50,0x61,0xcf,0xe6,0x19,0x4,0xac,0x58,0x65,0xd1,0x3,0x9d,0xcb,0x18,0x41,0xc5,0x1b,0x97,0x22,0xf1,0x84,0x2,0xc7,0x2f,0xd6,0x1a,0x70,0xba,0xb5,0xf3,0xc4,0x99,0x9f,0x75,0xbe,0xa5,0x9,0xfc,0x0,0x9c,0xe2,0xeb,0x6f,0x63,0xd3,0x7b,0xbc,0x64,0xfb,0xf9,0x2a,0xf5,0xa7,0x7e,0x83,0x5d,0x8c,0x2d,0x80,0x4b,0x74,0xa2,0x1d,0x10,0x52,0x23,0x8,0xef,0x54,0x2b,0xbb,0x7c,0xa6,0x9b,0x42,0x7f,0xee,0x5,0x6c,0x36,0x93,0x16,0x5f,0xae,0x67,0xd5,0xd,0xc,0x48,0xc3,0xb9,0x1e,0xb,0x85,0x25,0x55,0x5e,0xe5,0xfa,0xd5,0xa8,0xbf,0xa7,0xfa,0x67,0xe2,0x34,0xd6,0x8f,0xc4,0x32,0x17,0xe7,0xa9,0xde,0xd,0x60,0xa0,0x5f,0xb9,0xb3,0xfe,0xef,0x72,0x70,0x4,0xec,0x9a,0x45,0xaa,0x14,0x89,0x6b,0x73,0x1b,0xfb,0x6a,0x2f,0xa6,0x0,0xf8,0x43,0xc6,0x99,0xcb,0x23,0x30,0x7c,0xd3,0xdc,0x97,0x2,0x8c,0x20,0x9f,0xf6,0x6f,0x82,0x29,0x3e,0x12,0xc9,0x59,0x62,0xe9,0x91,0xdd,0xe3,0x40,0x3b,0x4b,0xbd,0x90,0x75,0x9c,0x5e,0x6d,0x93,0x4d,0x48,0x1d,0x52,0x87,0x13,0xc1,0x6e,0xaf,0xbc,0xd0,0x28,0x16,0xf3,0x5d,0x2c,0x53,0xbe,0x9,0xcc,0x85,0xdf,0x33,0xf4,0x61,0xfd,0xe,0x86,0x2b,0xc2,0x37,0xad,0x98,0xb7,0xf5,0xf7,0x56,0xf1,0x39,0x3a,0x4c,0x5b,0x81,0xe8,0xed,0xea,0x96,0xeb,0x8b,0xb,0x3d,0x8,0x8a,0x74,0xb8,0xa,0x7f,0x21,0xce,0xca,0xb2,0x58,0xe4,0x92,0x76,0xf,0xcf,0x1f,0xe1,0xf0,0x5a,0xcd,0x3,0x15,0xee,0x4a,0x57,0xa3,0x94,0xc5,0x9e,0x4f,0xa2,0x7,0xc0,0xe0,0x1,0x71,0xd8,0xc7,0x80,0xff,0x27,0xa5,0x8d,0x3c,0xa4,0x5,0x10,0x36,0x8e,0x79,0x49,0x9d,0x50,0xd1,0x7d,0x84,0xc,0xda,0xbb,0x24,0xb6,0x2e,0x44,0x64,0x7e,0x7a,0x2d,0x2a,0xdb,0x18,0x22,0x9b,0xb5,0x1e,0xba,0xac,0xab,0x42,0x31,0xf9,0x78,0x26,0xb1,0xe5,0x5c,0x88,0xb4,0xd2,0xd4,0x46,0x54,0xa1,0x35,0x38,0xae,0xe6,0x6,0x83,0x1c,0x3f,0x77,0x65,0x7b,0xb0,0x6c,0x55,0x11,0x95,0x19,0x63,0x25,0xfc,0xd9,0x41,0x66,0xc8,0xd7,0x1a,0xf2,0x51,0x69,0x68,0x4e,0xc3,0x47,0x44,0xe2,0x5a,0x27,0x72,0x2,0xfe,0xbf,0x8c,0x64,0x6c,0x96,0xfd,0x93,0x62,0xcc,0x4e,0x4,0xa3,0x9,0x3d,0xbc,0x94,0x8d,0x1f,0xfb,0xc7,0x41,0x71,0x40,0x59,0x63,0x29,0x5c,0x6a,0xaf,0x7b,0x82,0xdd,0xb7,0x18,0x17,0x69,0x5e,0x32,0x34,0x13,0xd8,0xb4,0x4b,0x1,0xa9,0xc8,0xf5,0xae,0x7c,0x66,0x30,0xec,0xb5,0xb6,0x68,0x8f,0x3a,0xa,0x58,0x2e,0xd3,0x21,0xf0,0x2d,0x80,0xd9,0xe6,0xb0,0xf,0xff,0xbd,0xa5,0x8e,0xa4,0x8,0xad,0x51,0x4f,0x31,0xc2,0x46,0x7e,0xce,0x11,0xd6,0x56,0xc9,0x87,0x54,0xca,0x3,0xa0,0x78,0xe5,0xa1,0x14,0x6e,0xa6,0xb3,0x88,0x28,0xf3,0xf8,0x57,0x48,0xf9,0x42,0x16,0x86,0xb,0xd1,0xef,0x36,0x43,0xd2,0xc1,0xa8,0x3e,0x9b,0xf2,0xbb,0xe8,0x74,0x3c,0xb9,0xc6,0x33,0x49,0x26,0xdc,0x73,0xc5,0x12,0x9d,0x1a,0xe4,0x92,0xcd,0x6f,0x79,0xeb,0xd0,0x6,0xc0,0xdb,0x8a,0x6b,0xd7,0x4c,0xc4,0xe,0xcb,0x2b,0x90,0xb8,0x2f,0x5b,0x5,0x25,0xaa,0x76,0x7f,0x9a,0x53,0x9e,0x5f,0x19,0xf4,0x24,0x70,0xe9,0x10,0x77,0xcf,0x3b,0x15,0x75,0x3f,0x65,0xf7,0x9f,0x5d,0xb1,0xfc,0xd5,0xc,0xda,0xb2,0xf1,0x37,0x39,0x35,0xbe,0xed,0x89,0xe7,0x38,0x20,0x1e,0xdf,0xc3,0x84,0x7a,0x45,0x1d,0x55,0x2c,0x0,0x97,0xe3,0x60,0x4d,0xa2,0xab,0xac,0x95,0x98,0xfa,0x47,0x2a,0x1c,0xea,0x1b,0xe1,0xe0,0xba,0xa7,0x50,0xd,0x52,0x7d,0x91,0x83,0x22,0x6d,0xde,0xd4,0x23,0xf6,0x81,0x85,0xee,0x99,0x9c,0x8b,0x7,0x61,0x4a,0x67,0xd0,0x17,0xc8,0x78,0x52,0x81,0xcf,0x50,0x57,0xab,0xe,0xa2,0x40,0xc4,0x37,0x49,0x9,0xb6,0xe0,0xdf,0x88,0xa3,0xbb,0xf9,0xd5,0x28,0x5e,0xc,0x86,0x2b,0xf6,0x27,0xae,0xc7,0xd4,0x45,0xbd,0xf4,0x9d,0x38,0x80,0x10,0x44,0xff,0x30,0xe9,0xd7,0xd,0x2e,0x8e,0xb5,0xa0,0x4e,0x51,0xfe,0xf5,0x7e,0xa6,0x5,0xcc,0x68,0x12,0xa7,0xe3,0x47,0xc1,0xfd,0x19,0x65,0x5f,0x46,0x77,0xf,0xa5,0x2,0x48,0x8b,0x92,0xba,0x3b,0x90,0x6a,0x62,0x8a,0xca,0x64,0x95,0xfb,0x21,0x5c,0xe4,0x42,0xb9,0xf8,0x4,0x74,0xb3,0xea,0x36,0x60,0x3c,0x89,0x6e,0xb0,0xaf,0x7,0x4d,0xb2,0x7a,0xa8,0xf3,0xce,0x58,0x6f,0x11,0x1e,0xde,0x15,0x32,0x34,0xa9,0x6c,0x5a,0x2f,0xb1,0xdb,0x84,0x7d,0xa4,0x4b,0x66,0xe5,0x9e,0x93,0xaa,0xad,0x1b,0x43,0x7c,0x82,0x91,0x6,0x2a,0x53,0x3e,0xe1,0x8f,0xeb,0xc5,0xd9,0x18,0x26,0xf7,0xb4,0xdc,0xa,0xb8,0x33,0x3f,0x31,0x8d,0x9a,0x9f,0xe8,0x61,0x4c,0x67,0x1,0xd2,0xd8,0x6b,0x24,0x83,0x87,0xf0,0x25,0xb,0x56,0xa1,0xbc,0x85,0x97,0x7b,0x54,0x1a,0x2c,0x41,0xfc,0xe6,0xe7,0x1d,0xec,0x4a,0xd1,0x6d,0x8c,0x2d,0xcd,0x8,0xc2,0xed,0x7f,0x69,0xcb,0xdd,0xc6,0x0,0xd6,0x14,0xc3,0x75,0xda,0x94,0xe2,0x1c,0x9b,0xbf,0x3a,0x72,0xee,0x20,0x4f,0x35,0xc0,0x99,0xf1,0x63,0x39,0xd3,0xfa,0xb7,0x5b,0x71,0x16,0xef,0x76,0x73,0x13,0x3d,0xc9,0x98,0x55,0x9c,0x79,0x22,0xf2,0x1f,0x59,0x5d,0x29,0xbe,0x96,0x70,0xac,0x23,0x3,0x69,0x2b,0x29,0x88,0x2f,0xe7,0xe4,0x92,0x85,0x5f,0x36,0x33,0x34,0x48,0x35,0x55,0x60,0xd7,0x12,0x5b,0x1,0xed,0x2a,0xbf,0x23,0xd0,0x58,0xf5,0x1c,0xe9,0x73,0x46,0x96,0xc3,0x8c,0x59,0xcd,0x1f,0xb0,0x71,0x62,0xe,0xf6,0xc8,0x2d,0x83,0xf2,0x8d,0xbc,0x37,0x4f,0x3,0x3d,0x9e,0xe5,0x95,0x63,0x4e,0xab,0x42,0x80,0xb3,0x4d,0x93,0xa2,0xd,0x2,0x49,0xdc,0x52,0xfe,0x41,0x28,0xb1,0x5c,0xf7,0xe0,0xcc,0x17,0x87,0x57,0xb5,0xad,0xc5,0x25,0xb4,0xf1,0x78,0xde,0x26,0x9d,0x18,0x47,0x15,0xfd,0xee,0xd3,0xbe,0x7e,0x81,0x67,0x6d,0x20,0x31,0xac,0xae,0xda,0x32,0x44,0x9b,0x74,0xca,0xb,0x76,0x61,0x79,0x24,0xb9,0x3c,0xea,0x8,0x51,0x1a,0xec,0xc9,0x39,0x77,0x0,0xbd,0xfb,0x22,0x7,0x9f,0xb8,0x16,0x9,0xc4,0x2c,0x8f,0xb7,0xb6,0x90,0x1d,0x99,0xe6,0x70,0x38,0xd8,0x5d,0xc2,0xe1,0xa9,0xbb,0xa5,0x6e,0xb2,0x8b,0xcf,0x4b,0xc7,0x9c,0xef,0x27,0xa6,0xf8,0x6f,0x3b,0x82,0x56,0x6a,0xc,0xa,0x98,0x8a,0x7f,0xeb,0xf0,0x9a,0xba,0xa0,0xa4,0xf3,0xf4,0x5,0xc6,0xfc,0x45,0x6b,0xc0,0x64,0x72,0x75,0xdb,0xce,0xe8,0x50,0xa7,0x97,0x43,0x8e,0xf,0xa3,0x5a,0xd2,0x4,0x65,0xfa,0x68,0x91,0x7c,0xd9,0x1e,0x3e,0xdf,0xaf,0x6,0x19,0x5e,0x21,0xf9,0x7b,0x53,0xe2,0x7a,0xd1,0x11,0xc1,0x3f,0x2e,0x84,0x13,0xdd,0xcb,0x30,0x94,0x89,0x7d,0x4a,0x1b,0x40,0xd5,0xe3,0xd6,0x54,0xaa,0x66,0xd4,0xa1,0xff,0x10,0x14,0x6c,0x86,0x3a,0x4c,0xa8,0x72,0x8e,0x7b,0xd7,0x1d,0x99,0x90,0xee,0xce,0x9,0xa1,0x11,0x58,0x8b,0x89,0x16,0xf1,0xc,0xd5,0x87,0xf2,0x5f,0xfe,0x2f,0x6f,0xd0,0x6,0x39,0x7a,0x51,0x20,0x62,0xc9,0x59,0x26,0x9d,0x30,0xe9,0xd4,0xe,0x1e,0x77,0x9c,0xd,0x2d,0x64,0xe1,0x44,0x7f,0xa7,0x15,0xdc,0xcb,0xb1,0x3a,0x7e,0x57,0xf7,0x79,0x6c,0x88,0x97,0x2c,0x27,0x7c,0xd6,0x91,0xdb,0x4b,0x52,0xe2,0x63,0x18,0x9e,0xc0,0x24,0x86,0xbc,0xae,0x9f,0x85,0xf8,0x9b,0x3d,0x21,0x60,0xad,0xdd,0xb3,0x49,0x53,0xbb,0xbd,0x13,0x22,0x4c,0xde,0x76,0x6b,0x94,0x71,0xa3,0x17,0x2a,0x33,0x6a,0xb9,0xef,0x50,0xe5,0x69,0xb7,0xb5,0x70,0xf6,0x83,0x2,0x68,0xa4,0x5d,0xb6,0x81,0xc7,0xc8,0xcc,0x7,0xed,0xeb,0x9a,0xc2,0x5b,0xa5,0xdf,0x48,0x8a,0xf3,0x92,0x7d,0x3c,0xbf,0x4a,0x47,0x74,0x73,0x6d,0x2e,0xd3,0x5,0xea,0x61,0xe8,0xe6,0x38,0xe7,0x32,0x56,0x0,0x1c,0xff,0xc1,0x1,0xb,0xfd,0xb2,0x5e,0x5a,0xfc,0x29,0x43,0x54,0x31,0x46,0x95,0xb8,0xd8,0xbe,0xf5,0xc3,0x25,0x98,0x3e,0x3f,0x35,0xc4,0x8f,0xd2,0x65,0x78,0x4e,0x5c,0x8d,0xa2,0xa6,0x34,0x12,0xb0,0x1f,0x4,0xf,0xd9,0x8,0x93,0x55,0xb4,0x14,0xf4,0x1b,0xd1,0xe3,0x66,0x37,0xab,0x96,0xf9,0x19,0xec,0x1a,0xcd,0x3,0xac,0x3b,0x4d,0x42,0xc5,0xcf,0xa8,0xaf,0x36,0xca,0xaa,0x10,0xe4,0x28,0x40,0xe0,0xba,0x23,0xa,0x82,0x6e,0xf0,0x84,0x4f,0x67,0x75,0xa9,0xda,0xfa,0x8c,0x41,0xa0,0x45,0x2b,0xfb,0x80,0xc6,0x5,0xa3,0x1b,0x66,0x33,0x43,0xbf,0xfe,0xcd,0x25,0x2d,0xd7,0xbc,0xd2,0x23,0x8d,0xf,0x45,0xe2,0x48,0x7c,0xfd,0xd5,0xcc,0x5e,0xba,0x86,0x0,0x30,0x1,0x18,0x22,0x68,0x1d,0x2b,0xee,0x3a,0xc3,0x9c,0xf6,0x59,0x56,0x28,0x1f,0x73,0x75,0x52,0x99,0xf5,0xa,0x40,0xe8,0x89,0xb4,0xef,0x3d,0x27,0x71,0xad,0xf4,0xf7,0x29,0xce,0x7b,0x4b,0x19,0x6f,0x92,0x60,0xb1,0x6c,0xc1,0x98,0xa7,0xf1,0x4e,0xbe,0xfc,0xe4,0xcf,0xe5,0x49,0xec,0x10,0xe,0x70,0x83,0x7,0x3f,0x8f,0x50,0x97,0x17,0x88,0xc6,0x15,0x8b,0x42,0xe1,0x39,0xa4,0xe0,0x55,0x2f,0xe7,0xf2,0xc9,0x69,0xb2,0xb9,0x16,0x9,0xb8,0x3,0x57,0xc7,0x4a,0x90,0xae,0x77,0x2,0x93,0x80,0xe9,0x7f,0xda,0xb3,0xfa,0xa9,0x35,0x7d,0xf8,0x87,0x72,0x8,0x67,0x9d,0x32,0x84,0x53,0xdc,0x5b,0xa5,0xd3,0x8c,0x2e,0x38,0xaa,0x91,0x47,0x81,0x9a,0xcb,0x2a,0x96,0xd,0x85,0x4f,0x8a,0x6a,0xd1,0xf9,0x6e,0x1a,0x44,0x64,0xeb,0x37,0x3e,0xdb,0x12,0xdf,0x1e,0x58,0xb5,0x65,0x31,0xa8,0x51,0x36,0x8e,0x7a,0x54,0x34,0x7e,0x24,0xb6,0xde,0x1c,0xf0,0xbd,0x94,0x4d,0x9b,0xf3,0xb0,0x76,0x78,0x74,0xff,0xac,0xc8,0xa6,0x79,0x61,0x5f,0x9e,0x82,0xc5,0x3b,0x4,0x5c,0x14,0x6d,0x41,0xd6,0xa2,0x21,0xc,0xe3,0xea,0xed,0xd4,0xd9,0xbb,0x6,0x6b,0x5d,0xab,0x5a,0xa0,0xa1,0xfb,0xe6,0x11,0x4c,0x13,0x3c,0xd0,0xc2,0x63,0x2c,0x9f,0x95,0x62,0xb7,0xc0,0xc4,0xaf,0xd8,0xdd,0xca,0x46,0x20,0xb,0x26,0xde,0x50,0xfc,0x43,0xa0,0xf,0x0,0x4b,0xe2,0xce,0x15,0x85,0x2a,0xb3,0x5e,0xf5,0x27,0xb6,0xf3,0x7a,0x55,0xb7,0xaf,0xc7,0x45,0x17,0xff,0xec,0xdc,0x24,0x9f,0x1a,0x65,0x6f,0x22,0x33,0xd1,0xbc,0x7c,0x83,0x46,0x99,0x76,0xc8,0xae,0xac,0xd8,0x30,0x26,0xbb,0x3e,0xe8,0x9,0x74,0x63,0x7b,0xcb,0x3b,0x75,0x2,0xa,0x53,0x18,0xee,0x2d,0xe5,0xe6,0x90,0x6b,0x29,0x2b,0x8a,0x36,0x4a,0x37,0x57,0x87,0x5d,0x34,0x31,0x3,0xef,0x28,0xbd,0x62,0xd5,0x10,0x59,0x1e,0xeb,0x71,0x44,0x21,0xd2,0x5a,0xf7,0xcf,0x1d,0xb2,0x73,0x94,0xc1,0x8e,0x5b,0x2f,0x81,0xf0,0x8f,0x60,0xc,0xf4,0xca,0x3f,0x9c,0xe7,0x97,0xbe,0x35,0x4d,0x1,0x82,0xb1,0x4f,0x91,0x61,0x4c,0xa9,0x40,0xa5,0x95,0x41,0x8c,0xd9,0xcc,0xea,0x52,0x6,0x67,0xf8,0x6a,0xd,0xa1,0x58,0xd0,0x3c,0xdd,0xad,0x4,0x93,0x7e,0xdb,0x1c,0x79,0x51,0xe0,0x78,0x1b,0x5c,0x23,0xfb,0x2c,0x86,0x11,0xdf,0xd3,0x13,0xc3,0x3d,0x7f,0x48,0x19,0x42,0xc9,0x32,0x96,0x8b,0xa8,0x64,0xd6,0xa3,0xd7,0xe1,0xd4,0x56,0x84,0x38,0x4e,0xaa,0xfd,0x12,0x16,0x6e,0x9d,0xba,0x14,0xb,0xbf,0xf9,0x20,0x5,0xb4,0x92,0x1f,0x9b,0xc6,0x2e,0x8d,0xb5,0x5f,0xc0,0xe3,0xab,0xe4,0x72,0x3a,0xda,0x89,0xcd,0x49,0xc5,0xb9,0xa7,0x6c,0xb0,0xfa,0x6d,0x39,0x80,0x9e,0xed,0x25,0xa4,0x9a,0x88,0x7d,0xe9,0x54,0x68,0xe,0x8,0xa6,0xf1,0xf6,0x7,0xf2,0x98,0xb8,0xa2,0xc2,0x66,0x70,0x77,0xc4,0xfe,0x47,0x69,0xfe,0x5c,0x7a,0xe8,0x97,0x41,0x4a,0x51,0xfa,0x1b,0xdd,0x46,0x9f,0x55,0xba,0x5a,0xe5,0x79,0x28,0xad,0xa2,0x57,0xb7,0xd8,0xe2,0x4d,0x83,0x54,0x8b,0xc,0x3,0x75,0x78,0xe1,0xe6,0x81,0xaa,0x5e,0xe4,0x84,0xf4,0xae,0xe,0x66,0x20,0xcc,0x44,0x6d,0x29,0x1,0xca,0xbe,0xb4,0x94,0xe7,0x3b,0xb,0xee,0xf,0xc2,0x88,0xce,0xb5,0x65,0xeb,0x15,0x8c,0xd4,0xbd,0xc4,0x6,0x91,0xf1,0x72,0x33,0xdc,0x3d,0x3a,0x9,0x4,0x4b,0x9d,0x60,0x23,0xa8,0xa6,0x2f,0xa4,0x18,0x7c,0xa9,0x76,0x8f,0xb1,0x52,0x4e,0xfc,0xb3,0x45,0x4f,0x67,0xb2,0x14,0x10,0x8,0x7f,0x1a,0xd,0xf0,0x96,0xf6,0xdb,0xd6,0x6b,0x8d,0xbb,0x8a,0x7b,0x71,0x70,0x36,0x2b,0x9c,0xc1,0xec,0xc3,0x12,0x0,0x95,0xdf,0x98,0x32,0x2d,0xac,0x1c,0x5,0x6a,0x8e,0xd0,0x56,0xd1,0xe0,0xf2,0xc8,0x73,0xd5,0xb6,0xcb,0x93,0xe3,0x2e,0x6f,0xf5,0x1d,0x7,0xfd,0x2,0x6c,0x5d,0xf3,0xda,0x25,0x38,0x90,0x64,0x59,0xed,0x3f,0xa1,0xf7,0x24,0x7d,0xf9,0x27,0xab,0x1e,0xcd,0xb8,0x3e,0xfb,0x13,0xea,0x26,0x4c,0x86,0x89,0xcf,0xf8,0xa5,0xa3,0x49,0x82,0x99,0x35,0xc0,0x3c,0xa0,0xde,0xd7,0x53,0x5f,0xef,0x47,0x80,0x58,0xc7,0xc5,0x16,0xc9,0x9b,0x42,0xbf,0x61,0xb0,0x11,0xbc,0x77,0x48,0x9e,0x21,0x2c,0x6e,0x1f,0x34,0xd3,0x68,0x17,0x87,0x40,0x9a,0xa7,0x7e,0x43,0xd2,0x39,0x50,0xa,0xaf,0x2a,0x63,0x92,0x5b,0xe9,0x31,0x30,0x74,0xff,0x85,0x22,0x37,0xb9,0x19,0x69,0x62,0xd9,0xc6,0x71,0x8d,0x78,0xd4,0x1e,0x9a,0x93,0xed,0xcd,0xa,0xa2,0x12,0x5b,0x88,0x8a,0x15,0xf2,0xf,0xd6,0x84,0xf1,0x5c,0xfd,0x2c,0x6c,0xd3,0x5,0x3a,0x79,0x52,0x23,0x61,0xca,0x5a,0x25,0x9e,0x33,0xea,0xd7,0xd,0x1d,0x74,0x9f,0xe,0x2e,0x67,0xe2,0x47,0x7c,0xa4,0x16,0xdf,0xc8,0xb2,0x39,0x7d,0x54,0xf4,0x7a,0x6f,0x8b,0x94,0x2f,0x24,0x7f,0xd5,0x92,0xd8,0x48,0x51,0xe1,0x60,0x1b,0x9d,0xc3,0x27,0x85,0xbf,0xad,0x9c,0x86,0xfb,0x98,0x3e,0x22,0x63,0xae,0xde,0xb0,0x4a,0x50,0xb8,0xbe,0x10,0x21,0x4f,0xdd,0x75,0x68,0x97,0x72,0xa0,0x14,0x29,0x30,0x69,0xba,0xec,0x53,0xe6,0x6a,0xb4,0xb6,0x73,0xf5,0x80,0x1,0x6b,0xa7,0x5e,0xb5,0x82,0xc4,0xcb,0xcf,0x4,0xee,0xe8,0x99,0xc1,0x58,0xa6,0xdc,0x4b,0x89,0xf0,0x91,0x7e,0x3f,0xbc,0x49,0x44,0x77,0x70,0x6e,0x2d,0xd0,0x6,0xe9,0x62,0xeb,0xe5,0x3b,0xe4,0x31,0x55,0x3,0x1f,0xfc,0xc2,0x2,0x8,0xfe,0xb1,0x5d,0x59,0xff,0x2a,0x40,0x57,0x32,0x45,0x96,0xbb,0xdb,0xbd,0xf6,0xc0,0x26,0x9b,0x3d,0x3c,0x36,0xc7,0x8c,0xd1,0x66,0x7b,0x4d,0x5f,0x8e,0xa1,0xa5,0x37,0x11,0xb3,0x1c,0x7,0xc,0xda,0xb,0x90,0x56,0xb7,0x17,0xf7,0x18,0xd2,0xe0,0x65,0x34,0xa8,0x95,0xfa,0x1a,0xef,0x19,0xce,0x0,0xaf,0x38,0x4e,0x41,0xc6,0xcc,0xab,0xac,0x35,0xc9,0xa9,0x13,0xe7,0x2b,0x43,0xe3,0xb9,0x20,0x9,0x81,0x6d,0xf3,0x87,0x4c,0x64,0x76,0xaa,0xd9,0xf9,0x8f,0x42,0xa3,0x46,0x28,0xf8,0x83,0xc5,0x9f,0x76,0x93,0xbe,0x4e,0x90,0x6e,0x5d,0xde,0x92,0xea,0x61,0x48,0x38,0x43,0xe0,0x15,0x2b,0xd3,0xbf,0x50,0x2f,0x5e,0xf0,0x84,0x51,0x1e,0x4b,0xac,0x6d,0xc2,0x10,0x28,0x85,0xd,0xfe,0x9b,0xae,0x34,0xc1,0x86,0xcf,0xa,0xbd,0x62,0xf7,0x30,0xdc,0xee,0xeb,0x82,0x58,0x88,0xe8,0x95,0xe9,0x55,0xf4,0xf6,0xb4,0x4f,0x39,0x3a,0xf2,0x31,0xc7,0x8c,0xd5,0xdd,0xaa,0xe4,0x14,0xa4,0xbc,0xab,0xd6,0x37,0xe1,0x64,0xf9,0xef,0x7,0x73,0x71,0x17,0xa9,0x46,0x99,0x5c,0xa3,0x63,0xe,0xec,0xfd,0xb0,0xba,0xc5,0x40,0xfb,0x3,0x33,0x20,0xc8,0x9a,0x18,0x70,0x68,0x8a,0xa5,0x2c,0x69,0xf8,0x2a,0x81,0x6c,0xf5,0x5a,0xca,0x11,0x3d,0x94,0xdf,0xd0,0x7f,0x9c,0x23,0x8f,0x1,0xb6,0x98,0x21,0x1b,0xa8,0xaf,0xb9,0x1d,0x7d,0x67,0x47,0x2d,0xd8,0x29,0x2e,0x79,0xd7,0xd1,0xb7,0x8b,0x36,0xa2,0x57,0x45,0x7b,0xfa,0x32,0x41,0x5f,0xe6,0xb2,0x25,0x6f,0xb3,0x78,0x66,0x1a,0x96,0x12,0x56,0x5,0xe5,0xad,0x3b,0x74,0x3c,0x1f,0x80,0x6a,0x52,0xf1,0x19,0x44,0xc0,0x4d,0x6b,0xda,0xff,0x26,0x60,0xd4,0xcb,0x65,0x42,0xb1,0xc9,0xcd,0x22,0x75,0x91,0xe7,0x5b,0x89,0xb,0x3e,0x8,0x7c,0x9,0xbb,0x77,0x54,0x49,0xed,0x16,0x9d,0xc6,0x97,0xa0,0xe2,0x1c,0xcc,0xc,0x0,0xce,0x59,0xf3,0x24,0xfc,0x83,0xc4,0xa7,0x3f,0x8e,0xa6,0xc3,0x4,0xa1,0x4c,0xdb,0x72,0x2,0xe3,0xf,0x87,0x7e,0xd2,0xb5,0x27,0xb8,0xd9,0x8d,0x35,0x13,0x6,0x53,0x9e,0x4a,0x7a,0x36,0xf1,0x2e,0x9e,0xb4,0x67,0x29,0xb6,0xb1,0x4d,0xe8,0x44,0xa6,0x22,0xd1,0xaf,0xef,0x50,0x6,0x39,0x6e,0x45,0x5d,0x1f,0x33,0xce,0xb8,0xea,0x60,0xcd,0x10,0xc1,0x48,0x21,0x32,0xa3,0x5b,0x12,0x7b,0xde,0x66,0xf6,0xa2,0x19,0xd6,0xf,0x31,0xeb,0xc8,0x68,0x53,0x46,0xa8,0xb7,0x18,0x13,0x98,0x40,0xe3,0x2a,0x8e,0xf4,0x41,0x5,0xa1,0x27,0x1b,0xff,0x83,0xb9,0xa0,0x91,0xe9,0x43,0xe4,0xae,0x6d,0x74,0x5c,0xdd,0x76,0x8c,0x84,0x6c,0x2c,0x82,0x73,0x1d,0xc7,0xba,0x2,0xa4,0x5f,0x1e,0xe2,0x92,0x55,0xc,0xd0,0x86,0xda,0x6f,0x88,0x56,0x49,0xe1,0xab,0x54,0x9c,0x4e,0x15,0x28,0xbe,0x89,0xf7,0xf8,0x38,0xf3,0xd4,0xd2,0x4f,0x8a,0xbc,0xc9,0x57,0x3d,0x62,0x9b,0x42,0xad,0x80,0x3,0x78,0x75,0x4c,0x4b,0xfd,0xa5,0x9a,0x64,0x77,0xe0,0xcc,0xb5,0xd8,0x7,0x69,0xd,0x23,0x3f,0xfe,0xc0,0x11,0x52,0x3a,0xec,0x5e,0xd5,0xd9,0xd7,0x6b,0x7c,0x79,0xe,0x87,0xaa,0x81,0xe7,0x34,0x3e,0x8d,0xc2,0x65,0x61,0x16,0xc3,0xed,0xb0,0x47,0x5a,0x63,0x71,0x9d,0xb2,0xfc,0xca,0xa7,0x1a,0x0,0x1,0xfb,0xa,0xac,0x37,0x8b,0x6a,0xcb,0x2b,0xee,0x24,0xb,0x99,0x8f,0x2d,0x3b,0x20,0xe6,0x30,0xf2,0x25,0x93,0x3c,0x72,0x4,0xfa,0x7d,0x59,0xdc,0x94,0x8,0xc6,0xa9,0xd3,0x26,0x7f,0x17,0x85,0xdf,0x35,0x1c,0x51,0xbd,0x97,0xf0,0x9,0x90,0x95,0xf5,0xdb,0x2f,0x7e,0xb3,0x7a,0x9f,0xc4,0x14,0xf9,0xbf,0xbb,0xcf,0x58,0x70,0x96,0x4a,0xc5,0xe5,0x2c,0x8e,0xa8,0x3a,0x45,0x93,0x98,0x83,0x28,0xc9,0xf,0x94,0x4d,0x87,0x68,0x88,0x37,0xab,0xfa,0x7f,0x70,0x85,0x65,0xa,0x30,0x9f,0x51,0x86,0x59,0xde,0xd1,0xa7,0xaa,0x33,0x34,0x53,0x78,0x8c,0x36,0x56,0x26,0x7c,0xdc,0xb4,0xf2,0x1e,0x96,0xbf,0xfb,0xd3,0x18,0x6c,0x66,0x46,0x35,0xe9,0xd9,0x3c,0xdd,0x10,0x5a,0x1c,0x67,0xb7,0x39,0xc7,0x5e,0x6,0x6f,0x16,0xd4,0x43,0x23,0xa0,0xe1,0xe,0xef,0xe8,0xdb,0xd6,0x99,0x4f,0xb2,0xf1,0x7a,0x74,0xfd,0x76,0xca,0xae,0x7b,0xa4,0x5d,0x63,0x80,0x9c,0x2e,0x61,0x97,0x9d,0xb5,0x60,0xc6,0xc2,0xda,0xad,0xc8,0xdf,0x22,0x44,0x24,0x9,0x4,0xb9,0x5f,0x69,0x58,0xa9,0xa3,0xa2,0xe4,0xf9,0x4e,0x13,0x3e,0x11,0xc0,0xd2,0x47,0xd,0x4a,0xe0,0xff,0x7e,0xce,0xd7,0xb8,0x5c,0x2,0x84,0x3,0x32,0x20,0x1a,0xa1,0x7,0x64,0x19,0x41,0x31,0xfc,0xbd,0x27,0xcf,0xd5,0x2f,0xd0,0xbe,0x8f,0x21,0x8,0xf7,0xea,0x42,0xb6,0x8b,0x3f,0xed,0x73,0x25,0xf6,0xaf,0x2b,0xf5,0x79,0xcc,0x1f,0x6a,0xec,0x29,0xc1,0x38,0xf4,0x9e,0x54,0x5b,0x1d,0x2a,0x77,0x71,0x9b,0x50,0x4b,0xe7,0x12,0xee,0x72,0xc,0x5,0x81,0x8d,0x3d,0x95,0x52,0x8a,0x15,0x17,0xc4,0x1b,0x49,0x90,0x6d,0xb3,0x62,0xc3,0x6e,0xa5,0x9a,0x4c,0xf3,0xfe,0xbc,0xcd,0xe6,0x1,0xba,0xc5,0x55,0x92,0x48,0x75,0xac,0x91,0x0,0xeb,0x82,0xd8,0x7d,0xf8,0xb1,0x40,0x89,0x3b,0xe3,0xe2,0xa6,0x2d,0x57,0xf0,0xe5,0x6b,0xcb,0xbb,0xb0,0xb,0x14,0x31,0x23,0xd6,0x42,0xff,0xc3,0xa5,0xa3,0x51,0xc6,0x92,0x2b,0x35,0x46,0x8e,0xf,0x69,0xcd,0xdb,0xdc,0x6f,0x55,0xec,0xc2,0xd,0x5a,0x5d,0xac,0x59,0x33,0x13,0x9,0x1f,0x39,0xb4,0x30,0x6d,0x85,0x26,0x1e,0x36,0x11,0xbf,0xa0,0x14,0x52,0x8b,0xae,0x22,0x66,0xe2,0x6e,0x12,0xc,0xc7,0x1b,0xf4,0x6b,0x48,0x0,0x4f,0xd9,0x91,0x71,0xd4,0xe3,0xb2,0xe9,0x62,0x99,0x3d,0x20,0x87,0x2d,0xba,0x74,0x78,0xb8,0x68,0x96,0x2f,0x93,0xe5,0x1,0x56,0xb9,0xbd,0xc5,0x3,0xcf,0x7d,0x8,0x7c,0x4a,0x7f,0xfd,0xad,0xcc,0x53,0xc1,0xa6,0xa,0xf3,0x7b,0xe,0x3e,0xea,0x27,0x72,0x67,0x41,0xf9,0xd2,0xfa,0x4b,0xd3,0xb0,0xf7,0x88,0x50,0x97,0x76,0x6,0xaf,0x38,0xd5,0x70,0xb7,0x84,0x2a,0x5b,0x24,0xcb,0xa7,0x5f,0x61,0x64,0xb6,0x19,0xd8,0x3f,0x6a,0x25,0xf0,0x29,0x1a,0xe4,0x3a,0xca,0xe7,0x2,0xeb,0x94,0x37,0x4c,0x3c,0x15,0x9e,0xe6,0xaa,0x9d,0xe1,0x9c,0xfc,0x2c,0xf6,0x9f,0x9a,0x86,0x4e,0x4d,0x3b,0xc0,0x82,0x80,0x21,0xb5,0x40,0xda,0xef,0x8a,0x79,0xf1,0x5c,0xa8,0x44,0x83,0x16,0xc9,0x7e,0xbb,0xf2,0xed,0x32,0xdd,0x63,0x5,0x7,0x73,0x9b,0xce,0xc4,0x89,0x98,0x7a,0x17,0xd7,0x28,0x60,0x90,0xde,0xa9,0xa1,0xf8,0xb3,0x45,0x8d,0x10,0x95,0x43,0xa2,0xdf,0xc8,0xd0,0x49,0x65,0xbe,0x2e,0x81,0x18,0xf5,0x5e,0x75,0xfb,0x57,0xe8,0xb,0xa4,0xab,0xe0,0xee,0xbc,0x54,0x47,0x77,0x8f,0x34,0xb1,0x8c,0x1d,0x58,0xd1,0xfe,0x1c,0x4,0x6c,0x6a,0xcc,0x74,0x9,0x5c,0x2c,0xd0,0x91,0xa2,0x4a,0x42,0xb8,0xd3,0xbd,0x4c,0xe2,0x60,0x2a,0x8d,0x27,0x13,0x92,0xba,0xa3,0x31,0xd5,0xe9,0x6f,0x5f,0x6e,0x77,0x4d,0x7,0x72,0x44,0x81,0x55,0xac,0xf3,0x99,0x36,0x39,0x47,0x70,0x1c,0x1a,0x3d,0xf6,0x9a,0x65,0x2f,0x87,0xe6,0xdb,0x80,0x52,0x48,0x1e,0xc2,0x9b,0x98,0x46,0xa1,0x14,0x24,0x76,0x0,0xfd,0xf,0xde,0x3,0xae,0xf7,0xc8,0x9e,0x21,0xd1,0x93,0x8b,0xa0,0x8a,0x26,0x83,0x7f,0x61,0x1f,0xec,0x68,0x50,0xe0,0x3f,0xf8,0x78,0xe7,0xa9,0x7a,0xe4,0x2d,0x8e,0x56,0xcb,0x8f,0x3a,0x40,0x88,0x9d,0xa6,0x6,0xdd,0xd6,0x79,0x66,0xd7,0x6c,0x38,0xa8,0x25,0xff,0xc1,0x18,0x6d,0xfc,0xef,0x86,0x10,0xb5,0xdc,0x95,0xc6,0x5a,0x12,0x97,0xe8,0x1d,0x67,0x8,0xf2,0x5d,0xeb,0x3c,0xb3,0x34,0xca,0xbc,0xe3,0x41,0x57,0xc5,0xfe,0x28,0xee,0xf5,0xa4,0x45,0xf9,0x62,0xea,0x20,0xe5,0x5,0xbe,0x96,0x1,0x75,0x2b,0xb,0x84,0x58,0x51,0xb4,0x7d,0xb0,0x71,0x37,0xda,0xa,0x5e,0xc7,0x3e,0x59,0xe1,0x15,0x3b,0x5b,0x11,0x4b,0xd9,0xb1,0x73,0x9f,0xd2,0xfb,0x22,0xf4,0x9c,0xdf,0x19,0x17,0x1b,0x90,0xc3,0xa7,0xc9,0x16,0xe,0x30,0xf1,0xed,0xaa,0x54,0x6b,0x33,0x7b,0x2,0x2e,0xb9,0xcd,0x4e,0x63,0x8c,0x85,0x82,0xbb,0xb6,0xd4,0x69,0x4,0x32,0xc4,0x35,0xcf,0xce,0x94,0x89,0x7e,0x23,0x7c,0x53,0xbf,0xad,0xc,0x43,0xf0,0xfa,0xd,0xd8,0xaf,0xab,0xc0,0xb7,0xb2,0xa5,0x29,0x4f,0x64,0x49,0xad,0x6a,0xb5,0x5,0x2f,0xfc,0xb2,0x2d,0x2a,0xd6,0x73,0xdf,0x3d,0xb9,0x4a,0x34,0x74,0xcb,0x9d,0xa2,0xf5,0xde,0xc6,0x84,0xa8,0x55,0x23,0x71,0xfb,0x56,0x8b,0x5a,0xd3,0xba,0xa9,0x38,0xc0,0x89,0xe0,0x45,0xfd,0x6d,0x39,0x82,0x4d,0x94,0xaa,0x70,0x53,0xf3,0xc8,0xdd,0x33,0x2c,0x83,0x88,0x3,0xdb,0x78,0xb1,0x15,0x6f,0xda,0x9e,0x3a,0xbc,0x80,0x64,0x18,0x22,0x3b,0xa,0x72,0xd8,0x7f,0x35,0xf6,0xef,0xc7,0x46,0xed,0x17,0x1f,0xf7,0xb7,0x19,0xe8,0x86,0x5c,0x21,0x99,0x3f,0xc4,0x85,0x79,0x9,0xce,0x97,0x4b,0x1d,0x41,0xf4,0x13,0xcd,0xd2,0x7a,0x30,0xcf,0x7,0xd5,0x8e,0xb3,0x25,0x12,0x6c,0x63,0xa3,0x68,0x4f,0x49,0xd4,0x11,0x27,0x52,0xcc,0xa6,0xf9,0x0,0xd9,0x36,0x1b,0x98,0xe3,0xee,0xd7,0xd0,0x66,0x3e,0x1,0xff,0xec,0x7b,0x57,0x2e,0x43,0x9c,0xf2,0x96,0xb8,0xa4,0x65,0x5b,0x8a,0xc9,0xa1,0x77,0xc5,0x4e,0x42,0x4c,0xf0,0xe7,0xe2,0x95,0x1c,0x31,0x1a,0x7c,0xaf,0xa5,0x16,0x59,0xfe,0xfa,0x8d,0x58,0x76,0x2b,0xdc,0xc1,0xf8,0xea,0x6,0x29,0x67,0x51,0x3c,0x81,0x9b,0x9a,0x60,0x91,0x37,0xac,0x10,0xf1,0x50,0xb0,0x75,0xbf,0x90,0x2,0x14,0xb6,0xa0,0xbb,0x7d,0xab,0x69,0xbe,0x8,0xa7,0xe9,0x9f,0x61,0xe6,0xc2,0x47,0xf,0x93,0x5d,0x32,0x48,0xbd,0xe4,0x8c,0x1e,0x44,0xae,0x87,0xca,0x26,0xc,0x6b,0x92,0xb,0xe,0x6e,0x40,0xb4,0xe5,0x28,0xe1,0x4,0x5f,0x8f,0x62,0x24,0x20,0x54,0xc3,0xeb,0xd,0xd1,0x5e,0x7e,0x57,0xf5,0xd3,0x41,0x3e,0xe8,0xe3,0xf8,0x53,0xb2,0x74,0xef,0x36,0xfc,0x13,0xf3,0x4c,0xd0,0x81,0x4,0xb,0xfe,0x1e,0x71,0x4b,0xe4,0x2a,0xfd,0x22,0xa5,0xaa,0xdc,0xd1,0x48,0x4f,0x28,0x3,0xf7,0x4d,0x2d,0x5d,0x7,0xa7,0xcf,0x89,0x65,0xed,0xc4,0x80,0xa8,0x63,0x17,0x1d,0x3d,0x4e,0x92,0xa2,0x47,0xa6,0x6b,0x21,0x67,0x1c,0xcc,0x42,0xbc,0x25,0x7d,0x14,0x6d,0xaf,0x38,0x58,0xdb,0x9a,0x75,0x94,0x93,0xa0,0xad,0xe2,0x34,0xc9,0x8a,0x1,0xf,0x86,0xd,0xb1,0xd5,0x0,0xdf,0x26,0x18,0xfb,0xe7,0x55,0x1a,0xec,0xe6,0xce,0x1b,0xbd,0xb9,0xa1,0xd6,0xb3,0xa4,0x59,0x3f,0x5f,0x72,0x7f,0xc2,0x24,0x12,0x23,0xd2,0xd8,0xd9,0x9f,0x82,0x35,0x68,0x45,0x6a,0xbb,0xa9,0x3c,0x76,0x31,0x9b,0x84,0x5,0xb5,0xac,0xc3,0x27,0x79,0xff,0x78,0x49,0x5b,0x61,0xda,0x7c,0x1f,0x62,0x3a,0x4a,0x87,0xc6,0x5c,0xb4,0xae,0x54,0xab,0xc5,0xf4,0x5a,0x73,0x8c,0x91,0x39,0xcd,0xf0,0x44,0x96,0x8,0x5e,0x8d,0xd4,0x50,0x8e,0x2,0xb7,0x64,0x11,0x97,0x52,0xba,0x43,0x8f,0xe5,0x2f,0x20,0x66,0x51,0xc,0xa,0xe0,0x2b,0x30,0x9c,0x69,0x95,0x9,0x77,0x7e,0xfa,0xf6,0x46,0xee,0x29,0xf1,0x6e,0x6c,0xbf,0x60,0x32,0xeb,0x16,0xc8,0x19,0xb8,0x15,0xde,0xe1,0x37,0x88,0x85,0xc7,0xb6,0x9d,0x7a,0xc1,0xbe,0x2e,0xe9,0x33,0xe,0xd7,0xea,0x7b,0x90,0xf9,0xa3,0x6,0x83,0xca,0x3b,0xf2,0x40,0x98,0x99,0xdd,0x56,0x2c,0x8b,0x9e,0x10,0xb0,0xc0,0xcb,0x70,0x6f,0x55,0xa9,0x5c,0xf0,0x3a,0xbe,0xb7,0xc9,0xe9,0x2e,0x86,0x36,0x7f,0xac,0xae,0x31,0xd6,0x2b,0xf2,0xa0,0xd5,0x78,0xd9,0x8,0x48,0xf7,0x21,0x1e,0x5d,0x76,0x7,0x45,0xee,0x7e,0x1,0xba,0x17,0xce,0xf3,0x29,0x39,0x50,0xbb,0x2a,0xa,0x43,0xc6,0x63,0x58,0x80,0x32,0xfb,0xec,0x96,0x1d,0x59,0x70,0xd0,0x5e,0x4b,0xaf,0xb0,0xb,0x0,0x5b,0xf1,0xb6,0xfc,0x6c,0x75,0xc5,0x44,0x3f,0xb9,0xe7,0x3,0xa1,0x9b,0x89,0xb8,0xa2,0xdf,0xbc,0x1a,0x6,0x47,0x8a,0xfa,0x94,0x6e,0x74,0x9c,0x9a,0x34,0x5,0x6b,0xf9,0x51,0x4c,0xb3,0x56,0x84,0x30,0xd,0x14,0x4d,0x9e,0xc8,0x77,0xc2,0x4e,0x90,0x92,0x57,0xd1,0xa4,0x25,0x4f,0x83,0x7a,0x91,0xa6,0xe0,0xef,0xeb,0x20,0xca,0xcc,0xbd,0xe5,0x7c,0x82,0xf8,0x6f,0xad,0xd4,0xb5,0x5a,0x1b,0x98,0x6d,0x60,0x53,0x54,0x4a,0x9,0xf4,0x22,0xcd,0x46,0xcf,0xc1,0x1f,0xc0,0x15,0x71,0x27,0x3b,0xd8,0xe6,0x26,0x2c,0xda,0x95,0x79,0x7d,0xdb,0xe,0x64,0x73,0x16,0x61,0xb2,0x9f,0xff,0x99,0xd2,0xe4,0x2,0xbf,0x19,0x18,0x12,0xe3,0xa8,0xf5,0x42,0x5f,0x69,0x7b,0xaa,0x85,0x81,0x13,0x35,0x97,0x38,0x23,0x28,0xfe,0x2f,0xb4,0x72,0x93,0x33,0xd3,0x3c,0xf6,0xc4,0x41,0x10,0x8c,0xb1,0xde,0x3e,0xcb,0x3d,0xea,0x24,0x8b,0x1c,0x6a,0x65,0xe2,0xe8,0x8f,0x88,0x11,0xed,0x8d,0x37,0xc3,0xf,0x67,0xc7,0x9d,0x4,0x2d,0xa5,0x49,0xd7,0xa3,0x68,0x40,0x52,0x8e,0xfd,0xdd,0xab,0x66,0x87,0x62,0xc,0xdc,0xa7,0xe1,0x46,0xe0,0x58,0x25,0x70,0x0,0xfc,0xbd,0x8e,0x66,0x6e,0x94,0xff,0x91,0x60,0xce,0x4c,0x6,0xa1,0xb,0x3f,0xbe,0x96,0x8f,0x1d,0xf9,0xc5,0x43,0x73,0x42,0x5b,0x61,0x2b,0x5e,0x68,0xad,0x79,0x80,0xdf,0xb5,0x1a,0x15,0x6b,0x5c,0x30,0x36,0x11,0xda,0xb6,0x49,0x3,0xab,0xca,0xf7,0xac,0x7e,0x64,0x32,0xee,0xb7,0xb4,0x6a,0x8d,0x38,0x8,0x5a,0x2c,0xd1,0x23,0xf2,0x2f,0x82,0xdb,0xe4,0xb2,0xd,0xfd,0xbf,0xa7,0x8c,0xa6,0xa,0xaf,0x53,0x4d,0x33,0xc0,0x44,0x7c,0xcc,0x13,0xd4,0x54,0xcb,0x85,0x56,0xc8,0x1,0xa2,0x7a,0xe7,0xa3,0x16,0x6c,0xa4,0xb1,0x8a,0x2a,0xf1,0xfa,0x55,0x4a,0xfb,0x40,0x14,0x84,0x9,0xd3,0xed,0x34,0x41,0xd0,0xc3,0xaa,0x3c,0x99,0xf0,0xb9,0xea,0x76,0x3e,0xbb,0xc4,0x31,0x4b,0x24,0xde,0x71,0xc7,0x10,0x9f,0x18,0xe6,0x90,0xcf,0x6d,0x7b,0xe9,0xd2,0x4,0xc2,0xd9,0x88,0x69,0xd5,0x4e,0xc6,0xc,0xc9,0x29,0x92,0xba,0x2d,0x59,0x7,0x27,0xa8,0x74,0x7d,0x98,0x51,0x9c,0x5d,0x1b,0xf6,0x26,0x72,0xeb,0x12,0x75,0xcd,0x39,0x17,0x77,0x3d,0x67,0xf5,0x9d,0x5f,0xb3,0xfe,0xd7,0xe,0xd8,0xb0,0xf3,0x35,0x3b,0x37,0xbc,0xef,0x8b,0xe5,0x3a,0x22,0x1c,0xdd,0xc1,0x86,0x78,0x47,0x1f,0x57,0x2e,0x2,0x95,0xe1,0x62,0x4f,0xa0,0xa9,0xae,0x97,0x9a,0xf8,0x45,0x28,0x1e,0xe8,0x19,0xe3,0xe2,0xb8,0xa5,0x52,0xf,0x50,0x7f,0x93,0x81,0x20,0x6f,0xdc,0xd6,0x21,0xf4,0x83,0x87,0xec,0x9b,0x9e,0x89,0x5,0x63,0x48,0x65,0x11,0xd6,0x9,0xb9,0x93,0x40,0xe,0x91,0x96,0x6a,0xcf,0x63,0x81,0x5,0xf6,0x88,0xc8,0x77,0x21,0x1e,0x49,0x62,0x7a,0x38,0x14,0xe9,0x9f,0xcd,0x47,0xea,0x37,0xe6,0x6f,0x6,0x15,0x84,0x7c,0x35,0x5c,0xf9,0x41,0xd1,0x85,0x3e,0xf1,0x28,0x16,0xcc,0xef,0x4f,0x74,0x61,0x8f,0x90,0x3f,0x34,0xbf,0x67,0xc4,0xd,0xa9,0xd3,0x66,0x22,0x86,0x0,0x3c,0xd8,0xa4,0x9e,0x87,0xb6,0xce,0x64,0xc3,0x89,0x4a,0x53,0x7b,0xfa,0x51,0xab,0xa3,0x4b,0xb,0xa5,0x54,0x3a,0xe0,0x9d,0x25,0x83,0x78,0x39,0xc5,0xb5,0x72,0x2b,0xf7,0xa1,0xfd,0x48,0xaf,0x71,0x6e,0xc6,0x8c,0x73,0xbb,0x69,0x32,0xf,0x99,0xae,0xd0,0xdf,0x1f,0xd4,0xf3,0xf5,0x68,0xad,0x9b,0xee,0x70,0x1a,0x45,0xbc,0x65,0x8a,0xa7,0x24,0x5f,0x52,0x6b,0x6c,0xda,0x82,0xbd,0x43,0x50,0xc7,0xeb,0x92,0xff,0x20,0x4e,0x2a,0x4,0x18,0xd9,0xe7,0x36,0x75,0x1d,0xcb,0x79,0xf2,0xfe,0xf0,0x4c,0x5b,0x5e,0x29,0xa0,0x8d,0xa6,0xc0,0x13,0x19,0xaa,0xe5,0x42,0x46,0x31,0xe4,0xca,0x97,0x60,0x7d,0x44,0x56,0xba,0x95,0xdb,0xed,0x80,0x3d,0x27,0x26,0xdc,0x2d,0x8b,0x10,0xac,0x4d,0xec,0xc,0xc9,0x3,0x2c,0xbe,0xa8,0xa,0x1c,0x7,0xc1,0x17,0xd5,0x2,0xb4,0x1b,0x55,0x23,0xdd,0x5a,0x7e,0xfb,0xb3,0x2f,0xe1,0x8e,0xf4,0x1,0x58,0x30,0xa2,0xf8,0x12,0x3b,0x76,0x9a,0xb0,0xd7,0x2e,0xb7,0xb2,0xd2,0xfc,0x8,0x59,0x94,0x5d,0xb8,0xe3,0x33,0xde,0x98,0x9c,0xe8,0x7f,0x57,0xb1,0x6d,0xe2,0xc2,0xa6,0x4,0x22,0xb0,0xcf,0x19,0x12,0x9,0xa2,0x43,0x85,0x1e,0xc7,0xd,0xe2,0x2,0xbd,0x21,0x70,0xf5,0xfa,0xf,0xef,0x80,0xba,0x15,0xdb,0xc,0xd3,0x54,0x5b,0x2d,0x20,0xb9,0xbe,0xd9,0xf2,0x6,0xbc,0xdc,0xac,0xf6,0x56,0x3e,0x78,0x94,0x1c,0x35,0x71,0x59,0x92,0xe6,0xec,0xcc,0xbf,0x63,0x53,0xb6,0x57,0x9a,0xd0,0x96,0xed,0x3d,0xb3,0x4d,0xd4,0x8c,0xe5,0x9c,0x5e,0xc9,0xa9,0x2a,0x6b,0x84,0x65,0x62,0x51,0x5c,0x13,0xc5,0x38,0x7b,0xf0,0xfe,0x77,0xfc,0x40,0x24,0xf1,0x2e,0xd7,0xe9,0xa,0x16,0xa4,0xeb,0x1d,0x17,0x3f,0xea,0x4c,0x48,0x50,0x27,0x42,0x55,0xa8,0xce,0xae,0x83,0x8e,0x33,0xd5,0xe3,0xd2,0x23,0x29,0x28,0x6e,0x73,0xc4,0x99,0xb4,0x9b,0x4a,0x58,0xcd,0x87,0xc0,0x6a,0x75,0xf4,0x44,0x5d,0x32,0xd6,0x88,0xe,0x89,0xb8,0xaa,0x90,0x2b,0x8d,0xee,0x93,0xcb,0xbb,0x76,0x37,0xad,0x45,0x5f,0xa5,0x5a,0x34,0x5,0xab,0x82,0x7d,0x60,0xc8,0x3c,0x1,0xb5,0x67,0xf9,0xaf,0x7c,0x25,0xa1,0x7f,0xf3,0x46,0x95,0xe0,0x66,0xa3,0x4b,0xb2,0x7e,0x14,0xde,0xd1,0x97,0xa0,0xfd,0xfb,0x11,0xda,0xc1,0x6d,0x98,0x64,0xf8,0x86,0x8f,0xb,0x7,0xb7,0x1f,0xd8,0x0,0x9f,0x9d,0x4e,0x91,0xc3,0x1a,0xe7,0x39,0xe8,0x49,0xe4,0x2f,0x10,0xc6,0x79,0x74,0x36,0x47,0x6c,0x8b,0x30,0x4f,0xdf,0x18,0xc2,0xff,0x26,0x1b,0x8a,0x61,0x8,0x52,0xf7,0x72,0x3b,0xca,0x3,0xb1,0x69,0x68,0x2c,0xa7,0xdd,0x7a,0x6f,0xe1,0x41,0x31,0x3a,0x81,0x9e,0xbc,0x40,0xb5,0x19,0xd3,0x57,0x5e,0x20,0x0,0xc7,0x6f,0xdf,0x96,0x45,0x47,0xd8,0x3f,0xc2,0x1b,0x49,0x3c,0x91,0x30,0xe1,0xa1,0x1e,0xc8,0xf7,0xb4,0x9f,0xee,0xac,0x7,0x97,0xe8,0x53,0xfe,0x27,0x1a,0xc0,0xd0,0xb9,0x52,0xc3,0xe3,0xaa,0x2f,0x8a,0xb1,0x69,0xdb,0x12,0x5,0x7f,0xf4,0xb0,0x99,0x39,0xb7,0xa2,0x46,0x59,0xe2,0xe9,0xb2,0x18,0x5f,0x15,0x85,0x9c,0x2c,0xad,0xd6,0x50,0xe,0xea,0x48,0x72,0x60,0x51,0x4b,0x36,0x55,0xf3,0xef,0xae,0x63,0x13,0x7d,0x87,0x9d,0x75,0x73,0xdd,0xec,0x82,0x10,0xb8,0xa5,0x5a,0xbf,0x6d,0xd9,0xe4,0xfd,0xa4,0x77,0x21,0x9e,0x2b,0xa7,0x79,0x7b,0xbe,0x38,0x4d,0xcc,0xa6,0x6a,0x93,0x78,0x4f,0x9,0x6,0x2,0xc9,0x23,0x25,0x54,0xc,0x95,0x6b,0x11,0x86,0x44,0x3d,0x5c,0xb3,0xf2,0x71,0x84,0x89,0xba,0xbd,0xa3,0xe0,0x1d,0xcb,0x24,0xaf,0x26,0x28,0xf6,0x29,0xfc,0x98,0xce,0xd2,0x31,0xf,0xcf,0xc5,0x33,0x7c,0x90,0x94,0x32,0xe7,0x8d,0x9a,0xff,0x88,0x5b,0x76,0x16,0x70,0x3b,0xd,0xeb,0x56,0xf0,0xf1,0xfb,0xa,0x41,0x1c,0xab,0xb6,0x80,0x92,0x43,0x6c,0x68,0xfa,0xdc,0x7e,0xd1,0xca,0xc1,0x17,0xc6,0x5d,0x9b,0x7a,0xda,0x3a,0xd5,0x1f,0x2d,0xa8,0xf9,0x65,0x58,0x37,0xd7,0x22,0xd4,0x3,0xcd,0x62,0xf5,0x83,0x8c,0xb,0x1,0x66,0x61,0xf8,0x4,0x64,0xde,0x2a,0xe6,0x8e,0x2e,0x74,0xed,0xc4,0x4c,0xa0,0x3e,0x4a,0x81,0xa9,0xbb,0x67,0x14,0x34,0x42,0x8f,0x6e,0x8b,0xe5,0x35,0x4e,0x8,0x62,0xc4,0x7c,0x1,0x54,0x24,0xd8,0x99,0xaa,0x42,0x4a,0xb0,0xdb,0xb5,0x44,0xea,0x68,0x22,0x85,0x2f,0x1b,0x9a,0xb2,0xab,0x39,0xdd,0xe1,0x67,0x57,0x66,0x7f,0x45,0xf,0x7a,0x4c,0x89,0x5d,0xa4,0xfb,0x91,0x3e,0x31,0x4f,0x78,0x14,0x12,0x35,0xfe,0x92,0x6d,0x27,0x8f,0xee,0xd3,0x88,0x5a,0x40,0x16,0xca,0x93,0x90,0x4e,0xa9,0x1c,0x2c,0x7e,0x8,0xf5,0x7,0xd6,0xb,0xa6,0xff,0xc0,0x96,0x29,0xd9,0x9b,0x83,0xa8,0x82,0x2e,0x8b,0x77,0x69,0x17,0xe4,0x60,0x58,0xe8,0x37,0xf0,0x70,0xef,0xa1,0x72,0xec,0x25,0x86,0x5e,0xc3,0x87,0x32,0x48,0x80,0x95,0xae,0xe,0xd5,0xde,0x71,0x6e,0xdf,0x64,0x30,0xa0,0x2d,0xf7,0xc9,0x10,0x65,0xf4,0xe7,0x8e,0x18,0xbd,0xd4,0x9d,0xce,0x52,0x1a,0x9f,0xe0,0x15,0x6f,0x0,0xfa,0x55,0xe3,0x34,0xbb,0x3c,0xc2,0xb4,0xeb,0x49,0x5f,0xcd,0xf6,0x20,0xe6,0xfd,0xac,0x4d,0xf1,0x6a,0xe2,0x28,0xed,0xd,0xb6,0x9e,0x9,0x7d,0x23,0x3,0x8c,0x50,0x59,0xbc,0x75,0xb8,0x79,0x3f,0xd2,0x2,0x56,0xcf,0x36,0x51,0xe9,0x1d,0x33,0x53,0x19,0x43,0xd1,0xb9,0x7b,0x97,0xda,0xf3,0x2a,0xfc,0x94,0xd7,0x11,0x1f,0x13,0x98,0xcb,0xaf,0xc1,0x1e,0x6,0x38,0xf9,0xe5,0xa2,0x5c,0x63,0x3b,0x73,0xa,0x26,0xb1,0xc5,0x46,0x6b,0x84,0x8d,0x8a,0xb3,0xbe,0xdc,0x61,0xc,0x3a,0xcc,0x3d,0xc7,0xc6,0x9c,0x81,0x76,0x2b,0x74,0x5b,0xb7,0xa5,0x4,0x4b,0xf8,0xf2,0x5,0xd0,0xa7,0xa3,0xc8,0xbf,0xba,0xad,0x21,0x47,0x6c,0x41,0x1c,0xdb,0x4,0xb4,0x9e,0x4d,0x3,0x9c,0x9b,0x67,0xc2,0x6e,0x8c,0x8,0xfb,0x85,0xc5,0x7a,0x2c,0x13,0x44,0x6f,0x77,0x35,0x19,0xe4,0x92,0xc0,0x4a,0xe7,0x3a,0xeb,0x62,0xb,0x18,0x89,0x71,0x38,0x51,0xf4,0x4c,0xdc,0x88,0x33,0xfc,0x25,0x1b,0xc1,0xe2,0x42,0x79,0x6c,0x82,0x9d,0x32,0x39,0xb2,0x6a,0xc9,0x0,0xa4,0xde,0x6b,0x2f,0x8b,0xd,0x31,0xd5,0xa9,0x93,0x8a,0xbb,0xc3,0x69,0xce,0x84,0x47,0x5e,0x76,0xf7,0x5c,0xa6,0xae,0x46,0x6,0xa8,0x59,0x37,0xed,0x90,0x28,0x8e,0x75,0x34,0xc8,0xb8,0x7f,0x26,0xfa,0xac,0xf0,0x45,0xa2,0x7c,0x63,0xcb,0x81,0x7e,0xb6,0x64,0x3f,0x2,0x94,0xa3,0xdd,0xd2,0x12,0xd9,0xfe,0xf8,0x65,0xa0,0x96,0xe3,0x7d,0x17,0x48,0xb1,0x68,0x87,0xaa,0x29,0x52,0x5f,0x66,0x61,0xd7,0x8f,0xb0,0x4e,0x5d,0xca,0xe6,0x9f,0xf2,0x2d,0x43,0x27,0x9,0x15,0xd4,0xea,0x3b,0x78,0x10,0xc6,0x74,0xff,0xf3,0xfd,0x41,0x56,0x53,0x24,0xad,0x80,0xab,0xcd,0x1e,0x14,0xa7,0xe8,0x4f,0x4b,0x3c,0xe9,0xc7,0x9a,0x6d,0x70,0x49,0x5b,0xb7,0x98,0xd6,0xe0,0x8d,0x30,0x2a,0x2b,0xd1,0x20,0x86,0x1d,0xa1,0x40,0xe1,0x1,0xc4,0xe,0x21,0xb3,0xa5,0x7,0x11,0xa,0xcc,0x1a,0xd8,0xf,0xb9,0x16,0x58,0x2e,0xd0,0x57,0x73,0xf6,0xbe,0x22,0xec,0x83,0xf9,0xc,0x55,0x3d,0xaf,0xf5,0x1f,0x36,0x7b,0x97,0xbd,0xda,0x23,0xba,0xbf,0xdf,0xf1,0x5,0x54,0x99,0x50,0xb5,0xee,0x3e,0xd3,0x95,0x91,0xe5,0x72,0x5a,0xbc,0x60,0xef,0xcf,0x7a,0xd8,0xfe,0x6c,0x13,0xc5,0xce,0xd5,0x7e,0x9f,0x59,0xc2,0x1b,0xd1,0x3e,0xde,0x61,0xfd,0xac,0x29,0x26,0xd3,0x33,0x5c,0x66,0xc9,0x7,0xd0,0xf,0x88,0x87,0xf1,0xfc,0x65,0x62,0x5,0x2e,0xda,0x60,0x0,0x70,0x2a,0x8a,0xe2,0xa4,0x48,0xc0,0xe9,0xad,0x85,0x4e,0x3a,0x30,0x10,0x63,0xbf,0x8f,0x6a,0x8b,0x46,0xc,0x4a,0x31,0xe1,0x6f,0x91,0x8,0x50,0x39,0x40,0x82,0x15,0x75,0xf6,0xb7,0x58,0xb9,0xbe,0x8d,0x80,0xcf,0x19,0xe4,0xa7,0x2c,0x22,0xab,0x20,0x9c,0xf8,0x2d,0xf2,0xb,0x35,0xd6,0xca,0x78,0x37,0xc1,0xcb,0xe3,0x36,0x90,0x94,0x8c,0xfb,0x9e,0x89,0x74,0x12,0x72,0x5f,0x52,0xef,0x9,0x3f,0xe,0xff,0xf5,0xf4,0xb2,0xaf,0x18,0x45,0x68,0x47,0x96,0x84,0x11,0x5b,0x1c,0xb6,0xa9,0x28,0x98,0x81,0xee,0xa,0x54,0xd2,0x55,0x64,0x76,0x4c,0xf7,0x51,0x32,0x4f,0x17,0x67,0xaa,0xeb,0x71,0x99,0x83,0x79,0x86,0xe8,0xd9,0x77,0x5e,0xa1,0xbc,0x14,0xe0,0xdd,0x69,0xbb,0x25,0x73,0xa0,0xf9,0x7d,0xa3,0x2f,0x9a,0x49,0x3c,0xba,0x7f,0x97,0x6e,0xa2,0xc8,0x2,0xd,0x4b,0x7c,0x21,0x27,0xcd,0x6,0x1d,0xb1,0x44,0xb8,0x24,0x5a,0x53,0xd7,0xdb,0x6b,0xc3,0x4,0xdc,0x43,0x41,0x92,0x4d,0x1f,0xc6,0x3b,0xe5,0x34,0x95,0x38,0xf3,0xcc,0x1a,0xa5,0xa8,0xea,0x9b,0xb0,0x57,0xec,0x93,0x3,0xc4,0x1e,0x23,0xfa,0xc7,0x56,0xbd,0xd4,0x8e,0x2b,0xae,0xe7,0x16,0xdf,0x6d,0xb5,0xb4,0xf0,0x7b,0x1,0xa6,0xb3,0x3d,0x9d,0xed,0xe6,0x5d,0x42,0x15,0xe9,0x1c,0xb0,0x7a,0xfe,0xf7,0x89,0xa9,0x6e,0xc6,0x76,0x3f,0xec,0xee,0x71,0x96,0x6b,0xb2,0xe0,0x95,0x38,0x99,0x48,0x8,0xb7,0x61,0x5e,0x1d,0x36,0x47,0x5,0xae,0x3e,0x41,0xfa,0x57,0x8e,0xb3,0x69,0x79,0x10,0xfb,0x6a,0x4a,0x3,0x86,0x23,0x18,0xc0,0x72,0xbb,0xac,0xd6,0x5d,0x19,0x30,0x90,0x1e,0xb,0xef,0xf0,0x4b,0x40,0x1b,0xb1,0xf6,0xbc,0x2c,0x35,0x85,0x4,0x7f,0xf9,0xa7,0x43,0xe1,0xdb,0xc9,0xf8,0xe2,0x9f,0xfc,0x5a,0x46,0x7,0xca,0xba,0xd4,0x2e,0x34,0xdc,0xda,0x74,0x45,0x2b,0xb9,0x11,0xc,0xf3,0x16,0xc4,0x70,0x4d,0x54,0xd,0xde,0x88,0x37,0x82,0xe,0xd0,0xd2,0x17,0x91,0xe4,0x65,0xf,0xc3,0x3a,0xd1,0xe6,0xa0,0xaf,0xab,0x60,0x8a,0x8c,0xfd,0xa5,0x3c,0xc2,0xb8,0x2f,0xed,0x94,0xf5,0x1a,0x5b,0xd8,0x2d,0x20,0x13,0x14,0xa,0x49,0xb4,0x62,0x8d,0x6,0x8f,0x81,0x5f,0x80,0x55,0x31,0x67,0x7b,0x98,0xa6,0x66,0x6c,0x9a,0xd5,0x39,0x3d,0x9b,0x4e,0x24,0x33,0x56,0x21,0xf2,0xdf,0xbf,0xd9,0x92,0xa4,0x42,0xff,0x59,0x58,0x52,0xa3,0xe8,0xb5,0x2,0x1f,0x29,0x3b,0xea,0xc5,0xc1,0x53,0x75,0xd7,0x78,0x63,0x68,0xbe,0x6f,0xf4,0x32,0xd3,0x73,0x93,0x7c,0xb6,0x84,0x1,0x50,0xcc,0xf1,0x9e,0x7e,0x8b,0x7d,0xaa,0x64,0xcb,0x5c,0x2a,0x25,0xa2,0xa8,0xcf,0xc8,0x51,0xad,0xcd,0x77,0x83,0x4f,0x27,0x87,0xdd,0x44,0x6d,0xe5,0x9,0x97,0xe3,0x28,0x0,0x12,0xce,0xbd,0x9d,0xeb,0x26,0xc7,0x22,0x4c,0x9c,0xe7,0xa1,0xe0,0x46,0xfe,0x83,0xd6,0xa6,0x5a,0x1b,0x28,0xc0,0xc8,0x32,0x59,0x37,0xc6,0x68,0xea,0xa0,0x7,0xad,0x99,0x18,0x30,0x29,0xbb,0x5f,0x63,0xe5,0xd5,0xe4,0xfd,0xc7,0x8d,0xf8,0xce,0xb,0xdf,0x26,0x79,0x13,0xbc,0xb3,0xcd,0xfa,0x96,0x90,0xb7,0x7c,0x10,0xef,0xa5,0xd,0x6c,0x51,0xa,0xd8,0xc2,0x94,0x48,0x11,0x12,0xcc,0x2b,0x9e,0xae,0xfc,0x8a,0x77,0x85,0x54,0x89,0x24,0x7d,0x42,0x14,0xab,0x5b,0x19,0x1,0x2a,0x0,0xac,0x9,0xf5,0xeb,0x95,0x66,0xe2,0xda,0x6a,0xb5,0x72,0xf2,0x6d,0x23,0xf0,0x6e,0xa7,0x4,0xdc,0x41,0x5,0xb0,0xca,0x2,0x17,0x2c,0x8c,0x57,0x5c,0xf3,0xec,0x5d,0xe6,0xb2,0x22,0xaf,0x75,0x4b,0x92,0xe7,0x76,0x65,0xc,0x9a,0x3f,0x56,0x1f,0x4c,0xd0,0x98,0x1d,0x62,0x97,0xed,0x82,0x78,0xd7,0x61,0xb6,0x39,0xbe,0x40,0x36,0x69,0xcb,0xdd,0x4f,0x74,0xa2,0x64,0x7f,0x2e,0xcf,0x73,0xe8,0x60,0xaa,0x6f,0x8f,0x34,0x1c,0x8b,0xff,0xa1,0x81,0xe,0xd2,0xdb,0x3e,0xf7,0x3a,0xfb,0xbd,0x50,0x80,0xd4,0x4d,0xb4,0xd3,0x6b,0x9f,0xb1,0xd1,0x9b,0xc1,0x53,0x3b,0xf9,0x15,0x58,0x71,0xa8,0x7e,0x16,0x55,0x93,0x9d,0x91,0x1a,0x49,0x2d,0x43,0x9c,0x84,0xba,0x7b,0x67,0x20,0xde,0xe1,0xb9,0xf1,0x88,0xa4,0x33,0x47,0xc4,0xe9,0x6,0xf,0x8,0x31,0x3c,0x5e,0xe3,0x8e,0xb8,0x4e,0xbf,0x45,0x44,0x1e,0x3,0xf4,0xa9,0xf6,0xd9,0x35,0x27,0x86,0xc9,0x7a,0x70,0x87,0x52,0x25,0x21,0x4a,0x3d,0x38,0x2f,0xa3,0xc5,0xee,0xc3,0x7f,0xb8,0x67,0xd7,0xfd,0x2e,0x60,0xff,0xf8,0x4,0xa1,0xd,0xef,0x6b,0x98,0xe6,0xa6,0x19,0x4f,0x70,0x27,0xc,0x14,0x56,0x7a,0x87,0xf1,0xa3,0x29,0x84,0x59,0x88,0x1,0x68,0x7b,0xea,0x12,0x5b,0x32,0x97,0x2f,0xbf,0xeb,0x50,0x9f,0x46,0x78,0xa2,0x81,0x21,0x1a,0xf,0xe1,0xfe,0x51,0x5a,0xd1,0x9,0xaa,0x63,0xc7,0xbd,0x8,0x4c,0xe8,0x6e,0x52,0xb6,0xca,0xf0,0xe9,0xd8,0xa0,0xa,0xad,0xe7,0x24,0x3d,0x15,0x94,0x3f,0xc5,0xcd,0x25,0x65,0xcb,0x3a,0x54,0x8e,0xf3,0x4b,0xed,0x16,0x57,0xab,0xdb,0x1c,0x45,0x99,0xcf,0x93,0x26,0xc1,0x1f,0x0,0xa8,0xe2,0x1d,0xd5,0x7,0x5c,0x61,0xf7,0xc0,0xbe,0xb1,0x71,0xba,0x9d,0x9b,0x6,0xc3,0xf5,0x80,0x1e,0x74,0x2b,0xd2,0xb,0xe4,0xc9,0x4a,0x31,0x3c,0x5,0x2,0xb4,0xec,0xd3,0x2d,0x3e,0xa9,0x85,0xfc,0x91,0x4e,0x20,0x44,0x6a,0x76,0xb7,0x89,0x58,0x1b,0x73,0xa5,0x17,0x9c,0x90,0x9e,0x22,0x35,0x30,0x47,0xce,0xe3,0xc8,0xae,0x7d,0x77,0xc4,0x8b,0x2c,0x28,0x5f,0x8a,0xa4,0xf9,0xe,0x13,0x2a,0x38,0xd4,0xfb,0xb5,0x83,0xee,0x53,0x49,0x48,0xb2,0x43,0xe5,0x7e,0xc2,0x23,0x82,0x62,0xa7,0x6d,0x42,0xd0,0xc6,0x64,0x72,0x69,0xaf,0x79,0xbb,0x6c,0xda,0x75,0x3b,0x4d,0xb3,0x34,0x10,0x95,0xdd,0x41,0x8f,0xe0,0x9a,0x6f,0x36,0x5e,0xcc,0x96,0x7c,0x55,0x18,0xf4,0xde,0xb9,0x40,0xd9,0xdc,0xbc,0x92,0x66,0x37,0xfa,0x33,0xd6,0x8d,0x5d,0xb0,0xf6,0xf2,0x86,0x11,0x39,0xdf,0x3,0x8c,0xac,0x24,0x86,0xa0,0x32,0x4d,0x9b,0x90,0x8b,0x20,0xc1,0x7,0x9c,0x45,0x8f,0x60,0x80,0x3f,0xa3,0xf2,0x77,0x78,0x8d,0x6d,0x2,0x38,0x97,0x59,0x8e,0x51,0xd6,0xd9,0xaf,0xa2,0x3b,0x3c,0x5b,0x70,0x84,0x3e,0x5e,0x2e,0x74,0xd4,0xbc,0xfa,0x16,0x9e,0xb7,0xf3,0xdb,0x10,0x64,0x6e,0x4e,0x3d,0xe1,0xd1,0x34,0xd5,0x18,0x52,0x14,0x6f,0xbf,0x31,0xcf,0x56,0xe,0x67,0x1e,0xdc,0x4b,0x2b,0xa8,0xe9,0x6,0xe7,0xe0,0xd3,0xde,0x91,0x47,0xba,0xf9,0x72,0x7c,0xf5,0x7e,0xc2,0xa6,0x73,0xac,0x55,0x6b,0x88,0x94,0x26,0x69,0x9f,0x95,0xbd,0x68,0xce,0xca,0xd2,0xa5,0xc0,0xd7,0x2a,0x4c,0x2c,0x1,0xc,0xb1,0x57,0x61,0x50,0xa1,0xab,0xaa,0xec,0xf1,0x46,0x1b,0x36,0x19,0xc8,0xda,0x4f,0x5,0x42,0xe8,0xf7,0x76,0xc6,0xdf,0xb0,0x54,0xa,0x8c,0xb,0x3a,0x28,0x12,0xa9,0xf,0x6c,0x11,0x49,0x39,0xf4,0xb5,0x2f,0xc7,0xdd,0x27,0xd8,0xb6,0x87,0x29,0x0,0xff,0xe2,0x4a,0xbe,0x83,0x37,0xe5,0x7b,0x2d,0xfe,0xa7,0x23,0xfd,0x71,0xc4,0x17,0x62,0xe4,0x21,0xc9,0x30,0xfc,0x96,0x5c,0x53,0x15,0x22,0x7f,0x79,0x93,0x58,0x43,0xef,0x1a,0xe6,0x7a,0x4,0xd,0x89,0x85,0x35,0x9d,0x5a,0x82,0x1d,0x1f,0xcc,0x13,0x41,0x98,0x65,0xbb,0x6a,0xcb,0x66,0xad,0x92,0x44,0xfb,0xf6,0xb4,0xc5,0xee,0x9,0xb2,0xcd,0x5d,0x9a,0x40,0x7d,0xa4,0x99,0x8,0xe3,0x8a,0xd0,0x75,0xf0,0xb9,0x48,0x81,0x33,0xeb,0xea,0xae,0x25,0x5f,0xf8,0xed,0x63,0xc3,0xb3,0xb8,0x3,0x1c,0x4a,0xb6,0x43,0xef,0x25,0xa1,0xa8,0xd6,0xf6,0x31,0x99,0x29,0x60,0xb3,0xb1,0x2e,0xc9,0x34,0xed,0xbf,0xca,0x67,0xc6,0x17,0x57,0xe8,0x3e,0x1,0x42,0x69,0x18,0x5a,0xf1,0x61,0x1e,0xa5,0x8,0xd1,0xec,0x36,0x26,0x4f,0xa4,0x35,0x15,0x5c,0xd9,0x7c,0x47,0x9f,0x2d,0xe4,0xf3,0x89,0x2,0x46,0x6f,0xcf,0x41,0x54,0xb0,0xaf,0x14,0x1f,0x44,0xee,0xa9,0xe3,0x73,0x6a,0xda,0x5b,0x20,0xa6,0xf8,0x1c,0xbe,0x84,0x96,0xa7,0xbd,0xc0,0xa3,0x5,0x19,0x58,0x95,0xe5,0x8b,0x71,0x6b,0x83,0x85,0x2b,0x1a,0x74,0xe6,0x4e,0x53,0xac,0x49,0x9b,0x2f,0x12,0xb,0x52,0x81,0xd7,0x68,0xdd,0x51,0x8f,0x8d,0x48,0xce,0xbb,0x3a,0x50,0x9c,0x65,0x8e,0xb9,0xff,0xf0,0xf4,0x3f,0xd5,0xd3,0xa2,0xfa,0x63,0x9d,0xe7,0x70,0xb2,0xcb,0xaa,0x45,0x4,0x87,0x72,0x7f,0x4c,0x4b,0x55,0x16,0xeb,0x3d,0xd2,0x59,0xd0,0xde,0x0,0xdf,0xa,0x6e,0x38,0x24,0xc7,0xf9,0x39,0x33,0xc5,0x8a,0x66,0x62,0xc4,0x11,0x7b,0x6c,0x9,0x7e,0xad,0x80,0xe0,0x86,0xcd,0xfb,0x1d,0xa0,0x6,0x7,0xd,0xfc,0xb7,0xea,0x5d,0x40,0x76,0x64,0xb5,0x9a,0x9e,0xc,0x2a,0x88,0x27,0x3c,0x37,0xe1,0x30,0xab,0x6d,0x8c,0x2c,0xcc,0x23,0xe9,0xdb,0x5e,0xf,0x93,0xae,0xc1,0x21,0xd4,0x22,0xf5,0x3b,0x94,0x3,0x75,0x7a,0xfd,0xf7,0x90,0x97,0xe,0xf2,0x92,0x28,0xdc,0x10,0x78,0xd8,0x82,0x1b,0x32,0xba,0x56,0xc8,0xbc,0x77,0x5f,0x4d,0x91,0xe2,0xc2,0xb4,0x79,0x98,0x7d,0x13,0xc3,0xb8,0xfe,0x5f,0xf9,0x41,0x3c,0x69,0x19,0xe5,0xa4,0x97,0x7f,0x77,0x8d,0xe6,0x88,0x79,0xd7,0x55,0x1f,0xb8,0x12,0x26,0xa7,0x8f,0x96,0x4,0xe0,0xdc,0x5a,0x6a,0x5b,0x42,0x78,0x32,0x47,0x71,0xb4,0x60,0x99,0xc6,0xac,0x3,0xc,0x72,0x45,0x29,0x2f,0x8,0xc3,0xaf,0x50,0x1a,0xb2,0xd3,0xee,0xb5,0x67,0x7d,0x2b,0xf7,0xae,0xad,0x73,0x94,0x21,0x11,0x43,0x35,0xc8,0x3a,0xeb,0x36,0x9b,0xc2,0xfd,0xab,0x14,0xe4,0xa6,0xbe,0x95,0xbf,0x13,0xb6,0x4a,0x54,0x2a,0xd9,0x5d,0x65,0xd5,0xa,0xcd,0x4d,0xd2,0x9c,0x4f,0xd1,0x18,0xbb,0x63,0xfe,0xba,0xf,0x75,0xbd,0xa8,0x93,0x33,0xe8,0xe3,0x4c,0x53,0xe2,0x59,0xd,0x9d,0x10,0xca,0xf4,0x2d,0x58,0xc9,0xda,0xb3,0x25,0x80,0xe9,0xa0,0xf3,0x6f,0x27,0xa2,0xdd,0x28,0x52,0x3d,0xc7,0x68,0xde,0x9,0x86,0x1,0xff,0x89,0xd6,0x74,0x62,0xf0,0xcb,0x1d,0xdb,0xc0,0x91,0x70,0xcc,0x57,0xdf,0x15,0xd0,0x30,0x8b,0xa3,0x34,0x40,0x1e,0x3e,0xb1,0x6d,0x64,0x81,0x48,0x85,0x44,0x2,0xef,0x3f,0x6b,0xf2,0xb,0x6c,0xd4,0x20,0xe,0x6e,0x24,0x7e,0xec,0x84,0x46,0xaa,0xe7,0xce,0x17,0xc1,0xa9,0xea,0x2c,0x22,0x2e,0xa5,0xf6,0x92,0xfc,0x23,0x3b,0x5,0xc4,0xd8,0x9f,0x61,0x5e,0x6,0x4e,0x37,0x1b,0x8c,0xf8,0x7b,0x56,0xb9,0xb0,0xb7,0x8e,0x83,0xe1,0x5c,0x31,0x7,0xf1,0x0,0xfa,0xfb,0xa1,0xbc,0x4b,0x16,0x49,0x66,0x8a,0x98,0x39,0x76,0xc5,0xcf,0x38,0xed,0x9a,0x9e,0xf5,0x82,0x87,0x90,0x1c,0x7a,0x51,0x7c,0x1,0xc6,0x19,0xa9,0x83,0x50,0x1e,0x81,0x86,0x7a,0xdf,0x73,0x91,0x15,0xe6,0x98,0xd8,0x67,0x31,0xe,0x59,0x72,0x6a,0x28,0x4,0xf9,0x8f,0xdd,0x57,0xfa,0x27,0xf6,0x7f,0x16,0x5,0x94,0x6c,0x25,0x4c,0xe9,0x51,0xc1,0x95,0x2e,0xe1,0x38,0x6,0xdc,0xff,0x5f,0x64,0x71,0x9f,0x80,0x2f,0x24,0xaf,0x77,0xd4,0x1d,0xb9,0xc3,0x76,0x32,0x96,0x10,0x2c,0xc8,0xb4,0x8e,0x97,0xa6,0xde,0x74,0xd3,0x99,0x5a,0x43,0x6b,0xea,0x41,0xbb,0xb3,0x5b,0x1b,0xb5,0x44,0x2a,0xf0,0x8d,0x35,0x93,0x68,0x29,0xd5,0xa5,0x62,0x3b,0xe7,0xb1,0xed,0x58,0xbf,0x61,0x7e,0xd6,0x9c,0x63,0xab,0x79,0x22,0x1f,0x89,0xbe,0xc0,0xcf,0xf,0xc4,0xe3,0xe5,0x78,0xbd,0x8b,0xfe,0x60,0xa,0x55,0xac,0x75,0x9a,0xb7,0x34,0x4f,0x42,0x7b,0x7c,0xca,0x92,0xad,0x53,0x40,0xd7,0xfb,0x82,0xef,0x30,0x5e,0x3a,0x14,0x8,0xc9,0xf7,0x26,0x65,0xd,0xdb,0x69,0xe2,0xee,0xe0,0x5c,0x4b,0x4e,0x39,0xb0,0x9d,0xb6,0xd0,0x3,0x9,0xba,0xf5,0x52,0x56,0x21,0xf4,0xda,0x87,0x70,0x6d,0x54,0x46,0xaa,0x85,0xcb,0xfd,0x90,0x2d,0x37,0x36,0xcc,0x3d,0x9b,0x0,0xbc,0x5d,0xfc,0x1c,0xd9,0x13,0x3c,0xae,0xb8,0x1a,0xc,0x17,0xd1,0x7,0xc5,0x12,0xa4,0xb,0x45,0x33,0xcd,0x4a,0x6e,0xeb,0xa3,0x3f,0xf1,0x9e,0xe4,0x11,0x48,0x20,0xb2,0xe8,0x2,0x2b,0x66,0x8a,0xa0,0xc7,0x3e,0xa7,0xa2,0xc2,0xec,0x18,0x49,0x84,0x4d,0xa8,0xf3,0x23,0xce,0x88,0x8c,0xf8,0x6f,0x47,0xa1,0x7d,0xf2,0xd2,0x7,0xa5,0x83,0x11,0x6e,0xb8,0xb3,0xa8,0x3,0xe2,0x24,0xbf,0x66,0xac,0x43,0xa3,0x1c,0x80,0xd1,0x54,0x5b,0xae,0x4e,0x21,0x1b,0xb4,0x7a,0xad,0x72,0xf5,0xfa,0x8c,0x81,0x18,0x1f,0x78,0x53,0xa7,0x1d,0x7d,0xd,0x57,0xf7,0x9f,0xd9,0x35,0xbd,0x94,0xd0,0xf8,0x33,0x47,0x4d,0x6d,0x1e,0xc2,0xf2,0x17,0xf6,0x3b,0x71,0x37,0x4c,0x9c,0x12,0xec,0x75,0x2d,0x44,0x3d,0xff,0x68,0x8,0x8b,0xca,0x25,0xc4,0xc3,0xf0,0xfd,0xb2,0x64,0x99,0xda,0x51,0x5f,0xd6,0x5d,0xe1,0x85,0x50,0x8f,0x76,0x48,0xab,0xb7,0x5,0x4a,0xbc,0xb6,0x9e,0x4b,0xed,0xe9,0xf1,0x86,0xe3,0xf4,0x9,0x6f,0xf,0x22,0x2f,0x92,0x74,0x42,0x73,0x82,0x88,0x89,0xcf,0xd2,0x65,0x38,0x15,0x3a,0xeb,0xf9,0x6c,0x26,0x61,0xcb,0xd4,0x55,0xe5,0xfc,0x93,0x77,0x29,0xaf,0x28,0x19,0xb,0x31,0x8a,0x2c,0x4f,0x32,0x6a,0x1a,0xd7,0x96,0xc,0xe4,0xfe,0x4,0xfb,0x95,0xa4,0xa,0x23,0xdc,0xc1,0x69,0x9d,0xa0,0x14,0xc6,0x58,0xe,0xdd,0x84,0x0,0xde,0x52,0xe7,0x34,0x41,0xc7,0x2,0xea,0x13,0xdf,0xb5,0x7f,0x70,0x36,0x1,0x5c,0x5a,0xb0,0x7b,0x60,0xcc,0x39,0xc5,0x59,0x27,0x2e,0xaa,0xa6,0x16,0xbe,0x79,0xa1,0x3e,0x3c,0xef,0x30,0x62,0xbb,0x46,0x98,0x49,0xe8,0x45,0x8e,0xb1,0x67,0xd8,0xd5,0x97,0xe6,0xcd,0x2a,0x91,0xee,0x7e,0xb9,0x63,0x5e,0x87,0xba,0x2b,0xc0,0xa9,0xf3,0x56,0xd3,0x9a,0x6b,0xa2,0x10,0xc8,0xc9,0x8d,0x6,0x7c,0xdb,0xce,0x40,0xe0,0x90,0x9b,0x20,0x3f,0xf9,0x5,0xf0,0x5c,0x96,0x12,0x1b,0x65,0x45,0x82,0x2a,0x9a,0xd3,0x0,0x2,0x9d,0x7a,0x87,0x5e,0xc,0x79,0xd4,0x75,0xa4,0xe4,0x5b,0x8d,0xb2,0xf1,0xda,0xab,0xe9,0x42,0xd2,0xad,0x16,0xbb,0x62,0x5f,0x85,0x95,0xfc,0x17,0x86,0xa6,0xef,0x6a,0xcf,0xf4,0x2c,0x9e,0x57,0x40,0x3a,0xb1,0xf5,0xdc,0x7c,0xf2,0xe7,0x3,0x1c,0xa7,0xac,0xf7,0x5d,0x1a,0x50,0xc0,0xd9,0x69,0xe8,0x93,0x15,0x4b,0xaf,0xd,0x37,0x25,0x14,0xe,0x73,0x10,0xb6,0xaa,0xeb,0x26,0x56,0x38,0xc2,0xd8,0x30,0x36,0x98,0xa9,0xc7,0x55,0xfd,0xe0,0x1f,0xfa,0x28,0x9c,0xa1,0xb8,0xe1,0x32,0x64,0xdb,0x6e,0xe2,0x3c,0x3e,0xfb,0x7d,0x8,0x89,0xe3,0x2f,0xd6,0x3d,0xa,0x4c,0x43,0x47,0x8c,0x66,0x60,0x11,0x49,0xd0,0x2e,0x54,0xc3,0x1,0x78,0x19,0xf6,0xb7,0x34,0xc1,0xcc,0xff,0xf8,0xe6,0xa5,0x58,0x8e,0x61,0xea,0x63,0x6d,0xb3,0x6c,0xb9,0xdd,0x8b,0x97,0x74,0x4a,0x8a,0x80,0x76,0x39,0xd5,0xd1,0x77,0xa2,0xc8,0xdf,0xba,0xcd,0x1e,0x33,0x53,0x35,0x7e,0x48,0xae,0x13,0xb5,0xb4,0xbe,0x4f,0x4,0x59,0xee,0xf3,0xc5,0xd7,0x6,0x29,0x2d,0xbf,0x99,0x3b,0x94,0x8f,0x84,0x52,0x83,0x18,0xde,0x3f,0x9f,0x7f,0x90,0x5a,0x68,0xed,0xbc,0x20,0x1d,0x72,0x92,0x67,0x91,0x46,0x88,0x27,0xb0,0xc6,0xc9,0x4e,0x44,0x23,0x24,0xbd,0x41,0x21,0x9b,0x6f,0xa3,0xcb,0x6b,0x31,0xa8,0x81,0x9,0xe5,0x7b,0xf,0xc4,0xec,0xfe,0x22,0x51,0x71,0x7,0xca,0x2b,0xce,0xa0,0x70,0xb,0x4d,0x87,0x21,0x99,0xe4,0xb1,0xc1,0x3d,0x7c,0x4f,0xa7,0xaf,0x55,0x3e,0x50,0xa1,0xf,0x8d,0xc7,0x60,0xca,0xfe,0x7f,0x57,0x4e,0xdc,0x38,0x4,0x82,0xb2,0x83,0x9a,0xa0,0xea,0x9f,0xa9,0x6c,0xb8,0x41,0x1e,0x74,0xdb,0xd4,0xaa,0x9d,0xf1,0xf7,0xd0,0x1b,0x77,0x88,0xc2,0x6a,0xb,0x36,0x6d,0xbf,0xa5,0xf3,0x2f,0x76,0x75,0xab,0x4c,0xf9,0xc9,0x9b,0xed,0x10,0xe2,0x33,0xee,0x43,0x1a,0x25,0x73,0xcc,0x3c,0x7e,0x66,0x4d,0x67,0xcb,0x6e,0x92,0x8c,0xf2,0x1,0x85,0xbd,0xd,0xd2,0x15,0x95,0xa,0x44,0x97,0x9,0xc0,0x63,0xbb,0x26,0x62,0xd7,0xad,0x65,0x70,0x4b,0xeb,0x30,0x3b,0x94,0x8b,0x3a,0x81,0xd5,0x45,0xc8,0x12,0x2c,0xf5,0x80,0x11,0x2,0x6b,0xfd,0x58,0x31,0x78,0x2b,0xb7,0xff,0x7a,0x5,0xf0,0x8a,0xe5,0x1f,0xb0,0x6,0xd1,0x5e,0xd9,0x27,0x51,0xe,0xac,0xba,0x28,0x13,0xc5,0x3,0x18,0x49,0xa8,0x14,0x8f,0x7,0xcd,0x8,0xe8,0x53,0x7b,0xec,0x98,0xc6,0xe6,0x69,0xb5,0xbc,0x59,0x90,0x5d,0x9c,0xda,0x37,0xe7,0xb3,0x2a,0xd3,0xb4,0xc,0xf8,0xd6,0xb6,0xfc,0xa6,0x34,0x5c,0x9e,0x72,0x3f,0x16,0xcf,0x19,0x71,0x32,0xf4,0xfa,0xf6,0x7d,0x2e,0x4a,0x24,0xfb,0xe3,0xdd,0x1c,0x0,0x47,0xb9,0x86,0xde,0x96,0xef,0xc3,0x54,0x20,0xa3,0x8e,0x61,0x68,0x6f,0x56,0x5b,0x39,0x84,0xe9,0xdf,0x29,0xd8,0x22,0x23,0x79,0x64,0x93,0xce,0x91,0xbe,0x52,0x40,0xe1,0xae,0x1d,0x17,0xe0,0x35,0x42,0x46,0x2d,0x5a,0x5f,0x48,0xc4,0xa2,0x89,0xa4,0xe4,0x23,0xfc,0x4c,0x66,0xb5,0xfb,0x64,0x63,0x9f,0x3a,0x96,0x74,0xf0,0x3,0x7d,0x3d,0x82,0xd4,0xeb,0xbc,0x97,0x8f,0xcd,0xe1,0x1c,0x6a,0x38,0xb2,0x1f,0xc2,0x13,0x9a,0xf3,0xe0,0x71,0x89,0xc0,0xa9,0xc,0xb4,0x24,0x70,0xcb,0x4,0xdd,0xe3,0x39,0x1a,0xba,0x81,0x94,0x7a,0x65,0xca,0xc1,0x4a,0x92,0x31,0xf8,0x5c,0x26,0x93,0xd7,0x73,0xf5,0xc9,0x2d,0x51,0x6b,0x72,0x43,0x3b,0x91,0x36,0x7c,0xbf,0xa6,0x8e,0xf,0xa4,0x5e,0x56,0xbe,0xfe,0x50,0xa1,0xcf,0x15,0x68,0xd0,0x76,0x8d,0xcc,0x30,0x40,0x87,0xde,0x2,0x54,0x8,0xbd,0x5a,0x84,0x9b,0x33,0x79,0x86,0x4e,0x9c,0xc7,0xfa,0x6c,0x5b,0x25,0x2a,0xea,0x21,0x6,0x0,0x9d,0x58,0x6e,0x1b,0x85,0xef,0xb0,0x49,0x90,0x7f,0x52,0xd1,0xaa,0xa7,0x9e,0x99,0x2f,0x77,0x48,0xb6,0xa5,0x32,0x1e,0x67,0xa,0xd5,0xbb,0xdf,0xf1,0xed,0x2c,0x12,0xc3,0x80,0xe8,0x3e,0x8c,0x7,0xb,0x5,0xb9,0xae,0xab,0xdc,0x55,0x78,0x53,0x35,0xe6,0xec,0x5f,0x10,0xb7,0xb3,0xc4,0x11,0x3f,0x62,0x95,0x88,0xb1,0xa3,0x4f,0x60,0x2e,0x18,0x75,0xc8,0xd2,0xd3,0x29,0xd8,0x7e,0xe5,0x59,0xb8,0x19,0xf9,0x3c,0xf6,0xd9,0x4b,0x5d,0xff,0xe9,0xf2,0x34,0xe2,0x20,0xf7,0x41,0xee,0xa0,0xd6,0x28,0xaf,0x8b,0xe,0x46,0xda,0x14,0x7b,0x1,0xf4,0xad,0xc5,0x57,0xd,0xe7,0xce,0x83,0x6f,0x45,0x22,0xdb,0x42,0x47,0x27,0x9,0xfd,0xac,0x61,0xa8,0x4d,0x16,0xc6,0x2b,0x6d,0x69,0x1d,0x8a,0xa2,0x44,0x98,0x17,0x37,0x7f,0xdd,0xfb,0x69,0x16,0xc0,0xcb,0xd0,0x7b,0x9a,0x5c,0xc7,0x1e,0xd4,0x3b,0xdb,0x64,0xf8,0xa9,0x2c,0x23,0xd6,0x36,0x59,0x63,0xcc,0x2,0xd5,0xa,0x8d,0x82,0xf4,0xf9,0x60,0x67,0x0,0x2b,0xdf,0x65,0x5,0x75,0x2f,0x8f,0xe7,0xa1,0x4d,0xc5,0xec,0xa8,0x80,0x4b,0x3f,0x35,0x15,0x66,0xba,0x8a,0x6f,0x8e,0x43,0x9,0x4f,0x34,0xe4,0x6a,0x94,0xd,0x55,0x3c,0x45,0x87,0x10,0x70,0xf3,0xb2,0x5d,0xbc,0xbb,0x88,0x85,0xca,0x1c,0xe1,0xa2,0x29,0x27,0xae,0x25,0x99,0xfd,0x28,0xf7,0xe,0x30,0xd3,0xcf,0x7d,0x32,0xc4,0xce,0xe6,0x33,0x95,0x91,0x89,0xfe,0x9b,0x8c,0x71,0x17,0x77,0x5a,0x57,0xea,0xc,0x3a,0xb,0xfa,0xf0,0xf1,0xb7,0xaa,0x1d,0x40,0x6d,0x42,0x93,0x81,0x14,0x5e,0x19,0xb3,0xac,0x2d,0x9d,0x84,0xeb,0xf,0x51,0xd7,0x50,0x61,0x73,0x49,0xf2,0x54,0x37,0x4a,0x12,0x62,0xaf,0xee,0x74,0x9c,0x86,0x7c,0x83,0xed,0xdc,0x72,0x5b,0xa4,0xb9,0x11,0xe5,0xd8,0x6c,0xbe,0x20,0x76,0xa5,0xfc,0x78,0xa6,0x2a,0x9f,0x4c,0x39,0xbf,0x7a,0x92,0x6b,0xa7,0xcd,0x7,0x8,0x4e,0x79,0x24,0x22,0xc8,0x3,0x18,0xb4,0x41,0xbd,0x21,0x5f,0x56,0xd2,0xde,0x6e,0xc6,0x1,0xd9,0x46,0x44,0x97,0x48,0x1a,0xc3,0x3e,0xe0,0x31,0x90,0x3d,0xf6,0xc9,0x1f,0xa0,0xad,0xef,0x9e,0xb5,0x52,0xe9,0x96,0x6,0xc1,0x1b,0x26,0xff,0xc2,0x53,0xb8,0xd1,0x8b,0x2e,0xab,0xe2,0x13,0xda,0x68,0xb0,0xb1,0xf5,0x7e,0x4,0xa3,0xb6,0x38,0x98,0xe8,0xe3,0x58,0x47,0x97,0x6b,0x9e,0x32,0xf8,0x7c,0x75,0xb,0x2b,0xec,0x44,0xf4,0xbd,0x6e,0x6c,0xf3,0x14,0xe9,0x30,0x62,0x17,0xba,0x1b,0xca,0x8a,0x35,0xe3,0xdc,0x9f,0xb4,0xc5,0x87,0x2c,0xbc,0xc3,0x78,0xd5,0xc,0x31,0xeb,0xfb,0x92,0x79,0xe8,0xc8,0x81,0x4,0xa1,0x9a,0x42,0xf0,0x39,0x2e,0x54,0xdf,0x9b,0xb2,0x12,0x9c,0x89,0x6d,0x72,0xc9,0xc2,0x99,0x33,0x74,0x3e,0xae,0xb7,0x7,0x86,0xfd,0x7b,0x25,0xc1,0x63,0x59,0x4b,0x7a,0x60,0x1d,0x7e,0xd8,0xc4,0x85,0x48,0x38,0x56,0xac,0xb6,0x5e,0x58,0xf6,0xc7,0xa9,0x3b,0x93,0x8e,0x71,0x94,0x46,0xf2,0xcf,0xd6,0x8f,0x5c,0xa,0xb5,0x0,0x8c,0x52,0x50,0x95,0x13,0x66,0xe7,0x8d,0x41,0xb8,0x53,0x64,0x22,0x2d,0x29,0xe2,0x8,0xe,0x7f,0x27,0xbe,0x40,0x3a,0xad,0x6f,0x16,0x77,0x98,0xd9,0x5a,0xaf,0xa2,0x91,0x96,0x88,0xcb,0x36,0xe0,0xf,0x84,0xd,0x3,0xdd,0x2,0xd7,0xb3,0xe5,0xf9,0x1a,0x24,0xe4,0xee,0x18,0x57,0xbb,0xbf,0x19,0xcc,0xa6,0xb1,0xd4,0xa3,0x70,0x5d,0x3d,0x5b,0x10,0x26,0xc0,0x7d,0xdb,0xda,0xd0,0x21,0x6a,0x37,0x80,0x9d,0xab,0xb9,0x68,0x47,0x43,0xd1,0xf7,0x55,0xfa,0xe1,0xea,0x3c,0xed,0x76,0xb0,0x51,0xf1,0x11,0xfe,0x34,0x6,0x83,0xd2,0x4e,0x73,0x1c,0xfc,0x9,0xff,0x28,0xe6,0x49,0xde,0xa8,0xa7,0x20,0x2a,0x4d,0x4a,0xd3,0x2f,0x4f,0xf5,0x1,0xcd,0xa5,0x5,0x5f,0xc6,0xef,0x67,0x8b,0x15,0x61,0xaa,0x82,0x90,0x4c,0x3f,0x1f,0x69,0xa4,0x45,0xa0,0xce,0x1e,0x65,0x23,0x6a,0xcc,0x74,0x9,0x5c,0x2c,0xd0,0x91,0xa2,0x4a,0x42,0xb8,0xd3,0xbd,0x4c,0xe2,0x60,0x2a,0x8d,0x27,0x13,0x92,0xba,0xa3,0x31,0xd5,0xe9,0x6f,0x5f,0x6e,0x77,0x4d,0x7,0x72,0x44,0x81,0x55,0xac,0xf3,0x99,0x36,0x39,0x47,0x70,0x1c,0x1a,0x3d,0xf6,0x9a,0x65,0x2f,0x87,0xe6,0xdb,0x80,0x52,0x48,0x1e,0xc2,0x9b,0x98,0x46,0xa1,0x14,0x24,0x76,0x0,0xfd,0xf,0xde,0x3,0xae,0xf7,0xc8,0x9e,0x21,0xd1,0x93,0x8b,0xa0,0x8a,0x26,0x83,0x7f,0x61,0x1f,0xec,0x68,0x50,0xe0,0x3f,0xf8,0x78,0xe7,0xa9,0x7a,0xe4,0x2d,0x8e,0x56,0xcb,0x8f,0x3a,0x40,0x88,0x9d,0xa6,0x6,0xdd,0xd6,0x79,0x66,0xd7,0x6c,0x38,0xa8,0x25,0xff,0xc1,0x18,0x6d,0xfc,0xef,0x86,0x10,0xb5,0xdc,0x95,0xc6,0x5a,0x12,0x97,0xe8,0x1d,0x67,0x8,0xf2,0x5d,0xeb,0x3c,0xb3,0x34,0xca,0xbc,0xe3,0x41,0x57,0xc5,0xfe,0x28,0xee,0xf5,0xa4,0x45,0xf9,0x62,0xea,0x20,0xe5,0x5,0xbe,0x96,0x1,0x75,0x2b,0xb,0x84,0x58,0x51,0xb4,0x7d,0xb0,0x71,0x37,0xda,0xa,0x5e,0xc7,0x3e,0x59,0xe1,0x15,0x3b,0x5b,0x11,0x4b,0xd9,0xb1,0x73,0x9f,0xd2,0xfb,0x22,0xf4,0x9c,0xdf,0x19,0x17,0x1b,0x90,0xc3,0xa7,0xc9,0x16,0xe,0x30,0xf1,0xed,0xaa,0x54,0x6b,0x33,0x7b,0x2,0x2e,0xb9,0xcd,0x4e,0x63,0x8c,0x85,0x82,0xbb,0xb6,0xd4,0x69,0x4,0x32,0xc4,0x35,0xcf,0xce,0x94,0x89,0x7e,0x23,0x7c,0x53,0xbf,0xad,0xc,0x43,0xf0,0xfa,0xd,0xd8,0xaf,0xab,0xc0,0xb7,0xb2,0xa5,0x29,0x4f,0x64,0x49,0x8e,0x49,0x96,0x26,0xc,0xdf,0x91,0xe,0x9,0xf5,0x50,0xfc,0x1e,0x9a,0x69,0x17,0x57,0xe8,0xbe,0x81,0xd6,0xfd,0xe5,0xa7,0x8b,0x76,0x0,0x52,0xd8,0x75,0xa8,0x79,0xf0,0x99,0x8a,0x1b,0xe3,0xaa,0xc3,0x66,0xde,0x4e,0x1a,0xa1,0x6e,0xb7,0x89,0x53,0x70,0xd0,0xeb,0xfe,0x10,0xf,0xa0,0xab,0x20,0xf8,0x5b,0x92,0x36,0x4c,0xf9,0xbd,0x19,0x9f,0xa3,0x47,0x3b,0x1,0x18,0x29,0x51,0xfb,0x5c,0x16,0xd5,0xcc,0xe4,0x65,0xce,0x34,0x3c,0xd4,0x94,0x3a,0xcb,0xa5,0x7f,0x2,0xba,0x1c,0xe7,0xa6,0x5a,0x2a,0xed,0xb4,0x68,0x3e,0x62,0xd7,0x30,0xee,0xf1,0x59,0x13,0xec,0x24,0xf6,0xad,0x90,0x6,0x31,0x4f,0x40,0x80,0x4b,0x6c,0x6a,0xf7,0x32,0x4,0x71,0xef,0x85,0xda,0x23,0xfa,0x15,0x38,0xbb,0xc0,0xcd,0xf4,0xf3,0x45,0x1d,0x22,0xdc,0xcf,0x58,0x74,0xd,0x60,0xbf,0xd1,0xb5,0x9b,0x87,0x46,0x78,0xa9,0xea,0x82,0x54,0xe6,0x6d,0x61,0x6f,0xd3,0xc4,0xc1,0xb6,0x3f,0x12,0x39,0x5f,0x8c,0x86,0x35,0x7a,0xdd,0xd9,0xae,0x7b,0x55,0x8,0xff,0xe2,0xdb,0xc9,0x25,0xa,0x44,0x72,0x1f,0xa2,0xb8,0xb9,0x43,0xb2,0x14,0x8f,0x33,0xd2,0x73,0x93,0x56,0x9c,0xb3,0x21,0x37,0x95,0x83,0x98,0x5e,0x88,0x4a,0x9d,0x2b,0x84,0xca,0xbc,0x42,0xc5,0xe1,0x64,0x2c,0xb0,0x7e,0x11,0x6b,0x9e,0xc7,0xaf,0x3d,0x67,0x8d,0xa4,0xe9,0x5,0x2f,0x48,0xb1,0x28,0x2d,0x4d,0x63,0x97,0xc6,0xb,0xc2,0x27,0x7c,0xac,0x41,0x7,0x3,0x77,0xe0,0xc8,0x2e,0xf2,0x7d,0x5d,0xa4,0x6,0x20,0xb2,0xcd,0x1b,0x10,0xb,0xa0,0x41,0x87,0x1c,0xc5,0xf,0xe0,0x0,0xbf,0x23,0x72,0xf7,0xf8,0xd,0xed,0x82,0xb8,0x17,0xd9,0xe,0xd1,0x56,0x59,0x2f,0x22,0xbb,0xbc,0xdb,0xf0,0x4,0xbe,0xde,0xae,0xf4,0x54,0x3c,0x7a,0x96,0x1e,0x37,0x73,0x5b,0x90,0xe4,0xee,0xce,0xbd,0x61,0x51,0xb4,0x55,0x98,0xd2,0x94,0xef,0x3f,0xb1,0x4f,0xd6,0x8e,0xe7,0x9e,0x5c,0xcb,0xab,0x28,0x69,0x86,0x67,0x60,0x53,0x5e,0x11,0xc7,0x3a,0x79,0xf2,0xfc,0x75,0xfe,0x42,0x26,0xf3,0x2c,0xd5,0xeb,0x8,0x14,0xa6,0xe9,0x1f,0x15,0x3d,0xe8,0x4e,0x4a,0x52,0x25,0x40,0x57,0xaa,0xcc,0xac,0x81,0x8c,0x31,0xd7,0xe1,0xd0,0x21,0x2b,0x2a,0x6c,0x71,0xc6,0x9b,0xb6,0x99,0x48,0x5a,0xcf,0x85,0xc2,0x68,0x77,0xf6,0x46,0x5f,0x30,0xd4,0x8a,0xc,0x8b,0xba,0xa8,0x92,0x29,0x8f,0xec,0x91,0xc9,0xb9,0x74,0x35,0xaf,0x47,0x5d,0xa7,0x58,0x36,0x7,0xa9,0x80,0x7f,0x62,0xca,0x3e,0x3,0xb7,0x65,0xfb,0xad,0x7e,0x27,0xa3,0x7d,0xf1,0x44,0x97,0xe2,0x64,0xa1,0x49,0xb0,0x7c,0x16,0xdc,0xd3,0x95,0xa2,0xff,0xf9,0x13,0xd8,0xc3,0x6f,0x9a,0x66,0xfa,0x84,0x8d,0x9,0x5,0xb5,0x1d,0xda,0x2,0x9d,0x9f,0x4c,0x93,0xc1,0x18,0xe5,0x3b,0xea,0x4b,0xe6,0x2d,0x12,0xc4,0x7b,0x76,0x34,0x45,0x6e,0x89,0x32,0x4d,0xdd,0x1a,0xc0,0xfd,0x24,0x19,0x88,0x63,0xa,0x50,0xf5,0x70,0x39,0xc8,0x1,0xb3,0x6b,0x6a,0x2e,0xa5,0xdf,0x78,0x6d,0xe3,0x43,0x33,0x38,0x83,0x9c,0x6f,0x93,0x66,0xca,0x0,0x84,0x8d,0xf3,0xd3,0x14,0xbc,0xc,0x45,0x96,0x94,0xb,0xec,0x11,0xc8,0x9a,0xef,0x42,0xe3,0x32,0x72,0xcd,0x1b,0x24,0x67,0x4c,0x3d,0x7f,0xd4,0x44,0x3b,0x80,0x2d,0xf4,0xc9,0x13,0x3,0x6a,0x81,0x10,0x30,0x79,0xfc,0x59,0x62,0xba,0x8,0xc1,0xd6,0xac,0x27,0x63,0x4a,0xea,0x64,0x71,0x95,0x8a,0x31,0x3a,0x61,0xcb,0x8c,0xc6,0x56,0x4f,0xff,0x7e,0x5,0x83,0xdd,0x39,0x9b,0xa1,0xb3,0x82,0x98,0xe5,0x86,0x20,0x3c,0x7d,0xb0,0xc0,0xae,0x54,0x4e,0xa6,0xa0,0xe,0x3f,0x51,0xc3,0x6b,0x76,0x89,0x6c,0xbe,0xa,0x37,0x2e,0x77,0xa4,0xf2,0x4d,0xf8,0x74,0xaa,0xa8,0x6d,0xeb,0x9e,0x1f,0x75,0xb9,0x40,0xab,0x9c,0xda,0xd5,0xd1,0x1a,0xf0,0xf6,0x87,0xdf,0x46,0xb8,0xc2,0x55,0x97,0xee,0x8f,0x60,0x21,0xa2,0x57,0x5a,0x69,0x6e,0x70,0x33,0xce,0x18,0xf7,0x7c,0xf5,0xfb,0x25,0xfa,0x2f,0x4b,0x1d,0x1,0xe2,0xdc,0x1c,0x16,0xe0,0xaf,0x43,0x47,0xe1,0x34,0x5e,0x49,0x2c,0x5b,0x88,0xa5,0xc5,0xa3,0xe8,0xde,0x38,0x85,0x23,0x22,0x28,0xd9,0x92,0xcf,0x78,0x65,0x53,0x41,0x90,0xbf,0xbb,0x29,0xf,0xad,0x2,0x19,0x12,0xc4,0x15,0x8e,0x48,0xa9,0x9,0xe9,0x6,0xcc,0xfe,0x7b,0x2a,0xb6,0x8b,0xe4,0x4,0xf1,0x7,0xd0,0x1e,0xb1,0x26,0x50,0x5f,0xd8,0xd2,0xb5,0xb2,0x2b,0xd7,0xb7,0xd,0xf9,0x35,0x5d,0xfd,0xa7,0x3e,0x17,0x9f,0x73,0xed,0x99,0x52,0x7a,0x68,0xb4,0xc7,0xe7,0x91,0x5c,0xbd,0x58,0x36,0xe6,0x9d,0xdb,0x96,0x30,0x88,0xf5,0xa0,0xd0,0x2c,0x6d,0x5e,0xb6,0xbe,0x44,0x2f,0x41,0xb0,0x1e,0x9c,0xd6,0x71,0xdb,0xef,0x6e,0x46,0x5f,0xcd,0x29,0x15,0x93,0xa3,0x92,0x8b,0xb1,0xfb,0x8e,0xb8,0x7d,0xa9,0x50,0xf,0x65,0xca,0xc5,0xbb,0x8c,0xe0,0xe6,0xc1,0xa,0x66,0x99,0xd3,0x7b,0x1a,0x27,0x7c,0xae,0xb4,0xe2,0x3e,0x67,0x64,0xba,0x5d,0xe8,0xd8,0x8a,0xfc,0x1,0xf3,0x22,0xff,0x52,0xb,0x34,0x62,0xdd,0x2d,0x6f,0x77,0x5c,0x76,0xda,0x7f,0x83,0x9d,0xe3,0x10,0x94,0xac,0x1c,0xc3,0x4,0x84,0x1b,0x55,0x86,0x18,0xd1,0x72,0xaa,0x37,0x73,0xc6,0xbc,0x74,0x61,0x5a,0xfa,0x21,0x2a,0x85,0x9a,0x2b,0x90,0xc4,0x54,0xd9,0x3,0x3d,0xe4,0x91,0x0,0x13,0x7a,0xec,0x49,0x20,0x69,0x3a,0xa6,0xee,0x6b,0x14,0xe1,0x9b,0xf4,0xe,0xa1,0x17,0xc0,0x4f,0xc8,0x36,0x40,0x1f,0xbd,0xab,0x39,0x2,0xd4,0x12,0x9,0x58,0xb9,0x5,0x9e,0x16,0xdc,0x19,0xf9,0x42,0x6a,0xfd,0x89,0xd7,0xf7,0x78,0xa4,0xad,0x48,0x81,0x4c,0x8d,0xcb,0x26,0xf6,0xa2,0x3b,0xc2,0xa5,0x1d,0xe9,0xc7,0xa7,0xed,0xb7,0x25,0x4d,0x8f,0x63,0x2e,0x7,0xde,0x8,0x60,0x23,0xe5,0xeb,0xe7,0x6c,0x3f,0x5b,0x35,0xea,0xf2,0xcc,0xd,0x11,0x56,0xa8,0x97,0xcf,0x87,0xfe,0xd2,0x45,0x31,0xb2,0x9f,0x70,0x79,0x7e,0x47,0x4a,0x28,0x95,0xf8,0xce,0x38,0xc9,0x33,0x32,0x68,0x75,0x82,0xdf,0x80,0xaf,0x43,0x51,0xf0,0xbf,0xc,0x6,0xf1,0x24,0x53,0x57,0x3c,0x4b,0x4e,0x59,0xd5,0xb3,0x98,0xb5,0x81,0x46,0x99,0x29,0x3,0xd0,0x9e,0x1,0x6,0xfa,0x5f,0xf3,0x11,0x95,0x66,0x18,0x58,0xe7,0xb1,0x8e,0xd9,0xf2,0xea,0xa8,0x84,0x79,0xf,0x5d,0xd7,0x7a,0xa7,0x76,0xff,0x96,0x85,0x14,0xec,0xa5,0xcc,0x69,0xd1,0x41,0x15,0xae,0x61,0xb8,0x86,0x5c,0x7f,0xdf,0xe4,0xf1,0x1f,0x0,0xaf,0xa4,0x2f,0xf7,0x54,0x9d,0x39,0x43,0xf6,0xb2,0x16,0x90,0xac,0x48,0x34,0xe,0x17,0x26,0x5e,0xf4,0x53,0x19,0xda,0xc3,0xeb,0x6a,0xc1,0x3b,0x33,0xdb,0x9b,0x35,0xc4,0xaa,0x70,0xd,0xb5,0x13,0xe8,0xa9,0x55,0x25,0xe2,0xbb,0x67,0x31,0x6d,0xd8,0x3f,0xe1,0xfe,0x56,0x1c,0xe3,0x2b,0xf9,0xa2,0x9f,0x9,0x3e,0x40,0x4f,0x8f,0x44,0x63,0x65,0xf8,0x3d,0xb,0x7e,0xe0,0x8a,0xd5,0x2c,0xf5,0x1a,0x37,0xb4,0xcf,0xc2,0xfb,0xfc,0x4a,0x12,0x2d,0xd3,0xc0,0x57,0x7b,0x2,0x6f,0xb0,0xde,0xba,0x94,0x88,0x49,0x77,0xa6,0xe5,0x8d,0x5b,0xe9,0x62,0x6e,0x60,0xdc,0xcb,0xce,0xb9,0x30,0x1d,0x36,0x50,0x83,0x89,0x3a,0x75,0xd2,0xd6,0xa1,0x74,0x5a,0x7,0xf0,0xed,0xd4,0xc6,0x2a,0x5,0x4b,0x7d,0x10,0xad,0xb7,0xb6,0x4c,0xbd,0x1b,0x80,0x3c,0xdd,0x7c,0x9c,0x59,0x93,0xbc,0x2e,0x38,0x9a,0x8c,0x97,0x51,0x87,0x45,0x92,0x24,0x8b,0xc5,0xb3,0x4d,0xca,0xee,0x6b,0x23,0xbf,0x71,0x1e,0x64,0x91,0xc8,0xa0,0x32,0x68,0x82,0xab,0xe6,0xa,0x20,0x47,0xbe,0x27,0x22,0x42,0x6c,0x98,0xc9,0x4,0xcd,0x28,0x73,0xa3,0x4e,0x8,0xc,0x78,0xef,0xc7,0x21,0xfd,0x72,0x52,0xdf,0x7d,0x5b,0xc9,0xb6,0x60,0x6b,0x70,0xdb,0x3a,0xfc,0x67,0xbe,0x74,0x9b,0x7b,0xc4,0x58,0x9,0x8c,0x83,0x76,0x96,0xf9,0xc3,0x6c,0xa2,0x75,0xaa,0x2d,0x22,0x54,0x59,0xc0,0xc7,0xa0,0x8b,0x7f,0xc5,0xa5,0xd5,0x8f,0x2f,0x47,0x1,0xed,0x65,0x4c,0x8,0x20,0xeb,0x9f,0x95,0xb5,0xc6,0x1a,0x2a,0xcf,0x2e,0xe3,0xa9,0xef,0x94,0x44,0xca,0x34,0xad,0xf5,0x9c,0xe5,0x27,0xb0,0xd0,0x53,0x12,0xfd,0x1c,0x1b,0x28,0x25,0x6a,0xbc,0x41,0x2,0x89,0x87,0xe,0x85,0x39,0x5d,0x88,0x57,0xae,0x90,0x73,0x6f,0xdd,0x92,0x64,0x6e,0x46,0x93,0x35,0x31,0x29,0x5e,0x3b,0x2c,0xd1,0xb7,0xd7,0xfa,0xf7,0x4a,0xac,0x9a,0xab,0x5a,0x50,0x51,0x17,0xa,0xbd,0xe0,0xcd,0xe2,0x33,0x21,0xb4,0xfe,0xb9,0x13,0xc,0x8d,0x3d,0x24,0x4b,0xaf,0xf1,0x77,0xf0,0xc1,0xd3,0xe9,0x52,0xf4,0x97,0xea,0xb2,0xc2,0xf,0x4e,0xd4,0x3c,0x26,0xdc,0x23,0x4d,0x7c,0xd2,0xfb,0x4,0x19,0xb1,0x45,0x78,0xcc,0x1e,0x80,0xd6,0x5,0x5c,0xd8,0x6,0x8a,0x3f,0xec,0x99,0x1f,0xda,0x32,0xcb,0x7,0x6d,0xa7,0xa8,0xee,0xd9,0x84,0x82,0x68,0xa3,0xb8,0x14,0xe1,0x1d,0x81,0xff,0xf6,0x72,0x7e,0xce,0x66,0xa1,0x79,0xe6,0xe4,0x37,0xe8,0xba,0x63,0x9e,0x40,0x91,0x30,0x9d,0x56,0x69,0xbf,0x0,0xd,0x4f,0x3e,0x15,0xf2,0x49,0x36,0xa6,0x61,0xbb,0x86,0x5f,0x62,0xf3,0x18,0x71,0x2b,0x8e,0xb,0x42,0xb3,0x7a,0xc8,0x10,0x11,0x55,0xde,0xa4,0x3,0x16,0x98,0x38,0x48,0x43,0xf8,0xe7,0x11,0xed,0x18,0xb4,0x7e,0xfa,0xf3,0x8d,0xad,0x6a,0xc2,0x72,0x3b,0xe8,0xea,0x75,0x92,0x6f,0xb6,0xe4,0x91,0x3c,0x9d,0x4c,0xc,0xb3,0x65,0x5a,0x19,0x32,0x43,0x1,0xaa,0x3a,0x45,0xfe,0x53,0x8a,0xb7,0x6d,0x7d,0x14,0xff,0x6e,0x4e,0x7,0x82,0x27,0x1c,0xc4,0x76,0xbf,0xa8,0xd2,0x59,0x1d,0x34,0x94,0x1a,0xf,0xeb,0xf4,0x4f,0x44,0x1f,0xb5,0xf2,0xb8,0x28,0x31,0x81,0x0,0x7b,0xfd,0xa3,0x47,0xe5,0xdf,0xcd,0xfc,0xe6,0x9b,0xf8,0x5e,0x42,0x3,0xce,0xbe,0xd0,0x2a,0x30,0xd8,0xde,0x70,0x41,0x2f,0xbd,0x15,0x8,0xf7,0x12,0xc0,0x74,0x49,0x50,0x9,0xda,0x8c,0x33,0x86,0xa,0xd4,0xd6,0x13,0x95,0xe0,0x61,0xb,0xc7,0x3e,0xd5,0xe2,0xa4,0xab,0xaf,0x64,0x8e,0x88,0xf9,0xa1,0x38,0xc6,0xbc,0x2b,0xe9,0x90,0xf1,0x1e,0x5f,0xdc,0x29,0x24,0x17,0x10,0xe,0x4d,0xb0,0x66,0x89,0x2,0x8b,0x85,0x5b,0x84,0x51,0x35,0x63,0x7f,0x9c,0xa2,0x62,0x68,0x9e,0xd1,0x3d,0x39,0x9f,0x4a,0x20,0x37,0x52,0x25,0xf6,0xdb,0xbb,0xdd,0x96,0xa0,0x46,0xfb,0x5d,0x5c,0x56,0xa7,0xec,0xb1,0x6,0x1b,0x2d,0x3f,0xee,0xc1,0xc5,0x57,0x71,0xd3,0x7c,0x67,0x6c,0xba,0x6b,0xf0,0x36,0xd7,0x77,0x97,0x78,0xb2,0x80,0x5,0x54,0xc8,0xf5,0x9a,0x7a,0x8f,0x79,0xae,0x60,0xcf,0x58,0x2e,0x21,0xa6,0xac,0xcb,0xcc,0x55,0xa9,0xc9,0x73,0x87,0x4b,0x23,0x83,0xd9,0x40,0x69,0xe1,0xd,0x93,0xe7,0x2c,0x4,0x16,0xca,0xb9,0x99,0xef,0x22,0xc3,0x26,0x48,0x98,0xe3,0xa5,0x81,0x27,0x9f,0xe2,0xb7,0xc7,0x3b,0x7a,0x49,0xa1,0xa9,0x53,0x38,0x56,0xa7,0x9,0x8b,0xc1,0x66,0xcc,0xf8,0x79,0x51,0x48,0xda,0x3e,0x2,0x84,0xb4,0x85,0x9c,0xa6,0xec,0x99,0xaf,0x6a,0xbe,0x47,0x18,0x72,0xdd,0xd2,0xac,0x9b,0xf7,0xf1,0xd6,0x1d,0x71,0x8e,0xc4,0x6c,0xd,0x30,0x6b,0xb9,0xa3,0xf5,0x29,0x70,0x73,0xad,0x4a,0xff,0xcf,0x9d,0xeb,0x16,0xe4,0x35,0xe8,0x45,0x1c,0x23,0x75,0xca,0x3a,0x78,0x60,0x4b,0x61,0xcd,0x68,0x94,0x8a,0xf4,0x7,0x83,0xbb,0xb,0xd4,0x13,0x93,0xc,0x42,0x91,0xf,0xc6,0x65,0xbd,0x20,0x64,0xd1,0xab,0x63,0x76,0x4d,0xed,0x36,0x3d,0x92,0x8d,0x3c,0x87,0xd3,0x43,0xce,0x14,0x2a,0xf3,0x86,0x17,0x4,0x6d,0xfb,0x5e,0x37,0x7e,0x2d,0xb1,0xf9,0x7c,0x3,0xf6,0x8c,0xe3,0x19,0xb6,0x0,0xd7,0x58,0xdf,0x21,0x57,0x8,0xaa,0xbc,0x2e,0x15,0xc3,0x5,0x1e,0x4f,0xae,0x12,0x89,0x1,0xcb,0xe,0xee,0x55,0x7d,0xea,0x9e,0xc0,0xe0,0x6f,0xb3,0xba,0x5f,0x96,0x5b,0x9a,0xdc,0x31,0xe1,0xb5,0x2c,0xd5,0xb2,0xa,0xfe,0xd0,0xb0,0xfa,0xa0,0x32,0x5a,0x98,0x74,0x39,0x10,0xc9,0x1f,0x77,0x34,0xf2,0xfc,0xf0,0x7b,0x28,0x4c,0x22,0xfd,0xe5,0xdb,0x1a,0x6,0x41,0xbf,0x80,0xd8,0x90,0xe9,0xc5,0x52,0x26,0xa5,0x88,0x67,0x6e,0x69,0x50,0x5d,0x3f,0x82,0xef,0xd9,0x2f,0xde,0x24,0x25,0x7f,0x62,0x95,0xc8,0x97,0xb8,0x54,0x46,0xe7,0xa8,0x1b,0x11,0xe6,0x33,0x44,0x40,0x2b,0x5c,0x59,0x4e,0xc2,0xa4,0x8f,0xa2,0xe4,0x23,0xfc,0x4c,0x66,0xb5,0xfb,0x64,0x63,0x9f,0x3a,0x96,0x74,0xf0,0x3,0x7d,0x3d,0x82,0xd4,0xeb,0xbc,0x97,0x8f,0xcd,0xe1,0x1c,0x6a,0x38,0xb2,0x1f,0xc2,0x13,0x9a,0xf3,0xe0,0x71,0x89,0xc0,0xa9,0xc,0xb4,0x24,0x70,0xcb,0x4,0xdd,0xe3,0x39,0x1a,0xba,0x81,0x94,0x7a,0x65,0xca,0xc1,0x4a,0x92,0x31,0xf8,0x5c,0x26,0x93,0xd7,0x73,0xf5,0xc9,0x2d,0x51,0x6b,0x72,0x43,0x3b,0x91,0x36,0x7c,0xbf,0xa6,0x8e,0xf,0xa4,0x5e,0x56,0xbe,0xfe,0x50,0xa1,0xcf,0x15,0x68,0xd0,0x76,0x8d,0xcc,0x30,0x40,0x87,0xde,0x2,0x54,0x8,0xbd,0x5a,0x84,0x9b,0x33,0x79,0x86,0x4e,0x9c,0xc7,0xfa,0x6c,0x5b,0x25,0x2a,0xea,0x21,0x6,0x0,0x9d,0x58,0x6e,0x1b,0x85,0xef,0xb0,0x49,0x90,0x7f,0x52,0xd1,0xaa,0xa7,0x9e,0x99,0x2f,0x77,0x48,0xb6,0xa5,0x32,0x1e,0x67,0xa,0xd5,0xbb,0xdf,0xf1,0xed,0x2c,0x12,0xc3,0x80,0xe8,0x3e,0x8c,0x7,0xb,0x5,0xb9,0xae,0xab,0xdc,0x55,0x78,0x53,0x35,0xe6,0xec,0x5f,0x10,0xb7,0xb3,0xc4,0x11,0x3f,0x62,0x95,0x88,0xb1,0xa3,0x4f,0x60,0x2e,0x18,0x75,0xc8,0xd2,0xd3,0x29,0xd8,0x7e,0xe5,0x59,0xb8,0x19,0xf9,0x3c,0xf6,0xd9,0x4b,0x5d,0xff,0xe9,0xf2,0x34,0xe2,0x20,0xf7,0x41,0xee,0xa0,0xd6,0x28,0xaf,0x8b,0xe,0x46,0xda,0x14,0x7b,0x1,0xf4,0xad,0xc5,0x57,0xd,0xe7,0xce,0x83,0x6f,0x45,0x22,0xdb,0x42,0x47,0x27,0x9,0xfd,0xac,0x61,0xa8,0x4d,0x16,0xc6,0x2b,0x6d,0x69,0x1d,0x8a,0xa2,0x44,0x98,0x17,0x37,0x71,0x7b,0x36,0x27,0xc5,0xa8,0x68,0x97,0x52,0x8d,0x62,0xdc,0xba,0xb8,0xcc,0x24,0x32,0xaf,0x2a,0xfc,0x1d,0x60,0x77,0x6f,0xdf,0x2f,0x61,0x16,0x1e,0x47,0xc,0xfa,0xca,0x44,0xe8,0x57,0xb4,0x1b,0x14,0x5f,0xf6,0xda,0x1,0x91,0x3e,0xa7,0x4a,0xe1,0x33,0xa2,0xe7,0x6e,0x41,0xa3,0xbb,0xd3,0x51,0x3,0xeb,0xf8,0xc8,0x30,0x8b,0xe,0xdb,0x9,0xa6,0x67,0x80,0xd5,0x9a,0x4f,0x3b,0x95,0xe4,0x9b,0x74,0x18,0xe0,0xde,0x2b,0x88,0xf3,0x83,0xaa,0x21,0x59,0x15,0x96,0xa5,0x5b,0x85,0x75,0x58,0xbd,0x54,0x39,0xf1,0xf2,0x84,0x7f,0x3d,0x3f,0x9e,0x22,0x5e,0x23,0x43,0x93,0x49,0x20,0x25,0x17,0xfb,0x3c,0xa9,0x76,0xc1,0x4,0x4d,0xa,0xff,0x65,0x50,0x35,0xc6,0x4e,0xe3,0x38,0x92,0x5,0xcb,0xc7,0x7,0xd7,0x29,0x6b,0x5c,0xd,0x56,0xdd,0x26,0x82,0x9f,0xbc,0x70,0xc2,0xb7,0xc3,0xf5,0xc0,0x42,0x90,0x2c,0x5a,0xbe,0xe9,0x6,0x2,0x7a,0xb1,0x81,0x55,0x98,0xcd,0xd8,0xfe,0x46,0x12,0x73,0xec,0x7e,0x19,0xb5,0x4c,0xc4,0x28,0xc9,0xb9,0x10,0x87,0x6a,0xcf,0x8,0x6d,0x45,0xf4,0x6c,0xf,0x48,0x37,0xef,0xee,0x79,0x2d,0x94,0x8a,0xf9,0x31,0xb0,0x8e,0x9c,0x69,0xfd,0x40,0x7c,0x1a,0x1c,0xb2,0xe5,0xe2,0x13,0xe6,0x8c,0xac,0xb6,0xd6,0x72,0x64,0x63,0xd0,0xea,0x53,0x7d,0x89,0xae,0x0,0x1f,0xab,0xed,0x34,0x11,0xa0,0x86,0xb,0x8f,0xd2,0x3a,0x99,0xa1,0x4b,0xd4,0xf7,0xbf,0xf0,0x66,0x2e,0xce,0x9d,0xd9,0x5d,0xd1,0xad,0xb3,0x78,0xa4,0x4e,0xb2,0x47,0xeb,0x21,0xa5,0xac,0xd2,0xf2,0x35,0x9d,0x2d,0x64,0xb7,0xb5,0x2a,0xcd,0x30,0xe9,0xbb,0xce,0x63,0xc2,0x13,0x53,0xec,0x3a,0x5,0x46,0x6d,0x1c,0x5e,0xf5,0x65,0x1a,0xa1,0xc,0xd5,0xe8,0x32,0x22,0x4b,0xa0,0x31,0x11,0x58,0xdd,0x78,0x43,0x9b,0x29,0xe0,0xf7,0x8d,0x6,0x42,0x6b,0xcb,0x45,0x50,0xb4,0xab,0x10,0x1b,0x40,0xea,0xad,0xe7,0x77,0x6e,0xde,0x5f,0x24,0xa2,0xfc,0x18,0xba,0x80,0x92,0xa3,0xb9,0xc4,0xa7,0x1,0x1d,0x5c,0x91,0xe1,0x8f,0x75,0x6f,0x87,0x81,0x2f,0x1e,0x70,0xe2,0x4a,0x57,0xa8,0x4d,0x9f,0x2b,0x16,0xf,0x56,0x85,0xd3,0x6c,0xd9,0x55,0x8b,0x89,0x4c,0xca,0xbf,0x3e,0x54,0x98,0x61,0x8a,0xbd,0xfb,0xf4,0xf0,0x3b,0xd1,0xd7,0xa6,0xfe,0x67,0x99,0xe3,0x74,0xb6,0xcf,0xae,0x41,0x0,0x83,0x76,0x7b,0x48,0x4f,0x51,0x12,0xef,0x39,0xd6,0x5d,0xd4,0xda,0x4,0xdb,0xe,0x6a,0x3c,0x20,0xc3,0xfd,0x3d,0x37,0xc1,0x8e,0x62,0x66,0xc0,0x15,0x7f,0x68,0xd,0x7a,0xa9,0x84,0xe4,0x82,0xc9,0xff,0x19,0xa4,0x2,0x3,0x9,0xf8,0xb3,0xee,0x59,0x44,0x72,0x60,0xb1,0x9e,0x9a,0x8,0x2e,0x8c,0x23,0x38,0x33,0xe5,0x34,0xaf,0x69,0x88,0x28,0xc8,0x27,0xed,0xdf,0x5a,0xb,0x97,0xaa,0xc5,0x25,0xd0,0x26,0xf1,0x3f,0x90,0x7,0x71,0x7e,0xf9,0xf3,0x94,0x93,0xa,0xf6,0x96,0x2c,0xd8,0x14,0x7c,0xdc,0x86,0x1f,0x36,0xbe,0x52,0xcc,0xb8,0x73,0x5b,0x49,0x95,0xe6,0xc6,0xb0,0x7d,0x9c,0x79,0x17,0xc7,0xbc,0xfa,0x2d,0x8b,0x33,0x4e,0x1b,0x6b,0x97,0xd6,0xe5,0xd,0x5,0xff,0x94,0xfa,0xb,0xa5,0x27,0x6d,0xca,0x60,0x54,0xd5,0xfd,0xe4,0x76,0x92,0xae,0x28,0x18,0x29,0x30,0xa,0x40,0x35,0x3,0xc6,0x12,0xeb,0xb4,0xde,0x71,0x7e,0x0,0x37,0x5b,0x5d,0x7a,0xb1,0xdd,0x22,0x68,0xc0,0xa1,0x9c,0xc7,0x15,0xf,0x59,0x85,0xdc,0xdf,0x1,0xe6,0x53,0x63,0x31,0x47,0xba,0x48,0x99,0x44,0xe9,0xb0,0x8f,0xd9,0x66,0x96,0xd4,0xcc,0xe7,0xcd,0x61,0xc4,0x38,0x26,0x58,0xab,0x2f,0x17,0xa7,0x78,0xbf,0x3f,0xa0,0xee,0x3d,0xa3,0x6a,0xc9,0x11,0x8c,0xc8,0x7d,0x7,0xcf,0xda,0xe1,0x41,0x9a,0x91,0x3e,0x21,0x90,0x2b,0x7f,0xef,0x62,0xb8,0x86,0x5f,0x2a,0xbb,0xa8,0xc1,0x57,0xf2,0x9b,0xd2,0x81,0x1d,0x55,0xd0,0xaf,0x5a,0x20,0x4f,0xb5,0x1a,0xac,0x7b,0xf4,0x73,0x8d,0xfb,0xa4,0x6,0x10,0x82,0xb9,0x6f,0xa9,0xb2,0xe3,0x2,0xbe,0x25,0xad,0x67,0xa2,0x42,0xf9,0xd1,0x46,0x32,0x6c,0x4c,0xc3,0x1f,0x16,0xf3,0x3a,0xf7,0x36,0x70,0x9d,0x4d,0x19,0x80,0x79,0x1e,0xa6,0x52,0x7c,0x1c,0x56,0xc,0x9e,0xf6,0x34,0xd8,0x95,0xbc,0x65,0xb3,0xdb,0x98,0x5e,0x50,0x5c,0xd7,0x84,0xe0,0x8e,0x51,0x49,0x77,0xb6,0xaa,0xed,0x13,0x2c,0x74,0x3c,0x45,0x69,0xfe,0x8a,0x9,0x24,0xcb,0xc2,0xc5,0xfc,0xf1,0x93,0x2e,0x43,0x75,0x83,0x72,0x88,0x89,0xd3,0xce,0x39,0x64,0x3b,0x14,0xf8,0xea,0x4b,0x4,0xb7,0xbd,0x4a,0x9f,0xe8,0xec,0x87,0xf0,0xf5,0xe2,0x6e,0x8,0x23,0xe,0xaf,0xf8,0x59,0xa8,0xc6,0xac,0xfc,0xe6,0x38,0x9c,0x29,0x2e,0xa0,0x9a,0x37,0x19,0x33,0xa4,0xde,0x67,0xb3,0xc0,0xfa,0x7b,0xd6,0xc4,0xb7,0x23,0x36,0xa,0x56,0x50,0x9e,0x1,0xf5,0xbd,0x2c,0xba,0x84,0x64,0x93,0xd7,0x9b,0x17,0xf9,0xe7,0xee,0x32,0xe4,0xc3,0x55,0x4a,0xa7,0xe1,0x5b,0x7e,0xcc,0xea,0xc5,0x41,0x70,0x98,0xeb,0xd3,0x3a,0xf6,0xfd,0x88,0xbf,0x89,0x8,0x8a,0x66,0xda,0xf4,0x10,0x4c,0xa3,0x30,0x48,0xd8,0x72,0x81,0x4f,0x4d,0x8d,0x63,0x9d,0x16,0x21,0x1c,0x47,0x6c,0x97,0xd5,0xc8,0x83,0x62,0x5a,0xf3,0x20,0xcd,0x42,0x85,0xf,0x27,0x26,0xbe,0x2,0x45,0xa5,0x7d,0xcb,0xfb,0xd2,0x1f,0x92,0x87,0xc,0xb4,0x39,0x58,0x34,0xa6,0xff,0x53,0x8e,0x6,0xc2,0x61,0xc9,0xb9,0x6b,0xe0,0x5f,0x13,0xef,0xdc,0xcf,0x11,0x12,0x3f,0x1e,0xf7,0x43,0x91,0x2d,0xec,0x9f,0xca,0x5,0xd0,0xdf,0x71,0xd1,0xae,0x52,0x3e,0x94,0xaa,0xb1,0x5d,0xe3,0x76,0x8b,0x3c,0x7,0x4e,0xb5,0x40,0x1a,0x2f,0x8c,0x7f,0xa9,0x4,0xbb,0x73,0xce,0xb8,0x77,0x35,0xd4,0x75,0x14,0x68,0x9,0x69,0x3,0xd9,0x6f,0x6a,0xe5,0x78,0xb6,0x60,0x2a,0x57,0x25,0x3d,0x65,0x95,0x5c,0x2b,0xd,0x54,0xb0,0x46,0x31,0x3b,0x6d,0x7c,0xe2,0x8f,0xdd,0x22,0xc7,0x18,0x96,0x28,0xf2,0xf0,0x6e,0x86,0xe8,0x79,0x24,0xad,0xe9,0xb,0x99,0xf1,0x49,0x1b,0xb2,0xa1,0x7a,0x82,0x44,0xc1,0xe,0x80,0x1d,0xa2,0x51,0xfe,0x15,0x5e,0x90,0xbc,0xdb,0x4b,0xed,0x74,0xab,0x0,0x33,0x91,0xb7,0x25,0x5a,0x8c,0x87,0x9c,0x37,0xd6,0x10,0x8b,0x52,0x98,0x77,0x97,0x28,0xb4,0xe5,0x60,0x6f,0x9a,0x7a,0x15,0x2f,0x80,0x4e,0x99,0x46,0xc1,0xce,0xb8,0xb5,0x2c,0x2b,0x4c,0x67,0x93,0x29,0x49,0x39,0x63,0xc3,0xab,0xed,0x1,0x89,0xa0,0xe4,0xcc,0x7,0x73,0x79,0x59,0x2a,0xf6,0xc6,0x23,0xc2,0xf,0x45,0x3,0x78,0xa8,0x26,0xd8,0x41,0x19,0x70,0x9,0xcb,0x5c,0x3c,0xbf,0xfe,0x11,0xf0,0xf7,0xc4,0xc9,0x86,0x50,0xad,0xee,0x65,0x6b,0xe2,0x69,0xd5,0xb1,0x64,0xbb,0x42,0x7c,0x9f,0x83,0x31,0x7e,0x88,0x82,0xaa,0x7f,0xd9,0xdd,0xc5,0xb2,0xd7,0xc0,0x3d,0x5b,0x3b,0x16,0x1b,0xa6,0x40,0x76,0x47,0xb6,0xbc,0xbd,0xfb,0xe6,0x51,0xc,0x21,0xe,0xdf,0xcd,0x58,0x12,0x55,0xff,0xe0,0x61,0xd1,0xc8,0xa7,0x43,0x1d,0x9b,0x1c,0x2d,0x3f,0x5,0xbe,0x18,0x7b,0x6,0x5e,0x2e,0xe3,0xa2,0x38,0xd0,0xca,0x30,0xcf,0xa1,0x90,0x3e,0x17,0xe8,0xf5,0x5d,0xa9,0x94,0x20,0xf2,0x6c,0x3a,0xe9,0xb0,0x34,0xea,0x66,0xd3,0x0,0x75,0xf3,0x36,0xde,0x27,0xeb,0x81,0x4b,0x44,0x2,0x35,0x68,0x6e,0x84,0x4f,0x54,0xf8,0xd,0xf1,0x6d,0x13,0x1a,0x9e,0x92,0x22,0x8a,0x4d,0x95,0xa,0x8,0xdb,0x4,0x56,0x8f,0x72,0xac,0x7d,0xdc,0x71,0xba,0x85,0x53,0xec,0xe1,0xa3,0xd2,0xf9,0x1e,0xa5,0xda,0x4a,0x8d,0x57,0x6a,0xb3,0x8e,0x1f,0xf4,0x9d,0xc7,0x62,0xe7,0xae,0x5f,0x96,0x24,0xfc,0xfd,0xb9,0x32,0x48,0xef,0xfa,0x74,0xd4,0xa4,0xaf,0x14,0xb,0xb5,0x49,0xbc,0x10,0xda,0x5e,0x57,0x29,0x9,0xce,0x66,0xd6,0x9f,0x4c,0x4e,0xd1,0x36,0xcb,0x12,0x40,0x35,0x98,0x39,0xe8,0xa8,0x17,0xc1,0xfe,0xbd,0x96,0xe7,0xa5,0xe,0x9e,0xe1,0x5a,0xf7,0x2e,0x13,0xc9,0xd9,0xb0,0x5b,0xca,0xea,0xa3,0x26,0x83,0xb8,0x60,0xd2,0x1b,0xc,0x76,0xfd,0xb9,0x90,0x30,0xbe,0xab,0x4f,0x50,0xeb,0xe0,0xbb,0x11,0x56,0x1c,0x8c,0x95,0x25,0xa4,0xdf,0x59,0x7,0xe3,0x41,0x7b,0x69,0x58,0x42,0x3f,0x5c,0xfa,0xe6,0xa7,0x6a,0x1a,0x74,0x8e,0x94,0x7c,0x7a,0xd4,0xe5,0x8b,0x19,0xb1,0xac,0x53,0xb6,0x64,0xd0,0xed,0xf4,0xad,0x7e,0x28,0x97,0x22,0xae,0x70,0x72,0xb7,0x31,0x44,0xc5,0xaf,0x63,0x9a,0x71,0x46,0x0,0xf,0xb,0xc0,0x2a,0x2c,0x5d,0x5,0x9c,0x62,0x18,0x8f,0x4d,0x34,0x55,0xba,0xfb,0x78,0x8d,0x80,0xb3,0xb4,0xaa,0xe9,0x14,0xc2,0x2d,0xa6,0x2f,0x21,0xff,0x20,0xf5,0x91,0xc7,0xdb,0x38,0x6,0xc6,0xcc,0x3a,0x75,0x99,0x9d,0x3b,0xee,0x84,0x93,0xf6,0x81,0x52,0x7f,0x1f,0x79,0x32,0x4,0xe2,0x5f,0xf9,0xf8,0xf2,0x3,0x48,0x15,0xa2,0xbf,0x89,0x9b,0x4a,0x65,0x61,0xf3,0xd5,0x77,0xd8,0xc3,0xc8,0x1e,0xcf,0x54,0x92,0x73,0xd3,0x33,0xdc,0x16,0x24,0xa1,0xf0,0x6c,0x51,0x3e,0xde,0x2b,0xdd,0xa,0xc4,0x6b,0xfc,0x8a,0x85,0x2,0x8,0x6f,0x68,0xf1,0xd,0x6d,0xd7,0x23,0xef,0x87,0x27,0x7d,0xe4,0xcd,0x45,0xa9,0x37,0x43,0x88,0xa0,0xb2,0x6e,0x1d,0x3d,0x4b,0x86,0x67,0x82,0xec,0x3c,0x47,0x1,0x4c,0x62,0xcf,0xf5,0x7b,0x7c,0xc9,0x6d,0xb3,0xa9,0xf9,0x93,0xfd,0xc,0xad,0xfa,0x5,0x3,0x5f,0x63,0x76,0xe2,0x91,0x83,0x2e,0xaf,0x95,0xe6,0x32,0x8b,0xf1,0x66,0x67,0xbb,0xb2,0xac,0x42,0xce,0x82,0xc6,0x31,0xd1,0xef,0x79,0xe8,0xa0,0x54,0xcb,0x86,0xbe,0xcd,0x25,0x14,0x90,0xbf,0x99,0x2b,0xe,0xb4,0xf2,0x1f,0x0,0x96,0xb1,0x1d,0x65,0xf6,0x19,0x45,0xa1,0x8f,0x33,0xdf,0x5d,0xdc,0xea,0xdd,0xa8,0xa3,0x6f,0x9d,0x80,0xc2,0x39,0x12,0x49,0x74,0x43,0xc8,0x36,0xd8,0x18,0x1a,0xd4,0x27,0x8d,0x28,0xf0,0x10,0x57,0xeb,0x73,0x72,0x5a,0xd0,0x17,0x98,0x75,0xa6,0xf,0x37,0xd6,0x53,0xdb,0x6,0xaa,0xf3,0x61,0xd,0x6c,0xe1,0x59,0xd2,0xc7,0x4a,0x87,0xae,0x9e,0xa2,0x4b,0x6a,0x47,0x44,0x9a,0x89,0xba,0x46,0xa,0xb5,0x3e,0xec,0x9c,0x34,0x97,0xff,0xc1,0x6b,0x7,0xfb,0x84,0x24,0x8a,0x85,0x50,0x9f,0xca,0xb9,0x78,0xc4,0x16,0x51,0xfc,0x2a,0xd9,0x7a,0x4f,0x15,0xe0,0x1b,0x52,0x69,0xde,0x23,0xb6,0x8,0xe4,0x3f,0x3a,0x8c,0x56,0x3c,0x5c,0x3d,0x41,0x20,0x81,0x60,0x22,0xed,0x9b,0x26,0xee,0x13,0xe5,0x1,0x58,0x7e,0x9,0xc0,0x30,0x68,0x70,0x2,0x7f,0x35,0xe3,0x2d,0xb0,0xd3,0x3b,0xa5,0xa7,0x7d,0xc3,0x4d,0x92,0x77,0x88,0xda,0xb7,0x29,0x38,0x6e,0x64,0x94,0x11,0xd7,0x2f,0xf4,0xe7,0x4e,0x1c,0xa4,0xcc,0x5e,0xbc,0xf8,0x71,0x2c,0xbd,0x55,0xfe,0x21,0xb8,0x1e,0x8e,0xe9,0xc5,0xb,0x40,0xab,0x4,0xf7,0x48,0xd5,0x5b,0x67,0xa0,0x7f,0xcf,0xe5,0x36,0x78,0xe7,0xe0,0x1c,0xb9,0x15,0xf7,0x73,0x80,0xfe,0xbe,0x1,0x57,0x68,0x3f,0x14,0xc,0x4e,0x62,0x9f,0xe9,0xbb,0x31,0x9c,0x41,0x90,0x19,0x70,0x63,0xf2,0xa,0x43,0x2a,0x8f,0x37,0xa7,0xf3,0x48,0x87,0x5e,0x60,0xba,0x99,0x39,0x2,0x17,0xf9,0xe6,0x49,0x42,0xc9,0x11,0xb2,0x7b,0xdf,0xa5,0x10,0x54,0xf0,0x76,0x4a,0xae,0xd2,0xe8,0xf1,0xc0,0xb8,0x12,0xb5,0xff,0x3c,0x25,0xd,0x8c,0x27,0xdd,0xd5,0x3d,0x7d,0xd3,0x22,0x4c,0x96,0xeb,0x53,0xf5,0xe,0x4f,0xb3,0xc3,0x4,0x5d,0x81,0xd7,0x8b,0x3e,0xd9,0x7,0x18,0xb0,0xfa,0x5,0xcd,0x1f,0x44,0x79,0xef,0xd8,0xa6,0xa9,0x69,0xa2,0x85,0x83,0x1e,0xdb,0xed,0x98,0x6,0x6c,0x33,0xca,0x13,0xfc,0xd1,0x52,0x29,0x24,0x1d,0x1a,0xac,0xf4,0xcb,0x35,0x26,0xb1,0x9d,0xe4,0x89,0x56,0x38,0x5c,0x72,0x6e,0xaf,0x91,0x40,0x3,0x6b,0xbd,0xf,0x84,0x88,0x86,0x3a,0x2d,0x28,0x5f,0xd6,0xfb,0xd0,0xb6,0x65,0x6f,0xdc,0x93,0x34,0x30,0x47,0x92,0xbc,0xe1,0x16,0xb,0x32,0x20,0xcc,0xe3,0xad,0x9b,0xf6,0x4b,0x51,0x50,0xaa,0x5b,0xfd,0x66,0xda,0x3b,0x9a,0x7a,0xbf,0x75,0x5a,0xc8,0xde,0x7c,0x6a,0x71,0xb7,0x61,0xa3,0x74,0xc2,0x6d,0x23,0x55,0xab,0x2c,0x8,0x8d,0xc5,0x59,0x97,0xf8,0x82,0x77,0x2e,0x46,0xd4,0x8e,0x64,0x4d,0x0,0xec,0xc6,0xa1,0x58,0xc1,0xc4,0xa4,0x8a,0x7e,0x2f,0xe2,0x2b,0xce,0x95,0x45,0xa8,0xee,0xea,0x9e,0x9,0x21,0xc7,0x1b,0x94,0xb4,0x9a,0x38,0x1e,0x8c,0xf3,0x25,0x2e,0x35,0x9e,0x7f,0xb9,0x22,0xfb,0x31,0xde,0x3e,0x81,0x1d,0x4c,0xc9,0xc6,0x33,0xd3,0xbc,0x86,0x29,0xe7,0x30,0xef,0x68,0x67,0x11,0x1c,0x85,0x82,0xe5,0xce,0x3a,0x80,0xe0,0x90,0xca,0x6a,0x2,0x44,0xa8,0x20,0x9,0x4d,0x65,0xae,0xda,0xd0,0xf0,0x83,0x5f,0x6f,0x8a,0x6b,0xa6,0xec,0xaa,0xd1,0x1,0x8f,0x71,0xe8,0xb0,0xd9,0xa0,0x62,0xf5,0x95,0x16,0x57,0xb8,0x59,0x5e,0x6d,0x60,0x2f,0xf9,0x4,0x47,0xcc,0xc2,0x4b,0xc0,0x7c,0x18,0xcd,0x12,0xeb,0xd5,0x36,0x2a,0x98,0xd7,0x21,0x2b,0x3,0xd6,0x70,0x74,0x6c,0x1b,0x7e,0x69,0x94,0xf2,0x92,0xbf,0xb2,0xf,0xe9,0xdf,0xee,0x1f,0x15,0x14,0x52,0x4f,0xf8,0xa5,0x88,0xa7,0x76,0x64,0xf1,0xbb,0xfc,0x56,0x49,0xc8,0x78,0x61,0xe,0xea,0xb4,0x32,0xb5,0x84,0x96,0xac,0x17,0xb1,0xd2,0xaf,0xf7,0x87,0x4a,0xb,0x91,0x79,0x63,0x99,0x66,0x8,0x39,0x97,0xbe,0x41,0x5c,0xf4,0x0,0x3d,0x89,0x5b,0xc5,0x93,0x40,0x19,0x9d,0x43,0xcf,0x7a,0xa9,0xdc,0x5a,0x9f,0x77,0x8e,0x42,0x28,0xe2,0xed,0xab,0x9c,0xc1,0xc7,0x2d,0xe6,0xfd,0x51,0xa4,0x58,0xc4,0xba,0xb3,0x37,0x3b,0x8b,0x23,0xe4,0x3c,0xa3,0xa1,0x72,0xad,0xff,0x26,0xdb,0x5,0xd4,0x75,0xd8,0x13,0x2c,0xfa,0x45,0x48,0xa,0x7b,0x50,0xb7,0xc,0x73,0xe3,0x24,0xfe,0xc3,0x1a,0x27,0xb6,0x5d,0x34,0x6e,0xcb,0x4e,0x7,0xf6,0x3f,0x8d,0x55,0x54,0x10,0x9b,0xe1,0x46,0x53,0xdd,0x7d,0xd,0x6,0xbd,0xa2,0x31,0x14,0xae,0xe8,0x5,0x1a,0x8c,0xab,0x9c,0xa4,0xd7,0x3f,0xe,0x8a,0xa5,0x83,0x2b,0xcb,0xf5,0x63,0xf2,0xba,0x4e,0xd1,0x7d,0xa1,0xa8,0xb6,0x58,0xd4,0x98,0xdc,0x34,0xb5,0x8f,0xfc,0x28,0x91,0xeb,0x7c,0x1f,0x19,0x45,0x79,0x6c,0xf8,0x8b,0x99,0xa9,0xb3,0xe3,0x89,0xe7,0x16,0xb7,0xe0,0x56,0x78,0xd5,0xef,0x61,0x66,0xd3,0x77,0xfb,0x43,0xc8,0xdd,0x50,0x9d,0xb4,0x84,0x49,0xc1,0x1c,0xb0,0xe9,0x7b,0x17,0x76,0xca,0xd,0x82,0x6f,0xbc,0x15,0x2d,0xcc,0x32,0xea,0xa,0x4d,0xf1,0x69,0x68,0x40,0xd2,0x2c,0xc2,0x2,0x0,0xce,0x3d,0x97,0x87,0x9a,0xd8,0x23,0x8,0x53,0x6e,0x59,0xc5,0x47,0xc6,0xf0,0xc7,0xb2,0xb9,0x75,0x7,0x7f,0xec,0x3,0x5f,0xbb,0x95,0x29,0x3a,0x9b,0x7a,0x38,0xf7,0x81,0x3c,0xf4,0x25,0x20,0x96,0x4c,0x26,0x46,0x27,0x5b,0x1,0x48,0x73,0xc4,0x39,0xac,0x12,0xfe,0x4b,0xe6,0x30,0xc3,0x60,0x55,0xf,0xfa,0x9f,0x4a,0x85,0xd0,0xa3,0x62,0xde,0xc,0xe5,0xdb,0x71,0x1d,0xe1,0x9e,0x3e,0x90,0x5c,0x10,0xaf,0x24,0xf6,0x86,0x2e,0x8d,0xb8,0x51,0x70,0x5d,0x5e,0x80,0x93,0xa0,0x11,0x5a,0xb1,0x1e,0xed,0x52,0xcf,0x41,0x4f,0xe4,0x3b,0xa2,0x4,0x94,0xf3,0xdf,0xbe,0xd6,0x44,0xa6,0xe2,0x6b,0x36,0xa7,0x8e,0xb,0xcd,0x35,0xee,0xfd,0x54,0x6,0x6d,0x92,0xc0,0xad,0x33,0x22,0x74,0x7e,0xc9,0x21,0xbf,0xbd,0x67,0xd9,0x57,0x88,0x72,0x6a,0x18,0x65,0x2f,0xf9,0x37,0xaa,0x9,0xff,0x1b,0x42,0x64,0x13,0xda,0x2a,0x2d,0x8b,0x33,0x4e,0x1b,0x6b,0x97,0xd6,0xe5,0xd,0x5,0xff,0x94,0xfa,0xb,0xa5,0x27,0x6d,0xca,0x60,0x54,0xd5,0xfd,0xe4,0x76,0x92,0xae,0x28,0x18,0x29,0x30,0xa,0x40,0x35,0x3,0xc6,0x12,0xeb,0xb4,0xde,0x71,0x7e,0x0,0x37,0x5b,0x5d,0x7a,0xb1,0xdd,0x22,0x68,0xc0,0xa1,0x9c,0xc7,0x15,0xf,0x59,0x85,0xdc,0xdf,0x1,0xe6,0x53,0x63,0x31,0x47,0xba,0x48,0x99,0x44,0xe9,0xb0,0x8f,0xd9,0x66,0x96,0xd4,0xcc,0xe7,0xcd,0x61,0xc4,0x38,0x26,0x58,0xab,0x2f,0x17,0xa7,0x78,0xbf,0x3f,0xa0,0xee,0x3d,0xa3,0x6a,0xc9,0x11,0x8c,0xc8,0x7d,0x7,0xcf,0xda,0xe1,0x41,0x9a,0x91,0x3e,0x21,0x90,0x2b,0x7f,0xef,0x62,0xb8,0x86,0x5f,0x2a,0xbb,0xa8,0xc1,0x57,0xf2,0x9b,0xd2,0x81,0x1d,0x55,0xd0,0xaf,0x5a,0x20,0x4f,0xb5,0x1a,0xac,0x7b,0xf4,0x73,0x8d,0xfb,0xa4,0x6,0x10,0x82,0xb9,0x6f,0xa9,0xb2,0xe3,0x2,0xbe,0x25,0xad,0x67,0xa2,0x42,0xf9,0xd1,0x46,0x32,0x6c,0x4c,0xc3,0x1f,0x16,0xf3,0x3a,0xf7,0x36,0x70,0x9d,0x4d,0x19,0x80,0x79,0x1e,0xa6,0x52,0x7c,0x1c,0x56,0xc,0x9e,0xf6,0x34,0xd8,0x95,0xbc,0x65,0xb3,0xdb,0x98,0x5e,0x50,0x5c,0xd7,0x84,0xe0,0x8e,0x51,0x49,0x77,0xb6,0xaa,0xed,0x13,0x2c,0x74,0x3c,0x45,0x69,0xfe,0x8a,0x9,0x24,0xcb,0xc2,0xc5,0xfc,0xf1,0x93,0x2e,0x43,0x75,0x83,0x72,0x88,0x89,0xd3,0xce,0x39,0x64,0x3b,0x14,0xf8,0xea,0x4b,0x4,0xb7,0xbd,0x4a,0x9f,0xe8,0xec,0x87,0xf0,0xf5,0xe2,0x6e,0x8,0x23,0xe,0xfa,0x3d,0xe2,0x52,0x78,0xab,0xe5,0x7a,0x7d,0x81,0x24,0x88,0x6a,0xee,0x1d,0x63,0x23,0x9c,0xca,0xf5,0xa2,0x89,0x91,0xd3,0xff,0x2,0x74,0x26,0xac,0x1,0xdc,0xd,0x84,0xed,0xfe,0x6f,0x97,0xde,0xb7,0x12,0xaa,0x3a,0x6e,0xd5,0x1a,0xc3,0xfd,0x27,0x4,0xa4,0x9f,0x8a,0x64,0x7b,0xd4,0xdf,0x54,0x8c,0x2f,0xe6,0x42,0x38,0x8d,0xc9,0x6d,0xeb,0xd7,0x33,0x4f,0x75,0x6c,0x5d,0x25,0x8f,0x28,0x62,0xa1,0xb8,0x90,0x11,0xba,0x40,0x48,0xa0,0xe0,0x4e,0xbf,0xd1,0xb,0x76,0xce,0x68,0x93,0xd2,0x2e,0x5e,0x99,0xc0,0x1c,0x4a,0x16,0xa3,0x44,0x9a,0x85,0x2d,0x67,0x98,0x50,0x82,0xd9,0xe4,0x72,0x45,0x3b,0x34,0xf4,0x3f,0x18,0x1e,0x83,0x46,0x70,0x5,0x9b,0xf1,0xae,0x57,0x8e,0x61,0x4c,0xcf,0xb4,0xb9,0x80,0x87,0x31,0x69,0x56,0xa8,0xbb,0x2c,0x0,0x79,0x14,0xcb,0xa5,0xc1,0xef,0xf3,0x32,0xc,0xdd,0x9e,0xf6,0x20,0x92,0x19,0x15,0x1b,0xa7,0xb0,0xb5,0xc2,0x4b,0x66,0x4d,0x2b,0xf8,0xf2,0x41,0xe,0xa9,0xad,0xda,0xf,0x21,0x7c,0x8b,0x96,0xaf,0xbd,0x51,0x7e,0x30,0x6,0x6b,0xd6,0xcc,0xcd,0x37,0xc6,0x60,0xfb,0x47,0xa6,0x7,0xe7,0x22,0xe8,0xc7,0x55,0x43,0xe1,0xf7,0xec,0x2a,0xfc,0x3e,0xe9,0x5f,0xf0,0xbe,0xc8,0x36,0xb1,0x95,0x10,0x58,0xc4,0xa,0x65,0x1f,0xea,0xb3,0xdb,0x49,0x13,0xf9,0xd0,0x9d,0x71,0x5b,0x3c,0xc5,0x5c,0x59,0x39,0x17,0xe3,0xb2,0x7f,0xb6,0x53,0x8,0xd8,0x35,0x73,0x77,0x3,0x94,0xbc,0x5a,0x86,0x9,0x29,0x6,0xbe,0x98,0x8d,0xd8,0x15,0xc1,0xf1,0x84,0xc,0xf5,0x59,0x3e,0xac,0x33,0x52,0x48,0x8f,0x2a,0xc7,0x50,0xf9,0x89,0x68,0xaf,0x77,0x8,0x4f,0x2c,0xb4,0x5,0x2d,0x69,0x97,0x47,0x87,0x8b,0x45,0xd2,0x78,0xdf,0xc2,0x66,0x9d,0x16,0x4d,0x1c,0x2b,0x2,0x80,0xb5,0x83,0xf7,0x82,0x30,0xfc,0x3a,0x42,0x46,0xa9,0xfe,0x1a,0x6c,0xd0,0x51,0x74,0xad,0xeb,0x5f,0x40,0xee,0xc9,0xe1,0xd9,0x7a,0x92,0xcf,0x4b,0xc6,0xe0,0x8e,0x6e,0x26,0xb0,0xff,0xb7,0x94,0xb,0xe4,0x38,0xf3,0xed,0x91,0x1d,0x99,0xdd,0xf0,0x71,0xb9,0xca,0xd4,0x6d,0x39,0xae,0x5c,0x5a,0x3c,0x0,0xbd,0x29,0xdc,0xce,0xf6,0xec,0xcc,0xa6,0x53,0xa2,0xa5,0xf2,0x3d,0x13,0xaa,0x90,0x23,0x24,0x32,0x96,0x1f,0x54,0x5b,0xf4,0x17,0xa8,0x4,0x8a,0xa1,0xa,0xe7,0x7e,0xd1,0x41,0x9a,0xb6,0x93,0xfb,0xe3,0x1,0x2e,0xa7,0xe2,0x73,0x4e,0xcb,0x70,0x88,0xb8,0xab,0x43,0x11,0xd7,0x28,0xe8,0x85,0x67,0x76,0x3b,0x31,0x64,0x8c,0xf8,0xfa,0x9c,0x22,0xcd,0x12,0x2f,0x37,0x20,0x5d,0xbc,0x6a,0xef,0x72,0xba,0x4c,0x7,0x5e,0x56,0x21,0x6f,0x9f,0xde,0x7f,0x7d,0x3f,0xc4,0xb2,0xb1,0x79,0x65,0x60,0x9,0xd3,0x3,0x63,0x1e,0x62,0xd,0x44,0x81,0x36,0xe9,0x7c,0xbb,0x57,0xa3,0xe,0x86,0x75,0x10,0x25,0xbf,0x4a,0xf,0xda,0x95,0xc0,0x27,0xe6,0x49,0x9b,0x9e,0xa0,0x58,0x34,0xdb,0xa4,0xd5,0x7b,0x55,0x19,0x61,0xea,0xc3,0xb3,0xc8,0x6b,0x14,0xfd,0x18,0x35,0xc5,0x1b,0xe5,0xd6,0x36,0xca,0x3f,0x93,0x59,0xdd,0xd4,0xaa,0x8a,0x4d,0xe5,0x55,0x1c,0xcf,0xcd,0x52,0xb5,0x48,0x91,0xc3,0xb6,0x1b,0xba,0x6b,0x2b,0x94,0x42,0x7d,0x3e,0x15,0x64,0x26,0x8d,0x1d,0x62,0xd9,0x74,0xad,0x90,0x4a,0x5a,0x33,0xd8,0x49,0x69,0x20,0xa5,0x0,0x3b,0xe3,0x51,0x98,0x8f,0xf5,0x7e,0x3a,0x13,0xb3,0x3d,0x28,0xcc,0xd3,0x68,0x63,0x38,0x92,0xd5,0x9f,0xf,0x16,0xa6,0x27,0x5c,0xda,0x84,0x60,0xc2,0xf8,0xea,0xdb,0xc1,0xbc,0xdf,0x79,0x65,0x24,0xe9,0x99,0xf7,0xd,0x17,0xff,0xf9,0x57,0x66,0x8,0x9a,0x32,0x2f,0xd0,0x35,0xe7,0x53,0x6e,0x77,0x2e,0xfd,0xab,0x14,0xa1,0x2d,0xf3,0xf1,0x34,0xb2,0xc7,0x46,0x2c,0xe0,0x19,0xf2,0xc5,0x83,0x8c,0x88,0x43,0xa9,0xaf,0xde,0x86,0x1f,0xe1,0x9b,0xc,0xce,0xb7,0xd6,0x39,0x78,0xfb,0xe,0x3,0x30,0x37,0x29,0x6a,0x97,0x41,0xae,0x25,0xac,0xa2,0x7c,0xa3,0x76,0x12,0x44,0x58,0xbb,0x85,0x45,0x4f,0xb9,0xf6,0x1a,0x1e,0xb8,0x6d,0x7,0x10,0x75,0x2,0xd1,0xfc,0x9c,0xfa,0xb1,0x87,0x61,0xdc,0x7a,0x7b,0x71,0x80,0xcb,0x96,0x21,0x3c,0xa,0x18,0xc9,0xe6,0xe2,0x70,0x56,0xf4,0x5b,0x40,0x4b,0x9d,0x4c,0xd7,0x11,0xf0,0x50,0xb0,0x5f,0x95,0xa7,0x22,0x73,0xef,0xd2,0xbd,0x5d,0xa8,0x5e,0x89,0x47,0xe8,0x7f,0x9,0x6,0x81,0x8b,0xec,0xeb,0x72,0x8e,0xee,0x54,0xa0,0x6c,0x4,0xa4,0xfe,0x67,0x4e,0xc6,0x2a,0xb4,0xc0,0xb,0x23,0x31,0xed,0x9e,0xbe,0xc8,0x5,0xe4,0x1,0x6f,0xbf,0xc4,0x82,0x29,0x8f,0x37,0x4a,0x1f,0x6f,0x93,0xd2,0xe1,0x9,0x1,0xfb,0x90,0xfe,0xf,0xa1,0x23,0x69,0xce,0x64,0x50,0xd1,0xf9,0xe0,0x72,0x96,0xaa,0x2c,0x1c,0x2d,0x34,0xe,0x44,0x31,0x7,0xc2,0x16,0xef,0xb0,0xda,0x75,0x7a,0x4,0x33,0x5f,0x59,0x7e,0xb5,0xd9,0x26,0x6c,0xc4,0xa5,0x98,0xc3,0x11,0xb,0x5d,0x81,0xd8,0xdb,0x5,0xe2,0x57,0x67,0x35,0x43,0xbe,0x4c,0x9d,0x40,0xed,0xb4,0x8b,0xdd,0x62,0x92,0xd0,0xc8,0xe3,0xc9,0x65,0xc0,0x3c,0x22,0x5c,0xaf,0x2b,0x13,0xa3,0x7c,0xbb,0x3b,0xa4,0xea,0x39,0xa7,0x6e,0xcd,0x15,0x88,0xcc,0x79,0x3,0xcb,0xde,0xe5,0x45,0x9e,0x95,0x3a,0x25,0x94,0x2f,0x7b,0xeb,0x66,0xbc,0x82,0x5b,0x2e,0xbf,0xac,0xc5,0x53,0xf6,0x9f,0xd6,0x85,0x19,0x51,0xd4,0xab,0x5e,0x24,0x4b,0xb1,0x1e,0xa8,0x7f,0xf0,0x77,0x89,0xff,0xa0,0x2,0x14,0x86,0xbd,0x6b,0xad,0xb6,0xe7,0x6,0xba,0x21,0xa9,0x63,0xa6,0x46,0xfd,0xd5,0x42,0x36,0x68,0x48,0xc7,0x1b,0x12,0xf7,0x3e,0xf3,0x32,0x74,0x99,0x49,0x1d,0x84,0x7d,0x1a,0xa2,0x56,0x78,0x18,0x52,0x8,0x9a,0xf2,0x30,0xdc,0x91,0xb8,0x61,0xb7,0xdf,0x9c,0x5a,0x54,0x58,0xd3,0x80,0xe4,0x8a,0x55,0x4d,0x73,0xb2,0xae,0xe9,0x17,0x28,0x70,0x38,0x41,0x6d,0xfa,0x8e,0xd,0x20,0xcf,0xc6,0xc1,0xf8,0xf5,0x97,0x2a,0x47,0x71,0x87,0x76,0x8c,0x8d,0xd7,0xca,0x3d,0x60,0x3f,0x10,0xfc,0xee,0x4f,0x0,0xb3,0xb9,0x4e,0x9b,0xec,0xe8,0x83,0xf4,0xf1,0xe6,0x6a,0xc,0x27,0xa,0x1,0xc6,0x19,0xa9,0x83,0x50,0x1e,0x81,0x86,0x7a,0xdf,0x73,0x91,0x15,0xe6,0x98,0xd8,0x67,0x31,0xe,0x59,0x72,0x6a,0x28,0x4,0xf9,0x8f,0xdd,0x57,0xfa,0x27,0xf6,0x7f,0x16,0x5,0x94,0x6c,0x25,0x4c,0xe9,0x51,0xc1,0x95,0x2e,0xe1,0x38,0x6,0xdc,0xff,0x5f,0x64,0x71,0x9f,0x80,0x2f,0x24,0xaf,0x77,0xd4,0x1d,0xb9,0xc3,0x76,0x32,0x96,0x10,0x2c,0xc8,0xb4,0x8e,0x97,0xa6,0xde,0x74,0xd3,0x99,0x5a,0x43,0x6b,0xea,0x41,0xbb,0xb3,0x5b,0x1b,0xb5,0x44,0x2a,0xf0,0x8d,0x35,0x93,0x68,0x29,0xd5,0xa5,0x62,0x3b,0xe7,0xb1,0xed,0x58,0xbf,0x61,0x7e,0xd6,0x9c,0x63,0xab,0x79,0x22,0x1f,0x89,0xbe,0xc0,0xcf,0xf,0xc4,0xe3,0xe5,0x78,0xbd,0x8b,0xfe,0x60,0xa,0x55,0xac,0x75,0x9a,0xb7,0x34,0x4f,0x42,0x7b,0x7c,0xca,0x92,0xad,0x53,0x40,0xd7,0xfb,0x82,0xef,0x30,0x5e,0x3a,0x14,0x8,0xc9,0xf7,0x26,0x65,0xd,0xdb,0x69,0xe2,0xee,0xe0,0x5c,0x4b,0x4e,0x39,0xb0,0x9d,0xb6,0xd0,0x3,0x9,0xba,0xf5,0x52,0x56,0x21,0xf4,0xda,0x87,0x70,0x6d,0x54,0x46,0xaa,0x85,0xcb,0xfd,0x90,0x2d,0x37,0x36,0xcc,0x3d,0x9b,0x0,0xbc,0x5d,0xfc,0x1c,0xd9,0x13,0x3c,0xae,0xb8,0x1a,0xc,0x17,0xd1,0x7,0xc5,0x12,0xa4,0xb,0x45,0x33,0xcd,0x4a,0x6e,0xeb,0xa3,0x3f,0xf1,0x9e,0xe4,0x11,0x48,0x20,0xb2,0xe8,0x2,0x2b,0x66,0x8a,0xa0,0xc7,0x3e,0xa7,0xa2,0xc2,0xec,0x18,0x49,0x84,0x4d,0xa8,0xf3,0x23,0xce,0x88,0x8c,0xf8,0x6f,0x47,0xa1,0x7d,0xf2,0xd2,0xfc,0x5e,0x78,0xea,0x95,0x43,0x48,0x53,0xf8,0x19,0xdf,0x44,0x9d,0x57,0xb8,0x58,0xe7,0x7b,0x2a,0xaf,0xa0,0x55,0xb5,0xda,0xe0,0x4f,0x81,0x56,0x89,0xe,0x1,0x77,0x7a,0xe3,0xe4,0x83,0xa8,0x5c,0xe6,0x86,0xf6,0xac,0xc,0x64,0x22,0xce,0x46,0x6f,0x2b,0x3,0xc8,0xbc,0xb6,0x96,0xe5,0x39,0x9,0xec,0xd,0xc0,0x8a,0xcc,0xb7,0x67,0xe9,0x17,0x8e,0xd6,0xbf,0xc6,0x4,0x93,0xf3,0x70,0x31,0xde,0x3f,0x38,0xb,0x6,0x49,0x9f,0x62,0x21,0xaa,0xa4,0x2d,0xa6,0x1a,0x7e,0xab,0x74,0x8d,0xb3,0x50,0x4c,0xfe,0xb1,0x47,0x4d,0x65,0xb0,0x16,0x12,0xa,0x7d,0x18,0xf,0xf2,0x94,0xf4,0xd9,0xd4,0x69,0x8f,0xb9,0x88,0x79,0x73,0x72,0x34,0x29,0x9e,0xc3,0xee,0xc1,0x10,0x2,0x97,0xdd,0x9a,0x30,0x2f,0xae,0x1e,0x7,0x68,0x8c,0xd2,0x54,0xd3,0xe2,0xf0,0xca,0x71,0xd7,0xb4,0xc9,0x91,0xe1,0x2c,0x6d,0xf7,0x1f,0x5,0xff,0x0,0x6e,0x5f,0xf1,0xd8,0x27,0x3a,0x92,0x66,0x5b,0xef,0x3d,0xa3,0xf5,0x26,0x7f,0xfb,0x25,0xa9,0x1c,0xcf,0xba,0x3c,0xf9,0x11,0xe8,0x24,0x4e,0x84,0x8b,0xcd,0xfa,0xa7,0xa1,0x4b,0x80,0x9b,0x37,0xc2,0x3e,0xa2,0xdc,0xd5,0x51,0x5d,0xed,0x45,0x82,0x5a,0xc5,0xc7,0x14,0xcb,0x99,0x40,0xbd,0x63,0xb2,0x13,0xbe,0x75,0x4a,0x9c,0x23,0x2e,0x6c,0x1d,0x36,0xd1,0x6a,0x15,0x85,0x42,0x98,0xa5,0x7c,0x41,0xd0,0x3b,0x52,0x8,0xad,0x28,0x61,0x90,0x59,0xeb,0x33,0x32,0x76,0xfd,0x87,0x20,0x35,0xbb,0x1b,0x6b,0x60,0xdb,0xc4,0xa2,0x5e,0xab,0x7,0xcd,0x49,0x40,0x3e,0x1e,0xd9,0x71,0xc1,0x88,0x5b,0x59,0xc6,0x21,0xdc,0x5,0x57,0x22,0x8f,0x2e,0xff,0xbf,0x0,0xd6,0xe9,0xaa,0x81,0xf0,0xb2,0x19,0x89,0xf6,0x4d,0xe0,0x39,0x4,0xde,0xce,0xa7,0x4c,0xdd,0xfd,0xb4,0x31,0x94,0xaf,0x77,0xc5,0xc,0x1b,0x61,0xea,0xae,0x87,0x27,0xa9,0xbc,0x58,0x47,0xfc,0xf7,0xac,0x6,0x41,0xb,0x9b,0x82,0x32,0xb3,0xc8,0x4e,0x10,0xf4,0x56,0x6c,0x7e,0x4f,0x55,0x28,0x4b,0xed,0xf1,0xb0,0x7d,0xd,0x63,0x99,0x83,0x6b,0x6d,0xc3,0xf2,0x9c,0xe,0xa6,0xbb,0x44,0xa1,0x73,0xc7,0xfa,0xe3,0xba,0x69,0x3f,0x80,0x35,0xb9,0x67,0x65,0xa0,0x26,0x53,0xd2,0xb8,0x74,0x8d,0x66,0x51,0x17,0x18,0x1c,0xd7,0x3d,0x3b,0x4a,0x12,0x8b,0x75,0xf,0x98,0x5a,0x23,0x42,0xad,0xec,0x6f,0x9a,0x97,0xa4,0xa3,0xbd,0xfe,0x3,0xd5,0x3a,0xb1,0x38,0x36,0xe8,0x37,0xe2,0x86,0xd0,0xcc,0x2f,0x11,0xd1,0xdb,0x2d,0x62,0x8e,0x8a,0x2c,0xf9,0x93,0x84,0xe1,0x96,0x45,0x68,0x8,0x6e,0x25,0x13,0xf5,0x48,0xee,0xef,0xe5,0x14,0x5f,0x2,0xb5,0xa8,0x9e,0x8c,0x5d,0x72,0x76,0xe4,0xc2,0x60,0xcf,0xd4,0xdf,0x9,0xd8,0x43,0x85,0x64,0xc4,0x24,0xcb,0x1,0x33,0xb6,0xe7,0x7b,0x46,0x29,0xc9,0x3c,0xca,0x1d,0xd3,0x7c,0xeb,0x9d,0x92,0x15,0x1f,0x78,0x7f,0xe6,0x1a,0x7a,0xc0,0x34,0xf8,0x90,0x30,0x6a,0xf3,0xda,0x52,0xbe,0x20,0x54,0x9f,0xb7,0xa5,0x79,0xa,0x2a,0x5c,0x91,0x70,0x95,0xfb,0x2b,0x50,0x16,0xf,0xa9,0x11,0x6c,0x39,0x49,0xb5,0xf4,0xc7,0x2f,0x27,0xdd,0xb6,0xd8,0x29,0x87,0x5,0x4f,0xe8,0x42,0x76,0xf7,0xdf,0xc6,0x54,0xb0,0x8c,0xa,0x3a,0xb,0x12,0x28,0x62,0x17,0x21,0xe4,0x30,0xc9,0x96,0xfc,0x53,0x5c,0x22,0x15,0x79,0x7f,0x58,0x93,0xff,0x0,0x4a,0xe2,0x83,0xbe,0xe5,0x37,0x2d,0x7b,0xa7,0xfe,0xfd,0x23,0xc4,0x71,0x41,0x13,0x65,0x98,0x6a,0xbb,0x66,0xcb,0x92,0xad,0xfb,0x44,0xb4,0xf6,0xee,0xc5,0xef,0x43,0xe6,0x1a,0x4,0x7a,0x89,0xd,0x35,0x85,0x5a,0x9d,0x1d,0x82,0xcc,0x1f,0x81,0x48,0xeb,0x33,0xae,0xea,0x5f,0x25,0xed,0xf8,0xc3,0x63,0xb8,0xb3,0x1c,0x3,0xb2,0x9,0x5d,0xcd,0x40,0x9a,0xa4,0x7d,0x8,0x99,0x8a,0xe3,0x75,0xd0,0xb9,0xf0,0xa3,0x3f,0x77,0xf2,0x8d,0x78,0x2,0x6d,0x97,0x38,0x8e,0x59,0xd6,0x51,0xaf,0xd9,0x86,0x24,0x32,0xa0,0x9b,0x4d,0x8b,0x90,0xc1,0x20,0x9c,0x7,0x8f,0x45,0x80,0x60,0xdb,0xf3,0x64,0x10,0x4e,0x6e,0xe1,0x3d,0x34,0xd1,0x18,0xd5,0x14,0x52,0xbf,0x6f,0x3b,0xa2,0x5b,0x3c,0x84,0x70,0x5e,0x3e,0x74,0x2e,0xbc,0xd4,0x16,0xfa,0xb7,0x9e,0x47,0x91,0xf9,0xba,0x7c,0x72,0x7e,0xf5,0xa6,0xc2,0xac,0x73,0x6b,0x55,0x94,0x88,0xcf,0x31,0xe,0x56,0x1e,0x67,0x4b,0xdc,0xa8,0x2b,0x6,0xe9,0xe0,0xe7,0xde,0xd3,0xb1,0xc,0x61,0x57,0xa1,0x50,0xaa,0xab,0xf1,0xec,0x1b,0x46,0x19,0x36,0xda,0xc8,0x69,0x26,0x95,0x9f,0x68,0xbd,0xca,0xce,0xa5,0xd2,0xd7,0xc0,0x4c,0x2a,0x1,0x2c,0xab,0x6c,0xb3,0x3,0x29,0xfa,0xb4,0x2b,0x2c,0xd0,0x75,0xd9,0x3b,0xbf,0x4c,0x32,0x72,0xcd,0x9b,0xa4,0xf3,0xd8,0xc0,0x82,0xae,0x53,0x25,0x77,0xfd,0x50,0x8d,0x5c,0xd5,0xbc,0xaf,0x3e,0xc6,0x8f,0xe6,0x43,0xfb,0x6b,0x3f,0x84,0x4b,0x92,0xac,0x76,0x55,0xf5,0xce,0xdb,0x35,0x2a,0x85,0x8e,0x5,0xdd,0x7e,0xb7,0x13,0x69,0xdc,0x98,0x3c,0xba,0x86,0x62,0x1e,0x24,0x3d,0xc,0x74,0xde,0x79,0x33,0xf0,0xe9,0xc1,0x40,0xeb,0x11,0x19,0xf1,0xb1,0x1f,0xee,0x80,0x5a,0x27,0x9f,0x39,0xc2,0x83,0x7f,0xf,0xc8,0x91,0x4d,0x1b,0x47,0xf2,0x15,0xcb,0xd4,0x7c,0x36,0xc9,0x1,0xd3,0x88,0xb5,0x23,0x14,0x6a,0x65,0xa5,0x6e,0x49,0x4f,0xd2,0x17,0x21,0x54,0xca,0xa0,0xff,0x6,0xdf,0x30,0x1d,0x9e,0xe5,0xe8,0xd1,0xd6,0x60,0x38,0x7,0xf9,0xea,0x7d,0x51,0x28,0x45,0x9a,0xf4,0x90,0xbe,0xa2,0x63,0x5d,0x8c,0xcf,0xa7,0x71,0xc3,0x48,0x44,0x4a,0xf6,0xe1,0xe4,0x93,0x1a,0x37,0x1c,0x7a,0xa9,0xa3,0x10,0x5f,0xf8,0xfc,0x8b,0x5e,0x70,0x2d,0xda,0xc7,0xfe,0xec,0x0,0x2f,0x61,0x57,0x3a,0x87,0x9d,0x9c,0x66,0x97,0x31,0xaa,0x16,0xf7,0x56,0xb6,0x73,0xb9,0x96,0x4,0x12,0xb0,0xa6,0xbd,0x7b,0xad,0x6f,0xb8,0xe,0xa1,0xef,0x99,0x67,0xe0,0xc4,0x41,0x9,0x95,0x5b,0x34,0x4e,0xbb,0xe2,0x8a,0x18,0x42,0xa8,0x81,0xcc,0x20,0xa,0x6d,0x94,0xd,0x8,0x68,0x46,0xb2,0xe3,0x2e,0xe7,0x2,0x59,0x89,0x64,0x22,0x26,0x52,0xc5,0xed,0xb,0xd7,0x58,0x78,0x89,0x2b,0xd,0x9f,0xe0,0x36,0x3d,0x26,0x8d,0x6c,0xaa,0x31,0xe8,0x22,0xcd,0x2d,0x92,0xe,0x5f,0xda,0xd5,0x20,0xc0,0xaf,0x95,0x3a,0xf4,0x23,0xfc,0x7b,0x74,0x2,0xf,0x96,0x91,0xf6,0xdd,0x29,0x93,0xf3,0x83,0xd9,0x79,0x11,0x57,0xbb,0x33,0x1a,0x5e,0x76,0xbd,0xc9,0xc3,0xe3,0x90,0x4c,0x7c,0x99,0x78,0xb5,0xff,0xb9,0xc2,0x12,0x9c,0x62,0xfb,0xa3,0xca,0xb3,0x71,0xe6,0x86,0x5,0x44,0xab,0x4a,0x4d,0x7e,0x73,0x3c,0xea,0x17,0x54,0xdf,0xd1,0x58,0xd3,0x6f,0xb,0xde,0x1,0xf8,0xc6,0x25,0x39,0x8b,0xc4,0x32,0x38,0x10,0xc5,0x63,0x67,0x7f,0x8,0x6d,0x7a,0x87,0xe1,0x81,0xac,0xa1,0x1c,0xfa,0xcc,0xfd,0xc,0x6,0x7,0x41,0x5c,0xeb,0xb6,0x9b,0xb4,0x65,0x77,0xe2,0xa8,0xef,0x45,0x5a,0xdb,0x6b,0x72,0x1d,0xf9,0xa7,0x21,0xa6,0x97,0x85,0xbf,0x4,0xa2,0xc1,0xbc,0xe4,0x94,0x59,0x18,0x82,0x6a,0x70,0x8a,0x75,0x1b,0x2a,0x84,0xad,0x52,0x4f,0xe7,0x13,0x2e,0x9a,0x48,0xd6,0x80,0x53,0xa,0x8e,0x50,0xdc,0x69,0xba,0xcf,0x49,0x8c,0x64,0x9d,0x51,0x3b,0xf1,0xfe,0xb8,0x8f,0xd2,0xd4,0x3e,0xf5,0xee,0x42,0xb7,0x4b,0xd7,0xa9,0xa0,0x24,0x28,0x98,0x30,0xf7,0x2f,0xb0,0xb2,0x61,0xbe,0xec,0x35,0xc8,0x16,0xc7,0x66,0xcb,0x0,0x3f,0xe9,0x56,0x5b,0x19,0x68,0x43,0xa4,0x1f,0x60,0xf0,0x37,0xed,0xd0,0x9,0x34,0xa5,0x4e,0x27,0x7d,0xd8,0x5d,0x14,0xe5,0x2c,0x9e,0x46,0x47,0x3,0x88,0xf2,0x55,0x40,0xce,0x6e,0x1e,0x15,0xae,0xb1,0xdb,0x27,0xd2,0x7e,0xb4,0x30,0x39,0x47,0x67,0xa0,0x8,0xb8,0xf1,0x22,0x20,0xbf,0x58,0xa5,0x7c,0x2e,0x5b,0xf6,0x57,0x86,0xc6,0x79,0xaf,0x90,0xd3,0xf8,0x89,0xcb,0x60,0xf0,0x8f,0x34,0x99,0x40,0x7d,0xa7,0xb7,0xde,0x35,0xa4,0x84,0xcd,0x48,0xed,0xd6,0xe,0xbc,0x75,0x62,0x18,0x93,0xd7,0xfe,0x5e,0xd0,0xc5,0x21,0x3e,0x85,0x8e,0xd5,0x7f,0x38,0x72,0xe2,0xfb,0x4b,0xca,0xb1,0x37,0x69,0x8d,0x2f,0x15,0x7,0x36,0x2c,0x51,0x32,0x94,0x88,0xc9,0x4,0x74,0x1a,0xe0,0xfa,0x12,0x14,0xba,0x8b,0xe5,0x77,0xdf,0xc2,0x3d,0xd8,0xa,0xbe,0x83,0x9a,0xc3,0x10,0x46,0xf9,0x4c,0xc0,0x1e,0x1c,0xd9,0x5f,0x2a,0xab,0xc1,0xd,0xf4,0x1f,0x28,0x6e,0x61,0x65,0xae,0x44,0x42,0x33,0x6b,0xf2,0xc,0x76,0xe1,0x23,0x5a,0x3b,0xd4,0x95,0x16,0xe3,0xee,0xdd,0xda,0xc4,0x87,0x7a,0xac,0x43,0xc8,0x41,0x4f,0x91,0x4e,0x9b,0xff,0xa9,0xb5,0x56,0x68,0xa8,0xa2,0x54,0x1b,0xf7,0xf3,0x55,0x80,0xea,0xfd,0x98,0xef,0x3c,0x11,0x71,0x17,0x5c,0x6a,0x8c,0x31,0x97,0x96,0x9c,0x6d,0x26,0x7b,0xcc,0xd1,0xe7,0xf5,0x24,0xb,0xf,0x9d,0xbb,0x19,0xb6,0xad,0xa6,0x70,0xa1,0x3a,0xfc,0x1d,0xbd,0x5d,0xb2,0x78,0x4a,0xcf,0x9e,0x2,0x3f,0x50,0xb0,0x45,0xb3,0x64,0xaa,0x5,0x92,0xe4,0xeb,0x6c,0x66,0x1,0x6,0x9f,0x63,0x3,0xb9,0x4d,0x81,0xe9,0x49,0x13,0x8a,0xa3,0x2b,0xc7,0x59,0x2d,0xe6,0xce,0xdc,0x0,0x73,0x53,0x25,0xe8,0x9,0xec,0x82,0x52,0x29,0x6f,0x8f,0x29,0x91,0xec,0xb9,0xc9,0x35,0x74,0x47,0xaf,0xa7,0x5d,0x36,0x58,0xa9,0x7,0x85,0xcf,0x68,0xc2,0xf6,0x77,0x5f,0x46,0xd4,0x30,0xc,0x8a,0xba,0x8b,0x92,0xa8,0xe2,0x97,0xa1,0x64,0xb0,0x49,0x16,0x7c,0xd3,0xdc,0xa2,0x95,0xf9,0xff,0xd8,0x13,0x7f,0x80,0xca,0x62,0x3,0x3e,0x65,0xb7,0xad,0xfb,0x27,0x7e,0x7d,0xa3,0x44,0xf1,0xc1,0x93,0xe5,0x18,0xea,0x3b,0xe6,0x4b,0x12,0x2d,0x7b,0xc4,0x34,0x76,0x6e,0x45,0x6f,0xc3,0x66,0x9a,0x84,0xfa,0x9,0x8d,0xb5,0x5,0xda,0x1d,0x9d,0x2,0x4c,0x9f,0x1,0xc8,0x6b,0xb3,0x2e,0x6a,0xdf,0xa5,0x6d,0x78,0x43,0xe3,0x38,0x33,0x9c,0x83,0x32,0x89,0xdd,0x4d,0xc0,0x1a,0x24,0xfd,0x88,0x19,0xa,0x63,0xf5,0x50,0x39,0x70,0x23,0xbf,0xf7,0x72,0xd,0xf8,0x82,0xed,0x17,0xb8,0xe,0xd9,0x56,0xd1,0x2f,0x59,0x6,0xa4,0xb2,0x20,0x1b,0xcd,0xb,0x10,0x41,0xa0,0x1c,0x87,0xf,0xc5,0x0,0xe0,0x5b,0x73,0xe4,0x90,0xce,0xee,0x61,0xbd,0xb4,0x51,0x98,0x55,0x94,0xd2,0x3f,0xef,0xbb,0x22,0xdb,0xbc,0x4,0xf0,0xde,0xbe,0xf4,0xae,0x3c,0x54,0x96,0x7a,0x37,0x1e,0xc7,0x11,0x79,0x3a,0xfc,0xf2,0xfe,0x75,0x26,0x42,0x2c,0xf3,0xeb,0xd5,0x14,0x8,0x4f,0xb1,0x8e,0xd6,0x9e,0xe7,0xcb,0x5c,0x28,0xab,0x86,0x69,0x60,0x67,0x5e,0x53,0x31,0x8c,0xe1,0xd7,0x21,0xd0,0x2a,0x2b,0x71,0x6c,0x9b,0xc6,0x99,0xb6,0x5a,0x48,0xe9,0xa6,0x15,0x1f,0xe8,0x3d,0x4a,0x4e,0x25,0x52,0x57,0x40,0xcc,0xaa,0x81,0xac,0x55,0x92,0x4d,0xfd,0xd7,0x4,0x4a,0xd5,0xd2,0x2e,0x8b,0x27,0xc5,0x41,0xb2,0xcc,0x8c,0x33,0x65,0x5a,0xd,0x26,0x3e,0x7c,0x50,0xad,0xdb,0x89,0x3,0xae,0x73,0xa2,0x2b,0x42,0x51,0xc0,0x38,0x71,0x18,0xbd,0x5,0x95,0xc1,0x7a,0xb5,0x6c,0x52,0x88,0xab,0xb,0x30,0x25,0xcb,0xd4,0x7b,0x70,0xfb,0x23,0x80,0x49,0xed,0x97,0x22,0x66,0xc2,0x44,0x78,0x9c,0xe0,0xda,0xc3,0xf2,0x8a,0x20,0x87,0xcd,0xe,0x17,0x3f,0xbe,0x15,0xef,0xe7,0xf,0x4f,0xe1,0x10,0x7e,0xa4,0xd9,0x61,0xc7,0x3c,0x7d,0x81,0xf1,0x36,0x6f,0xb3,0xe5,0xb9,0xc,0xeb,0x35,0x2a,0x82,0xc8,0x37,0xff,0x2d,0x76,0x4b,0xdd,0xea,0x94,0x9b,0x5b,0x90,0xb7,0xb1,0x2c,0xe9,0xdf,0xaa,0x34,0x5e,0x1,0xf8,0x21,0xce,0xe3,0x60,0x1b,0x16,0x2f,0x28,0x9e,0xc6,0xf9,0x7,0x14,0x83,0xaf,0xd6,0xbb,0x64,0xa,0x6e,0x40,0x5c,0x9d,0xa3,0x72,0x31,0x59,0x8f,0x3d,0xb6,0xba,0xb4,0x8,0x1f,0x1a,0x6d,0xe4,0xc9,0xe2,0x84,0x57,0x5d,0xee,0xa1,0x6,0x2,0x75,0xa0,0x8e,0xd3,0x24,0x39,0x0,0x12,0xfe,0xd1,0x9f,0xa9,0xc4,0x79,0x63,0x62,0x98,0x69,0xcf,0x54,0xe8,0x9,0xa8,0x48,0x8d,0x47,0x68,0xfa,0xec,0x4e,0x58,0x43,0x85,0x53,0x91,0x46,0xf0,0x5f,0x11,0x67,0x99,0x1e,0x3a,0xbf,0xf7,0x6b,0xa5,0xca,0xb0,0x45,0x1c,0x74,0xe6,0xbc,0x56,0x7f,0x32,0xde,0xf4,0x93,0x6a,0xf3,0xf6,0x96,0xb8,0x4c,0x1d,0xd0,0x19,0xfc,0xa7,0x77,0x9a,0xdc,0xd8,0xac,0x3b,0x13,0xf5,0x29,0xa6,0x86,0x27,0x85,0xa3,0x31,0x4e,0x98,0x93,0x88,0x23,0xc2,0x4,0x9f,0x46,0x8c,0x63,0x83,0x3c,0xa0,0xf1,0x74,0x7b,0x8e,0x6e,0x1,0x3b,0x94,0x5a,0x8d,0x52,0xd5,0xda,0xac,0xa1,0x38,0x3f,0x58,0x73,0x87,0x3d,0x5d,0x2d,0x77,0xd7,0xbf,0xf9,0x15,0x9d,0xb4,0xf0,0xd8,0x13,0x67,0x6d,0x4d,0x3e,0xe2,0xd2,0x37,0xd6,0x1b,0x51,0x17,0x6c,0xbc,0x32,0xcc,0x55,0xd,0x64,0x1d,0xdf,0x48,0x28,0xab,0xea,0x5,0xe4,0xe3,0xd0,0xdd,0x92,0x44,0xb9,0xfa,0x71,0x7f,0xf6,0x7d,0xc1,0xa5,0x70,0xaf,0x56,0x68,0x8b,0x97,0x25,0x6a,0x9c,0x96,0xbe,0x6b,0xcd,0xc9,0xd1,0xa6,0xc3,0xd4,0x29,0x4f,0x2f,0x2,0xf,0xb2,0x54,0x62,0x53,0xa2,0xa8,0xa9,0xef,0xf2,0x45,0x18,0x35,0x1a,0xcb,0xd9,0x4c,0x6,0x41,0xeb,0xf4,0x75,0xc5,0xdc,0xb3,0x57,0x9,0x8f,0x8,0x39,0x2b,0x11,0xaa,0xc,0x6f,0x12,0x4a,0x3a,0xf7,0xb6,0x2c,0xc4,0xde,0x24,0xdb,0xb5,0x84,0x2a,0x3,0xfc,0xe1,0x49,0xbd,0x80,0x34,0xe6,0x78,0x2e,0xfd,0xa4,0x20,0xfe,0x72,0xc7,0x14,0x61,0xe7,0x22,0xca,0x33,0xff,0x95,0x5f,0x50,0x16,0x21,0x7c,0x7a,0x90,0x5b,0x40,0xec,0x19,0xe5,0x79,0x7,0xe,0x8a,0x86,0x36,0x9e,0x59,0x81,0x1e,0x1c,0xcf,0x10,0x42,0x9b,0x66,0xb8,0x69,0xc8,0x65,0xae,0x91,0x47,0xf8,0xf5,0xb7,0xc6,0xed,0xa,0xb1,0xce,0x5e,0x99,0x43,0x7e,0xa7,0x9a,0xb,0xe0,0x89,0xd3,0x76,0xf3,0xba,0x4b,0x82,0x30,0xe8,0xe9,0xad,0x26,0x5c,0xfb,0xee,0x60,0xc0,0xb0,0xbb,0x0,0x1f,0xd7,0x2b,0xde,0x72,0xb8,0x3c,0x35,0x4b,0x6b,0xac,0x4,0xb4,0xfd,0x2e,0x2c,0xb3,0x54,0xa9,0x70,0x22,0x57,0xfa,0x5b,0x8a,0xca,0x75,0xa3,0x9c,0xdf,0xf4,0x85,0xc7,0x6c,0xfc,0x83,0x38,0x95,0x4c,0x71,0xab,0xbb,0xd2,0x39,0xa8,0x88,0xc1,0x44,0xe1,0xda,0x2,0xb0,0x79,0x6e,0x14,0x9f,0xdb,0xf2,0x52,0xdc,0xc9,0x2d,0x32,0x89,0x82,0xd9,0x73,0x34,0x7e,0xee,0xf7,0x47,0xc6,0xbd,0x3b,0x65,0x81,0x23,0x19,0xb,0x3a,0x20,0x5d,0x3e,0x98,0x84,0xc5,0x8,0x78,0x16,0xec,0xf6,0x1e,0x18,0xb6,0x87,0xe9,0x7b,0xd3,0xce,0x31,0xd4,0x6,0xb2,0x8f,0x96,0xcf,0x1c,0x4a,0xf5,0x40,0xcc,0x12,0x10,0xd5,0x53,0x26,0xa7,0xcd,0x1,0xf8,0x13,0x24,0x62,0x6d,0x69,0xa2,0x48,0x4e,0x3f,0x67,0xfe,0x0,0x7a,0xed,0x2f,0x56,0x37,0xd8,0x99,0x1a,0xef,0xe2,0xd1,0xd6,0xc8,0x8b,0x76,0xa0,0x4f,0xc4,0x4d,0x43,0x9d,0x42,0x97,0xf3,0xa5,0xb9,0x5a,0x64,0xa4,0xae,0x58,0x17,0xfb,0xff,0x59,0x8c,0xe6,0xf1,0x94,0xe3,0x30,0x1d,0x7d,0x1b,0x50,0x66,0x80,0x3d,0x9b,0x9a,0x90,0x61,0x2a,0x77,0xc0,0xdd,0xeb,0xf9,0x28,0x7,0x3,0x91,0xb7,0x15,0xba,0xa1,0xaa,0x7c,0xad,0x36,0xf0,0x11,0xb1,0x51,0xbe,0x74,0x46,0xc3,0x92,0xe,0x33,0x5c,0xbc,0x49,0xbf,0x68,0xa6,0x9,0x9e,0xe8,0xe7,0x60,0x6a,0xd,0xa,0x93,0x6f,0xf,0xb5,0x41,0x8d,0xe5,0x45,0x1f,0x86,0xaf,0x27,0xcb,0x55,0x21,0xea,0xc2,0xd0,0xc,0x7f,0x5f,0x29,0xe4,0x5,0xe0,0x8e,0x5e,0x25,0x63,0xcc,0x6a,0xd2,0xaf,0xfa,0x8a,0x76,0x37,0x4,0xec,0xe4,0x1e,0x75,0x1b,0xea,0x44,0xc6,0x8c,0x2b,0x81,0xb5,0x34,0x1c,0x5,0x97,0x73,0x4f,0xc9,0xf9,0xc8,0xd1,0xeb,0xa1,0xd4,0xe2,0x27,0xf3,0xa,0x55,0x3f,0x90,0x9f,0xe1,0xd6,0xba,0xbc,0x9b,0x50,0x3c,0xc3,0x89,0x21,0x40,0x7d,0x26,0xf4,0xee,0xb8,0x64,0x3d,0x3e,0xe0,0x7,0xb2,0x82,0xd0,0xa6,0x5b,0xa9,0x78,0xa5,0x8,0x51,0x6e,0x38,0x87,0x77,0x35,0x2d,0x6,0x2c,0x80,0x25,0xd9,0xc7,0xb9,0x4a,0xce,0xf6,0x46,0x99,0x5e,0xde,0x41,0xf,0xdc,0x42,0x8b,0x28,0xf0,0x6d,0x29,0x9c,0xe6,0x2e,0x3b,0x0,0xa0,0x7b,0x70,0xdf,0xc0,0x71,0xca,0x9e,0xe,0x83,0x59,0x67,0xbe,0xcb,0x5a,0x49,0x20,0xb6,0x13,0x7a,0x33,0x60,0xfc,0xb4,0x31,0x4e,0xbb,0xc1,0xae,0x54,0xfb,0x4d,0x9a,0x15,0x92,0x6c,0x1a,0x45,0xe7,0xf1,0x63,0x58,0x8e,0x48,0x53,0x2,0xe3,0x5f,0xc4,0x4c,0x86,0x43,0xa3,0x18,0x30,0xa7,0xd3,0x8d,0xad,0x22,0xfe,0xf7,0x12,0xdb,0x16,0xd7,0x91,0x7c,0xac,0xf8,0x61,0x98,0xff,0x47,0xb3,0x9d,0xfd,0xb7,0xed,0x7f,0x17,0xd5,0x39,0x74,0x5d,0x84,0x52,0x3a,0x79,0xbf,0xb1,0xbd,0x36,0x65,0x1,0x6f,0xb0,0xa8,0x96,0x57,0x4b,0xc,0xf2,0xcd,0x95,0xdd,0xa4,0x88,0x1f,0x6b,0xe8,0xc5,0x2a,0x23,0x24,0x1d,0x10,0x72,0xcf,0xa2,0x94,0x62,0x93,0x69,0x68,0x32,0x2f,0xd8,0x85,0xda,0xf5,0x19,0xb,0xaa,0xe5,0x56,0x5c,0xab,0x7e,0x9,0xd,0x66,0x11,0x14,0x3,0x8f,0xe9,0xc2,0xef,0xb5,0x72,0xad,0x1d,0x37,0xe4,0xaa,0x35,0x32,0xce,0x6b,0xc7,0x25,0xa1,0x52,0x2c,0x6c,0xd3,0x85,0xba,0xed,0xc6,0xde,0x9c,0xb0,0x4d,0x3b,0x69,0xe3,0x4e,0x93,0x42,0xcb,0xa2,0xb1,0x20,0xd8,0x91,0xf8,0x5d,0xe5,0x75,0x21,0x9a,0x55,0x8c,0xb2,0x68,0x4b,0xeb,0xd0,0xc5,0x2b,0x34,0x9b,0x90,0x1b,0xc3,0x60,0xa9,0xd,0x77,0xc2,0x86,0x22,0xa4,0x98,0x7c,0x0,0x3a,0x23,0x12,0x6a,0xc0,0x67,0x2d,0xee,0xf7,0xdf,0x5e,0xf5,0xf,0x7,0xef,0xaf,0x1,0xf0,0x9e,0x44,0x39,0x81,0x27,0xdc,0x9d,0x61,0x11,0xd6,0x8f,0x53,0x5,0x59,0xec,0xb,0xd5,0xca,0x62,0x28,0xd7,0x1f,0xcd,0x96,0xab,0x3d,0xa,0x74,0x7b,0xbb,0x70,0x57,0x51,0xcc,0x9,0x3f,0x4a,0xd4,0xbe,0xe1,0x18,0xc1,0x2e,0x3,0x80,0xfb,0xf6,0xcf,0xc8,0x7e,0x26,0x19,0xe7,0xf4,0x63,0x4f,0x36,0x5b,0x84,0xea,0x8e,0xa0,0xbc,0x7d,0x43,0x92,0xd1,0xb9,0x6f,0xdd,0x56,0x5a,0x54,0xe8,0xff,0xfa,0x8d,0x4,0x29,0x2,0x64,0xb7,0xbd,0xe,0x41,0xe6,0xe2,0x95,0x40,0x6e,0x33,0xc4,0xd9,0xe0,0xf2,0x1e,0x31,0x7f,0x49,0x24,0x99,0x83,0x82,0x78,0x89,0x2f,0xb4,0x8,0xe9,0x48,0xa8,0x6d,0xa7,0x88,0x1a,0xc,0xae,0xb8,0xa3,0x65,0xb3,0x71,0xa6,0x10,0xbf,0xf1,0x87,0x79,0xfe,0xda,0x5f,0x17,0x8b,0x45,0x2a,0x50,0xa5,0xfc,0x94,0x6,0x5c,0xb6,0x9f,0xd2,0x3e,0x14,0x73,0x8a,0x13,0x16,0x76,0x58,0xac,0xfd,0x30,0xf9,0x1c,0x47,0x97,0x7a,0x3c,0x38,0x4c,0xdb,0xf3,0x15,0xc9,0x46,0x66,0x26,0x84,0xa2,0x30,0x4f,0x99,0x92,0x89,0x22,0xc3,0x5,0x9e,0x47,0x8d,0x62,0x82,0x3d,0xa1,0xf0,0x75,0x7a,0x8f,0x6f,0x0,0x3a,0x95,0x5b,0x8c,0x53,0xd4,0xdb,0xad,0xa0,0x39,0x3e,0x59,0x72,0x86,0x3c,0x5c,0x2c,0x76,0xd6,0xbe,0xf8,0x14,0x9c,0xb5,0xf1,0xd9,0x12,0x66,0x6c,0x4c,0x3f,0xe3,0xd3,0x36,0xd7,0x1a,0x50,0x16,0x6d,0xbd,0x33,0xcd,0x54,0xc,0x65,0x1c,0xde,0x49,0x29,0xaa,0xeb,0x4,0xe5,0xe2,0xd1,0xdc,0x93,0x45,0xb8,0xfb,0x70,0x7e,0xf7,0x7c,0xc0,0xa4,0x71,0xae,0x57,0x69,0x8a,0x96,0x24,0x6b,0x9d,0x97,0xbf,0x6a,0xcc,0xc8,0xd0,0xa7,0xc2,0xd5,0x28,0x4e,0x2e,0x3,0xe,0xb3,0x55,0x63,0x52,0xa3,0xa9,0xa8,0xee,0xf3,0x44,0x19,0x34,0x1b,0xca,0xd8,0x4d,0x7,0x40,0xea,0xf5,0x74,0xc4,0xdd,0xb2,0x56,0x8,0x8e,0x9,0x38,0x2a,0x10,0xab,0xd,0x6e,0x13,0x4b,0x3b,0xf6,0xb7,0x2d,0xc5,0xdf,0x25,0xda,0xb4,0x85,0x2b,0x2,0xfd,0xe0,0x48,0xbc,0x81,0x35,0xe7,0x79,0x2f,0xfc,0xa5,0x21,0xff,0x73,0xc6,0x15,0x60,0xe6,0x23,0xcb,0x32,0xfe,0x94,0x5e,0x51,0x17,0x20,0x7d,0x7b,0x91,0x5a,0x41,0xed,0x18,0xe4,0x78,0x6,0xf,0x8b,0x87,0x37,0x9f,0x58,0x80,0x1f,0x1d,0xce,0x11,0x43,0x9a,0x67,0xb9,0x68,0xc9,0x64,0xaf,0x90,0x46,0xf9,0xf4,0xb6,0xc7,0xec,0xb,0xb0,0xcf,0x5f,0x98,0x42,0x7f,0xa6,0x9b,0xa,0xe1,0x88,0xd2,0x77,0xf2,0xbb,0x4a,0x83,0x31,0xe9,0xe8,0xac,0x27,0x5d,0xfa,0xef,0x61,0xc1,0xb1,0xba,0x1,0x1e,0x99,0x65,0x90,0x3c,0xf6,0x72,0x7b,0x5,0x25,0xe2,0x4a,0xfa,0xb3,0x60,0x62,0xfd,0x1a,0xe7,0x3e,0x6c,0x19,0xb4,0x15,0xc4,0x84,0x3b,0xed,0xd2,0x91,0xba,0xcb,0x89,0x22,0xb2,0xcd,0x76,0xdb,0x2,0x3f,0xe5,0xf5,0x9c,0x77,0xe6,0xc6,0x8f,0xa,0xaf,0x94,0x4c,0xfe,0x37,0x20,0x5a,0xd1,0x95,0xbc,0x1c,0x92,0x87,0x63,0x7c,0xc7,0xcc,0x97,0x3d,0x7a,0x30,0xa0,0xb9,0x9,0x88,0xf3,0x75,0x2b,0xcf,0x6d,0x57,0x45,0x74,0x6e,0x13,0x70,0xd6,0xca,0x8b,0x46,0x36,0x58,0xa2,0xb8,0x50,0x56,0xf8,0xc9,0xa7,0x35,0x9d,0x80,0x7f,0x9a,0x48,0xfc,0xc1,0xd8,0x81,0x52,0x4,0xbb,0xe,0x82,0x5c,0x5e,0x9b,0x1d,0x68,0xe9,0x83,0x4f,0xb6,0x5d,0x6a,0x2c,0x23,0x27,0xec,0x6,0x0,0x71,0x29,0xb0,0x4e,0x34,0xa3,0x61,0x18,0x79,0x96,0xd7,0x54,0xa1,0xac,0x9f,0x98,0x86,0xc5,0x38,0xee,0x1,0x8a,0x3,0xd,0xd3,0xc,0xd9,0xbd,0xeb,0xf7,0x14,0x2a,0xea,0xe0,0x16,0x59,0xb5,0xb1,0x17,0xc2,0xa8,0xbf,0xda,0xad,0x7e,0x53,0x33,0x55,0x1e,0x28,0xce,0x73,0xd5,0xd4,0xde,0x2f,0x64,0x39,0x8e,0x93,0xa5,0xb7,0x66,0x49,0x4d,0xdf,0xf9,0x5b,0xf4,0xef,0xe4,0x32,0xe3,0x78,0xbe,0x5f,0xff,0x1f,0xf0,0x3a,0x8,0x8d,0xdc,0x40,0x7d,0x12,0xf2,0x7,0xf1,0x26,0xe8,0x47,0xd0,0xa6,0xa9,0x2e,0x24,0x43,0x44,0xdd,0x21,0x41,0xfb,0xf,0xc3,0xab,0xb,0x51,0xc8,0xe1,0x69,0x85,0x1b,0x6f,0xa4,0x8c,0x9e,0x42,0x31,0x11,0x67,0xaa,0x4b,0xae,0xc0,0x10,0x6b,0x2d,0xca,0x6c,0xd4,0xa9,0xfc,0x8c,0x70,0x31,0x2,0xea,0xe2,0x18,0x73,0x1d,0xec,0x42,0xc0,0x8a,0x2d,0x87,0xb3,0x32,0x1a,0x3,0x91,0x75,0x49,0xcf,0xff,0xce,0xd7,0xed,0xa7,0xd2,0xe4,0x21,0xf5,0xc,0x53,0x39,0x96,0x99,0xe7,0xd0,0xbc,0xba,0x9d,0x56,0x3a,0xc5,0x8f,0x27,0x46,0x7b,0x20,0xf2,0xe8,0xbe,0x62,0x3b,0x38,0xe6,0x1,0xb4,0x84,0xd6,0xa0,0x5d,0xaf,0x7e,0xa3,0xe,0x57,0x68,0x3e,0x81,0x71,0x33,0x2b,0x0,0x2a,0x86,0x23,0xdf,0xc1,0xbf,0x4c,0xc8,0xf0,0x40,0x9f,0x58,0xd8,0x47,0x9,0xda,0x44,0x8d,0x2e,0xf6,0x6b,0x2f,0x9a,0xe0,0x28,0x3d,0x6,0xa6,0x7d,0x76,0xd9,0xc6,0x77,0xcc,0x98,0x8,0x85,0x5f,0x61,0xb8,0xcd,0x5c,0x4f,0x26,0xb0,0x15,0x7c,0x35,0x66,0xfa,0xb2,0x37,0x48,0xbd,0xc7,0xa8,0x52,0xfd,0x4b,0x9c,0x13,0x94,0x6a,0x1c,0x43,0xe1,0xf7,0x65,0x5e,0x88,0x4e,0x55,0x4,0xe5,0x59,0xc2,0x4a,0x80,0x45,0xa5,0x1e,0x36,0xa1,0xd5,0x8b,0xab,0x24,0xf8,0xf1,0x14,0xdd,0x10,0xd1,0x97,0x7a,0xaa,0xfe,0x67,0x9e,0xf9,0x41,0xb5,0x9b,0xfb,0xb1,0xeb,0x79,0x11,0xd3,0x3f,0x72,0x5b,0x82,0x54,0x3c,0x7f,0xb9,0xb7,0xbb,0x30,0x63,0x7,0x69,0xb6,0xae,0x90,0x51,0x4d,0xa,0xf4,0xcb,0x93,0xdb,0xa2,0x8e,0x19,0x6d,0xee,0xc3,0x2c,0x25,0x22,0x1b,0x16,0x74,0xc9,0xa4,0x92,0x64,0x95,0x6f,0x6e,0x34,0x29,0xde,0x83,0xdc,0xf3,0x1f,0xd,0xac,0xe3,0x50,0x5a,0xad,0x78,0xf,0xb,0x60,0x17,0x12,0x5,0x89,0xef,0xc4,0xe9,0x9f,0x58,0x87,0x37,0x1d,0xce,0x80,0x1f,0x18,0xe4,0x41,0xed,0xf,0x8b,0x78,0x6,0x46,0xf9,0xaf,0x90,0xc7,0xec,0xf4,0xb6,0x9a,0x67,0x11,0x43,0xc9,0x64,0xb9,0x68,0xe1,0x88,0x9b,0xa,0xf2,0xbb,0xd2,0x77,0xcf,0x5f,0xb,0xb0,0x7f,0xa6,0x98,0x42,0x61,0xc1,0xfa,0xef,0x1,0x1e,0xb1,0xba,0x31,0xe9,0x4a,0x83,0x27,0x5d,0xe8,0xac,0x8,0x8e,0xb2,0x56,0x2a,0x10,0x9,0x38,0x40,0xea,0x4d,0x7,0xc4,0xdd,0xf5,0x74,0xdf,0x25,0x2d,0xc5,0x85,0x2b,0xda,0xb4,0x6e,0x13,0xab,0xd,0xf6,0xb7,0x4b,0x3b,0xfc,0xa5,0x79,0x2f,0x73,0xc6,0x21,0xff,0xe0,0x48,0x2,0xfd,0x35,0xe7,0xbc,0x81,0x17,0x20,0x5e,0x51,0x91,0x5a,0x7d,0x7b,0xe6,0x23,0x15,0x60,0xfe,0x94,0xcb,0x32,0xeb,0x4,0x29,0xaa,0xd1,0xdc,0xe5,0xe2,0x54,0xc,0x33,0xcd,0xde,0x49,0x65,0x1c,0x71,0xae,0xc0,0xa4,0x8a,0x96,0x57,0x69,0xb8,0xfb,0x93,0x45,0xf7,0x7c,0x70,0x7e,0xc2,0xd5,0xd0,0xa7,0x2e,0x3,0x28,0x4e,0x9d,0x97,0x24,0x6b,0xcc,0xc8,0xbf,0x6a,0x44,0x19,0xee,0xf3,0xca,0xd8,0x34,0x1b,0x55,0x63,0xe,0xb3,0xa9,0xa8,0x52,0xa3,0x5,0x9e,0x22,0xc3,0x62,0x82,0x47,0x8d,0xa2,0x30,0x26,0x84,0x92,0x89,0x4f,0x99,0x5b,0x8c,0x3a,0x95,0xdb,0xad,0x53,0xd4,0xf0,0x75,0x3d,0xa1,0x6f,0x0,0x7a,0x8f,0xd6,0xbe,0x2c,0x76,0x9c,0xb5,0xf8,0x14,0x3e,0x59,0xa0,0x39,0x3c,0x5c,0x72,0x86,0xd7,0x1a,0xd3,0x36,0x6d,0xbd,0x50,0x16,0x12,0x66,0xf1,0xd9,0x3f,0xe3,0x6c,0x4c,0x9f,0x3d,0x1b,0x89,0xf6,0x20,0x2b,0x30,0x9b,0x7a,0xbc,0x27,0xfe,0x34,0xdb,0x3b,0x84,0x18,0x49,0xcc,0xc3,0x36,0xd6,0xb9,0x83,0x2c,0xe2,0x35,0xea,0x6d,0x62,0x14,0x19,0x80,0x87,0xe0,0xcb,0x3f,0x85,0xe5,0x95,0xcf,0x6f,0x7,0x41,0xad,0x25,0xc,0x48,0x60,0xab,0xdf,0xd5,0xf5,0x86,0x5a,0x6a,0x8f,0x6e,0xa3,0xe9,0xaf,0xd4,0x4,0x8a,0x74,0xed,0xb5,0xdc,0xa5,0x67,0xf0,0x90,0x13,0x52,0xbd,0x5c,0x5b,0x68,0x65,0x2a,0xfc,0x1,0x42,0xc9,0xc7,0x4e,0xc5,0x79,0x1d,0xc8,0x17,0xee,0xd0,0x33,0x2f,0x9d,0xd2,0x24,0x2e,0x6,0xd3,0x75,0x71,0x69,0x1e,0x7b,0x6c,0x91,0xf7,0x97,0xba,0xb7,0xa,0xec,0xda,0xeb,0x1a,0x10,0x11,0x57,0x4a,0xfd,0xa0,0x8d,0xa2,0x73,0x61,0xf4,0xbe,0xf9,0x53,0x4c,0xcd,0x7d,0x64,0xb,0xef,0xb1,0x37,0xb0,0x81,0x93,0xa9,0x12,0xb4,0xd7,0xaa,0xf2,0x82,0x4f,0xe,0x94,0x7c,0x66,0x9c,0x63,0xd,0x3c,0x92,0xbb,0x44,0x59,0xf1,0x5,0x38,0x8c,0x5e,0xc0,0x96,0x45,0x1c,0x98,0x46,0xca,0x7f,0xac,0xd9,0x5f,0x9a,0x72,0x8b,0x47,0x2d,0xe7,0xe8,0xae,0x99,0xc4,0xc2,0x28,0xe3,0xf8,0x54,0xa1,0x5d,0xc1,0xbf,0xb6,0x32,0x3e,0x8e,0x26,0xe1,0x39,0xa6,0xa4,0x77,0xa8,0xfa,0x23,0xde,0x0,0xd1,0x70,0xdd,0x16,0x29,0xff,0x40,0x4d,0xf,0x7e,0x55,0xb2,0x9,0x76,0xe6,0x21,0xfb,0xc6,0x1f,0x22,0xb3,0x58,0x31,0x6b,0xce,0x4b,0x2,0xf3,0x3a,0x88,0x50,0x51,0x15,0x9e,0xe4,0x43,0x56,0xd8,0x78,0x8,0x3,0xb8,0xa7,0xe7,0x1b,0xee,0x42,0x88,0xc,0x5,0x7b,0x5b,0x9c,0x34,0x84,0xcd,0x1e,0x1c,0x83,0x64,0x99,0x40,0x12,0x67,0xca,0x6b,0xba,0xfa,0x45,0x93,0xac,0xef,0xc4,0xb5,0xf7,0x5c,0xcc,0xb3,0x8,0xa5,0x7c,0x41,0x9b,0x8b,0xe2,0x9,0x98,0xb8,0xf1,0x74,0xd1,0xea,0x32,0x80,0x49,0x5e,0x24,0xaf,0xeb,0xc2,0x62,0xec,0xf9,0x1d,0x2,0xb9,0xb2,0xe9,0x43,0x4,0x4e,0xde,0xc7,0x77,0xf6,0x8d,0xb,0x55,0xb1,0x13,0x29,0x3b,0xa,0x10,0x6d,0xe,0xa8,0xb4,0xf5,0x38,0x48,0x26,0xdc,0xc6,0x2e,0x28,0x86,0xb7,0xd9,0x4b,0xe3,0xfe,0x1,0xe4,0x36,0x82,0xbf,0xa6,0xff,0x2c,0x7a,0xc5,0x70,0xfc,0x22,0x20,0xe5,0x63,0x16,0x97,0xfd,0x31,0xc8,0x23,0x14,0x52,0x5d,0x59,0x92,0x78,0x7e,0xf,0x57,0xce,0x30,0x4a,0xdd,0x1f,0x66,0x7,0xe8,0xa9,0x2a,0xdf,0xd2,0xe1,0xe6,0xf8,0xbb,0x46,0x90,0x7f,0xf4,0x7d,0x73,0xad,0x72,0xa7,0xc3,0x95,0x89,0x6a,0x54,0x94,0x9e,0x68,0x27,0xcb,0xcf,0x69,0xbc,0xd6,0xc1,0xa4,0xd3,0x0,0x2d,0x4d,0x2b,0x60,0x56,0xb0,0xd,0xab,0xaa,0xa0,0x51,0x1a,0x47,0xf0,0xed,0xdb,0xc9,0x18,0x37,0x33,0xa1,0x87,0x25,0x8a,0x91,0x9a,0x4c,0x9d,0x6,0xc0,0x21,0x81,0x61,0x8e,0x44,0x76,0xf3,0xa2,0x3e,0x3,0x6c,0x8c,0x79,0x8f,0x58,0x96,0x39,0xae,0xd8,0xd7,0x50,0x5a,0x3d,0x3a,0xa3,0x5f,0x3f,0x85,0x71,0xbd,0xd5,0x75,0x2f,0xb6,0x9f,0x17,0xfb,0x65,0x11,0xda,0xf2,0xe0,0x3c,0x4f,0x6f,0x19,0xd4,0x35,0xd0,0xbe,0x6e,0x15,0x53,0xa7,0x1,0xb9,0xc4,0x91,0xe1,0x1d,0x5c,0x6f,0x87,0x8f,0x75,0x1e,0x70,0x81,0x2f,0xad,0xe7,0x40,0xea,0xde,0x5f,0x77,0x6e,0xfc,0x18,0x24,0xa2,0x92,0xa3,0xba,0x80,0xca,0xbf,0x89,0x4c,0x98,0x61,0x3e,0x54,0xfb,0xf4,0x8a,0xbd,0xd1,0xd7,0xf0,0x3b,0x57,0xa8,0xe2,0x4a,0x2b,0x16,0x4d,0x9f,0x85,0xd3,0xf,0x56,0x55,0x8b,0x6c,0xd9,0xe9,0xbb,0xcd,0x30,0xc2,0x13,0xce,0x63,0x3a,0x5,0x53,0xec,0x1c,0x5e,0x46,0x6d,0x47,0xeb,0x4e,0xb2,0xac,0xd2,0x21,0xa5,0x9d,0x2d,0xf2,0x35,0xb5,0x2a,0x64,0xb7,0x29,0xe0,0x43,0x9b,0x6,0x42,0xf7,0x8d,0x45,0x50,0x6b,0xcb,0x10,0x1b,0xb4,0xab,0x1a,0xa1,0xf5,0x65,0xe8,0x32,0xc,0xd5,0xa0,0x31,0x22,0x4b,0xdd,0x78,0x11,0x58,0xb,0x97,0xdf,0x5a,0x25,0xd0,0xaa,0xc5,0x3f,0x90,0x26,0xf1,0x7e,0xf9,0x7,0x71,0x2e,0x8c,0x9a,0x8,0x33,0xe5,0x23,0x38,0x69,0x88,0x34,0xaf,0x27,0xed,0x28,0xc8,0x73,0x5b,0xcc,0xb8,0xe6,0xc6,0x49,0x95,0x9c,0x79,0xb0,0x7d,0xbc,0xfa,0x17,0xc7,0x93,0xa,0xf3,0x94,0x2c,0xd8,0xf6,0x96,0xdc,0x86,0x14,0x7c,0xbe,0x52,0x1f,0x36,0xef,0x39,0x51,0x12,0xd4,0xda,0xd6,0x5d,0xe,0x6a,0x4,0xdb,0xc3,0xfd,0x3c,0x20,0x67,0x99,0xa6,0xfe,0xb6,0xcf,0xe3,0x74,0x0,0x83,0xae,0x41,0x48,0x4f,0x76,0x7b,0x19,0xa4,0xc9,0xff,0x9,0xf8,0x2,0x3,0x59,0x44,0xb3,0xee,0xb1,0x9e,0x72,0x60,0xc1,0x8e,0x3d,0x37,0xc0,0x15,0x62,0x66,0xd,0x7a,0x7f,0x68,0xe4,0x82,0xa9,0x84,0xb,0xcc,0x13,0xa3,0x89,0x5a,0x14,0x8b,0x8c,0x70,0xd5,0x79,0x9b,0x1f,0xec,0x92,0xd2,0x6d,0x3b,0x4,0x53,0x78,0x60,0x22,0xe,0xf3,0x85,0xd7,0x5d,0xf0,0x2d,0xfc,0x75,0x1c,0xf,0x9e,0x66,0x2f,0x46,0xe3,0x5b,0xcb,0x9f,0x24,0xeb,0x32,0xc,0xd6,0xf5,0x55,0x6e,0x7b,0x95,0x8a,0x25,0x2e,0xa5,0x7d,0xde,0x17,0xb3,0xc9,0x7c,0x38,0x9c,0x1a,0x26,0xc2,0xbe,0x84,0x9d,0xac,0xd4,0x7e,0xd9,0x93,0x50,0x49,0x61,0xe0,0x4b,0xb1,0xb9,0x51,0x11,0xbf,0x4e,0x20,0xfa,0x87,0x3f,0x99,0x62,0x23,0xdf,0xaf,0x68,0x31,0xed,0xbb,0xe7,0x52,0xb5,0x6b,0x74,0xdc,0x96,0x69,0xa1,0x73,0x28,0x15,0x83,0xb4,0xca,0xc5,0x5,0xce,0xe9,0xef,0x72,0xb7,0x81,0xf4,0x6a,0x0,0x5f,0xa6,0x7f,0x90,0xbd,0x3e,0x45,0x48,0x71,0x76,0xc0,0x98,0xa7,0x59,0x4a,0xdd,0xf1,0x88,0xe5,0x3a,0x54,0x30,0x1e,0x2,0xc3,0xfd,0x2c,0x6f,0x7,0xd1,0x63,0xe8,0xe4,0xea,0x56,0x41,0x44,0x33,0xba,0x97,0xbc,0xda,0x9,0x3,0xb0,0xff,0x58,0x5c,0x2b,0xfe,0xd0,0x8d,0x7a,0x67,0x5e,0x4c,0xa0,0x8f,0xc1,0xf7,0x9a,0x27,0x3d,0x3c,0xc6,0x37,0x91,0xa,0xb6,0x57,0xf6,0x16,0xd3,0x19,0x36,0xa4,0xb2,0x10,0x6,0x1d,0xdb,0xd,0xcf,0x18,0xae,0x1,0x4f,0x39,0xc7,0x40,0x64,0xe1,0xa9,0x35,0xfb,0x94,0xee,0x1b,0x42,0x2a,0xb8,0xe2,0x8,0x21,0x6c,0x80,0xaa,0xcd,0x34,0xad,0xa8,0xc8,0xe6,0x12,0x43,0x8e,0x47,0xa2,0xf9,0x29,0xc4,0x82,0x86,0xf2,0x65,0x4d,0xab,0x77,0xf8,0xd8,0xea,0x48,0x6e,0xfc,0x83,0x55,0x5e,0x45,0xee,0xf,0xc9,0x52,0x8b,0x41,0xae,0x4e,0xf1,0x6d,0x3c,0xb9,0xb6,0x43,0xa3,0xcc,0xf6,0x59,0x97,0x40,0x9f,0x18,0x17,0x61,0x6c,0xf5,0xf2,0x95,0xbe,0x4a,0xf0,0x90,0xe0,0xba,0x1a,0x72,0x34,0xd8,0x50,0x79,0x3d,0x15,0xde,0xaa,0xa0,0x80,0xf3,0x2f,0x1f,0xfa,0x1b,0xd6,0x9c,0xda,0xa1,0x71,0xff,0x1,0x98,0xc0,0xa9,0xd0,0x12,0x85,0xe5,0x66,0x27,0xc8,0x29,0x2e,0x1d,0x10,0x5f,0x89,0x74,0x37,0xbc,0xb2,0x3b,0xb0,0xc,0x68,0xbd,0x62,0x9b,0xa5,0x46,0x5a,0xe8,0xa7,0x51,0x5b,0x73,0xa6,0x0,0x4,0x1c,0x6b,0xe,0x19,0xe4,0x82,0xe2,0xcf,0xc2,0x7f,0x99,0xaf,0x9e,0x6f,0x65,0x64,0x22,0x3f,0x88,0xd5,0xf8,0xd7,0x6,0x14,0x81,0xcb,0x8c,0x26,0x39,0xb8,0x8,0x11,0x7e,0x9a,0xc4,0x42,0xc5,0xf4,0xe6,0xdc,0x67,0xc1,0xa2,0xdf,0x87,0xf7,0x3a,0x7b,0xe1,0x9,0x13,0xe9,0x16,0x78,0x49,0xe7,0xce,0x31,0x2c,0x84,0x70,0x4d,0xf9,0x2b,0xb5,0xe3,0x30,0x69,0xed,0x33,0xbf,0xa,0xd9,0xac,0x2a,0xef,0x7,0xfe,0x32,0x58,0x92,0x9d,0xdb,0xec,0xb1,0xb7,0x5d,0x96,0x8d,0x21,0xd4,0x28,0xb4,0xca,0xc3,0x47,0x4b,0xfb,0x53,0x94,0x4c,0xd3,0xd1,0x2,0xdd,0x8f,0x56,0xab,0x75,0xa4,0x5,0xa8,0x63,0x5c,0x8a,0x35,0x38,0x7a,0xb,0x20,0xc7,0x7c,0x3,0x93,0x54,0x8e,0xb3,0x6a,0x57,0xc6,0x2d,0x44,0x1e,0xbb,0x3e,0x77,0x86,0x4f,0xfd,0x25,0x24,0x60,0xeb,0x91,0x36,0x23,0xad,0xd,0x7d,0x76,0xcd,0xd2,0x13,0xef,0x1a,0xb6,0x7c,0xf8,0xf1,0x8f,0xaf,0x68,0xc0,0x70,0x39,0xea,0xe8,0x77,0x90,0x6d,0xb4,0xe6,0x93,0x3e,0x9f,0x4e,0xe,0xb1,0x67,0x58,0x1b,0x30,0x41,0x3,0xa8,0x38,0x47,0xfc,0x51,0x88,0xb5,0x6f,0x7f,0x16,0xfd,0x6c,0x4c,0x5,0x80,0x25,0x1e,0xc6,0x74,0xbd,0xaa,0xd0,0x5b,0x1f,0x36,0x96,0x18,0xd,0xe9,0xf6,0x4d,0x46,0x1d,0xb7,0xf0,0xba,0x2a,0x33,0x83,0x2,0x79,0xff,0xa1,0x45,0xe7,0xdd,0xcf,0xfe,0xe4,0x99,0xfa,0x5c,0x40,0x1,0xcc,0xbc,0xd2,0x28,0x32,0xda,0xdc,0x72,0x43,0x2d,0xbf,0x17,0xa,0xf5,0x10,0xc2,0x76,0x4b,0x52,0xb,0xd8,0x8e,0x31,0x84,0x8,0xd6,0xd4,0x11,0x97,0xe2,0x63,0x9,0xc5,0x3c,0xd7,0xe0,0xa6,0xa9,0xad,0x66,0x8c,0x8a,0xfb,0xa3,0x3a,0xc4,0xbe,0x29,0xeb,0x92,0xf3,0x1c,0x5d,0xde,0x2b,0x26,0x15,0x12,0xc,0x4f,0xb2,0x64,0x8b,0x0,0x89,0x87,0x59,0x86,0x53,0x37,0x61,0x7d,0x9e,0xa0,0x60,0x6a,0x9c,0xd3,0x3f,0x3b,0x9d,0x48,0x22,0x35,0x50,0x27,0xf4,0xd9,0xb9,0xdf,0x94,0xa2,0x44,0xf9,0x5f,0x5e,0x54,0xa5,0xee,0xb3,0x4,0x19,0x2f,0x3d,0xec,0xc3,0xc7,0x55,0x73,0xd1,0x7e,0x65,0x6e,0xb8,0x69,0xf2,0x34,0xd5,0x75,0x95,0x7a,0xb0,0x82,0x7,0x56,0xca,0xf7,0x98,0x78,0x8d,0x7b,0xac,0x62,0xcd,0x5a,0x2c,0x23,0xa4,0xae,0xc9,0xce,0x57,0xab,0xcb,0x71,0x85,0x49,0x21,0x81,0xdb,0x42,0x6b,0xe3,0xf,0x91,0xe5,0x2e,0x6,0x14,0xc8,0xbb,0x9b,0xed,0x20,0xc1,0x24,0x4a,0x9a,0xe1,0xa7,0x18,0xbe,0x6,0x7b,0x2e,0x5e,0xa2,0xe3,0xd0,0x38,0x30,0xca,0xa1,0xcf,0x3e,0x90,0x12,0x58,0xff,0x55,0x61,0xe0,0xc8,0xd1,0x43,0xa7,0x9b,0x1d,0x2d,0x1c,0x5,0x3f,0x75,0x0,0x36,0xf3,0x27,0xde,0x81,0xeb,0x44,0x4b,0x35,0x2,0x6e,0x68,0x4f,0x84,0xe8,0x17,0x5d,0xf5,0x94,0xa9,0xf2,0x20,0x3a,0x6c,0xb0,0xe9,0xea,0x34,0xd3,0x66,0x56,0x4,0x72,0x8f,0x7d,0xac,0x71,0xdc,0x85,0xba,0xec,0x53,0xa3,0xe1,0xf9,0xd2,0xf8,0x54,0xf1,0xd,0x13,0x6d,0x9e,0x1a,0x22,0x92,0x4d,0x8a,0xa,0x95,0xdb,0x8,0x96,0x5f,0xfc,0x24,0xb9,0xfd,0x48,0x32,0xfa,0xef,0xd4,0x74,0xaf,0xa4,0xb,0x14,0xa5,0x1e,0x4a,0xda,0x57,0x8d,0xb3,0x6a,0x1f,0x8e,0x9d,0xf4,0x62,0xc7,0xae,0xe7,0xb4,0x28,0x60,0xe5,0x9a,0x6f,0x15,0x7a,0x80,0x2f,0x99,0x4e,0xc1,0x46,0xb8,0xce,0x91,0x33,0x25,0xb7,0x8c,0x5a,0x9c,0x87,0xd6,0x37,0x8b,0x10,0x98,0x52,0x97,0x77,0xcc,0xe4,0x73,0x7,0x59,0x79,0xf6,0x2a,0x23,0xc6,0xf,0xc2,0x3,0x45,0xa8,0x78,0x2c,0xb5,0x4c,0x2b,0x93,0x67,0x49,0x29,0x63,0x39,0xab,0xc3,0x1,0xed,0xa0,0x89,0x50,0x86,0xee,0xad,0x6b,0x65,0x69,0xe2,0xb1,0xd5,0xbb,0x64,0x7c,0x42,0x83,0x9f,0xd8,0x26,0x19,0x41,0x9,0x70,0x5c,0xcb,0xbf,0x3c,0x11,0xfe,0xf7,0xf0,0xc9,0xc4,0xa6,0x1b,0x76,0x40,0xb6,0x47,0xbd,0xbc,0xe6,0xfb,0xc,0x51,0xe,0x21,0xcd,0xdf,0x7e,0x31,0x82,0x88,0x7f,0xaa,0xdd,0xd9,0xb2,0xc5,0xc0,0xd7,0x5b,0x3d,0x16,0x3b,0xe4,0x23,0xfc,0x4c,0x66,0xb5,0xfb,0x64,0x63,0x9f,0x3a,0x96,0x74,0xf0,0x3,0x7d,0x3d,0x82,0xd4,0xeb,0xbc,0x97,0x8f,0xcd,0xe1,0x1c,0x6a,0x38,0xb2,0x1f,0xc2,0x13,0x9a,0xf3,0xe0,0x71,0x89,0xc0,0xa9,0xc,0xb4,0x24,0x70,0xcb,0x4,0xdd,0xe3,0x39,0x1a,0xba,0x81,0x94,0x7a,0x65,0xca,0xc1,0x4a,0x92,0x31,0xf8,0x5c,0x26,0x93,0xd7,0x73,0xf5,0xc9,0x2d,0x51,0x6b,0x72,0x43,0x3b,0x91,0x36,0x7c,0xbf,0xa6,0x8e,0xf,0xa4,0x5e,0x56,0xbe,0xfe,0x50,0xa1,0xcf,0x15,0x68,0xd0,0x76,0x8d,0xcc,0x30,0x40,0x87,0xde,0x2,0x54,0x8,0xbd,0x5a,0x84,0x9b,0x33,0x79,0x86,0x4e,0x9c,0xc7,0xfa,0x6c,0x5b,0x25,0x2a,0xea,0x21,0x6,0x0,0x9d,0x58,0x6e,0x1b,0x85,0xef,0xb0,0x49,0x90,0x7f,0x52,0xd1,0xaa,0xa7,0x9e,0x99,0x2f,0x77,0x48,0xb6,0xa5,0x32,0x1e,0x67,0xa,0xd5,0xbb,0xdf,0xf1,0xed,0x2c,0x12,0xc3,0x80,0xe8,0x3e,0x8c,0x7,0xb,0x5,0xb9,0xae,0xab,0xdc,0x55,0x78,0x53,0x35,0xe6,0xec,0x5f,0x10,0xb7,0xb3,0xc4,0x11,0x3f,0x62,0x95,0x88,0xb1,0xa3,0x4f,0x60,0x2e,0x18,0x75,0xc8,0xd2,0xd3,0x29,0xd8,0x7e,0xe5,0x59,0xb8,0x19,0xf9,0x3c,0xf6,0xd9,0x4b,0x5d,0xff,0xe9,0xf2,0x34,0xe2,0x20,0xf7,0x41,0xee,0xa0,0xd6,0x28,0xaf,0x8b,0xe,0x46,0xda,0x14,0x7b,0x1,0xf4,0xad,0xc5,0x57,0xd,0xe7,0xce,0x83,0x6f,0x45,0x22,0xdb,0x42,0x47,0x27,0x9,0xfd,0xac,0x61,0xa8,0x4d,0x16,0xc6,0x2b,0x6d,0x69,0x1d,0x8a,0xa2,0x44,0x98,0x17,0x37,0x90,0x32,0x14,0x86,0xf9,0x2f,0x24,0x3f,0x94,0x75,0xb3,0x28,0xf1,0x3b,0xd4,0x34,0x8b,0x17,0x46,0xc3,0xcc,0x39,0xd9,0xb6,0x8c,0x23,0xed,0x3a,0xe5,0x62,0x6d,0x1b,0x16,0x8f,0x88,0xef,0xc4,0x30,0x8a,0xea,0x9a,0xc0,0x60,0x8,0x4e,0xa2,0x2a,0x3,0x47,0x6f,0xa4,0xd0,0xda,0xfa,0x89,0x55,0x65,0x80,0x61,0xac,0xe6,0xa0,0xdb,0xb,0x85,0x7b,0xe2,0xba,0xd3,0xaa,0x68,0xff,0x9f,0x1c,0x5d,0xb2,0x53,0x54,0x67,0x6a,0x25,0xf3,0xe,0x4d,0xc6,0xc8,0x41,0xca,0x76,0x12,0xc7,0x18,0xe1,0xdf,0x3c,0x20,0x92,0xdd,0x2b,0x21,0x9,0xdc,0x7a,0x7e,0x66,0x11,0x74,0x63,0x9e,0xf8,0x98,0xb5,0xb8,0x5,0xe3,0xd5,0xe4,0x15,0x1f,0x1e,0x58,0x45,0xf2,0xaf,0x82,0xad,0x7c,0x6e,0xfb,0xb1,0xf6,0x5c,0x43,0xc2,0x72,0x6b,0x4,0xe0,0xbe,0x38,0xbf,0x8e,0x9c,0xa6,0x1d,0xbb,0xd8,0xa5,0xfd,0x8d,0x40,0x1,0x9b,0x73,0x69,0x93,0x6c,0x2,0x33,0x9d,0xb4,0x4b,0x56,0xfe,0xa,0x37,0x83,0x51,0xcf,0x99,0x4a,0x13,0x97,0x49,0xc5,0x70,0xa3,0xd6,0x50,0x95,0x7d,0x84,0x48,0x22,0xe8,0xe7,0xa1,0x96,0xcb,0xcd,0x27,0xec,0xf7,0x5b,0xae,0x52,0xce,0xb0,0xb9,0x3d,0x31,0x81,0x29,0xee,0x36,0xa9,0xab,0x78,0xa7,0xf5,0x2c,0xd1,0xf,0xde,0x7f,0xd2,0x19,0x26,0xf0,0x4f,0x42,0x0,0x71,0x5a,0xbd,0x6,0x79,0xe9,0x2e,0xf4,0xc9,0x10,0x2d,0xbc,0x57,0x3e,0x64,0xc1,0x44,0xd,0xfc,0x35,0x87,0x5f,0x5e,0x1a,0x91,0xeb,0x4c,0x59,0xd7,0x77,0x7,0xc,0xb7,0xa8,0x23,0xdf,0x2a,0x86,0x4c,0xc8,0xc1,0xbf,0x9f,0x58,0xf0,0x40,0x9,0xda,0xd8,0x47,0xa0,0x5d,0x84,0xd6,0xa3,0xe,0xaf,0x7e,0x3e,0x81,0x57,0x68,0x2b,0x0,0x71,0x33,0x98,0x8,0x77,0xcc,0x61,0xb8,0x85,0x5f,0x4f,0x26,0xcd,0x5c,0x7c,0x35,0xb0,0x15,0x2e,0xf6,0x44,0x8d,0x9a,0xe0,0x6b,0x2f,0x6,0xa6,0x28,0x3d,0xd9,0xc6,0x7d,0x76,0x2d,0x87,0xc0,0x8a,0x1a,0x3,0xb3,0x32,0x49,0xcf,0x91,0x75,0xd7,0xed,0xff,0xce,0xd4,0xa9,0xca,0x6c,0x70,0x31,0xfc,0x8c,0xe2,0x18,0x2,0xea,0xec,0x42,0x73,0x1d,0x8f,0x27,0x3a,0xc5,0x20,0xf2,0x46,0x7b,0x62,0x3b,0xe8,0xbe,0x1,0xb4,0x38,0xe6,0xe4,0x21,0xa7,0xd2,0x53,0x39,0xf5,0xc,0xe7,0xd0,0x96,0x99,0x9d,0x56,0xbc,0xba,0xcb,0x93,0xa,0xf4,0x8e,0x19,0xdb,0xa2,0xc3,0x2c,0x6d,0xee,0x1b,0x16,0x25,0x22,0x3c,0x7f,0x82,0x54,0xbb,0x30,0xb9,0xb7,0x69,0xb6,0x63,0x7,0x51,0x4d,0xae,0x90,0x50,0x5a,0xac,0xe3,0xf,0xb,0xad,0x78,0x12,0x5,0x60,0x17,0xc4,0xe9,0x89,0xef,0xa4,0x92,0x74,0xc9,0x6f,0x6e,0x64,0x95,0xde,0x83,0x34,0x29,0x1f,0xd,0xdc,0xf3,0xf7,0x65,0x43,0xe1,0x4e,0x55,0x5e,0x88,0x59,0xc2,0x4,0xe5,0x45,0xa5,0x4a,0x80,0xb2,0x37,0x66,0xfa,0xc7,0xa8,0x48,0xbd,0x4b,0x9c,0x52,0xfd,0x6a,0x1c,0x13,0x94,0x9e,0xf9,0xfe,0x67,0x9b,0xfb,0x41,0xb5,0x79,0x11,0xb1,0xeb,0x72,0x5b,0xd3,0x3f,0xa1,0xd5,0x1e,0x36,0x24,0xf8,0x8b,0xab,0xdd,0x10,0xf1,0x14,0x7a,0xaa,0xd1,0x97,0xce,0x68,0xd0,0xad,0xf8,0x88,0x74,0x35,0x6,0xee,0xe6,0x1c,0x77,0x19,0xe8,0x46,0xc4,0x8e,0x29,0x83,0xb7,0x36,0x1e,0x7,0x95,0x71,0x4d,0xcb,0xfb,0xca,0xd3,0xe9,0xa3,0xd6,0xe0,0x25,0xf1,0x8,0x57,0x3d,0x92,0x9d,0xe3,0xd4,0xb8,0xbe,0x99,0x52,0x3e,0xc1,0x8b,0x23,0x42,0x7f,0x24,0xf6,0xec,0xba,0x66,0x3f,0x3c,0xe2,0x5,0xb0,0x80,0xd2,0xa4,0x59,0xab,0x7a,0xa7,0xa,0x53,0x6c,0x3a,0x85,0x75,0x37,0x2f,0x4,0x2e,0x82,0x27,0xdb,0xc5,0xbb,0x48,0xcc,0xf4,0x44,0x9b,0x5c,0xdc,0x43,0xd,0xde,0x40,0x89,0x2a,0xf2,0x6f,0x2b,0x9e,0xe4,0x2c,0x39,0x2,0xa2,0x79,0x72,0xdd,0xc2,0x73,0xc8,0x9c,0xc,0x81,0x5b,0x65,0xbc,0xc9,0x58,0x4b,0x22,0xb4,0x11,0x78,0x31,0x62,0xfe,0xb6,0x33,0x4c,0xb9,0xc3,0xac,0x56,0xf9,0x4f,0x98,0x17,0x90,0x6e,0x18,0x47,0xe5,0xf3,0x61,0x5a,0x8c,0x4a,0x51,0x0,0xe1,0x5d,0xc6,0x4e,0x84,0x41,0xa1,0x1a,0x32,0xa5,0xd1,0x8f,0xaf,0x20,0xfc,0xf5,0x10,0xd9,0x14,0xd5,0x93,0x7e,0xae,0xfa,0x63,0x9a,0xfd,0x45,0xb1,0x9f,0xff,0xb5,0xef,0x7d,0x15,0xd7,0x3b,0x76,0x5f,0x86,0x50,0x38,0x7b,0xbd,0xb3,0xbf,0x34,0x67,0x3,0x6d,0xb2,0xaa,0x94,0x55,0x49,0xe,0xf0,0xcf,0x97,0xdf,0xa6,0x8a,0x1d,0x69,0xea,0xc7,0x28,0x21,0x26,0x1f,0x12,0x70,0xcd,0xa0,0x96,0x60,0x91,0x6b,0x6a,0x30,0x2d,0xda,0x87,0xd8,0xf7,0x1b,0x9,0xa8,0xe7,0x54,0x5e,0xa9,0x7c,0xb,0xf,0x64,0x13,0x16,0x1,0x8d,0xeb,0xc0,0xed,0x2,0xc5,0x1a,0xaa,0x80,0x53,0x1d,0x82,0x85,0x79,0xdc,0x70,0x92,0x16,0xe5,0x9b,0xdb,0x64,0x32,0xd,0x5a,0x71,0x69,0x2b,0x7,0xfa,0x8c,0xde,0x54,0xf9,0x24,0xf5,0x7c,0x15,0x6,0x97,0x6f,0x26,0x4f,0xea,0x52,0xc2,0x96,0x2d,0xe2,0x3b,0x5,0xdf,0xfc,0x5c,0x67,0x72,0x9c,0x83,0x2c,0x27,0xac,0x74,0xd7,0x1e,0xba,0xc0,0x75,0x31,0x95,0x13,0x2f,0xcb,0xb7,0x8d,0x94,0xa5,0xdd,0x77,0xd0,0x9a,0x59,0x40,0x68,0xe9,0x42,0xb8,0xb0,0x58,0x18,0xb6,0x47,0x29,0xf3,0x8e,0x36,0x90,0x6b,0x2a,0xd6,0xa6,0x61,0x38,0xe4,0xb2,0xee,0x5b,0xbc,0x62,0x7d,0xd5,0x9f,0x60,0xa8,0x7a,0x21,0x1c,0x8a,0xbd,0xc3,0xcc,0xc,0xc7,0xe0,0xe6,0x7b,0xbe,0x88,0xfd,0x63,0x9,0x56,0xaf,0x76,0x99,0xb4,0x37,0x4c,0x41,0x78,0x7f,0xc9,0x91,0xae,0x50,0x43,0xd4,0xf8,0x81,0xec,0x33,0x5d,0x39,0x17,0xb,0xca,0xf4,0x25,0x66,0xe,0xd8,0x6a,0xe1,0xed,0xe3,0x5f,0x48,0x4d,0x3a,0xb3,0x9e,0xb5,0xd3,0x0,0xa,0xb9,0xf6,0x51,0x55,0x22,0xf7,0xd9,0x84,0x73,0x6e,0x57,0x45,0xa9,0x86,0xc8,0xfe,0x93,0x2e,0x34,0x35,0xcf,0x3e,0x98,0x3,0xbf,0x5e,0xff,0x1f,0xda,0x10,0x3f,0xad,0xbb,0x19,0xf,0x14,0xd2,0x4,0xc6,0x11,0xa7,0x8,0x46,0x30,0xce,0x49,0x6d,0xe8,0xa0,0x3c,0xf2,0x9d,0xe7,0x12,0x4b,0x23,0xb1,0xeb,0x1,0x28,0x65,0x89,0xa3,0xc4,0x3d,0xa4,0xa1,0xc1,0xef,0x1b,0x4a,0x87,0x4e,0xab,0xf0,0x20,0xcd,0x8b,0x8f,0xfb,0x6c,0x44,0xa2,0x7e,0xf1,0xd1,0x3a,0x98,0xbe,0x2c,0x53,0x85,0x8e,0x95,0x3e,0xdf,0x19,0x82,0x5b,0x91,0x7e,0x9e,0x21,0xbd,0xec,0x69,0x66,0x93,0x73,0x1c,0x26,0x89,0x47,0x90,0x4f,0xc8,0xc7,0xb1,0xbc,0x25,0x22,0x45,0x6e,0x9a,0x20,0x40,0x30,0x6a,0xca,0xa2,0xe4,0x8,0x80,0xa9,0xed,0xc5,0xe,0x7a,0x70,0x50,0x23,0xff,0xcf,0x2a,0xcb,0x6,0x4c,0xa,0x71,0xa1,0x2f,0xd1,0x48,0x10,0x79,0x0,0xc2,0x55,0x35,0xb6,0xf7,0x18,0xf9,0xfe,0xcd,0xc0,0x8f,0x59,0xa4,0xe7,0x6c,0x62,0xeb,0x60,0xdc,0xb8,0x6d,0xb2,0x4b,0x75,0x96,0x8a,0x38,0x77,0x81,0x8b,0xa3,0x76,0xd0,0xd4,0xcc,0xbb,0xde,0xc9,0x34,0x52,0x32,0x1f,0x12,0xaf,0x49,0x7f,0x4e,0xbf,0xb5,0xb4,0xf2,0xef,0x58,0x5,0x28,0x7,0xd6,0xc4,0x51,0x1b,0x5c,0xf6,0xe9,0x68,0xd8,0xc1,0xae,0x4a,0x14,0x92,0x15,0x24,0x36,0xc,0xb7,0x11,0x72,0xf,0x57,0x27,0xea,0xab,0x31,0xd9,0xc3,0x39,0xc6,0xa8,0x99,0x37,0x1e,0xe1,0xfc,0x54,0xa0,0x9d,0x29,0xfb,0x65,0x33,0xe0,0xb9,0x3d,0xe3,0x6f,0xda,0x9,0x7c,0xfa,0x3f,0xd7,0x2e,0xe2,0x88,0x42,0x4d,0xb,0x3c,0x61,0x67,0x8d,0x46,0x5d,0xf1,0x4,0xf8,0x64,0x1a,0x13,0x97,0x9b,0x2b,0x83,0x44,0x9c,0x3,0x1,0xd2,0xd,0x5f,0x86,0x7b,0xa5,0x74,0xd5,0x78,0xb3,0x8c,0x5a,0xe5,0xe8,0xaa,0xdb,0xf0,0x17,0xac,0xd3,0x43,0x84,0x5e,0x63,0xba,0x87,0x16,0xfd,0x94,0xce,0x6b,0xee,0xa7,0x56,0x9f,0x2d,0xf5,0xf4,0xb0,0x3b,0x41,0xe6,0xf3,0x7d,0xdd,0xad,0xa6,0x1d,0x2,0x6d,0x91,0x64,0xc8,0x2,0x86,0x8f,0xf1,0xd1,0x16,0xbe,0xe,0x47,0x94,0x96,0x9,0xee,0x13,0xca,0x98,0xed,0x40,0xe1,0x30,0x70,0xcf,0x19,0x26,0x65,0x4e,0x3f,0x7d,0xd6,0x46,0x39,0x82,0x2f,0xf6,0xcb,0x11,0x1,0x68,0x83,0x12,0x32,0x7b,0xfe,0x5b,0x60,0xb8,0xa,0xc3,0xd4,0xae,0x25,0x61,0x48,0xe8,0x66,0x73,0x97,0x88,0x33,0x38,0x63,0xc9,0x8e,0xc4,0x54,0x4d,0xfd,0x7c,0x7,0x81,0xdf,0x3b,0x99,0xa3,0xb1,0x80,0x9a,0xe7,0x84,0x22,0x3e,0x7f,0xb2,0xc2,0xac,0x56,0x4c,0xa4,0xa2,0xc,0x3d,0x53,0xc1,0x69,0x74,0x8b,0x6e,0xbc,0x8,0x35,0x2c,0x75,0xa6,0xf0,0x4f,0xfa,0x76,0xa8,0xaa,0x6f,0xe9,0x9c,0x1d,0x77,0xbb,0x42,0xa9,0x9e,0xd8,0xd7,0xd3,0x18,0xf2,0xf4,0x85,0xdd,0x44,0xba,0xc0,0x57,0x95,0xec,0x8d,0x62,0x23,0xa0,0x55,0x58,0x6b,0x6c,0x72,0x31,0xcc,0x1a,0xf5,0x7e,0xf7,0xf9,0x27,0xf8,0x2d,0x49,0x1f,0x3,0xe0,0xde,0x1e,0x14,0xe2,0xad,0x41,0x45,0xe3,0x36,0x5c,0x4b,0x2e,0x59,0x8a,0xa7,0xc7,0xa1,0xea,0xdc,0x3a,0x87,0x21,0x20,0x2a,0xdb,0x90,0xcd,0x7a,0x67,0x51,0x43,0x92,0xbd,0xb9,0x2b,0xd,0xaf,0x0,0x1b,0x10,0xc6,0x17,0x8c,0x4a,0xab,0xb,0xeb,0x4,0xce,0xfc,0x79,0x28,0xb4,0x89,0xe6,0x6,0xf3,0x5,0xd2,0x1c,0xb3,0x24,0x52,0x5d,0xda,0xd0,0xb7,0xb0,0x29,0xd5,0xb5,0xf,0xfb,0x37,0x5f,0xff,0xa5,0x3c,0x15,0x9d,0x71,0xef,0x9b,0x50,0x78,0x6a,0xb6,0xc5,0xe5,0x93,0x5e,0xbf,0x5a,0x34,0xe4,0x9f,0xd9,0xc8,0x6e,0xd6,0xab,0xfe,0x8e,0x72,0x33,0x0,0xe8,0xe0,0x1a,0x71,0x1f,0xee,0x40,0xc2,0x88,0x2f,0x85,0xb1,0x30,0x18,0x1,0x93,0x77,0x4b,0xcd,0xfd,0xcc,0xd5,0xef,0xa5,0xd0,0xe6,0x23,0xf7,0xe,0x51,0x3b,0x94,0x9b,0xe5,0xd2,0xbe,0xb8,0x9f,0x54,0x38,0xc7,0x8d,0x25,0x44,0x79,0x22,0xf0,0xea,0xbc,0x60,0x39,0x3a,0xe4,0x3,0xb6,0x86,0xd4,0xa2,0x5f,0xad,0x7c,0xa1,0xc,0x55,0x6a,0x3c,0x83,0x73,0x31,0x29,0x2,0x28,0x84,0x21,0xdd,0xc3,0xbd,0x4e,0xca,0xf2,0x42,0x9d,0x5a,0xda,0x45,0xb,0xd8,0x46,0x8f,0x2c,0xf4,0x69,0x2d,0x98,0xe2,0x2a,0x3f,0x4,0xa4,0x7f,0x74,0xdb,0xc4,0x75,0xce,0x9a,0xa,0x87,0x5d,0x63,0xba,0xcf,0x5e,0x4d,0x24,0xb2,0x17,0x7e,0x37,0x64,0xf8,0xb0,0x35,0x4a,0xbf,0xc5,0xaa,0x50,0xff,0x49,0x9e,0x11,0x96,0x68,0x1e,0x41,0xe3,0xf5,0x67,0x5c,0x8a,0x4c,0x57,0x6,0xe7,0x5b,0xc0,0x48,0x82,0x47,0xa7,0x1c,0x34,0xa3,0xd7,0x89,0xa9,0x26,0xfa,0xf3,0x16,0xdf,0x12,0xd3,0x95,0x78,0xa8,0xfc,0x65,0x9c,0xfb,0x43,0xb7,0x99,0xf9,0xb3,0xe9,0x7b,0x13,0xd1,0x3d,0x70,0x59,0x80,0x56,0x3e,0x7d,0xbb,0xb5,0xb9,0x32,0x61,0x5,0x6b,0xb4,0xac,0x92,0x53,0x4f,0x8,0xf6,0xc9,0x91,0xd9,0xa0,0x8c,0x1b,0x6f,0xec,0xc1,0x2e,0x27,0x20,0x19,0x14,0x76,0xcb,0xa6,0x90,0x66,0x97,0x6d,0x6c,0x36,0x2b,0xdc,0x81,0xde,0xf1,0x1d,0xf,0xae,0xe1,0x52,0x58,0xaf,0x7a,0xd,0x9,0x62,0x15,0x10,0x7,0x8b,0xed,0xc6,0xeb,0xf3,0x4d,0xc3,0x1c,0x5d,0xb5,0x2b,0x29,0xa7,0xb6,0xe0,0xea,0xf9,0x6,0x54,0x39,0xf0,0x87,0x4e,0xbe,0x9d,0x6b,0x8f,0xd6,0xbb,0x6d,0xa3,0x3e,0xe6,0xfe,0x8c,0xf1,0x90,0x0,0x67,0x4b,0xdb,0x70,0xaf,0x36,0x79,0xc6,0x5b,0xd5,0x85,0xce,0x25,0x8a,0x7a,0x69,0xc0,0x92,0x1a,0x9f,0x59,0xa1,0x76,0xff,0xa2,0x33,0x2a,0x42,0xd0,0x32,0x75,0xa,0xaa,0x4,0x71,0x4f,0xe5,0x89,0x37,0xf6,0x4a,0x98,0xb,0xde,0x11,0x44,0xca,0x14,0x7,0x34,0x2c,0xc5,0xe4,0xc9,0x62,0x12,0xba,0x19,0xc8,0x84,0x3b,0xb0,0xb2,0xd2,0xb3,0xcf,0xb1,0xb4,0x2,0xd8,0x63,0x15,0xa8,0x60,0xae,0xf,0xee,0xac,0xf4,0xc1,0x9b,0x6e,0xdf,0x72,0xa4,0x57,0xad,0x38,0x86,0x6a,0x95,0xdc,0xe7,0x50,0x9c,0xc7,0xfa,0xcd,0x13,0xe,0x4c,0xb7,0x94,0x5a,0xa9,0x3,0x46,0xb8,0x56,0x96,0xcb,0x2f,0x1,0xbd,0x93,0xeb,0x78,0x97,0x53,0x26,0x2d,0xe1,0x51,0xd3,0x52,0x64,0x7d,0xef,0x83,0xe2,0xdd,0x55,0x88,0x24,0xc4,0x9,0x20,0x10,0x6f,0xd7,0x5c,0x49,0x65,0xfd,0xfc,0xd4,0xa6,0x7e,0x9e,0xd9,0x28,0x81,0xb9,0x58,0x5e,0x99,0x16,0xfb,0xf8,0x6c,0x1f,0xd,0x8b,0x8d,0xd1,0xed,0xbc,0x5,0x7f,0xe8,0xa0,0x21,0x1b,0x68,0xf5,0xf2,0x47,0xe3,0xc2,0xec,0x41,0x7b,0x73,0x82,0x23,0x74,0x3d,0x27,0x77,0x1d,0x9a,0x1e,0x31,0x17,0x8,0x30,0x43,0xab,0x91,0x8e,0x18,0x3f,0xa5,0x80,0x3a,0x7c,0xcc,0x40,0xc,0x48,0xe9,0x35,0x3c,0x22,0x66,0x2e,0xda,0x45,0xbf,0x5f,0x61,0xf7,0xb0,0x12,0x34,0xa6,0xd9,0xf,0x4,0x1f,0xb4,0x55,0x93,0x8,0xd1,0x1b,0xf4,0x14,0xab,0x37,0x66,0xe3,0xec,0x19,0xf9,0x96,0xac,0x3,0xcd,0x1a,0xc5,0x42,0x4d,0x3b,0x36,0xaf,0xa8,0xcf,0xe4,0x10,0xaa,0xca,0xba,0xe0,0x40,0x28,0x6e,0x82,0xa,0x23,0x67,0x4f,0x84,0xf0,0xfa,0xda,0xa9,0x75,0x45,0xa0,0x41,0x8c,0xc6,0x80,0xfb,0x2b,0xa5,0x5b,0xc2,0x9a,0xf3,0x8a,0x48,0xdf,0xbf,0x3c,0x7d,0x92,0x73,0x74,0x47,0x4a,0x5,0xd3,0x2e,0x6d,0xe6,0xe8,0x61,0xea,0x56,0x32,0xe7,0x38,0xc1,0xff,0x1c,0x0,0xb2,0xfd,0xb,0x1,0x29,0xfc,0x5a,0x5e,0x46,0x31,0x54,0x43,0xbe,0xd8,0xb8,0x95,0x98,0x25,0xc3,0xf5,0xc4,0x35,0x3f,0x3e,0x78,0x65,0xd2,0x8f,0xa2,0x8d,0x5c,0x4e,0xdb,0x91,0xd6,0x7c,0x63,0xe2,0x52,0x4b,0x24,0xc0,0x9e,0x18,0x9f,0xae,0xbc,0x86,0x3d,0x9b,0xf8,0x85,0xdd,0xad,0x60,0x21,0xbb,0x53,0x49,0xb3,0x4c,0x22,0x13,0xbd,0x94,0x6b,0x76,0xde,0x2a,0x17,0xa3,0x71,0xef,0xb9,0x6a,0x33,0xb7,0x69,0xe5,0x50,0x83,0xf6,0x70,0xb5,0x5d,0xa4,0x68,0x2,0xc8,0xc7,0x81,0xb6,0xeb,0xed,0x7,0xcc,0xd7,0x7b,0x8e,0x72,0xee,0x90,0x99,0x1d,0x11,0xa1,0x9,0xce,0x16,0x89,0x8b,0x58,0x87,0xd5,0xc,0xf1,0x2f,0xfe,0x5f,0xf2,0x39,0x6,0xd0,0x6f,0x62,0x20,0x51,0x7a,0x9d,0x26,0x59,0xc9,0xe,0xd4,0xe9,0x30,0xd,0x9c,0x77,0x1e,0x44,0xe1,0x64,0x2d,0xdc,0x15,0xa7,0x7f,0x7e,0x3a,0xb1,0xcb,0x6c,0x79,0xf7,0x57,0x27,0x2c,0x97,0x88,0xd,0xf1,0x4,0xa8,0x62,0xe6,0xef,0x91,0xb1,0x76,0xde,0x6e,0x27,0xf4,0xf6,0x69,0x8e,0x73,0xaa,0xf8,0x8d,0x20,0x81,0x50,0x10,0xaf,0x79,0x46,0x5,0x2e,0x5f,0x1d,0xb6,0x26,0x59,0xe2,0x4f,0x96,0xab,0x71,0x61,0x8,0xe3,0x72,0x52,0x1b,0x9e,0x3b,0x0,0xd8,0x6a,0xa3,0xb4,0xce,0x45,0x1,0x28,0x88,0x6,0x13,0xf7,0xe8,0x53,0x58,0x3,0xa9,0xee,0xa4,0x34,0x2d,0x9d,0x1c,0x67,0xe1,0xbf,0x5b,0xf9,0xc3,0xd1,0xe0,0xfa,0x87,0xe4,0x42,0x5e,0x1f,0xd2,0xa2,0xcc,0x36,0x2c,0xc4,0xc2,0x6c,0x5d,0x33,0xa1,0x9,0x14,0xeb,0xe,0xdc,0x68,0x55,0x4c,0x15,0xc6,0x90,0x2f,0x9a,0x16,0xc8,0xca,0xf,0x89,0xfc,0x7d,0x17,0xdb,0x22,0xc9,0xfe,0xb8,0xb7,0xb3,0x78,0x92,0x94,0xe5,0xbd,0x24,0xda,0xa0,0x37,0xf5,0x8c,0xed,0x2,0x43,0xc0,0x35,0x38,0xb,0xc,0x12,0x51,0xac,0x7a,0x95,0x1e,0x97,0x99,0x47,0x98,0x4d,0x29,0x7f,0x63,0x80,0xbe,0x7e,0x74,0x82,0xcd,0x21,0x25,0x83,0x56,0x3c,0x2b,0x4e,0x39,0xea,0xc7,0xa7,0xc1,0x8a,0xbc,0x5a,0xe7,0x41,0x40,0x4a,0xbb,0xf0,0xad,0x1a,0x7,0x31,0x23,0xf2,0xdd,0xd9,0x4b,0x6d,0xcf,0x60,0x7b,0x70,0xa6,0x77,0xec,0x2a,0xcb,0x6b,0x8b,0x64,0xae,0x9c,0x19,0x48,0xd4,0xe9,0x86,0x66,0x93,0x65,0xb2,0x7c,0xd3,0x44,0x32,0x3d,0xba,0xb0,0xd7,0xd0,0x49,0xb5,0xd5,0x6f,0x9b,0x57,0x3f,0x9f,0xc5,0x5c,0x75,0xfd,0x11,0x8f,0xfb,0x30,0x18,0xa,0xd6,0xa5,0x85,0xf3,0x3e,0xdf,0x3a,0x54,0x84,0xff,0xb9,0x7a,0xdb,0x3a,0x78,0xb7,0xc1,0x7c,0xb4,0x65,0x60,0xd6,0xc,0x66,0x6,0x67,0x1b,0x41,0x8,0x33,0x84,0x79,0xec,0x52,0xbe,0xb,0xa6,0x70,0x83,0x20,0x15,0x4f,0xba,0xdf,0xa,0xc5,0x90,0xe3,0x22,0x9e,0x4c,0xa5,0x9b,0x31,0x5d,0xa1,0xde,0x7e,0xd0,0x1c,0x50,0xef,0x64,0xb6,0xc6,0x6e,0xcd,0xf8,0x11,0x30,0x1d,0x1e,0xc0,0xd3,0xe0,0x51,0x1a,0xf1,0x5e,0xad,0x12,0x8f,0x1,0xf,0xa4,0x7b,0xe2,0x44,0xd4,0xb3,0x9f,0xfe,0x96,0x4,0xe6,0xa2,0x2b,0x76,0xe7,0xce,0x4b,0x8d,0x75,0xae,0xbd,0x14,0x46,0x2d,0xd2,0x80,0xed,0x73,0x62,0x34,0x3e,0x89,0x61,0xff,0xfd,0x27,0x99,0x17,0xc8,0x32,0x2a,0x58,0x25,0x6f,0xb9,0x77,0xea,0x49,0xbf,0x5b,0x2,0x24,0x53,0x9a,0x6a,0x71,0x54,0xee,0xa8,0x45,0x5a,0xcc,0xeb,0xdc,0xe4,0x97,0x7f,0x4e,0xca,0xe5,0xc3,0x6b,0x8b,0xb5,0x23,0xb2,0xfa,0xe,0x91,0x3d,0xe1,0xe8,0xf6,0x18,0x94,0xd8,0x9c,0x74,0xf5,0xcf,0xbc,0x68,0xd1,0xab,0x3c,0x5f,0x59,0x5,0x39,0x2c,0xb8,0xcb,0xd9,0xe9,0xf3,0xa3,0xc9,0xa7,0x56,0xf7,0xa0,0x16,0x38,0x95,0xaf,0x21,0x26,0x93,0x37,0xbb,0x3,0x88,0x9d,0x10,0xdd,0xf4,0xc4,0x9,0x81,0x5c,0xf0,0xa9,0x3b,0x57,0x36,0x8a,0x4d,0xc2,0x2f,0xfc,0x55,0x6d,0x8c,0x72,0xaa,0x4a,0xd,0xb1,0x29,0x28,0x0,0x92,0x6c,0x82,0x42,0x40,0x8e,0x7d,0xd7,0xc7,0xda,0x98,0x63,0x48,0x13,0x2e,0x19,0x85,0x7,0x86,0xb0,0x87,0xf2,0xf9,0x35,0x47,0x3f,0xac,0x43,0x1f,0xfb,0xd5,0x69,0x53,0x94,0x4b,0xfb,0xd1,0x2,0x4c,0xd3,0xd4,0x28,0x8d,0x21,0xc3,0x47,0xb4,0xca,0x8a,0x35,0x63,0x5c,0xb,0x20,0x38,0x7a,0x56,0xab,0xdd,0x8f,0x5,0xa8,0x75,0xa4,0x2d,0x44,0x57,0xc6,0x3e,0x77,0x1e,0xbb,0x3,0x93,0xc7,0x7c,0xb3,0x6a,0x54,0x8e,0xad,0xd,0x36,0x23,0xcd,0xd2,0x7d,0x76,0xfd,0x25,0x86,0x4f,0xeb,0x91,0x24,0x60,0xc4,0x42,0x7e,0x9a,0xe6,0xdc,0xc5,0xf4,0x8c,0x26,0x81,0xcb,0x8,0x11,0x39,0xb8,0x13,0xe9,0xe1,0x9,0x49,0xe7,0x16,0x78,0xa2,0xdf,0x67,0xc1,0x3a,0x7b,0x87,0xf7,0x30,0x69,0xb5,0xe3,0xbf,0xa,0xed,0x33,0x2c,0x84,0xce,0x31,0xf9,0x2b,0x70,0x4d,0xdb,0xec,0x92,0x9d,0x5d,0x96,0xb1,0xb7,0x2a,0xef,0xd9,0xac,0x32,0x58,0x7,0xfe,0x27,0xc8,0xe5,0x66,0x1d,0x10,0x29,0x2e,0x98,0xc0,0xff,0x1,0x12,0x85,0xa9,0xd0,0xbd,0x62,0xc,0x68,0x46,0x5a,0x9b,0xa5,0x74,0x37,0x5f,0x89,0x3b,0xb0,0xbc,0xb2,0xe,0x19,0x1c,0x6b,0xe2,0xcf,0xe4,0x82,0x51,0x5b,0xe8,0xa7,0x0,0x4,0x73,0xa6,0x88,0xd5,0x22,0x3f,0x6,0x14,0xf8,0xd7,0x99,0xaf,0xc2,0x7f,0x65,0x64,0x9e,0x6f,0xc9,0x52,0xee,0xf,0xae,0x4e,0x8b,0x41,0x6e,0xfc,0xea,0x48,0x5e,0x45,0x83,0x55,0x97,0x40,0xf6,0x59,0x17,0x61,0x9f,0x18,0x3c,0xb9,0xf1,0x6d,0xa3,0xcc,0xb6,0x43,0x1a,0x72,0xe0,0xba,0x50,0x79,0x34,0xd8,0xf2,0x95,0x6c,0xf5,0xf0,0x90,0xbe,0x4a,0x1b,0xd6,0x1f,0xfa,0xa1,0x71,0x9c,0xda,0xde,0xaa,0x3d,0x15,0xf3,0x2f,0xa0,0x80,0x63,0xc1,0xe7,0x75,0xa,0xdc,0xd7,0xcc,0x67,0x86,0x40,0xdb,0x2,0xc8,0x27,0xc7,0x78,0xe4,0xb5,0x30,0x3f,0xca,0x2a,0x45,0x7f,0xd0,0x1e,0xc9,0x16,0x91,0x9e,0xe8,0xe5,0x7c,0x7b,0x1c,0x37,0xc3,0x79,0x19,0x69,0x33,0x93,0xfb,0xbd,0x51,0xd9,0xf0,0xb4,0x9c,0x57,0x23,0x29,0x9,0x7a,0xa6,0x96,0x73,0x92,0x5f,0x15,0x53,0x28,0xf8,0x76,0x88,0x11,0x49,0x20,0x59,0x9b,0xc,0x6c,0xef,0xae,0x41,0xa0,0xa7,0x94,0x99,0xd6,0x0,0xfd,0xbe,0x35,0x3b,0xb2,0x39,0x85,0xe1,0x34,0xeb,0x12,0x2c,0xcf,0xd3,0x61,0x2e,0xd8,0xd2,0xfa,0x2f,0x89,0x8d,0x95,0xe2,0x87,0x90,0x6d,0xb,0x6b,0x46,0x4b,0xf6,0x10,0x26,0x17,0xe6,0xec,0xed,0xab,0xb6,0x1,0x5c,0x71,0x5e,0x8f,0x9d,0x8,0x42,0x5,0xaf,0xb0,0x31,0x81,0x98,0xf7,0x13,0x4d,0xcb,0x4c,0x7d,0x6f,0x55,0xee,0x48,0x2b,0x56,0xe,0x7e,0xb3,0xf2,0x68,0x80,0x9a,0x60,0x9f,0xf1,0xc0,0x6e,0x47,0xb8,0xa5,0xd,0xf9,0xc4,0x70,0xa2,0x3c,0x6a,0xb9,0xe0,0x64,0xba,0x36,0x83,0x50,0x25,0xa3,0x66,0x8e,0x77,0xbb,0xd1,0x1b,0x14,0x52,0x65,0x38,0x3e,0xd4,0x1f,0x4,0xa8,0x5d,0xa1,0x3d,0x43,0x4a,0xce,0xc2,0x72,0xda,0x1d,0xc5,0x5a,0x58,0x8b,0x54,0x6,0xdf,0x22,0xfc,0x2d,0x8c,0x21,0xea,0xd5,0x3,0xbc,0xb1,0xf3,0x82,0xa9,0x4e,0xf5,0x8a,0x1a,0xdd,0x7,0x3a,0xe3,0xde,0x4f,0xa4,0xcd,0x97,0x32,0xb7,0xfe,0xf,0xc6,0x74,0xac,0xad,0xe9,0x62,0x18,0xbf,0xaa,0x24,0x84,0xf4,0xff,0x44,0x5b,0x9c,0xb9,0x60,0x26,0x92,0x8d,0x23,0x4,0x2c,0x14,0xb7,0x5f,0x2,0x86,0xb,0x2d,0x43,0xa3,0xeb,0x7d,0x32,0x7a,0x59,0xc6,0x29,0xf5,0x3e,0x20,0x5c,0xd0,0x54,0x10,0x3d,0xbc,0x74,0x7,0x19,0xa0,0xf4,0x63,0x91,0x97,0xf1,0xcd,0x70,0xe4,0x11,0x3,0x3b,0x21,0x1,0x6b,0x9e,0x6f,0x68,0x3f,0xf0,0xde,0x67,0x5d,0xee,0xe9,0xff,0x5b,0xcb,0x73,0x55,0x40,0x15,0xd8,0xc,0x3c,0x49,0xc1,0x38,0x94,0xf3,0x61,0xfe,0x9f,0x85,0x42,0xe7,0xa,0x9d,0x34,0x44,0xa5,0x62,0xba,0xc5,0x82,0xe1,0x79,0xc8,0xe0,0xa4,0x5a,0x8a,0x4a,0x46,0x88,0x1f,0xb5,0x12,0xf,0xab,0x50,0xdb,0x80,0xd1,0xe6,0xcf,0x4d,0x78,0x4e,0x3a,0x4f,0xfd,0x31,0xf7,0x8f,0x8b,0x64,0x33,0xd7,0xa1,0x1d,0x13,0xb2,0xb0,0xf2,0x9,0x7f,0x7c,0xb4,0xa8,0xad,0xc4,0x1e,0xce,0xae,0xd3,0xaf,0xc0,0x89,0x4c,0xfb,0x24,0xb1,0x76,0x9a,0x6e,0xc3,0x4b,0xb8,0xdd,0xe8,0x72,0x87,0xc2,0x17,0x58,0xd,0xea,0x2b,0x84,0x56,0x53,0x6d,0x95,0xf9,0x16,0x69,0x18,0xb6,0x98,0xd4,0xac,0x27,0xe,0x7e,0x5,0xa6,0xd9,0x30,0xd5,0xf8,0x8,0xd6,0x28,0x1b,0xd2,0x99,0x96,0x39,0xda,0x65,0xc9,0x47,0x6c,0xc7,0x2a,0xb3,0x1c,0x8c,0x57,0x7b,0x5e,0x36,0x2e,0xcc,0xe3,0x6a,0x2f,0xbe,0x83,0x6,0xbd,0x45,0x75,0x66,0x8e,0xdc,0x1a,0xe5,0x25,0x48,0xaa,0xbb,0xf6,0xfc,0xa9,0x41,0x35,0x37,0x51,0xef,0x0,0xdf,0xe2,0xfa,0xed,0x90,0x71,0xa7,0x22,0xbf,0x77,0x81,0xca,0x93,0x9b,0xec,0xa2,0x52,0xa1,0x7,0xbf,0xc2,0x97,0xe7,0x1b,0x5a,0x69,0x81,0x89,0x73,0x18,0x76,0x87,0x29,0xab,0xe1,0x46,0xec,0xd8,0x59,0x71,0x68,0xfa,0x1e,0x22,0xa4,0x94,0xa5,0xbc,0x86,0xcc,0xb9,0x8f,0x4a,0x9e,0x67,0x38,0x52,0xfd,0xf2,0x8c,0xbb,0xd7,0xd1,0xf6,0x3d,0x51,0xae,0xe4,0x4c,0x2d,0x10,0x4b,0x99,0x83,0xd5,0x9,0x50,0x53,0x8d,0x6a,0xdf,0xef,0xbd,0xcb,0x36,0xc4,0x15,0xc8,0x65,0x3c,0x3,0x55,0xea,0x1a,0x58,0x40,0x6b,0x41,0xed,0x48,0xb4,0xaa,0xd4,0x27,0xa3,0x9b,0x2b,0xf4,0x33,0xb3,0x2c,0x62,0xb1,0x2f,0xe6,0x45,0x9d,0x0,0x44,0xf1,0x8b,0x43,0x56,0x6d,0xcd,0x16,0x1d,0xb2,0xad,0x1c,0xa7,0xf3,0x63,0xee,0x34,0xa,0xd3,0xa6,0x37,0x24,0x4d,0xdb,0x7e,0x17,0x5e,0xd,0x91,0xd9,0x5c,0x23,0xd6,0xac,0xc3,0x39,0x96,0x20,0xf7,0x78,0xff,0x1,0x77,0x28,0x8a,0x9c,0xe,0x35,0xe3,0x25,0x3e,0x6f,0x8e,0x32,0xa9,0x21,0xeb,0x2e,0xce,0x75,0x5d,0xca,0xbe,0xe0,0xc0,0x4f,0x93,0x9a,0x7f,0xb6,0x7b,0xba,0xfc,0x11,0xc1,0x95,0xc,0xf5,0x92,0x2a,0xde,0xf0,0x90,0xda,0x80,0x12,0x7a,0xb8,0x54,0x19,0x30,0xe9,0x3f,0x57,0x14,0xd2,0xdc,0xd0,0x5b,0x8,0x6c,0x2,0xdd,0xc5,0xfb,0x3a,0x26,0x61,0x9f,0xa0,0xf8,0xb0,0xc9,0xe5,0x72,0x6,0x85,0xa8,0x47,0x4e,0x49,0x70,0x7d,0x1f,0xa2,0xcf,0xf9,0xf,0xfe,0x4,0x5,0x5f,0x42,0xb5,0xe8,0xb7,0x98,0x74,0x66,0xc7,0x88,0x3b,0x31,0xc6,0x13,0x64,0x60,0xb,0x7c,0x79,0x6e,0xe2,0x84,0xaf,0x82,0x28,0xef,0x30,0x80,0xaa,0x79,0x37,0xa8,0xaf,0x53,0xf6,0x5a,0xb8,0x3c,0xcf,0xb1,0xf1,0x4e,0x18,0x27,0x70,0x5b,0x43,0x1,0x2d,0xd0,0xa6,0xf4,0x7e,0xd3,0xe,0xdf,0x56,0x3f,0x2c,0xbd,0x45,0xc,0x65,0xc0,0x78,0xe8,0xbc,0x7,0xc8,0x11,0x2f,0xf5,0xd6,0x76,0x4d,0x58,0xb6,0xa9,0x6,0xd,0x86,0x5e,0xfd,0x34,0x90,0xea,0x5f,0x1b,0xbf,0x39,0x5,0xe1,0x9d,0xa7,0xbe,0x8f,0xf7,0x5d,0xfa,0xb0,0x73,0x6a,0x42,0xc3,0x68,0x92,0x9a,0x72,0x32,0x9c,0x6d,0x3,0xd9,0xa4,0x1c,0xba,0x41,0x0,0xfc,0x8c,0x4b,0x12,0xce,0x98,0xc4,0x71,0x96,0x48,0x57,0xff,0xb5,0x4a,0x82,0x50,0xb,0x36,0xa0,0x97,0xe9,0xe6,0x26,0xed,0xca,0xcc,0x51,0x94,0xa2,0xd7,0x49,0x23,0x7c,0x85,0x5c,0xb3,0x9e,0x1d,0x66,0x6b,0x52,0x55,0xe3,0xbb,0x84,0x7a,0x69,0xfe,0xd2,0xab,0xc6,0x19,0x77,0x13,0x3d,0x21,0xe0,0xde,0xf,0x4c,0x24,0xf2,0x40,0xcb,0xc7,0xc9,0x75,0x62,0x67,0x10,0x99,0xb4,0x9f,0xf9,0x2a,0x20,0x93,0xdc,0x7b,0x7f,0x8,0xdd,0xf3,0xae,0x59,0x44,0x7d,0x6f,0x83,0xac,0xe2,0xd4,0xb9,0x4,0x1e,0x1f,0xe5,0x14,0xb2,0x29,0x95,0x74,0xd5,0x35,0xf0,0x3a,0x15,0x87,0x91,0x33,0x25,0x3e,0xf8,0x2e,0xec,0x3b,0x8d,0x22,0x6c,0x1a,0xe4,0x63,0x47,0xc2,0x8a,0x16,0xd8,0xb7,0xcd,0x38,0x61,0x9,0x9b,0xc1,0x2b,0x2,0x4f,0xa3,0x89,0xee,0x17,0x8e,0x8b,0xeb,0xc5,0x31,0x60,0xad,0x64,0x81,0xda,0xa,0xe7,0xa1,0xa5,0xd1,0x46,0x6e,0x88,0x54,0xdb,0xfb,0xc8,0x1a,0xb5,0x74,0x93,0xc6,0x89,0x5c,0x28,0x86,0xf7,0x88,0x67,0xb,0xf3,0xcd,0x38,0x9b,0xe0,0x90,0xb9,0x32,0x4a,0x6,0x85,0xb6,0x48,0x96,0x66,0x4b,0xae,0x47,0x2a,0xe2,0xe1,0x97,0x6c,0x2e,0x2c,0x8d,0x31,0x4d,0x30,0x50,0x80,0x5a,0x33,0x36,0x4,0xe8,0x2f,0xba,0x65,0xd2,0x17,0x5e,0x19,0xec,0x76,0x43,0x26,0xd5,0x5d,0xf0,0x62,0x68,0x25,0x34,0xd6,0xbb,0x7b,0x84,0x41,0x9e,0x71,0xcf,0xa9,0xab,0xdf,0x37,0x21,0xbc,0x39,0xef,0xe,0x73,0x64,0x7c,0xcc,0x3c,0x72,0x5,0xd,0x54,0x1f,0xe9,0xd9,0x57,0xfb,0x44,0xa7,0x8,0x7,0x4c,0xe5,0xc9,0x12,0x82,0x2d,0xb4,0x59,0xf2,0x20,0xb1,0xf4,0x7d,0x52,0xb0,0xa8,0xc0,0x42,0x10,0xf8,0xeb,0xdb,0x23,0x98,0x1d,0xfd,0x6a,0x3e,0x87,0x99,0xea,0x22,0xa3,0x9d,0x8f,0x7a,0xee,0x53,0x6f,0x9,0xf,0xa1,0xf6,0xf1,0x0,0xf5,0x9f,0xbf,0xa5,0xc5,0x61,0x77,0x70,0xc3,0xf9,0x40,0x6e,0x9a,0xbd,0x13,0xc,0xb8,0xfe,0x27,0x2,0xb3,0x95,0x18,0x9c,0xc1,0x29,0x8a,0xb2,0x58,0xc7,0xe4,0xac,0xe3,0x75,0x3d,0xdd,0x8e,0xca,0x4e,0xc2,0xbe,0xa0,0x6b,0xb7,0x2b,0x81,0x16,0xd8,0xd4,0x14,0xc4,0x3a,0x78,0x4f,0x1e,0x45,0xce,0x35,0x91,0x8c,0xaf,0x63,0xd1,0xa4,0xd0,0xe6,0xd3,0x51,0x83,0x3f,0x49,0xad,0xfa,0x15,0x11,0x69,0xa2,0x92,0x46,0x8b,0xde,0xcb,0xed,0x55,0x1,0x60,0xff,0x6d,0xa,0xa6,0x5f,0xd7,0x3b,0xda,0xaa,0x3,0x94,0x79,0xdc,0x1b,0x7e,0x56,0xe7,0x7f,0x1c,0x5b,0x24,0xfc,0xf0,0xc,0xf9,0x55,0x9f,0x1b,0x12,0x6c,0x4c,0x8b,0x23,0x93,0xda,0x9,0xb,0x94,0x73,0x8e,0x57,0x5,0x70,0xdd,0x7c,0xad,0xed,0x52,0x84,0xbb,0xf8,0xd3,0xa2,0xe0,0x4b,0xdb,0xa4,0x1f,0xb2,0x6b,0x56,0x8c,0x9c,0xf5,0x1e,0x8f,0xaf,0xe6,0x63,0xc6,0xfd,0x25,0x97,0x5e,0x49,0x33,0xb8,0xfc,0xd5,0x75,0xfb,0xee,0xa,0x15,0xae,0xa5,0xfe,0x54,0x13,0x59,0xc9,0xd0,0x60,0xe1,0x9a,0x1c,0x42,0xa6,0x4,0x3e,0x2c,0x1d,0x7,0x7a,0x19,0xbf,0xa3,0xe2,0x2f,0x5f,0x31,0xcb,0xd1,0x39,0x3f,0x91,0xa0,0xce,0x5c,0xf4,0xe9,0x16,0xf3,0x21,0x95,0xa8,0xb1,0xe8,0x3b,0x6d,0xd2,0x67,0xeb,0x35,0x37,0xf2,0x74,0x1,0x80,0xea,0x26,0xdf,0x34,0x3,0x45,0x4a,0x4e,0x85,0x6f,0x69,0x18,0x40,0xd9,0x27,0x5d,0xca,0x8,0x71,0x10,0xff,0xbe,0x3d,0xc8,0xc5,0xf6,0xf1,0xef,0xac,0x51,0x87,0x68,0xe3,0x6a,0x64,0xba,0x65,0xb0,0xd4,0x82,0x9e,0x7d,0x43,0x83,0x89,0x7f,0x30,0xdc,0xd8,0x7e,0xab,0xc1,0xd6,0xb3,0xc4,0x17,0x3a,0x5a,0x3c,0x77,0x41,0xa7,0x1a,0xbc,0xbd,0xb7,0x46,0xd,0x50,0xe7,0xfa,0xcc,0xde,0xf,0x20,0x24,0xb6,0x90,0x32,0x9d,0x86,0x8d,0x5b,0x8a,0x11,0xd7,0x36,0x96,0x76,0x99,0x53,0x61,0xe4,0xb5,0x29,0x14,0x7b,0x9b,0x6e,0x98,0x4f,0x81,0x2e,0xb9,0xcf,0xc0,0x47,0x4d,0x2a,0x2d,0xb4,0x48,0x28,0x92,0x66,0xaa,0xc2,0x62,0x38,0xa1,0x88,0x0,0xec,0x72,0x6,0xcd,0xe5,0xf7,0x2b,0x58,0x78,0xe,0xc3,0x22,0xc7,0xa9,0x79,0x2,0x44,0x8f,0x29,0x91,0xec,0xb9,0xc9,0x35,0x74,0x47,0xaf,0xa7,0x5d,0x36,0x58,0xa9,0x7,0x85,0xcf,0x68,0xc2,0xf6,0x77,0x5f,0x46,0xd4,0x30,0xc,0x8a,0xba,0x8b,0x92,0xa8,0xe2,0x97,0xa1,0x64,0xb0,0x49,0x16,0x7c,0xd3,0xdc,0xa2,0x95,0xf9,0xff,0xd8,0x13,0x7f,0x80,0xca,0x62,0x3,0x3e,0x65,0xb7,0xad,0xfb,0x27,0x7e,0x7d,0xa3,0x44,0xf1,0xc1,0x93,0xe5,0x18,0xea,0x3b,0xe6,0x4b,0x12,0x2d,0x7b,0xc4,0x34,0x76,0x6e,0x45,0x6f,0xc3,0x66,0x9a,0x84,0xfa,0x9,0x8d,0xb5,0x5,0xda,0x1d,0x9d,0x2,0x4c,0x9f,0x1,0xc8,0x6b,0xb3,0x2e,0x6a,0xdf,0xa5,0x6d,0x78,0x43,0xe3,0x38,0x33,0x9c,0x83,0x32,0x89,0xdd,0x4d,0xc0,0x1a,0x24,0xfd,0x88,0x19,0xa,0x63,0xf5,0x50,0x39,0x70,0x23,0xbf,0xf7,0x72,0xd,0xf8,0x82,0xed,0x17,0xb8,0xe,0xd9,0x56,0xd1,0x2f,0x59,0x6,0xa4,0xb2,0x20,0x1b,0xcd,0xb,0x10,0x41,0xa0,0x1c,0x87,0xf,0xc5,0x0,0xe0,0x5b,0x73,0xe4,0x90,0xce,0xee,0x61,0xbd,0xb4,0x51,0x98,0x55,0x94,0xd2,0x3f,0xef,0xbb,0x22,0xdb,0xbc,0x4,0xf0,0xde,0xbe,0xf4,0xae,0x3c,0x54,0x96,0x7a,0x37,0x1e,0xc7,0x11,0x79,0x3a,0xfc,0xf2,0xfe,0x75,0x26,0x42,0x2c,0xf3,0xeb,0xd5,0x14,0x8,0x4f,0xb1,0x8e,0xd6,0x9e,0xe7,0xcb,0x5c,0x28,0xab,0x86,0x69,0x60,0x67,0x5e,0x53,0x31,0x8c,0xe1,0xd7,0x21,0xd0,0x2a,0x2b,0x71,0x6c,0x9b,0xc6,0x99,0xb6,0x5a,0x48,0xe9,0xa6,0x15,0x1f,0xe8,0x3d,0x4a,0x4e,0x25,0x52,0x57,0x40,0xcc,0xaa,0x81,0xac,0xa7,0x25,0x10,0x26,0x52,0x27,0x95,0x59,0x9f,0xe7,0xe3,0xc,0x5b,0xbf,0xc9,0x75,0xcc,0x32,0xe2,0x22,0x2e,0xe0,0x77,0xdd,0x7a,0x67,0xc3,0x38,0xb3,0xe8,0xb9,0x8e,0xed,0x2a,0x8f,0x62,0xf5,0x5c,0x2c,0xcd,0xa,0xd2,0xad,0xea,0x89,0x11,0xa0,0x88,0xa3,0x1b,0x3d,0x28,0x7d,0xb0,0x64,0x54,0x21,0xa9,0x50,0xfc,0x9b,0x9,0x96,0xf7,0x53,0x49,0x69,0x3,0xf6,0x7,0x0,0x57,0x98,0xb6,0xf,0x35,0x86,0x81,0x97,0x33,0x55,0xd4,0x1c,0x6f,0x71,0xc8,0x9c,0xb,0xf9,0xff,0x99,0xa5,0x18,0x8c,0x79,0x6b,0x2b,0xcb,0x83,0x15,0x5a,0x12,0x31,0xae,0x41,0x9d,0x56,0x48,0x34,0xb8,0x3c,0x78,0xf4,0xd1,0x8,0x4e,0xfa,0xe5,0x4b,0x6c,0x44,0x7c,0xdf,0x37,0x6a,0xee,0x63,0x45,0x8a,0x92,0x85,0xf8,0x19,0xcf,0x4a,0xd7,0x1f,0xe9,0xa2,0xfb,0xf3,0x84,0xca,0x3a,0x72,0x8d,0x4d,0x20,0xc2,0xd3,0x9e,0x94,0xc1,0x29,0x5d,0x5f,0x39,0x87,0x68,0xb7,0x36,0x5e,0x46,0xa4,0x8b,0x2,0x47,0xd6,0xeb,0x6e,0xd5,0x2d,0x1d,0xe,0xe6,0xb4,0xba,0xf1,0xfe,0x51,0xb2,0xd,0xa1,0x2f,0x4,0xaf,0x42,0xdb,0x74,0xe4,0x3f,0x13,0xf0,0xbc,0xc4,0x4f,0x66,0x16,0x6d,0xce,0xb1,0x58,0xbd,0x90,0x60,0xbe,0x40,0x73,0xaa,0x7f,0x30,0x65,0x82,0x43,0xec,0x3e,0x3b,0x5,0xfd,0x91,0x7e,0x1,0x70,0xde,0xa8,0xe1,0x24,0x93,0x4c,0xd9,0x1e,0xf2,0x6,0xab,0x23,0xd0,0xb5,0x80,0x1a,0xef,0x7b,0xda,0xd8,0x9a,0x61,0x17,0x14,0xdc,0xc0,0xc5,0xac,0x76,0xa6,0xc6,0xbb,0xc7,0x7e,0xdc,0xfa,0x68,0x17,0xc1,0xca,0xd1,0x7a,0x9b,0x5d,0xc6,0x1f,0xd5,0x3a,0xda,0x65,0xf9,0xa8,0x2d,0x22,0xd7,0x37,0x58,0x62,0xcd,0x3,0xd4,0xb,0x8c,0x83,0xf5,0xf8,0x61,0x66,0x1,0x2a,0xde,0x64,0x4,0x74,0x2e,0x8e,0xe6,0xa0,0x4c,0xc4,0xed,0xa9,0x81,0x4a,0x3e,0x34,0x14,0x67,0xbb,0x8b,0x6e,0x8f,0x42,0x8,0x4e,0x35,0xe5,0x6b,0x95,0xc,0x54,0x3d,0x44,0x86,0x11,0x71,0xf2,0xb3,0x5c,0xbd,0xba,0x89,0x84,0xcb,0x1d,0xe0,0xa3,0x28,0x26,0xaf,0x24,0x98,0xfc,0x29,0xf6,0xf,0x31,0xd2,0xce,0x7c,0x33,0xc5,0xcf,0xe7,0x32,0x94,0x90,0x88,0xff,0x9a,0x8d,0x70,0x16,0x76,0x5b,0x56,0xeb,0xd,0x3b,0xa,0xfb,0xf1,0xf0,0xb6,0xab,0x1c,0x41,0x6c,0x43,0x92,0x80,0x15,0x5f,0x18,0xb2,0xad,0x2c,0x9c,0x85,0xea,0xe,0x50,0xd6,0x51,0x60,0x72,0x48,0xf3,0x55,0x36,0x4b,0x13,0x63,0xae,0xef,0x75,0x9d,0x87,0x7d,0x82,0xec,0xdd,0x73,0x5a,0xa5,0xb8,0x10,0xe4,0xd9,0x6d,0xbf,0x21,0x77,0xa4,0xfd,0x79,0xa7,0x2b,0x9e,0x4d,0x38,0xbe,0x7b,0x93,0x6a,0xa6,0xcc,0x6,0x9,0x4f,0x78,0x25,0x23,0xc9,0x2,0x19,0xb5,0x40,0xbc,0x20,0x5e,0x57,0xd3,0xdf,0x6f,0xc7,0x0,0xd8,0x47,0x45,0x96,0x49,0x1b,0xc2,0x3f,0xe1,0x30,0x91,0x3c,0xf7,0xc8,0x1e,0xa1,0xac,0xee,0x9f,0xb4,0x53,0xe8,0x97,0x7,0xc0,0x1a,0x27,0xfe,0xc3,0x52,0xb9,0xd0,0x8a,0x2f,0xaa,0xe3,0x12,0xdb,0x69,0xb1,0xb0,0xf4,0x7f,0x5,0xa2,0xb7,0x39,0x99,0xe9,0xe2,0x59,0x46,0x54,0xa8,0x5d,0xf1,0x3b,0xbf,0xb6,0xc8,0xe8,0x2f,0x87,0x37,0x7e,0xad,0xaf,0x30,0xd7,0x2a,0xf3,0xa1,0xd4,0x79,0xd8,0x9,0x49,0xf6,0x20,0x1f,0x5c,0x77,0x6,0x44,0xef,0x7f,0x0,0xbb,0x16,0xcf,0xf2,0x28,0x38,0x51,0xba,0x2b,0xb,0x42,0xc7,0x62,0x59,0x81,0x33,0xfa,0xed,0x97,0x1c,0x58,0x71,0xd1,0x5f,0x4a,0xae,0xb1,0xa,0x1,0x5a,0xf0,0xb7,0xfd,0x6d,0x74,0xc4,0x45,0x3e,0xb8,0xe6,0x2,0xa0,0x9a,0x88,0xb9,0xa3,0xde,0xbd,0x1b,0x7,0x46,0x8b,0xfb,0x95,0x6f,0x75,0x9d,0x9b,0x35,0x4,0x6a,0xf8,0x50,0x4d,0xb2,0x57,0x85,0x31,0xc,0x15,0x4c,0x9f,0xc9,0x76,0xc3,0x4f,0x91,0x93,0x56,0xd0,0xa5,0x24,0x4e,0x82,0x7b,0x90,0xa7,0xe1,0xee,0xea,0x21,0xcb,0xcd,0xbc,0xe4,0x7d,0x83,0xf9,0x6e,0xac,0xd5,0xb4,0x5b,0x1a,0x99,0x6c,0x61,0x52,0x55,0x4b,0x8,0xf5,0x23,0xcc,0x47,0xce,0xc0,0x1e,0xc1,0x14,0x70,0x26,0x3a,0xd9,0xe7,0x27,0x2d,0xdb,0x94,0x78,0x7c,0xda,0xf,0x65,0x72,0x17,0x60,0xb3,0x9e,0xfe,0x98,0xd3,0xe5,0x3,0xbe,0x18,0x19,0x13,0xe2,0xa9,0xf4,0x43,0x5e,0x68,0x7a,0xab,0x84,0x80,0x12,0x34,0x96,0x39,0x22,0x29,0xff,0x2e,0xb5,0x73,0x92,0x32,0xd2,0x3d,0xf7,0xc5,0x40,0x11,0x8d,0xb0,0xdf,0x3f,0xca,0x3c,0xeb,0x25,0x8a,0x1d,0x6b,0x64,0xe3,0xe9,0x8e,0x89,0x10,0xec,0x8c,0x36,0xc2,0xe,0x66,0xc6,0x9c,0x5,0x2c,0xa4,0x48,0xd6,0xa2,0x69,0x41,0x53,0x8f,0xfc,0xdc,0xaa,0x67,0x86,0x63,0xd,0xdd,0xa6,0xe0}; uint32_t table_s9[] = {0x7cba6f01,0x2c06b734,0x220ec640,0x72b21e75,0x82c46d87,0xd278b5b2,0xdc70c4c6,0x8ccc1cf3,0xa4a8a905,0xf4147130,0xfa1c0044,0xaaa0d871,0x5ad6ab83,0xa6a73b6,0x46202c2,0x54dedaf7,0x2854fa3e,0x78e8220b,0x76e0537f,0x265c8b4a,0xd62af8b8,0x8696208d,0x889e51f9,0xd82289cc,0xf0463c3a,0xa0fae40f,0xaef2957b,0xfe4e4d4e,0xe383ebc,0x5e84e689,0x508c97fd,0x304fc8,0x613fde08,0x3183063d,0x3f8b7749,0x6f37af7c,0x9f41dc8e,0xcffd04bb,0xc1f575cf,0x9149adfa,0xb92d180c,0xe991c039,0xe799b14d,0xb7256978,0x47531a8a,0x17efc2bf,0x19e7b3cb,0x495b6bfe,0x35d14b37,0x656d9302,0x6b65e276,0x3bd93a43,0xcbaf49b1,0x9b139184,0x951be0f0,0xc5a738c5,0xedc38d33,0xbd7f5506,0xb3772472,0xe3cbfc47,0x13bd8fb5,0x43015780,0x4d0926f4,0x1db5fec1,0x8ab92d9,0x58174aec,0x561f3b98,0x6a3e3ad,0xf6d5905f,0xa669486a,0xa861391e,0xf8dde12b,0xd0b954dd,0x80058ce8,0x8e0dfd9c,0xdeb125a9,0x2ec7565b,0x7e7b8e6e,0x7073ff1a,0x20cf272f,0x5c4507e6,0xcf9dfd3,0x2f1aea7,0x524d7692,0xa23b0560,0xf287dd55,0xfc8fac21,0xac337414,0x8457c1e2,0xd4eb19d7,0xdae368a3,0x8a5fb096,0x7a29c364,0x2a951b51,0x249d6a25,0x7421b210,0x152e23d0,0x4592fbe5,0x4b9a8a91,0x1b2652a4,0xeb502156,0xbbecf963,0xb5e48817,0xe5585022,0xcd3ce5d4,0x9d803de1,0x93884c95,0xc33494a0,0x3342e752,0x63fe3f67,0x6df64e13,0x3d4a9626,0x41c0b6ef,0x117c6eda,0x1f741fae,0x4fc8c79b,0xbfbeb469,0xef026c5c,0xe10a1d28,0xb1b6c51d,0x99d270eb,0xc96ea8de,0xc766d9aa,0x97da019f,0x67ac726d,0x3710aa58,0x3918db2c,0x69a40319,0xec5d851c,0xbce15d29,0xb2e92c5d,0xe255f468,0x1223879a,0x429f5faf,0x4c972edb,0x1c2bf6ee,0x344f4318,0x64f39b2d,0x6afbea59,0x3a47326c,0xca31419e,0x9a8d99ab,0x9485e8df,0xc43930ea,0xb8b31023,0xe80fc816,0xe607b962,0xb6bb6157,0x46cd12a5,0x1671ca90,0x1879bbe4,0x48c563d1,0x60a1d627,0x301d0e12,0x3e157f66,0x6ea9a753,0x9edfd4a1,0xce630c94,0xc06b7de0,0x90d7a5d5,0xf1d83415,0xa164ec20,0xaf6c9d54,0xffd04561,0xfa63693,0x5f1aeea6,0x51129fd2,0x1ae47e7,0x29caf211,0x79762a24,0x777e5b50,0x27c28365,0xd7b4f097,0x870828a2,0x890059d6,0xd9bc81e3,0xa536a12a,0xf58a791f,0xfb82086b,0xab3ed05e,0x5b48a3ac,0xbf47b99,0x5fc0aed,0x5540d2d8,0x7d24672e,0x2d98bf1b,0x2390ce6f,0x732c165a,0x835a65a8,0xd3e6bd9d,0xddeecce9,0x8d5214dc,0x984c78c4,0xc8f0a0f1,0xc6f8d185,0x964409b0,0x66327a42,0x368ea277,0x3886d303,0x683a0b36,0x405ebec0,0x10e266f5,0x1eea1781,0x4e56cfb4,0xbe20bc46,0xee9c6473,0xe0941507,0xb028cd32,0xcca2edfb,0x9c1e35ce,0x921644ba,0xc2aa9c8f,0x32dcef7d,0x62603748,0x6c68463c,0x3cd49e09,0x14b02bff,0x440cf3ca,0x4a0482be,0x1ab85a8b,0xeace2979,0xba72f14c,0xb47a8038,0xe4c6580d,0x85c9c9cd,0xd57511f8,0xdb7d608c,0x8bc1b8b9,0x7bb7cb4b,0x2b0b137e,0x2503620a,0x75bfba3f,0x5ddb0fc9,0xd67d7fc,0x36fa688,0x53d37ebd,0xa3a50d4f,0xf319d57a,0xfd11a40e,0xadad7c3b,0xd1275cf2,0x819b84c7,0x8f93f5b3,0xdf2f2d86,0x2f595e74,0x7fe58641,0x71edf735,0x21512f00,0x9359af6,0x598942c3,0x578133b7,0x73deb82,0xf74b9870,0xa7f74045,0xa9ff3131,0xf943e904,0xcdbd827d,0x7165b72d,0x7914c323,0xc5ccf673,0xb3bf0483,0xf6731d3,0x71645dd,0xbbce708d,0xdf7b86a5,0x63a3b3f5,0x6bd2c7fb,0xd70af2ab,0xa179005b,0x1da1350b,0x15d04105,0xa9087455,0x2328bd29,0x9ff08879,0x9781fc77,0x2b59c927,0x5d2a3bd7,0xe1f20e87,0xe9837a89,0x555b4fd9,0x31eeb9f1,0x8d368ca1,0x8547f8af,0x399fcdff,0x4fec3f0f,0xf3340a5f,0xfb457e51,0x479d4b01,0x480c8b60,0xf4d4be30,0xfca5ca3e,0x407dff6e,0x360e0d9e,0x8ad638ce,0x82a74cc0,0x3e7f7990,0x5aca8fb8,0xe612bae8,0xee63cee6,0x52bbfbb6,0x24c80946,0x98103c16,0x90614818,0x2cb97d48,0xa699b434,0x1a418164,0x1230f56a,0xaee8c03a,0xd89b32ca,0x6443079a,0x6c327394,0xd0ea46c4,0xb45fb0ec,0x88785bc,0xf6f1b2,0xbc2ec4e2,0xca5d3612,0x76850342,0x7ef4774c,0xc22c421c,0xdc405a09,0x60986f59,0x68e91b57,0xd4312e07,0xa242dcf7,0x1e9ae9a7,0x16eb9da9,0xaa33a8f9,0xce865ed1,0x725e6b81,0x7a2f1f8f,0xc6f72adf,0xb084d82f,0xc5ced7f,0x42d9971,0xb8f5ac21,0x32d5655d,0x8e0d500d,0x867c2403,0x3aa41153,0x4cd7e3a3,0xf00fd6f3,0xf87ea2fd,0x44a697ad,0x20136185,0x9ccb54d5,0x94ba20db,0x2862158b,0x5e11e77b,0xe2c9d22b,0xeab8a625,0x56609375,0x59f15314,0xe5296644,0xed58124a,0x5180271a,0x27f3d5ea,0x9b2be0ba,0x935a94b4,0x2f82a1e4,0x4b3757cc,0xf7ef629c,0xff9e1692,0x434623c2,0x3535d132,0x89ede462,0x819c906c,0x3d44a53c,0xb7646c40,0xbbc5910,0x3cd2d1e,0xbf15184e,0xc966eabe,0x75bedfee,0x7dcfabe0,0xc1179eb0,0xa5a26898,0x197a5dc8,0x110b29c6,0xadd31c96,0xdba0ee66,0x6778db36,0x6f09af38,0xd3d19a68,0x2a579fed,0x968faabd,0x9efedeb3,0x2226ebe3,0x54551913,0xe88d2c43,0xe0fc584d,0x5c246d1d,0x38919b35,0x8449ae65,0x8c38da6b,0x30e0ef3b,0x46931dcb,0xfa4b289b,0xf23a5c95,0x4ee269c5,0xc4c2a0b9,0x781a95e9,0x706be1e7,0xccb3d4b7,0xbac02647,0x6181317,0xe696719,0xb2b15249,0xd604a461,0x6adc9131,0x62ade53f,0xde75d06f,0xa806229f,0x14de17cf,0x1caf63c1,0xa0775691,0xafe696f0,0x133ea3a0,0x1b4fd7ae,0xa797e2fe,0xd1e4100e,0x6d3c255e,0x654d5150,0xd9956400,0xbd209228,0x1f8a778,0x989d376,0xb551e626,0xc32214d6,0x7ffa2186,0x778b5588,0xcb5360d8,0x4173a9a4,0xfdab9cf4,0xf5dae8fa,0x4902ddaa,0x3f712f5a,0x83a91a0a,0x8bd86e04,0x37005b54,0x53b5ad7c,0xef6d982c,0xe71cec22,0x5bc4d972,0x2db72b82,0x916f1ed2,0x991e6adc,0x25c65f8c,0x3baa4799,0x877272c9,0x8f0306c7,0x33db3397,0x45a8c167,0xf970f437,0xf1018039,0x4dd9b569,0x296c4341,0x95b47611,0x9dc5021f,0x211d374f,0x576ec5bf,0xebb6f0ef,0xe3c784e1,0x5f1fb1b1,0xd53f78cd,0x69e74d9d,0x61963993,0xdd4e0cc3,0xab3dfe33,0x17e5cb63,0x1f94bf6d,0xa34c8a3d,0xc7f97c15,0x7b214945,0x73503d4b,0xcf88081b,0xb9fbfaeb,0x523cfbb,0xd52bbb5,0xb18a8ee5,0xbe1b4e84,0x2c37bd4,0xab20fda,0xb66a3a8a,0xc019c87a,0x7cc1fd2a,0x74b08924,0xc868bc74,0xacdd4a5c,0x10057f0c,0x18740b02,0xa4ac3e52,0xd2dfcca2,0x6e07f9f2,0x66768dfc,0xdaaeb8ac,0x508e71d0,0xec564480,0xe427308e,0x58ff05de,0x2e8cf72e,0x9254c27e,0x9a25b670,0x26fd8320,0x42487508,0xfe904058,0xf6e13456,0x4a390106,0x3c4af3f6,0x8092c6a6,0x88e3b2a8,0x343b87f8,0xd78d63dd,0xfb83361,0x7ecc3d69,0xa6f96dd5,0xd50b9da3,0xd3ecd1f,0x7c4ac317,0xa47f93ab,0x1189bbcf,0xc9bceb73,0xb8c8e57b,0x60fdb5c7,0x130f45b1,0xcb3a150d,0xba4e1b05,0x627b4bb9,0x42b23733,0x9a87678f,0xebf36987,0x33c6393b,0x4034c94d,0x980199f1,0xe97597f9,0x3140c745,0x84b6ef21,0x5c83bf9d,0x2df7b195,0xf5c2e129,0x8630115f,0x5e0541e3,0x2f714feb,0xf7441f57,0x66847e58,0xbeb12ee4,0xcfc520ec,0x17f07050,0x64028026,0xbc37d09a,0xcd43de92,0x15768e2e,0xa080a64a,0x78b5f6f6,0x9c1f8fe,0xd1f4a842,0xa2065834,0x7a330888,0xb470680,0xd372563c,0xf3bb2ab6,0x2b8e7a0a,0x5afa7402,0x82cf24be,0xf13dd4c8,0x29088474,0x587c8a7c,0x8049dac0,0x35bff2a4,0xed8aa218,0x9cfeac10,0x44cbfcac,0x37390cda,0xef0c5c66,0x9e78526e,0x464d02d2,0x2a5517cc,0xf2604770,0x83144978,0x5b2119c4,0x28d3e9b2,0xf0e6b90e,0x8192b706,0x59a7e7ba,0xec51cfde,0x34649f62,0x4510916a,0x9d25c1d6,0xeed731a0,0x36e2611c,0x47966f14,0x9fa33fa8,0xbf6a4322,0x675f139e,0x162b1d96,0xce1e4d2a,0xbdecbd5c,0x65d9ede0,0x14ade3e8,0xcc98b354,0x796e9b30,0xa15bcb8c,0xd02fc584,0x81a9538,0x7be8654e,0xa3dd35f2,0xd2a93bfa,0xa9c6b46,0x9b5c0a49,0x43695af5,0x321d54fd,0xea280441,0x99daf437,0x41efa48b,0x309baa83,0xe8aefa3f,0x5d58d25b,0x856d82e7,0xf4198cef,0x2c2cdc53,0x5fde2c25,0x87eb7c99,0xf69f7291,0x2eaa222d,0xe635ea7,0xd6560e1b,0xa7220013,0x7f1750af,0xce5a0d9,0xd4d0f065,0xa5a4fe6d,0x7d91aed1,0xc86786b5,0x1052d609,0x6126d801,0xb91388bd,0xcae178cb,0x12d42877,0x63a0267f,0xbb9576c3,0x3d90f33a,0xe5a5a386,0x94d1ad8e,0x4ce4fd32,0x3f160d44,0xe7235df8,0x965753f0,0x4e62034c,0xfb942b28,0x23a17b94,0x52d5759c,0x8ae02520,0xf912d556,0x212785ea,0x50538be2,0x8866db5e,0xa8afa7d4,0x709af768,0x1eef960,0xd9dba9dc,0xaa2959aa,0x721c0916,0x368071e,0xdb5d57a2,0x6eab7fc6,0xb69e2f7a,0xc7ea2172,0x1fdf71ce,0x6c2d81b8,0xb418d104,0xc56cdf0c,0x1d598fb0,0x8c99eebf,0x54acbe03,0x25d8b00b,0xfdede0b7,0x8e1f10c1,0x562a407d,0x275e4e75,0xff6b1ec9,0x4a9d36ad,0x92a86611,0xe3dc6819,0x3be938a5,0x481bc8d3,0x902e986f,0xe15a9667,0x396fc6db,0x19a6ba51,0xc193eaed,0xb0e7e4e5,0x68d2b459,0x1b20442f,0xc3151493,0xb2611a9b,0x6a544a27,0xdfa26243,0x79732ff,0x76e33cf7,0xaed66c4b,0xdd249c3d,0x511cc81,0x7465c289,0xac509235,0xc048872b,0x187dd797,0x6909d99f,0xb13c8923,0xc2ce7955,0x1afb29e9,0x6b8f27e1,0xb3ba775d,0x64c5f39,0xde790f85,0xaf0d018d,0x77385131,0x4caa147,0xdcfff1fb,0xad8bfff3,0x75beaf4f,0x5577d3c5,0x8d428379,0xfc368d71,0x2403ddcd,0x57f12dbb,0x8fc47d07,0xfeb0730f,0x268523b3,0x93730bd7,0x4b465b6b,0x3a325563,0xe20705df,0x91f5f5a9,0x49c0a515,0x38b4ab1d,0xe081fba1,0x71419aae,0xa974ca12,0xd800c41a,0x3594a6,0x73c764d0,0xabf2346c,0xda863a64,0x2b36ad8,0xb74542bc,0x6f701200,0x1e041c08,0xc6314cb4,0xb5c3bcc2,0x6df6ec7e,0x1c82e276,0xc4b7b2ca,0xe47ece40,0x3c4b9efc,0x4d3f90f4,0x950ac048,0xe6f8303e,0x3ecd6082,0x4fb96e8a,0x978c3e36,0x227a1652,0xfa4f46ee,0x8b3b48e6,0x530e185a,0x20fce82c,0xf8c9b890,0x89bdb698,0x5188e624,0x52ae490,0x307a5848,0x44745039,0x7124ece1,0x83d49a92,0xb684264a,0xc28a2e3b,0xf7da92e3,0x1f2f656,0x34a24a8e,0x40ac42ff,0x75fcfe27,0x870c8854,0xb25c348c,0xc6523cfd,0xf3028025,0x3a7e0a05,0xf2eb6dd,0x7b20beac,0x4e700274,0xbc807407,0x89d0c8df,0xfddec0ae,0xc88e7c76,0x3ea618c3,0xbf6a41b,0x7ff8ac6a,0x4aa810b2,0xb85866c1,0x8d08da19,0xf906d268,0xcc566eb0,0xc376121,0x3967ddf9,0x4d69d588,0x78396950,0x8ac91f23,0xbf99a3fb,0xcb97ab8a,0xfec71752,0x8ef73e7,0x3dbfcf3f,0x49b1c74e,0x7ce17b96,0x8e110de5,0xbb41b13d,0xcf4fb94c,0xfa1f0594,0x33638fb4,0x633336c,0x723d3b1d,0x476d87c5,0xb59df1b6,0x80cd4d6e,0xf4c3451f,0xc193f9c7,0x37bb9d72,0x2eb21aa,0x76e529db,0x43b59503,0xb145e370,0x84155fa8,0xf01b57d9,0xc54beb01,0xdd5ef56d,0xe80e49b5,0x9c0041c4,0xa950fd1c,0x5ba08b6f,0x6ef037b7,0x1afe3fc6,0x2fae831e,0xd986e7ab,0xecd65b73,0x98d85302,0xad88efda,0x5f7899a9,0x6a282571,0x1e262d00,0x2b7691d8,0xe20a1bf8,0xd75aa720,0xa354af51,0x96041389,0x64f465fa,0x51a4d922,0x25aad153,0x10fa6d8b,0xe6d2093e,0xd382b5e6,0xa78cbd97,0x92dc014f,0x602c773c,0x557ccbe4,0x2172c395,0x14227f4d,0xd44370dc,0xe113cc04,0x951dc475,0xa04d78ad,0x52bd0ede,0x67edb206,0x13e3ba77,0x26b306af,0xd09b621a,0xe5cbdec2,0x91c5d6b3,0xa4956a6b,0x56651c18,0x6335a0c0,0x173ba8b1,0x226b1469,0xeb179e49,0xde472291,0xaa492ae0,0x9f199638,0x6de9e04b,0x58b95c93,0x2cb754e2,0x19e7e83a,0xefcf8c8f,0xda9f3057,0xae913826,0x9bc184fe,0x6931f28d,0x5c614e55,0x286f4624,0x1d3ffafc,0x18ba037a,0x2deabfa2,0x59e4b7d3,0x6cb40b0b,0x9e447d78,0xab14c1a0,0xdf1ac9d1,0xea4a7509,0x1c6211bc,0x2932ad64,0x5d3ca515,0x686c19cd,0x9a9c6fbe,0xafccd366,0xdbc2db17,0xee9267cf,0x27eeedef,0x12be5137,0x66b05946,0x53e0e59e,0xa11093ed,0x94402f35,0xe04e2744,0xd51e9b9c,0x2336ff29,0x166643f1,0x62684b80,0x5738f758,0xa5c8812b,0x90983df3,0xe4963582,0xd1c6895a,0x11a786cb,0x24f73a13,0x50f93262,0x65a98eba,0x9759f8c9,0xa2094411,0xd6074c60,0xe357f0b8,0x157f940d,0x202f28d5,0x542120a4,0x61719c7c,0x9381ea0f,0xa6d156d7,0xd2df5ea6,0xe78fe27e,0x2ef3685e,0x1ba3d486,0x6faddcf7,0x5afd602f,0xa80d165c,0x9d5daa84,0xe953a2f5,0xdc031e2d,0x2a2b7a98,0x1f7bc640,0x6b75ce31,0x5e2572e9,0xacd5049a,0x9985b842,0xed8bb033,0xd8db0ceb,0xc0ce1287,0xf59eae5f,0x8190a62e,0xb4c01af6,0x46306c85,0x7360d05d,0x76ed82c,0x323e64f4,0xc4160041,0xf146bc99,0x8548b4e8,0xb0180830,0x42e87e43,0x77b8c29b,0x3b6caea,0x36e67632,0xff9afc12,0xcaca40ca,0xbec448bb,0x8b94f463,0x79648210,0x4c343ec8,0x383a36b9,0xd6a8a61,0xfb42eed4,0xce12520c,0xba1c5a7d,0x8f4ce6a5,0x7dbc90d6,0x48ec2c0e,0x3ce2247f,0x9b298a7,0xc9d39736,0xfc832bee,0x888d239f,0xbddd9f47,0x4f2de934,0x7a7d55ec,0xe735d9d,0x3b23e145,0xcd0b85f0,0xf85b3928,0x8c553159,0xb9058d81,0x4bf5fbf2,0x7ea5472a,0xaab4f5b,0x3ffbf383,0xf68779a3,0xc3d7c57b,0xb7d9cd0a,0x828971d2,0x707907a1,0x4529bb79,0x3127b308,0x4770fd0,0xf25f6b65,0xc70fd7bd,0xb301dfcc,0x86516314,0x74a11567,0x41f1a9bf,0x35ffa1ce,0xaf1d16}; unsigned char table_s10[] = {0x54,0x67,0xc5,0x1a,0x53,0x9,0xa6,0xeb,0xac,0x7,0xc2,0xe7,0x6c,0xa7,0x8d,0x7b,0xc1,0x83,0x2a,0x6,0x51,0x21,0xb7,0x36,0x52,0xe6,0x74,0x14,0x99,0x8e,0xf,0x17,0x55,0x4f,0x48,0x35,0xc,0xe3,0x3f,0x2e,0x42,0x97,0x82,0x1f,0x84,0xe,0x4d,0x7f,0xe4,0x81,0xc3,0xbf,0xa1,0xa9,0xaf,0x1c,0x57,0xd4,0x28,0x7e,0xb4,0x18,0x66,0x41,0xcc,0x95,0x45,0x70,0x90,0xe9,0x8f,0xb3,0xe5,0xbd,0x3e,0x8c,0x3c,0xbb,0xa0,0xfc,0x3a,0x9c,0x65,0xca,0x5b,0x4e,0x34,0x4,0x4c,0x2b,0x1d,0x30,0xda,0x3b,0xa3,0x8a,0xf1,0x93,0xe0,0xc6,0x77,0x7a,0x5d,0x92,0x6a,0xf4,0x76,0xcf,0x23,0x2c,0x40,0x4b,0xb6,0xde,0xd,0x39,0x56,0x20,0xe2,0x5e,0x44,0xea,0xfe,0x25,0x9b,0x62,0xb9,0x31,0xf2,0xd9,0xcb,0x61,0xee,0x1e,0xd1,0x80,0xa5,0xc9,0x24,0xd7,0xe8,0x12,0xed,0x3d,0xe1,0x8,0x5c,0x38,0xba,0xd3,0x64,0xb5,0x26,0xd2,0xaa,0x91,0xbe,0x16,0x6b,0x5,0x6d,0xfb,0xdf,0x5f,0x19,0x4a,0x75,0x89,0xd6,0xf8,0x9a,0x22,0x85,0xd8,0x33,0xd0,0x3,0x68,0x87,0x13,0xb1,0xdb,0xc7,0x43,0x1,0x9d,0xf9,0xb8,0xd5,0xa4,0xf6,0xfa,0x46,0x2f,0x6e,0x73,0xc4,0x8b,0x94,0x71,0xb2,0xec,0x27,0x11,0xa,0xc8,0x6f,0xae,0x69,0x96,0xce,0x2,0x10,0x15,0x59,0x7d,0xfd,0xdd,0xb,0xb0,0xef,0xff,0x2d,0xa8,0x7c,0x9e,0x9f,0x98,0xa2,0x88,0xad,0x37,0xab,0xf0,0x50,0xdc,0x0,0x86,0xf7,0x79,0x5a,0x58,0xf5,0x60,0xc0,0x63,0x29,0xf3,0x78,0x32,0x72,0xbc,0x49,0x47,0x1b,0xcd,0xee,0xc3,0xf5,0x92,0x54,0x7d,0xe5,0x4,0x14,0xbb,0x42,0xe4,0xda,0xea,0x90,0x85,0x52,0xe0,0x63,0x3b,0x22,0x7e,0x65,0xe2,0xae,0x9b,0x4b,0x12,0x6d,0x51,0x37,0x4e,0xfb,0x20,0x34,0x9a,0xef,0x67,0xbc,0x45,0xe7,0xd3,0x0,0x68,0x80,0x3c,0xfe,0x88,0x11,0xa8,0x2a,0xb4,0x95,0x9e,0xf2,0xfd,0x18,0x3e,0x4d,0x2f,0x4c,0x83,0xa4,0xa9,0xca,0xaa,0x38,0x8c,0xc9,0xd1,0x50,0x47,0xd8,0xf4,0x5d,0x1f,0xe8,0x69,0xff,0x8f,0x39,0x1c,0xd9,0x72,0xa5,0x53,0x79,0xb2,0xc4,0x1b,0xb9,0x8a,0x35,0x78,0xd7,0x8d,0xa0,0xf6,0xa,0x89,0x9f,0xb8,0xc6,0x6a,0x61,0x1d,0x5f,0x3a,0xc2,0x71,0x77,0x7f,0xc1,0x5c,0x49,0x9c,0xa1,0x93,0xd0,0x5a,0xeb,0x96,0x91,0x8b,0xf0,0xe1,0x3d,0xd2,0x6e,0xd5,0x3,0x23,0x76,0xf3,0x21,0x31,0xdc,0x10,0x48,0xb7,0xa3,0x87,0xcb,0xce,0xcf,0xf9,0x32,0x6c,0x70,0xb1,0x16,0xd4,0xad,0xb0,0xf1,0x98,0xaf,0x4a,0x55,0x1a,0x62,0xac,0xec,0xa6,0x13,0xc5,0x99,0x97,0xbe,0x2b,0x86,0x84,0x2d,0xf7,0xbd,0x1e,0x2,0x8e,0x2e,0x75,0xa7,0x29,0x58,0xde,0x46,0x41,0x40,0xa2,0xe9,0x73,0x56,0x7c,0x4f,0x74,0xc,0xf8,0xdb,0xb5,0xc8,0x60,0xe6,0x82,0xd6,0x3f,0x6b,0xba,0xd,0x64,0x9,0xfa,0x17,0x7b,0xe3,0x33,0xcc,0x36,0xbf,0x15,0x7,0x2c,0x5e,0xf,0xc0,0x30,0x66,0x27,0x43,0xdf,0x24,0x28,0x7a,0xb,0xcd,0x59,0xb6,0xdd,0x9d,0x19,0x5,0x6f,0xfc,0x44,0x26,0x8,0xe,0xed,0x6,0x5b,0x81,0x1,0x25,0xb3,0x57,0xab,0x94,0xc7,0x26,0xcf,0x16,0x72,0xfd,0x94,0x9b,0x4a,0xfc,0x8,0xbf,0x84,0x38,0x90,0x2b,0x45,0xf7,0xdc,0x4f,0xe5,0x30,0xc0,0xae,0xff,0xe7,0x8b,0xf9,0xa,0x3c,0xc6,0x13,0xc3,0x46,0x2d,0x3d,0xa9,0xf5,0x9f,0x6d,0xe9,0xb3,0x2f,0x96,0xd7,0x8a,0xfb,0xd4,0xd8,0xd5,0x43,0x71,0xf1,0x64,0x37,0xa7,0x5b,0xd6,0xf8,0xc,0xb4,0xf6,0xab,0xfe,0x1d,0xb8,0x47,0x2c,0xe0,0x3b,0x3e,0x53,0x77,0xf3,0xd3,0x9e,0x25,0xd1,0xc1,0x86,0x3,0x1,0x68,0x5d,0x40,0xa5,0xea,0x5f,0xba,0xc2,0x9c,0x3f,0x9,0xe6,0x24,0x80,0x41,0x76,0x74,0x4e,0xdb,0x4d,0xee,0xdd,0x7,0x1c,0x56,0x92,0x5c,0x69,0x67,0xe3,0x35,0xb0,0x52,0xb6,0xb1,0xa6,0x8c,0x19,0x83,0xde,0x85,0xf2,0x7e,0xa8,0x2e,0x57,0xd9,0xad,0xef,0x28,0x4,0xf,0x7f,0x18,0x99,0xc8,0x7c,0x3a,0x5a,0xa0,0xb7,0x39,0x21,0x49,0x7a,0x34,0xeb,0x27,0x7d,0xc5,0x88,0x29,0x82,0xc9,0xec,0x89,0x42,0x55,0xa3,0xaf,0xca,0x91,0xed,0x87,0x8f,0x32,0x81,0xfa,0x79,0x50,0x6,0x36,0x9a,0x6f,0x48,0x61,0x7b,0x1b,0x66,0xcd,0x22,0x0,0x11,0xb9,0x6c,0x31,0xac,0x20,0xaa,0x51,0x63,0xb2,0x14,0xe4,0x4b,0x60,0x75,0x2a,0x1a,0x5,0x62,0x1e,0x33,0x15,0xf4,0xa4,0x8d,0xbb,0xe2,0x5e,0x6b,0xc7,0xbe,0x9d,0xa1,0x93,0xcb,0xa2,0x10,0x95,0x12,0xd2,0x8e,0xf0,0x98,0x17,0x23,0xe,0x78,0x70,0xcc,0xc4,0x6a,0xb,0xd0,0x4c,0xb5,0x1f,0x97,0xbd,0xdf,0xe8,0xce,0x54,0x59,0xbc,0x73,0xda,0x44,0xe1,0x58,0x2,0xd,0x65,0x6e,0x3,0xac,0x5c,0xfa,0x52,0x62,0x3d,0x28,0x7b,0x56,0x2a,0x4d,0xc5,0xec,0xbc,0x5d,0x23,0x16,0xaa,0xf3,0xe9,0xd5,0xf6,0x8f,0x58,0xea,0x83,0xdb,0xc6,0x9a,0x5a,0xdd,0x6b,0x5f,0xd0,0xb8,0x84,0x38,0x30,0x46,0x98,0x43,0x22,0x8c,0xdf,0x57,0xfd,0x4,0x86,0xa0,0x97,0xf5,0x3b,0xf4,0x11,0x1c,0x10,0xa9,0xc,0x92,0x26,0x2d,0x45,0x4a,0x4c,0x60,0xa7,0xe5,0xd1,0x50,0x37,0x47,0x12,0x72,0x34,0x80,0x69,0x71,0xff,0xe8,0xa3,0x7c,0x32,0x1,0xc0,0x8d,0x35,0x6f,0xa4,0x81,0xca,0x61,0xeb,0x1d,0xa,0xc1,0xa5,0xd9,0x82,0xe7,0xc9,0x7a,0xc7,0xcf,0x4e,0x18,0x31,0xb2,0x0,0x27,0xd2,0x7e,0x2e,0x53,0x33,0x29,0x59,0x48,0x6a,0x85,0xe4,0x79,0x24,0xf1,0x2b,0x19,0xe2,0x68,0xa8,0x64,0xf,0xf0,0x3f,0x1b,0x76,0x73,0x6d,0xd6,0x9b,0xbb,0x4b,0xce,0x89,0x99,0x8,0x15,0x20,0x49,0xf2,0x17,0xa2,0xed,0x41,0x77,0xd4,0x8a,0x9,0xc8,0x6c,0xae,0x93,0x6,0x3c,0x3e,0x4f,0x95,0xa6,0x5,0x14,0xda,0x1e,0x54,0x7d,0xab,0x2f,0x21,0xf9,0xfe,0x1a,0xf8,0xcb,0x51,0xc4,0xee,0x36,0xba,0xcd,0x96,0x91,0x1f,0x66,0xe0,0x3a,0x5e,0x87,0x6e,0x2,0xd3,0xdc,0xb5,0xcc,0xf7,0x40,0xb4,0xd,0x63,0xd8,0x70,0xad,0x7,0x94,0xbf,0xb7,0xe6,0x88,0x78,0x42,0xb1,0xc3,0xaf,0x8b,0x5b,0x8e,0x74,0xe1,0x75,0x65,0xe,0xa1,0x25,0xd7,0xbd,0x9f,0xde,0x67,0xfb,0x90,0x9c,0xb3,0xc2,0xb9,0x39,0xb,0x9d,0x13,0xef,0x7f,0x2c,0xfc,0x44,0xb0,0x9e,0x55,0xb6,0xe3,0xbe,0xe4,0xd7,0x75,0xaa,0xe3,0xb9,0x16,0x5b,0x1c,0xb7,0x72,0x57,0xdc,0x17,0x3d,0xcb,0x71,0x33,0x9a,0xb6,0xe1,0x91,0x7,0x86,0xe2,0x56,0xc4,0xa4,0x29,0x3e,0xbf,0xa7,0xe5,0xff,0xf8,0x85,0xbc,0x53,0x8f,0x9e,0xf2,0x27,0x32,0xaf,0x34,0xbe,0xfd,0xcf,0x54,0x31,0x73,0xf,0x11,0x19,0x1f,0xac,0xe7,0x64,0x98,0xce,0x4,0xa8,0xd6,0xf1,0x7c,0x25,0xf5,0xc0,0x20,0x59,0x3f,0x3,0x55,0xd,0x8e,0x3c,0x8c,0xb,0x10,0x4c,0x8a,0x2c,0xd5,0x7a,0xeb,0xfe,0x84,0xb4,0xfc,0x9b,0xad,0x80,0x6a,0x8b,0x13,0x3a,0x41,0x23,0x50,0x76,0xc7,0xca,0xed,0x22,0xda,0x44,0xc6,0x7f,0x93,0x9c,0xf0,0xfb,0x6,0x6e,0xbd,0x89,0xe6,0x90,0x52,0xee,0xf4,0x5a,0x4e,0x95,0x2b,0xd2,0x9,0x81,0x42,0x69,0x7b,0xd1,0x5e,0xae,0x61,0x30,0x15,0x79,0x94,0x67,0x58,0xa2,0x5d,0x8d,0x51,0xb8,0xec,0x88,0xa,0x63,0xd4,0x5,0x96,0x62,0x1a,0x21,0xe,0xa6,0xdb,0xb5,0xdd,0x4b,0x6f,0xef,0xa9,0xfa,0xc5,0x39,0x66,0x48,0x2a,0x92,0x35,0x68,0x83,0x60,0xb3,0xd8,0x37,0xa3,0x1,0x6b,0x77,0xf3,0xb1,0x2d,0x49,0x8,0x65,0x14,0x46,0x4a,0xf6,0x9f,0xde,0xc3,0x74,0x3b,0x24,0xc1,0x2,0x5c,0x97,0xa1,0xba,0x78,0xdf,0x1e,0xd9,0x26,0x7e,0xb2,0xa0,0xa5,0xe9,0xcd,0x4d,0x6d,0xbb,0x0,0x5f,0x4f,0x9d,0x18,0xcc,0x2e,0x2f,0x28,0x12,0x38,0x1d,0x87,0x1b,0x40,0xe0,0x6c,0xb0,0x36,0x47,0xc9,0xea,0xe8,0x45,0xd0,0x70,0xd3,0x99,0x43,0xc8,0x82,0xc2,0xc,0xf9,0xf7,0xab,0x7d,0x3d,0x10,0x26,0x41,0x87,0xae,0x36,0xd7,0xc7,0x68,0x91,0x37,0x9,0x39,0x43,0x56,0x81,0x33,0xb0,0xe8,0xf1,0xad,0xb6,0x31,0x7d,0x48,0x98,0xc1,0xbe,0x82,0xe4,0x9d,0x28,0xf3,0xe7,0x49,0x3c,0xb4,0x6f,0x96,0x34,0x0,0xd3,0xbb,0x53,0xef,0x2d,0x5b,0xc2,0x7b,0xf9,0x67,0x46,0x4d,0x21,0x2e,0xcb,0xed,0x9e,0xfc,0x9f,0x50,0x77,0x7a,0x19,0x79,0xeb,0x5f,0x1a,0x2,0x83,0x94,0xb,0x27,0x8e,0xcc,0x3b,0xba,0x2c,0x5c,0xea,0xcf,0xa,0xa1,0x76,0x80,0xaa,0x61,0x17,0xc8,0x6a,0x59,0xe6,0xab,0x4,0x5e,0x73,0x25,0xd9,0x5a,0x4c,0x6b,0x15,0xb9,0xb2,0xce,0x8c,0xe9,0x11,0xa2,0xa4,0xac,0x12,0x8f,0x9a,0x4f,0x72,0x40,0x3,0x89,0x38,0x45,0x42,0x58,0x23,0x32,0xee,0x1,0xbd,0x6,0xd0,0xf0,0xa5,0x20,0xf2,0xe2,0xf,0xc3,0x9b,0x64,0x70,0x54,0x18,0x1d,0x1c,0x2a,0xe1,0xbf,0xa3,0x62,0xc5,0x7,0x7e,0x63,0x22,0x4b,0x7c,0x99,0x86,0xc9,0xb1,0x7f,0x3f,0x75,0xc0,0x16,0x4a,0x44,0x6d,0xf8,0x55,0x57,0xfe,0x24,0x6e,0xcd,0xd1,0x5d,0xfd,0xa6,0x74,0xfa,0x8b,0xd,0x95,0x92,0x93,0x71,0x3a,0xa0,0x85,0xaf,0x9c,0xa7,0xdf,0x2b,0x8,0x66,0x1b,0xb3,0x35,0x51,0x5,0xec,0xb8,0x69,0xde,0xb7,0xda,0x29,0xc4,0xa8,0x30,0xe0,0x1f,0xe5,0x6c,0xc6,0xd4,0xff,0x8d,0xdc,0x13,0xe3,0xb5,0xf4,0x90,0xc,0xf7,0xfb,0xa9,0xd8,0x1e,0x8a,0x65,0xe,0x4e,0xca,0xd6,0xbc,0x2f,0x97,0xf5,0xdb,0xdd,0x3e,0xd5,0x88,0x52,0xd2,0xf6,0x60,0x84,0x78,0x47,0x14,0x2c,0xc5,0x1c,0x78,0xf7,0x9e,0x91,0x40,0xf6,0x2,0xb5,0x8e,0x32,0x9a,0x21,0x4f,0xfd,0xd6,0x45,0xef,0x3a,0xca,0xa4,0xf5,0xed,0x81,0xf3,0x0,0x36,0xcc,0x19,0xc9,0x4c,0x27,0x37,0xa3,0xff,0x95,0x67,0xe3,0xb9,0x25,0x9c,0xdd,0x80,0xf1,0xde,0xd2,0xdf,0x49,0x7b,0xfb,0x6e,0x3d,0xad,0x51,0xdc,0xf2,0x6,0xbe,0xfc,0xa1,0xf4,0x17,0xb2,0x4d,0x26,0xea,0x31,0x34,0x59,0x7d,0xf9,0xd9,0x94,0x2f,0xdb,0xcb,0x8c,0x9,0xb,0x62,0x57,0x4a,0xaf,0xe0,0x55,0xb0,0xc8,0x96,0x35,0x3,0xec,0x2e,0x8a,0x4b,0x7c,0x7e,0x44,0xd1,0x47,0xe4,0xd7,0xd,0x16,0x5c,0x98,0x56,0x63,0x6d,0xe9,0x3f,0xba,0x58,0xbc,0xbb,0xac,0x86,0x13,0x89,0xd4,0x8f,0xf8,0x74,0xa2,0x24,0x5d,0xd3,0xa7,0xe5,0x22,0xe,0x5,0x75,0x12,0x93,0xc2,0x76,0x30,0x50,0xaa,0xbd,0x33,0x2b,0x43,0x70,0x3e,0xe1,0x2d,0x77,0xcf,0x82,0x23,0x88,0xc3,0xe6,0x83,0x48,0x5f,0xa9,0xa5,0xc0,0x9b,0xe7,0x8d,0x85,0x38,0x8b,0xf0,0x73,0x5a,0xc,0x3c,0x90,0x65,0x42,0x6b,0x71,0x11,0x6c,0xc7,0x28,0xa,0x1b,0xb3,0x66,0x3b,0xa6,0x2a,0xa0,0x5b,0x69,0xb8,0x1e,0xee,0x41,0x6a,0x7f,0x20,0x10,0xf,0x68,0x14,0x39,0x1f,0xfe,0xae,0x87,0xb1,0xe8,0x54,0x61,0xcd,0xb4,0x97,0xab,0x99,0xc1,0xa8,0x1a,0x9f,0x18,0xd8,0x84,0xfa,0x92,0x1d,0x29,0x4,0x72,0x7a,0xc6,0xce,0x60,0x1,0xda,0x46,0xbf,0x15,0x9d,0xb7,0xd5,0xe2,0xc4,0x5e,0x53,0xb6,0x79,0xd0,0x4e,0xeb,0x52,0x8,0x7,0x6f,0x64,0x9d,0x32,0xc2,0x64,0xcc,0xfc,0xa3,0xb6,0xe5,0xc8,0xb4,0xd3,0x5b,0x72,0x22,0xc3,0xbd,0x88,0x34,0x6d,0x77,0x4b,0x68,0x11,0xc6,0x74,0x1d,0x45,0x58,0x4,0xc4,0x43,0xf5,0xc1,0x4e,0x26,0x1a,0xa6,0xae,0xd8,0x6,0xdd,0xbc,0x12,0x41,0xc9,0x63,0x9a,0x18,0x3e,0x9,0x6b,0xa5,0x6a,0x8f,0x82,0x8e,0x37,0x92,0xc,0xb8,0xb3,0xdb,0xd4,0xd2,0xfe,0x39,0x7b,0x4f,0xce,0xa9,0xd9,0x8c,0xec,0xaa,0x1e,0xf7,0xef,0x61,0x76,0x3d,0xe2,0xac,0x9f,0x5e,0x13,0xab,0xf1,0x3a,0x1f,0x54,0xff,0x75,0x83,0x94,0x5f,0x3b,0x47,0x1c,0x79,0x57,0xe4,0x59,0x51,0xd0,0x86,0xaf,0x2c,0x9e,0xb9,0x4c,0xe0,0xb0,0xcd,0xad,0xb7,0xc7,0xd6,0xf4,0x1b,0x7a,0xe7,0xba,0x6f,0xb5,0x87,0x7c,0xf6,0x36,0xfa,0x91,0x6e,0xa1,0x85,0xe8,0xed,0xf3,0x48,0x5,0x25,0xd5,0x50,0x17,0x7,0x96,0x8b,0xbe,0xd7,0x6c,0x89,0x3c,0x73,0xdf,0xe9,0x4a,0x14,0x97,0x56,0xf2,0x30,0xd,0x98,0xa2,0xa0,0xd1,0xb,0x38,0x9b,0x8a,0x44,0x80,0xca,0xe3,0x35,0xb1,0xbf,0x67,0x60,0x84,0x66,0x55,0xcf,0x5a,0x70,0xa8,0x24,0x53,0x8,0xf,0x81,0xf8,0x7e,0xa4,0xc0,0x19,0xf0,0x9c,0x4d,0x42,0x2b,0x52,0x69,0xde,0x2a,0x93,0xfd,0x46,0xee,0x33,0x99,0xa,0x21,0x29,0x78,0x16,0xe6,0xdc,0x2f,0x5d,0x31,0x15,0xc5,0x10,0xea,0x7f,0xeb,0xfb,0x90,0x3f,0xbb,0x49,0x23,0x1,0x40,0xf9,0x65,0xe,0x2,0x2d,0x5c,0x27,0xa7,0x95,0x3,0x8d,0x71,0xe1,0xb2,0x62,0xda,0x2e,0x0,0xcb,0x28,0x7d,0x20,0x86,0xb5,0x17,0xc8,0x81,0xdb,0x74,0x39,0x7e,0xd5,0x10,0x35,0xbe,0x75,0x5f,0xa9,0x13,0x51,0xf8,0xd4,0x83,0xf3,0x65,0xe4,0x80,0x34,0xa6,0xc6,0x4b,0x5c,0xdd,0xc5,0x87,0x9d,0x9a,0xe7,0xde,0x31,0xed,0xfc,0x90,0x45,0x50,0xcd,0x56,0xdc,0x9f,0xad,0x36,0x53,0x11,0x6d,0x73,0x7b,0x7d,0xce,0x85,0x6,0xfa,0xac,0x66,0xca,0xb4,0x93,0x1e,0x47,0x97,0xa2,0x42,0x3b,0x5d,0x61,0x37,0x6f,0xec,0x5e,0xee,0x69,0x72,0x2e,0xe8,0x4e,0xb7,0x18,0x89,0x9c,0xe6,0xd6,0x9e,0xf9,0xcf,0xe2,0x8,0xe9,0x71,0x58,0x23,0x41,0x32,0x14,0xa5,0xa8,0x8f,0x40,0xb8,0x26,0xa4,0x1d,0xf1,0xfe,0x92,0x99,0x64,0xc,0xdf,0xeb,0x84,0xf2,0x30,0x8c,0x96,0x38,0x2c,0xf7,0x49,0xb0,0x6b,0xe3,0x20,0xb,0x19,0xb3,0x3c,0xcc,0x3,0x52,0x77,0x1b,0xf6,0x5,0x3a,0xc0,0x3f,0xef,0x33,0xda,0x8e,0xea,0x68,0x1,0xb6,0x67,0xf4,0x0,0x78,0x43,0x6c,0xc4,0xb9,0xd7,0xbf,0x29,0xd,0x8d,0xcb,0x98,0xa7,0x5b,0x4,0x2a,0x48,0xf0,0x57,0xa,0xe1,0x2,0xd1,0xba,0x55,0xc1,0x63,0x9,0x15,0x91,0xd3,0x4f,0x2b,0x6a,0x7,0x76,0x24,0x28,0x94,0xfd,0xbc,0xa1,0x16,0x59,0x46,0xa3,0x60,0x3e,0xf5,0xc3,0xd8,0x1a,0xbd,0x7c,0xbb,0x44,0x1c,0xd0,0xc2,0xc7,0x8b,0xaf,0x2f,0xf,0xd9,0x62,0x3d,0x2d,0xff,0x7a,0xae,0x4c,0x4d,0x4a,0x70,0x5a,0x7f,0xe5,0x79,0x22,0x82,0xe,0xd2,0x54,0x25,0xab,0x88,0x8a,0x27,0xb2,0x12,0xb1,0xfb,0x21,0xaa,0xe0,0xa0,0x6e,0x9b,0x95,0xc9,0x1f,0xcd,0xe0,0xd6,0xb1,0x77,0x5e,0xc6,0x27,0x37,0x98,0x61,0xc7,0xf9,0xc9,0xb3,0xa6,0x71,0xc3,0x40,0x18,0x1,0x5d,0x46,0xc1,0x8d,0xb8,0x68,0x31,0x4e,0x72,0x14,0x6d,0xd8,0x3,0x17,0xb9,0xcc,0x44,0x9f,0x66,0xc4,0xf0,0x23,0x4b,0xa3,0x1f,0xdd,0xab,0x32,0x8b,0x9,0x97,0xb6,0xbd,0xd1,0xde,0x3b,0x1d,0x6e,0xc,0x6f,0xa0,0x87,0x8a,0xe9,0x89,0x1b,0xaf,0xea,0xf2,0x73,0x64,0xfb,0xd7,0x7e,0x3c,0xcb,0x4a,0xdc,0xac,0x1a,0x3f,0xfa,0x51,0x86,0x70,0x5a,0x91,0xe7,0x38,0x9a,0xa9,0x16,0x5b,0xf4,0xae,0x83,0xd5,0x29,0xaa,0xbc,0x9b,0xe5,0x49,0x42,0x3e,0x7c,0x19,0xe1,0x52,0x54,0x5c,0xe2,0x7f,0x6a,0xbf,0x82,0xb0,0xf3,0x79,0xc8,0xb5,0xb2,0xa8,0xd3,0xc2,0x1e,0xf1,0x4d,0xf6,0x20,0x0,0x55,0xd0,0x2,0x12,0xff,0x33,0x6b,0x94,0x80,0xa4,0xe8,0xed,0xec,0xda,0x11,0x4f,0x53,0x92,0x35,0xf7,0x8e,0x93,0xd2,0xbb,0x8c,0x69,0x76,0x39,0x41,0x8f,0xcf,0x85,0x30,0xe6,0xba,0xb4,0x9d,0x8,0xa5,0xa7,0xe,0xd4,0x9e,0x3d,0x21,0xad,0xd,0x56,0x84,0xa,0x7b,0xfd,0x65,0x62,0x63,0x81,0xca,0x50,0x75,0x5f,0x6c,0x57,0x2f,0xdb,0xf8,0x96,0xeb,0x43,0xc5,0xa1,0xf5,0x1c,0x48,0x99,0x2e,0x47,0x2a,0xd9,0x34,0x58,0xc0,0x10,0xef,0x15,0x9c,0x36,0x24,0xf,0x7d,0x2c,0xe3,0x13,0x45,0x4,0x60,0xfc,0x7,0xb,0x59,0x28,0xee,0x7a,0x95,0xfe,0xbe,0x3a,0x26,0x4c,0xdf,0x67,0x5,0x2b,0x2d,0xce,0x25,0x78,0xa2,0x22,0x6,0x90,0x74,0x88,0xb7,0xe4,0x76,0x9f,0x46,0x22,0xad,0xc4,0xcb,0x1a,0xac,0x58,0xef,0xd4,0x68,0xc0,0x7b,0x15,0xa7,0x8c,0x1f,0xb5,0x60,0x90,0xfe,0xaf,0xb7,0xdb,0xa9,0x5a,0x6c,0x96,0x43,0x93,0x16,0x7d,0x6d,0xf9,0xa5,0xcf,0x3d,0xb9,0xe3,0x7f,0xc6,0x87,0xda,0xab,0x84,0x88,0x85,0x13,0x21,0xa1,0x34,0x67,0xf7,0xb,0x86,0xa8,0x5c,0xe4,0xa6,0xfb,0xae,0x4d,0xe8,0x17,0x7c,0xb0,0x6b,0x6e,0x3,0x27,0xa3,0x83,0xce,0x75,0x81,0x91,0xd6,0x53,0x51,0x38,0xd,0x10,0xf5,0xba,0xf,0xea,0x92,0xcc,0x6f,0x59,0xb6,0x74,0xd0,0x11,0x26,0x24,0x1e,0x8b,0x1d,0xbe,0x8d,0x57,0x4c,0x6,0xc2,0xc,0x39,0x37,0xb3,0x65,0xe0,0x2,0xe6,0xe1,0xf6,0xdc,0x49,0xd3,0x8e,0xd5,0xa2,0x2e,0xf8,0x7e,0x7,0x89,0xfd,0xbf,0x78,0x54,0x5f,0x2f,0x48,0xc9,0x98,0x2c,0x6a,0xa,0xf0,0xe7,0x69,0x71,0x19,0x2a,0x64,0xbb,0x77,0x2d,0x95,0xd8,0x79,0xd2,0x99,0xbc,0xd9,0x12,0x5,0xf3,0xff,0x9a,0xc1,0xbd,0xd7,0xdf,0x62,0xd1,0xaa,0x29,0x0,0x56,0x66,0xca,0x3f,0x18,0x31,0x2b,0x4b,0x36,0x9d,0x72,0x50,0x41,0xe9,0x3c,0x61,0xfc,0x70,0xfa,0x1,0x33,0xe2,0x44,0xb4,0x1b,0x30,0x25,0x7a,0x4a,0x55,0x32,0x4e,0x63,0x45,0xa4,0xf4,0xdd,0xeb,0xb2,0xe,0x3b,0x97,0xee,0xcd,0xf1,0xc3,0x9b,0xf2,0x40,0xc5,0x42,0x82,0xde,0xa0,0xc8,0x47,0x73,0x5e,0x28,0x20,0x9c,0x94,0x3a,0x5b,0x80,0x1c,0xe5,0x4f,0xc7,0xed,0x8f,0xb8,0x9e,0x4,0x9,0xec,0x23,0x8a,0x14,0xb1,0x8,0x52,0x5d,0x35,0x3e,0xc4,0x6b,0x9b,0x3d,0x95,0xa5,0xfa,0xef,0xbc,0x91,0xed,0x8a,0x2,0x2b,0x7b,0x9a,0xe4,0xd1,0x6d,0x34,0x2e,0x12,0x31,0x48,0x9f,0x2d,0x44,0x1c,0x1,0x5d,0x9d,0x1a,0xac,0x98,0x17,0x7f,0x43,0xff,0xf7,0x81,0x5f,0x84,0xe5,0x4b,0x18,0x90,0x3a,0xc3,0x41,0x67,0x50,0x32,0xfc,0x33,0xd6,0xdb,0xd7,0x6e,0xcb,0x55,0xe1,0xea,0x82,0x8d,0x8b,0xa7,0x60,0x22,0x16,0x97,0xf0,0x80,0xd5,0xb5,0xf3,0x47,0xae,0xb6,0x38,0x2f,0x64,0xbb,0xf5,0xc6,0x7,0x4a,0xf2,0xa8,0x63,0x46,0xd,0xa6,0x2c,0xda,0xcd,0x6,0x62,0x1e,0x45,0x20,0xe,0xbd,0x0,0x8,0x89,0xdf,0xf6,0x75,0xc7,0xe0,0x15,0xb9,0xe9,0x94,0xf4,0xee,0x9e,0x8f,0xad,0x42,0x23,0xbe,0xe3,0x36,0xec,0xde,0x25,0xaf,0x6f,0xa3,0xc8,0x37,0xf8,0xdc,0xb1,0xb4,0xaa,0x11,0x5c,0x7c,0x8c,0x9,0x4e,0x5e,0xcf,0xd2,0xe7,0x8e,0x35,0xd0,0x65,0x2a,0x86,0xb0,0x13,0x4d,0xce,0xf,0xab,0x69,0x54,0xc1,0xfb,0xf9,0x88,0x52,0x61,0xc2,0xd3,0x1d,0xd9,0x93,0xba,0x6c,0xe8,0xe6,0x3e,0x39,0xdd,0x3f,0xc,0x96,0x3,0x29,0xf1,0x7d,0xa,0x51,0x56,0xd8,0xa1,0x27,0xfd,0x99,0x40,0xa9,0xc5,0x14,0x1b,0x72,0xb,0x30,0x87,0x73,0xca,0xa4,0x1f,0xb7,0x6a,0xc0,0x53,0x78,0x70,0x21,0x4f,0xbf,0x85,0x76,0x4,0x68,0x4c,0x9c,0x49,0xb3,0x26,0xb2,0xa2,0xc9,0x66,0xe2,0x10,0x7a,0x58,0x19,0xa0,0x3c,0x57,0x5b,0x74,0x5,0x7e,0xfe,0xcc,0x5a,0xd4,0x28,0xb8,0xeb,0x3b,0x83,0x77,0x59,0x92,0x71,0x24,0x79,0xf,0x3c,0x9e,0x41,0x8,0x52,0xfd,0xb0,0xf7,0x5c,0x99,0xbc,0x37,0xfc,0xd6,0x20,0x9a,0xd8,0x71,0x5d,0xa,0x7a,0xec,0x6d,0x9,0xbd,0x2f,0x4f,0xc2,0xd5,0x54,0x4c,0xe,0x14,0x13,0x6e,0x57,0xb8,0x64,0x75,0x19,0xcc,0xd9,0x44,0xdf,0x55,0x16,0x24,0xbf,0xda,0x98,0xe4,0xfa,0xf2,0xf4,0x47,0xc,0x8f,0x73,0x25,0xef,0x43,0x3d,0x1a,0x97,0xce,0x1e,0x2b,0xcb,0xb2,0xd4,0xe8,0xbe,0xe6,0x65,0xd7,0x67,0xe0,0xfb,0xa7,0x61,0xc7,0x3e,0x91,0x0,0x15,0x6f,0x5f,0x17,0x70,0x46,0x6b,0x81,0x60,0xf8,0xd1,0xaa,0xc8,0xbb,0x9d,0x2c,0x21,0x6,0xc9,0x31,0xaf,0x2d,0x94,0x78,0x77,0x1b,0x10,0xed,0x85,0x56,0x62,0xd,0x7b,0xb9,0x5,0x1f,0xb1,0xa5,0x7e,0xc0,0x39,0xe2,0x6a,0xa9,0x82,0x90,0x3a,0xb5,0x45,0x8a,0xdb,0xfe,0x92,0x7f,0x8c,0xb3,0x49,0xb6,0x66,0xba,0x53,0x7,0x63,0xe1,0x88,0x3f,0xee,0x7d,0x89,0xf1,0xca,0xe5,0x4d,0x30,0x5e,0x36,0xa0,0x84,0x4,0x42,0x11,0x2e,0xd2,0x8d,0xa3,0xc1,0x79,0xde,0x83,0x68,0x8b,0x58,0x33,0xdc,0x48,0xea,0x80,0x9c,0x18,0x5a,0xc6,0xa2,0xe3,0x8e,0xff,0xad,0xa1,0x1d,0x74,0x35,0x28,0x9f,0xd0,0xcf,0x2a,0xe9,0xb7,0x7c,0x4a,0x51,0x93,0x34,0xf5,0x32,0xcd,0x95,0x59,0x4b,0x4e,0x2,0x26,0xa6,0x86,0x50,0xeb,0xb4,0xa4,0x76,0xf3,0x27,0xc5,0xc4,0xc3,0xf9,0xd3,0xf6,0x6c,0xf0,0xab,0xb,0x87,0x5b,0xdd,0xac,0x22,0x1,0x3,0xae,0x3b,0x9b,0x38,0x72,0xa8,0x23,0x69,0x29,0xe7,0x12,0x1c,0x40,0x96,0xae,0x83,0xb5,0xd2,0x14,0x3d,0xa5,0x44,0x54,0xfb,0x2,0xa4,0x9a,0xaa,0xd0,0xc5,0x12,0xa0,0x23,0x7b,0x62,0x3e,0x25,0xa2,0xee,0xdb,0xb,0x52,0x2d,0x11,0x77,0xe,0xbb,0x60,0x74,0xda,0xaf,0x27,0xfc,0x5,0xa7,0x93,0x40,0x28,0xc0,0x7c,0xbe,0xc8,0x51,0xe8,0x6a,0xf4,0xd5,0xde,0xb2,0xbd,0x58,0x7e,0xd,0x6f,0xc,0xc3,0xe4,0xe9,0x8a,0xea,0x78,0xcc,0x89,0x91,0x10,0x7,0x98,0xb4,0x1d,0x5f,0xa8,0x29,0xbf,0xcf,0x79,0x5c,0x99,0x32,0xe5,0x13,0x39,0xf2,0x84,0x5b,0xf9,0xca,0x75,0x38,0x97,0xcd,0xe0,0xb6,0x4a,0xc9,0xdf,0xf8,0x86,0x2a,0x21,0x5d,0x1f,0x7a,0x82,0x31,0x37,0x3f,0x81,0x1c,0x9,0xdc,0xe1,0xd3,0x90,0x1a,0xab,0xd6,0xd1,0xcb,0xb0,0xa1,0x7d,0x92,0x2e,0x95,0x43,0x63,0x36,0xb3,0x61,0x71,0x9c,0x50,0x8,0xf7,0xe3,0xc7,0x8b,0x8e,0x8f,0xb9,0x72,0x2c,0x30,0xf1,0x56,0x94,0xed,0xf0,0xb1,0xd8,0xef,0xa,0x15,0x5a,0x22,0xec,0xac,0xe6,0x53,0x85,0xd9,0xd7,0xfe,0x6b,0xc6,0xc4,0x6d,0xb7,0xfd,0x5e,0x42,0xce,0x6e,0x35,0xe7,0x69,0x18,0x9e,0x6,0x1,0x0,0xe2,0xa9,0x33,0x16,0x3c,0xf,0x34,0x4c,0xb8,0x9b,0xf5,0x88,0x20,0xa6,0xc2,0x96,0x7f,0x2b,0xfa,0x4d,0x24,0x49,0xba,0x57,0x3b,0xa3,0x73,0x8c,0x76,0xff,0x55,0x47,0x6c,0x1e,0x4f,0x80,0x70,0x26,0x67,0x3,0x9f,0x64,0x68,0x3a,0x4b,0x8d,0x19,0xf6,0x9d,0xdd,0x59,0x45,0x2f,0xbc,0x4,0x66,0x48,0x4e,0xad,0x46,0x1b,0xc1,0x41,0x65,0xf3,0x17,0xeb,0xd4,0x87,0x11,0xf8,0x21,0x45,0xca,0xa3,0xac,0x7d,0xcb,0x3f,0x88,0xb3,0xf,0xa7,0x1c,0x72,0xc0,0xeb,0x78,0xd2,0x7,0xf7,0x99,0xc8,0xd0,0xbc,0xce,0x3d,0xb,0xf1,0x24,0xf4,0x71,0x1a,0xa,0x9e,0xc2,0xa8,0x5a,0xde,0x84,0x18,0xa1,0xe0,0xbd,0xcc,0xe3,0xef,0xe2,0x74,0x46,0xc6,0x53,0x0,0x90,0x6c,0xe1,0xcf,0x3b,0x83,0xc1,0x9c,0xc9,0x2a,0x8f,0x70,0x1b,0xd7,0xc,0x9,0x64,0x40,0xc4,0xe4,0xa9,0x12,0xe6,0xf6,0xb1,0x34,0x36,0x5f,0x6a,0x77,0x92,0xdd,0x68,0x8d,0xf5,0xab,0x8,0x3e,0xd1,0x13,0xb7,0x76,0x41,0x43,0x79,0xec,0x7a,0xd9,0xea,0x30,0x2b,0x61,0xa5,0x6b,0x5e,0x50,0xd4,0x2,0x87,0x65,0x81,0x86,0x91,0xbb,0x2e,0xb4,0xe9,0xb2,0xc5,0x49,0x9f,0x19,0x60,0xee,0x9a,0xd8,0x1f,0x33,0x38,0x48,0x2f,0xae,0xff,0x4b,0xd,0x6d,0x97,0x80,0xe,0x16,0x7e,0x4d,0x3,0xdc,0x10,0x4a,0xf2,0xbf,0x1e,0xb5,0xfe,0xdb,0xbe,0x75,0x62,0x94,0x98,0xfd,0xa6,0xda,0xb0,0xb8,0x5,0xb6,0xcd,0x4e,0x67,0x31,0x1,0xad,0x58,0x7f,0x56,0x4c,0x2c,0x51,0xfa,0x15,0x37,0x26,0x8e,0x5b,0x6,0x9b,0x17,0x9d,0x66,0x54,0x85,0x23,0xd3,0x7c,0x57,0x42,0x1d,0x2d,0x32,0x55,0x29,0x4,0x22,0xc3,0x93,0xba,0x8c,0xd5,0x69,0x5c,0xf0,0x89,0xaa,0x96,0xa4,0xfc,0x95,0x27,0xa2,0x25,0xe5,0xb9,0xc7,0xaf,0x20,0x14,0x39,0x4f,0x47,0xfb,0xf3,0x5d,0x3c,0xe7,0x7b,0x82,0x28,0xa0,0x8a,0xe8,0xdf,0xf9,0x63,0x6e,0x8b,0x44,0xed,0x73,0xd6,0x6f,0x35,0x3a,0x52,0x59,0x93,0x3c,0xcc,0x6a,0xc2,0xf2,0xad,0xb8,0xeb,0xc6,0xba,0xdd,0x55,0x7c,0x2c,0xcd,0xb3,0x86,0x3a,0x63,0x79,0x45,0x66,0x1f,0xc8,0x7a,0x13,0x4b,0x56,0xa,0xca,0x4d,0xfb,0xcf,0x40,0x28,0x14,0xa8,0xa0,0xd6,0x8,0xd3,0xb2,0x1c,0x4f,0xc7,0x6d,0x94,0x16,0x30,0x7,0x65,0xab,0x64,0x81,0x8c,0x80,0x39,0x9c,0x2,0xb6,0xbd,0xd5,0xda,0xdc,0xf0,0x37,0x75,0x41,0xc0,0xa7,0xd7,0x82,0xe2,0xa4,0x10,0xf9,0xe1,0x6f,0x78,0x33,0xec,0xa2,0x91,0x50,0x1d,0xa5,0xff,0x34,0x11,0x5a,0xf1,0x7b,0x8d,0x9a,0x51,0x35,0x49,0x12,0x77,0x59,0xea,0x57,0x5f,0xde,0x88,0xa1,0x22,0x90,0xb7,0x42,0xee,0xbe,0xc3,0xa3,0xb9,0xc9,0xd8,0xfa,0x15,0x74,0xe9,0xb4,0x61,0xbb,0x89,0x72,0xf8,0x38,0xf4,0x9f,0x60,0xaf,0x8b,0xe6,0xe3,0xfd,0x46,0xb,0x2b,0xdb,0x5e,0x19,0x9,0x98,0x85,0xb0,0xd9,0x62,0x87,0x32,0x7d,0xd1,0xe7,0x44,0x1a,0x99,0x58,0xfc,0x3e,0x3,0x96,0xac,0xae,0xdf,0x5,0x36,0x95,0x84,0x4a,0x8e,0xc4,0xed,0x3b,0xbf,0xb1,0x69,0x6e,0x8a,0x68,0x5b,0xc1,0x54,0x7e,0xa6,0x2a,0x5d,0x6,0x1,0x8f,0xf6,0x70,0xaa,0xce,0x17,0xfe,0x92,0x43,0x4c,0x25,0x5c,0x67,0xd0,0x24,0x9d,0xf3,0x48,0xe0,0x3d,0x97,0x4,0x2f,0x27,0x76,0x18,0xe8,0xd2,0x21,0x53,0x3f,0x1b,0xcb,0x1e,0xe4,0x71,0xe5,0xf5,0x9e,0x31,0xb5,0x47,0x2d,0xf,0x4e,0xf7,0x6b,0x0,0xc,0x23,0x52,0x29,0xa9,0x9b,0xd,0x83,0x7f,0xef,0xbc,0x6c,0xd4,0x20,0xe,0xc5,0x26,0x73,0x2e}; UxPlay-1.71.1/lib/playfair/playfair.c000066400000000000000000000020011473013662600173540ustar00rootroot00000000000000#include #include "playfair.h" void generate_key_schedule(unsigned char* key_material, uint32_t key_schedule[11][4]); void generate_session_key(unsigned char* oldSap, unsigned char* messageIn, unsigned char* sessionKey); void cycle(unsigned char* block, uint32_t key_schedule[11][4]); void z_xor(unsigned char* in, unsigned char* out, int blocks); void x_xor(unsigned char* in, unsigned char* out, int blocks); extern unsigned char default_sap[]; void playfair_decrypt(unsigned char* message3, unsigned char* cipherText, unsigned char* keyOut) { unsigned char* chunk1 = &cipherText[16]; unsigned char* chunk2 = &cipherText[56]; int i; unsigned char blockIn[16]; unsigned char sapKey[16]; uint32_t key_schedule[11][4]; generate_session_key(default_sap, message3, sapKey); generate_key_schedule(sapKey, key_schedule); z_xor(chunk2, blockIn, 1); cycle(blockIn, key_schedule); for (i = 0; i < 16; i++) { keyOut[i] = blockIn[i] ^ chunk1[i]; } x_xor(keyOut, keyOut, 1); z_xor(keyOut, keyOut, 1); } UxPlay-1.71.1/lib/playfair/playfair.h000066400000000000000000000002211473013662600173630ustar00rootroot00000000000000#ifndef PLAYFAIR_H #define PLAYFAIR_H void playfair_decrypt(unsigned char* message3, unsigned char* cipherText, unsigned char* keyOut); #endif UxPlay-1.71.1/lib/playfair/sap_hash.c000066400000000000000000000064351473013662600173520ustar00rootroot00000000000000#include #include #include #define printf(...) (void)0; void garble(unsigned char*, unsigned char*, unsigned char*, unsigned char*, unsigned char*); unsigned char rol8(unsigned char input, int count) { return ((input << count) & 0xff) | (input & 0xff) >> (8-count); } uint32_t rol8x(unsigned char input, int count) { return ((input << count)) | (input) >> (8-count); } void sap_hash(unsigned char* blockIn, unsigned char* keyOut) { uint32_t* block_words = (uint32_t*)blockIn; uint32_t* out_words = (uint32_t*)keyOut; unsigned char buffer0[20] = {0x96, 0x5F, 0xC6, 0x53, 0xF8, 0x46, 0xCC, 0x18, 0xDF, 0xBE, 0xB2, 0xF8, 0x38, 0xD7, 0xEC, 0x22, 0x03, 0xD1, 0x20, 0x8F}; unsigned char buffer1[210]; unsigned char buffer2[35] = {0x43, 0x54, 0x62, 0x7A, 0x18, 0xC3, 0xD6, 0xB3, 0x9A, 0x56, 0xF6, 0x1C, 0x14, 0x3F, 0x0C, 0x1D, 0x3B, 0x36, 0x83, 0xB1, 0x39, 0x51, 0x4A, 0xAA, 0x09, 0x3E, 0xFE, 0x44, 0xAF, 0xDE, 0xC3, 0x20, 0x9D, 0x42, 0x3A}; unsigned char buffer3[132]; unsigned char buffer4[21] = {0xED, 0x25, 0xD1, 0xBB, 0xBC, 0x27, 0x9F, 0x02, 0xA2, 0xA9, 0x11, 0x00, 0x0C, 0xB3, 0x52, 0xC0, 0xBD, 0xE3, 0x1B, 0x49, 0xC7}; int i0_index[11] = {18, 22, 23, 0, 5, 19, 32, 31, 10, 21, 30}; uint8_t w,x,y,z; int i, j; // Load the input into the buffer for (i = 0; i < 210; i++) { // We need to swap the byte order around so it is the right endianness uint32_t in_word = block_words[((i % 64)>>2)]; uint32_t in_byte = (in_word >> ((3-(i % 4)) << 3)) & 0xff; buffer1[i] = in_byte; } // Next a scrambling for (i = 0; i < 840; i++) { // We have to do unsigned, 32-bit modulo, or we get the wrong indices x = buffer1[((i-155) & 0xffffffff) % 210]; y = buffer1[((i-57) & 0xffffffff) % 210]; z = buffer1[((i-13) & 0xffffffff) % 210]; w = buffer1[(i & 0xffffffff) % 210]; buffer1[i % 210] = (rol8(y, 5) + (rol8(z, 3) ^ w) - rol8(x,7)) & 0xff; } printf("Garbling...\n"); // I have no idea what this is doing (yet), but it gives the right output garble(buffer0, buffer1, buffer2, buffer3, buffer4); // Fill the output with 0xE1 for (i = 0; i < 16; i++) keyOut[i] = 0xE1; // Now we use all the buffers we have calculated to grind out the output. First buffer3 for (i = 0; i < 11; i++) { // Note that this is addition (mod 255) and not XOR // Also note that we only use certain indices // And that index 3 is hard-coded to be 0x3d (Maybe we can hack this up by changing buffer3[0] to be 0xdc? if (i == 3) keyOut[i] = 0x3d; else keyOut[i] = ((keyOut[i] + buffer3[i0_index[i] * 4]) & 0xff); } // Then buffer0 for (i = 0; i < 20; i++) keyOut[i % 16] ^= buffer0[i]; // Then buffer2 for (i = 0; i < 35; i++) keyOut[i % 16] ^= buffer2[i]; // Do buffer1 for (i = 0; i < 210; i++) keyOut[(i % 16)] ^= buffer1[i]; // Now we do a kind of reverse-scramble for (j = 0; j < 16; j++) { for (i = 0; i < 16; i++) { x = keyOut[((i-7) & 0xffffffff) % 16]; y = keyOut[i % 16]; z = keyOut[((i-37) & 0xffffffff) % 16]; w = keyOut[((i-177) & 0xffffffff) % 16]; keyOut[i] = rol8(x, 1) ^ y ^ rol8(z, 6) ^ rol8(w, 5); } } } UxPlay-1.71.1/lib/raop.c000066400000000000000000000635001473013662600147120ustar00rootroot00000000000000/** * Copyright (C) 2011-2012 Juho Vähä-Herttua * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * *=================================================================== * modified by fduncanh 2021-23 */ #include #include #include #include #include "raop.h" #include "raop_rtp.h" #include "pairing.h" #include "httpd.h" #include "global.h" #include "fairplay.h" #include "netutils.h" #include "logger.h" #include "compat.h" #include "raop_rtp_mirror.h" #include "raop_ntp.h" struct raop_s { /* Callbacks for audio and video */ raop_callbacks_t callbacks; /* Logger instance */ logger_t *logger; /* Pairing, HTTP daemon and RSA key */ pairing_t *pairing; httpd_t *httpd; dnssd_t *dnssd; /* local network ports */ unsigned short port; unsigned short timing_lport; unsigned short control_lport; unsigned short data_lport; unsigned short mirror_data_lport; /* configurable plist items: width, height, refreshRate, maxFPS, overscanned * * also clientFPSdata, which controls whether video stream info received * * from the client is shown on terminal monitor. */ uint16_t width; uint16_t height; uint8_t refreshRate; uint8_t maxFPS; uint8_t overscanned; uint8_t clientFPSdata; int audio_delay_micros; int max_ntp_timeouts; /* for temporary storage of pin during pair-pin start */ unsigned short pin; bool use_pin; /* public key as string */ char pk_str[2*ED25519_KEY_SIZE + 1]; /* place to store media_data_store */ airplay_video_t *airplay_video; /* activate support for HLS live streaming */ bool hls_support; }; struct raop_conn_s { raop_t *raop; raop_ntp_t *raop_ntp; raop_rtp_t *raop_rtp; raop_rtp_mirror_t *raop_rtp_mirror; fairplay_t *fairplay; pairing_session_t *session; airplay_video_t *airplay_video; unsigned char *local; int locallen; unsigned char *remote; int remotelen; unsigned int zone_id; connection_type_t connection_type; char *client_session_id; bool have_active_remote; }; typedef struct raop_conn_s raop_conn_t; #include "raop_handlers.h" #include "http_handlers.h" static void * conn_init(void *opaque, unsigned char *local, int locallen, unsigned char *remote, int remotelen, unsigned int zone_id) { raop_t *raop = opaque; raop_conn_t *conn; char ip_address[40]; assert(raop); conn = calloc(1, sizeof(raop_conn_t)); if (!conn) { return NULL; } conn->raop = raop; conn->raop_rtp = NULL; conn->raop_rtp_mirror = NULL; conn->raop_ntp = NULL; conn->fairplay = fairplay_init(raop->logger); if (!conn->fairplay) { free(conn); return NULL; } conn->session = pairing_session_init(raop->pairing); if (!conn->session) { fairplay_destroy(conn->fairplay); free(conn); return NULL; } utils_ipaddress_to_string(locallen, local, zone_id, ip_address, (int) sizeof(ip_address)); logger_log(conn->raop->logger, LOGGER_INFO, "Local : %s", ip_address); utils_ipaddress_to_string(remotelen, remote, zone_id, ip_address, (int) sizeof(ip_address)); logger_log(conn->raop->logger, LOGGER_INFO, "Remote: %s", ip_address); conn->local = malloc(locallen); assert(conn->local); memcpy(conn->local, local, locallen); conn->remote = malloc(remotelen); assert(conn->remote); memcpy(conn->remote, remote, remotelen); conn->zone_id = zone_id; conn->locallen = locallen; conn->remotelen = remotelen; conn->connection_type = CONNECTION_TYPE_UNKNOWN; conn->client_session_id = NULL; conn->airplay_video = NULL; conn->have_active_remote = false; if (raop->callbacks.conn_init) { raop->callbacks.conn_init(raop->callbacks.cls); } return conn; } static void conn_request(void *ptr, http_request_t *request, http_response_t **response) { char *response_data = NULL; int response_datalen = 0; raop_conn_t *conn = ptr; bool hls_request = false; logger_log(conn->raop->logger, LOGGER_DEBUG, "conn_request"); bool logger_debug = (logger_get_level(conn->raop->logger) >= LOGGER_DEBUG); /* All requests arriving here have been parsed by llhttp to obtain method | url | protocol (RTSP/1.0 or HTTP/1.1) There are three types of connections supplying these requests: Connections from the AirPlay client: (1) type RAOP connections with CSeq seqence header, and no X-Apple-Session-ID header (2) type AIRPLAY connection with an X-Apple-Sequence-ID header and no Cseq header Connections from localhost: (3) type HLS internal connections from the local HLS server (gstreamer) at localhost with neither of these headers, but a Host: localhost:[port] header. method = GET. */ const char *method = http_request_get_method(request); if (!method) { return; } /* this rejects messages from _airplay._tcp for video streaming protocol unless bool raop->hls_support is true*/ const char *cseq = http_request_get_header(request, "CSeq"); const char *protocol = http_request_get_protocol(request); if (!cseq && !conn->raop->hls_support) { logger_log(conn->raop->logger, LOGGER_INFO, "ignoring AirPlay video streaming request (use option -hls to activate HLS support)"); return; } const char *url = http_request_get_url(request); const char *client_session_id = http_request_get_header(request, "X-Apple-Session-ID"); const char *host = http_request_get_header(request, "Host"); hls_request = (host && !cseq && !client_session_id); if (conn->connection_type == CONNECTION_TYPE_UNKNOWN) { if (cseq) { if (httpd_count_connection_type(conn->raop->httpd, CONNECTION_TYPE_RAOP)) { char ipaddr[40]; utils_ipaddress_to_string(conn->remotelen, conn->remote, conn->zone_id, ipaddr, (int) (sizeof(ipaddr))); if (httpd_nohold(conn->raop->httpd)) { logger_log(conn->raop->logger, LOGGER_INFO, "\"nohold\" feature: switch to new connection request from %s", ipaddr); if (conn->raop->callbacks.video_reset) { conn->raop->callbacks.video_reset(conn->raop->callbacks.cls); } httpd_remove_known_connections(conn->raop->httpd); } else { logger_log(conn->raop->logger, LOGGER_WARNING, "rejecting new connection request from %s", ipaddr); *response = http_response_create(); http_response_init(*response, protocol, 409, "Conflict: Server is connected to another client"); goto finish; } } logger_log(conn->raop->logger, LOGGER_DEBUG, "New connection %p identified as Connection type RAOP", ptr); httpd_set_connection_type(conn->raop->httpd, ptr, CONNECTION_TYPE_RAOP); conn->connection_type = CONNECTION_TYPE_RAOP; } else if (client_session_id) { logger_log(conn->raop->logger, LOGGER_DEBUG, "New connection %p identified as Connection type AirPlay", ptr); httpd_set_connection_type(conn->raop->httpd, ptr, CONNECTION_TYPE_AIRPLAY); conn->connection_type = CONNECTION_TYPE_AIRPLAY; size_t len = strlen(client_session_id) + 1; conn->client_session_id = (char *) malloc(len); strncpy(conn->client_session_id, client_session_id, len); /* airplay video has been requested: shut down any running RAOP udp services */ raop_conn_t *raop_conn = (raop_conn_t *) httpd_get_connection_by_type(conn->raop->httpd, CONNECTION_TYPE_RAOP, 1); if (raop_conn) { raop_rtp_mirror_t *raop_rtp_mirror = raop_conn->raop_rtp_mirror; if (raop_rtp_mirror) { logger_log(conn->raop->logger, LOGGER_DEBUG, "New AirPlay connection: stopping RAOP mirror" " service on RAOP connection %p", raop_conn); raop_rtp_mirror_stop(raop_rtp_mirror); } raop_rtp_t *raop_rtp = raop_conn->raop_rtp; if (raop_rtp) { logger_log(conn->raop->logger, LOGGER_DEBUG, "New AirPlay connection: stopping RAOP audio" " service on RAOP connection %p", raop_conn); raop_rtp_stop(raop_rtp); } raop_ntp_t *raop_ntp = raop_conn->raop_ntp; if (raop_rtp) { logger_log(conn->raop->logger, LOGGER_DEBUG, "New AirPlay connection: stopping NTP time" " service on RAOP connection %p", raop_conn); raop_ntp_stop(raop_ntp); } } } else if (host) { logger_log(conn->raop->logger, LOGGER_DEBUG, "New connection %p identified as Connection type HLS", ptr); httpd_set_connection_type(conn->raop->httpd, ptr, CONNECTION_TYPE_HLS); conn->connection_type = CONNECTION_TYPE_HLS; } else { logger_log(conn->raop->logger, LOGGER_WARNING, "connection from unknown connection type"); } } /* this response code and message will be modified by the handler if necessary */ *response = http_response_create(); http_response_init(*response, protocol, 200, "OK"); /* is this really necessary? or is it obsolete? (added for all RTSP requests EXCEPT "RECORD") */ if (cseq && strcmp(method, "RECORD")) { http_response_add_header(*response, "Audio-Jack-Status", "connected; type=digital"); } if (!conn->have_active_remote) { const char *active_remote = http_request_get_header(request, "Active-Remote"); if (active_remote) { conn->have_active_remote = true; if (conn->raop->callbacks.export_dacp) { const char *dacp_id = http_request_get_header(request, "DACP-ID"); conn->raop->callbacks.export_dacp(conn->raop->callbacks.cls, active_remote, dacp_id); } } } logger_log(conn->raop->logger, LOGGER_DEBUG, "\n%s %s %s", method, url, protocol); char *header_str= NULL; http_request_get_header_string(request, &header_str); if (header_str) { logger_log(conn->raop->logger, LOGGER_DEBUG, "%s", header_str); bool data_is_plist = (strstr(header_str,"apple-binary-plist") != NULL); bool data_is_text = (strstr(header_str,"text/") != NULL); free(header_str); int request_datalen; const char *request_data = http_request_get_data(request, &request_datalen); if (request_data && logger_debug) { if (request_datalen > 0) { /* logger has a buffer limit of 4096 */ if (data_is_plist) { plist_t req_root_node = NULL; plist_from_bin(request_data, request_datalen, &req_root_node); char * plist_xml; uint32_t plist_len; plist_to_xml(req_root_node, &plist_xml, &plist_len); logger_log(conn->raop->logger, LOGGER_DEBUG, "%s", plist_xml); free(plist_xml); plist_free(req_root_node); } else if (data_is_text) { char *data_str = utils_data_to_text((char *) request_data, request_datalen); logger_log(conn->raop->logger, LOGGER_DEBUG, "%s", data_str); free(data_str); } else { char *data_str = utils_data_to_string((unsigned char *) request_data, request_datalen, 16); logger_log(conn->raop->logger, LOGGER_DEBUG, "%s", data_str); free(data_str); } } } } if (client_session_id) { assert(!strcmp(client_session_id, conn->client_session_id)); } logger_log(conn->raop->logger, LOGGER_DEBUG, "Handling request %s with URL %s", method, url); raop_handler_t handler = NULL; if (!hls_request && !strcmp(protocol, "RTSP/1.0")) { if (!strcmp(method, "POST")) { if (!strcmp(url, "/feedback")) { handler = &raop_handler_feedback; } else if (!strcmp(url, "/pair-pin-start")) { handler = &raop_handler_pairpinstart; } else if (!strcmp(url, "/pair-setup-pin")) { handler = &raop_handler_pairsetup_pin; } else if (!strcmp(url, "/pair-setup")) { handler = &raop_handler_pairsetup; } else if (!strcmp(url, "/pair-verify")) { handler = &raop_handler_pairverify; } else if (!strcmp(url, "/fp-setup")) { handler = &raop_handler_fpsetup; } else if (!strcmp(url, "/getProperty")) { handler = &http_handler_get_property; } else if (!strcmp(url, "/audioMode")) { //handler = &http_handler_audioMode; } } else if (!strcmp(method, "GET")) { if (!strcmp(url, "/info")) { handler = &raop_handler_info; } } else if (!strcmp(method, "OPTIONS")) { handler = &raop_handler_options; } else if (!strcmp(method, "SETUP")) { handler = &raop_handler_setup; } else if (!strcmp(method, "GET_PARAMETER")) { handler = &raop_handler_get_parameter; } else if (!strcmp(method, "SET_PARAMETER")) { handler = &raop_handler_set_parameter; } else if (!strcmp(method, "RECORD")) { handler = &raop_handler_record; } else if (!strcmp(method, "FLUSH")) { handler = &raop_handler_flush; } else if (!strcmp(method, "TEARDOWN")) { handler = &raop_handler_teardown; } } else if (!hls_request && !strcmp(protocol, "HTTP/1.1")) { if (!strcmp(method, "POST")) { if (!strcmp(url, "/reverse")) { handler = &http_handler_reverse; } else if (!strcmp(url, "/play")) { handler = &http_handler_play; } else if (!strncmp (url, "/getProperty?", strlen("/getProperty?"))) { handler = &http_handler_get_property; } else if (!strncmp(url, "/scrub?", strlen("/scrub?"))) { handler = &http_handler_scrub; } else if (!strncmp(url, "/rate?", strlen("/rate?"))) { handler = &http_handler_rate; } else if (!strcmp(url, "/stop")) { handler = &http_handler_stop; } else if (!strcmp(url, "/action")) { handler = &http_handler_action; } else if (!strcmp(url, "/fp-setup2")) { handler = &http_handler_fpsetup2; } } else if (!strcmp(method, "GET")) { if (!strcmp(url, "/server-info")) { handler = &http_handler_server_info; } else if (!strcmp(url, "/playback-info")) { handler = &http_handler_playback_info; } } else if (!strcmp(method, "PUT")) { if (!strncmp (url, "/setProperty?", strlen("/setProperty?"))) { handler = &http_handler_set_property; } else { } } } else if (hls_request) { handler = &http_handler_hls; } if (handler != NULL) { handler(conn, request, *response, &response_data, &response_datalen); } else { logger_log(conn->raop->logger, LOGGER_INFO, "Unhandled Client Request: %s %s %s", method, url, protocol); } finish:; if (!hls_request) { http_response_add_header(*response, "Server", "AirTunes/"GLOBAL_VERSION); if (cseq) { http_response_add_header(*response, "CSeq", cseq); } } http_response_finish(*response, response_data, response_datalen); int len; const char *data = http_response_get_data(*response, &len); if (response_data && response_datalen > 0) { len -= response_datalen; } else { len -= 2; } header_str = utils_data_to_text(data, len); logger_log(conn->raop->logger, LOGGER_DEBUG, "\n%s", header_str); bool data_is_plist = (strstr(header_str,"apple-binary-plist") != NULL); bool data_is_text = (strstr(header_str,"text/") != NULL || strstr(header_str, "x-mpegURL") != NULL); free(header_str); if (response_data) { if (response_datalen > 0 && logger_debug) { /* logger has a buffer limit of 4096 */ if (data_is_plist) { plist_t res_root_node = NULL; plist_from_bin(response_data, response_datalen, &res_root_node); char * plist_xml; uint32_t plist_len; plist_to_xml(res_root_node, &plist_xml, &plist_len); plist_free(res_root_node); logger_log(conn->raop->logger, LOGGER_DEBUG, "%s", plist_xml); free(plist_xml); } else if (data_is_text) { char *data_str = utils_data_to_text((char*) response_data, response_datalen); logger_log(conn->raop->logger, LOGGER_DEBUG, "%s", data_str); free(data_str); } else { char *data_str = utils_data_to_string((unsigned char *) response_data, response_datalen, 16); logger_log(conn->raop->logger, LOGGER_DEBUG, "%s", data_str); free(data_str); } } if (response_data) { free(response_data); } } } static void conn_destroy(void *ptr) { raop_conn_t *conn = ptr; logger_log(conn->raop->logger, LOGGER_DEBUG, "Destroying connection"); if (conn->raop->callbacks.conn_destroy) { conn->raop->callbacks.conn_destroy(conn->raop->callbacks.cls); } if (conn->raop_rtp) { /* This is done in case TEARDOWN was not called */ raop_rtp_destroy(conn->raop_rtp); } if (conn->raop_rtp_mirror) { /* This is done in case TEARDOWN was not called */ raop_rtp_mirror_destroy(conn->raop_rtp_mirror); } if (conn->raop_ntp) { raop_ntp_destroy(conn->raop_ntp); } if (conn->raop->callbacks.video_flush) { conn->raop->callbacks.video_flush(conn->raop->callbacks.cls); } free(conn->local); free(conn->remote); pairing_session_destroy(conn->session); fairplay_destroy(conn->fairplay); if (conn->client_session_id) { free(conn->client_session_id); } if (conn->airplay_video) { airplay_video_service_destroy(conn->airplay_video); } free(conn); } raop_t * raop_init(raop_callbacks_t *callbacks) { raop_t *raop; assert(callbacks); /* Initialize the network */ if (netutils_init() < 0) { return NULL; } /* Validate the callbacks structure */ if (!callbacks->audio_process || !callbacks->video_process) { return NULL; } /* Allocate the raop_t structure */ raop = calloc(1, sizeof(raop_t)); if (!raop) { return NULL; } /* Initialize the logger */ raop->logger = logger_init(); /* Copy callbacks structure */ memcpy(&raop->callbacks, callbacks, sizeof(raop_callbacks_t)); /* initialize network port list */ raop->port = 0; raop->timing_lport = 0; raop->control_lport = 0; raop->data_lport = 0; raop->mirror_data_lport = 0; /* initialize configurable plist parameters */ raop->width = 1920; raop->height = 1080; raop->refreshRate = 60; raop->maxFPS = 30; raop->overscanned = 0; /* initialise stored pin */ raop->pin = 0; raop->use_pin = false; /* initialize switch for display of client's streaming data records */ raop->clientFPSdata = 0; raop->max_ntp_timeouts = 0; raop->audio_delay_micros = 250000; raop->hls_support = false; return raop; } int raop_init2(raop_t *raop, int nohold, const char *device_id, const char *keyfile) { pairing_t *pairing; httpd_t *httpd; httpd_callbacks_t httpd_cbs; /* create a new public key for pairing */ int new_key; pairing = pairing_init_generate(device_id, keyfile, &new_key); if (!pairing) { logger_log(raop->logger, LOGGER_ERR, "failed to create new public key for pairing"); return -1; } /* store PK as a string in raop->pk_str */ memset(raop->pk_str, 0, sizeof(raop->pk_str)); #ifdef PK strncpy(raop->pk_str, PK, 2*ED25519_KEY_SIZE); #else unsigned char public_key[ED25519_KEY_SIZE]; pairing_get_public_key(pairing, public_key); char *pk_str = utils_pk_to_string(public_key, ED25519_KEY_SIZE); strncpy(raop->pk_str, (const char *) pk_str, 2*ED25519_KEY_SIZE); free(pk_str); #endif if (new_key) { logger_log(raop->logger, LOGGER_INFO,"*** A new Public Key has been created and stored in %s", keyfile); } /* Set HTTP callbacks to our handlers */ memset(&httpd_cbs, 0, sizeof(httpd_cbs)); httpd_cbs.opaque = raop; httpd_cbs.conn_init = &conn_init; httpd_cbs.conn_request = &conn_request; httpd_cbs.conn_destroy = &conn_destroy; /* Initialize the http daemon */ httpd = httpd_init(raop->logger, &httpd_cbs, nohold); if (!httpd) { logger_log(raop->logger, LOGGER_ERR, "failed to initialize http daemon"); pairing_destroy(pairing); return -1; } raop->pairing = pairing; raop->httpd = httpd; return 0; } void raop_destroy(raop_t *raop) { if (raop) { raop_destroy_airplay_video(raop); raop_stop(raop); pairing_destroy(raop->pairing); httpd_destroy(raop->httpd); logger_destroy(raop->logger); free(raop); /* Cleanup the network */ netutils_cleanup(); } } int raop_is_running(raop_t *raop) { assert(raop); return httpd_is_running(raop->httpd); } void raop_set_log_level(raop_t *raop, int level) { assert(raop); logger_set_level(raop->logger, level); } int raop_set_plist(raop_t *raop, const char *plist_item, const int value) { int retval = 0; assert(raop); assert(plist_item); if (strcmp(plist_item, "width") == 0) { raop->width = (uint16_t) value; if ((int) raop->width != value) retval = 1; } else if (strcmp(plist_item, "height") == 0) { raop->height = (uint16_t) value; if ((int) raop->height != value) retval = 1; } else if (strcmp(plist_item, "refreshRate") == 0) { raop->refreshRate = (uint8_t) value; if ((int) raop->refreshRate != value) retval = 1; } else if (strcmp(plist_item, "maxFPS") == 0) { raop->maxFPS = (uint8_t) value; if ((int) raop->maxFPS != value) retval = 1; } else if (strcmp(plist_item, "overscanned") == 0) { raop->overscanned = (uint8_t) (value ? 1 : 0); if ((int) raop->overscanned != value) retval = 1; } else if (strcmp(plist_item, "clientFPSdata") == 0) { raop->clientFPSdata = (value ? 1 : 0); if ((int) raop->clientFPSdata != value) retval = 1; } else if (strcmp(plist_item, "max_ntp_timeouts") == 0) { raop->max_ntp_timeouts = (value > 0 ? value : 0); if (raop->max_ntp_timeouts != value) retval = 1; } else if (strcmp(plist_item, "audio_delay_micros") == 0) { if (value >= 0 && value <= 10 * SECOND_IN_USECS) { raop->audio_delay_micros = value; } if (raop->audio_delay_micros != value) retval = 1; } else if (strcmp(plist_item, "pin") == 0) { raop->pin = value; raop->use_pin = true; } else if (strcmp(plist_item, "hls") == 0) { raop->hls_support = (value > 0 ? true : false); } else { retval = -1; } return retval; } void raop_set_port(raop_t *raop, unsigned short port) { assert(raop); raop->port = port; } void raop_set_udp_ports(raop_t *raop, unsigned short udp[3]) { assert(raop); raop->timing_lport = udp[0]; raop->control_lport = udp[1]; raop->data_lport = udp[2]; } void raop_set_tcp_ports(raop_t *raop, unsigned short tcp[2]) { assert(raop); raop->mirror_data_lport = tcp[0]; raop->port = tcp[1]; } unsigned short raop_get_port(raop_t *raop) { assert(raop); return raop->port; } void * raop_get_callback_cls(raop_t *raop) { assert(raop); return raop->callbacks.cls; } void raop_set_log_callback(raop_t *raop, raop_log_callback_t callback, void *cls) { assert(raop); logger_set_callback(raop->logger, callback, cls); } void raop_set_dnssd(raop_t *raop, dnssd_t *dnssd) { assert(dnssd); dnssd_set_pk(dnssd, raop->pk_str); raop->dnssd = dnssd; } int raop_start(raop_t *raop, unsigned short *port) { assert(raop); assert(port); return httpd_start(raop->httpd, port); } void raop_stop(raop_t *raop) { assert(raop); httpd_stop(raop->httpd); } void raop_remove_known_connections(raop_t * raop) { httpd_remove_known_connections(raop->httpd); } airplay_video_t *deregister_airplay_video(raop_t *raop) { airplay_video_t *airplay_video = raop->airplay_video; raop->airplay_video = NULL; return airplay_video; } bool register_airplay_video(raop_t *raop, airplay_video_t *airplay_video) { if (raop->airplay_video) { return false; } raop->airplay_video = airplay_video; return true; } airplay_video_t * get_airplay_video(raop_t *raop) { return raop->airplay_video; } void raop_destroy_airplay_video(raop_t *raop) { if (raop->airplay_video) { airplay_video_service_destroy(raop->airplay_video); raop->airplay_video = NULL; } } UxPlay-1.71.1/lib/raop.h000066400000000000000000000124761473013662600147250ustar00rootroot00000000000000/** * Copyright (C) 2012-2015 Juho Vähä-Herttua * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * *=================================================================== * modified by fduncanh 2021-23 */ #ifndef RAOP_H #define RAOP_H #include "dnssd.h" #include "stream.h" #include "raop_ntp.h" #include "airplay_video.h" #if defined (WIN32) && defined(DLL_EXPORT) # define RAOP_API __declspec(dllexport) #else # define RAOP_API #endif #ifdef __cplusplus extern "C" { #endif typedef struct raop_s raop_t; typedef void (*raop_log_callback_t)(void *cls, int level, const char *msg); typedef struct playback_info_s { //char * uuid; uint32_t stallcount; double duration; double position; float rate; bool ready_to_play; bool playback_buffer_empty; bool playback_buffer_full; bool playback_likely_to_keep_up; int num_loaded_time_ranges; int num_seekable_time_ranges; void *loadedTimeRanges; void *seekableTimeRanges; } playback_info_t; typedef enum video_codec_e { VIDEO_CODEC_UNKNOWN, VIDEO_CODEC_H264, VIDEO_CODEC_H265 } video_codec_t; struct raop_callbacks_s { void* cls; void (*audio_process)(void *cls, raop_ntp_t *ntp, audio_decode_struct *data); void (*video_process)(void *cls, raop_ntp_t *ntp, video_decode_struct *data); void (*video_pause)(void *cls); void (*video_resume)(void *cls); /* Optional but recommended callback functions */ void (*conn_init)(void *cls); void (*conn_destroy)(void *cls); void (*conn_reset) (void *cls, int timeouts, bool reset_video); void (*conn_teardown)(void *cls, bool *teardown_96, bool *teardown_110 ); void (*audio_flush)(void *cls); void (*video_flush)(void *cls); void (*audio_set_volume)(void *cls, float volume); void (*audio_set_metadata)(void *cls, const void *buffer, int buflen); void (*audio_set_coverart)(void *cls, const void *buffer, int buflen); void (*audio_remote_control_id)(void *cls, const char *dacp_id, const char *active_remote_header); void (*audio_set_progress)(void *cls, unsigned int start, unsigned int curr, unsigned int end); void (*audio_get_format)(void *cls, unsigned char *ct, unsigned short *spf, bool *usingScreen, bool *isMedia, uint64_t *audioFormat); void (*video_report_size)(void *cls, float *width_source, float *height_source, float *width, float *height); void (*report_client_request) (void *cls, char *deviceid, char *model, char *name, bool *admit); void (*display_pin) (void *cls, char * pin); void (*register_client) (void *cls, const char *device_id, const char *pk_str, const char *name); bool (*check_register) (void *cls, const char *pk_str); void (*export_dacp) (void *cls, const char *active_remote, const char *dacp_id); void (*video_reset) (void *cls); void (*video_set_codec)(void *cls, video_codec_t codec); /* for HLS video player controls */ void (*on_video_play) (void *cls, const char *location, const float start_position); void (*on_video_scrub) (void *cls, const float position); void (*on_video_rate) (void *cls, const float rate); void (*on_video_stop) (void *cls); void (*on_video_acquire_playback_info) (void *cls, playback_info_t *playback_video); }; typedef struct raop_callbacks_s raop_callbacks_t; raop_ntp_t *raop_ntp_init(logger_t *logger, raop_callbacks_t *callbacks, const char *remote, int remote_addr_len, unsigned short timing_rport, timing_protocol_t *time_protocol); int airplay_video_service_init(raop_t *raop, unsigned short port, const char *session_id); bool register_airplay_video(raop_t *raop, airplay_video_t *airplay_video); airplay_video_t *get_airplay_video(raop_t *raop); airplay_video_t *deregister_airplay_video(raop_t *raop); RAOP_API raop_t *raop_init(raop_callbacks_t *callbacks); RAOP_API int raop_init2(raop_t *raop, int nohold, const char *device_id, const char *keyfile); RAOP_API void raop_set_log_level(raop_t *raop, int level); RAOP_API void raop_set_log_callback(raop_t *raop, raop_log_callback_t callback, void *cls); RAOP_API int raop_set_plist(raop_t *raop, const char *plist_item, const int value); RAOP_API void raop_set_port(raop_t *raop, unsigned short port); RAOP_API void raop_set_udp_ports(raop_t *raop, unsigned short port[3]); RAOP_API void raop_set_tcp_ports(raop_t *raop, unsigned short port[2]); RAOP_API unsigned short raop_get_port(raop_t *raop); RAOP_API void *raop_get_callback_cls(raop_t *raop); RAOP_API int raop_start(raop_t *raop, unsigned short *port); RAOP_API int raop_is_running(raop_t *raop); RAOP_API void raop_stop(raop_t *raop); RAOP_API void raop_set_dnssd(raop_t *raop, dnssd_t *dnssd); RAOP_API void raop_destroy(raop_t *raop); RAOP_API void raop_remove_known_connections(raop_t * raop); RAOP_API void raop_destroy_airplay_video(raop_t *raop); #ifdef __cplusplus } #endif #endif UxPlay-1.71.1/lib/raop_buffer.c000066400000000000000000000230661473013662600162460ustar00rootroot00000000000000/** * Copyright (C) 2011-2012 Juho Vähä-Herttua * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * *================================================================== * modified by fduncanh 2021-2023 */ #include #include #include #include #include #include #include #include "raop_buffer.h" #include "raop_rtp.h" #include "crypto.h" #include "compat.h" #include "stream.h" #include "global.h" #include "utils.h" #include "byteutils.h" #define RAOP_BUFFER_LENGTH 32 typedef struct { /* Data available */ int filled; /* RTP header */ unsigned short seqnum; uint64_t rtp_timestamp; uint64_t ntp_timestamp; /* Payload data */ unsigned int payload_size; void *payload_data; } raop_buffer_entry_t; struct raop_buffer_s { logger_t *logger; /* AES CTX used for decryption */ aes_ctx_t *aes_ctx; /* First and last seqnum */ int is_empty; unsigned short first_seqnum; unsigned short last_seqnum; /* RTP buffer entries */ raop_buffer_entry_t entries[RAOP_BUFFER_LENGTH]; }; raop_buffer_t * raop_buffer_init(logger_t *logger, const unsigned char *aeskey, const unsigned char *aesiv) { raop_buffer_t *raop_buffer; assert(aeskey); assert(aesiv); raop_buffer = calloc(1, sizeof(raop_buffer_t)); if (!raop_buffer) { return NULL; } raop_buffer->logger = logger; // Need to be initialized internally raop_buffer->aes_ctx = aes_cbc_init(aeskey, aesiv, AES_DECRYPT); for (int i = 0; i < RAOP_BUFFER_LENGTH; i++) { raop_buffer_entry_t *entry = &raop_buffer->entries[i]; entry->payload_data = NULL; entry->payload_size = 0; } raop_buffer->is_empty = 1; return raop_buffer; } void raop_buffer_destroy(raop_buffer_t *raop_buffer) { for (int i = 0; i < RAOP_BUFFER_LENGTH; i++) { raop_buffer_entry_t *entry = &raop_buffer->entries[i]; if (entry->payload_data != NULL) { free(entry->payload_data); } } if (raop_buffer) { aes_cbc_destroy(raop_buffer->aes_ctx); free(raop_buffer); } } static short seqnum_cmp(unsigned short s1, unsigned short s2) { return (s1 - s2); } int raop_buffer_decrypt(raop_buffer_t *raop_buffer, unsigned char *data, unsigned char* output, unsigned int payload_size, unsigned int *outputlen) { assert(raop_buffer); int encryptedlen; if (DECRYPTION_TEST) { char *str = utils_data_to_string(data,12,12); logger_log(raop_buffer->logger, LOGGER_INFO, "encrypted 12 byte header %s", str); free(str); if (payload_size) { str = utils_data_to_string(&data[12],16,16); logger_log(raop_buffer->logger, LOGGER_INFO, "len %d before decryption:\n%s", payload_size, str); free(str); } } encryptedlen = payload_size / 16*16; memset(output, 0, payload_size); aes_cbc_decrypt(raop_buffer->aes_ctx, &data[12], output, encryptedlen); aes_cbc_reset(raop_buffer->aes_ctx); memcpy(output + encryptedlen, &data[12 + encryptedlen], payload_size - encryptedlen); *outputlen = payload_size; if (payload_size && DECRYPTION_TEST){ switch (output[0]) { case 0x8c: case 0x8d: case 0x8e: case 0x80: case 0x81: case 0x82: case 0x20: break; default: logger_log(raop_buffer->logger, LOGGER_INFO, "***ERROR AUDIO FRAME IS NOT AAC_ELD OR ALAC"); break; } if (DECRYPTION_TEST == 2) { logger_log(raop_buffer->logger, LOGGER_INFO, "decrypted audio frame, len = %d", *outputlen); char *str = utils_data_to_string(output,payload_size,16); logger_log(raop_buffer->logger, LOGGER_INFO,"%s",str); free(str); } else { char *str = utils_data_to_string(output,16,16); logger_log(raop_buffer->logger, LOGGER_INFO, "%d after \n%s", payload_size, str); free(str); } } return 1; } int raop_buffer_enqueue(raop_buffer_t *raop_buffer, unsigned char *data, unsigned short datalen, uint64_t *ntp_timestamp, uint64_t *rtp_timestamp, int use_seqnum) { unsigned char empty_packet_marker[] = { 0x00, 0x68, 0x34, 0x00 }; assert(raop_buffer); /* Check packet data length is valid */ if (datalen < 12 || datalen > RAOP_PACKET_LEN) { return -1; } /* before time is synchronized, some empty data packets are sent */ if (datalen == 16 && !memcmp(&data[12], empty_packet_marker, 4)) { return 0; } int payload_size = datalen - 12; /* Get correct seqnum for the packet */ unsigned short seqnum; if (use_seqnum) { seqnum = byteutils_get_short_be(data, 2); } else { seqnum = raop_buffer->first_seqnum; } /* If this packet is too late, just skip it */ if (!raop_buffer->is_empty && seqnum_cmp(seqnum, raop_buffer->first_seqnum) < 0) { return 0; } /* Check that there is always space in the buffer, otherwise flush */ if (seqnum_cmp(seqnum, raop_buffer->first_seqnum + RAOP_BUFFER_LENGTH) >= 0) { raop_buffer_flush(raop_buffer, seqnum); } /* Get entry corresponding our seqnum */ raop_buffer_entry_t *entry = &raop_buffer->entries[seqnum % RAOP_BUFFER_LENGTH]; if (entry->filled && seqnum_cmp(entry->seqnum, seqnum) == 0) { /* Packet resend, we can safely ignore */ return 0; } /* Update the raop_buffer entry header */ entry->seqnum = seqnum; entry->rtp_timestamp = *rtp_timestamp; entry->ntp_timestamp = *ntp_timestamp; entry->filled = 1; entry->payload_data = malloc(payload_size); int decrypt_ret = raop_buffer_decrypt(raop_buffer, data, entry->payload_data, payload_size, &entry->payload_size); assert(decrypt_ret >= 0); assert(entry->payload_size <= payload_size); /* Update the raop_buffer seqnums */ if (raop_buffer->is_empty) { raop_buffer->first_seqnum = seqnum; raop_buffer->last_seqnum = seqnum; raop_buffer->is_empty = 0; } if (seqnum_cmp(seqnum, raop_buffer->last_seqnum) > 0) { raop_buffer->last_seqnum = seqnum; } return 1; } void * raop_buffer_dequeue(raop_buffer_t *raop_buffer, unsigned int *length, uint64_t *ntp_timestamp, uint64_t *rtp_timestamp, unsigned short *seqnum, int no_resend) { assert(raop_buffer); /* Calculate number of entries in the current buffer */ short entry_count = seqnum_cmp(raop_buffer->last_seqnum, raop_buffer->first_seqnum)+1; /* Cannot dequeue from empty buffer */ if (raop_buffer->is_empty || entry_count <= 0) { return NULL; } /* Get the first buffer entry for inspection */ raop_buffer_entry_t *entry = &raop_buffer->entries[raop_buffer->first_seqnum % RAOP_BUFFER_LENGTH]; if (no_resend) { /* If we do no resends, always return the first entry */ } else if (!entry->filled) { /* Check how much we have space left in the buffer */ if (entry_count < RAOP_BUFFER_LENGTH) { /* Return nothing and hope resend gets on time */ return NULL; } /* Risk of buffer overrun, return empty buffer */ } /* Update buffer and validate entry */ raop_buffer->first_seqnum += 1; if (!entry->filled) { return NULL; } entry->filled = 0; /* Return entry payload buffer */ *rtp_timestamp = entry->rtp_timestamp; *ntp_timestamp = entry->ntp_timestamp; *seqnum = entry->seqnum; *length = entry->payload_size; entry->payload_size = 0; void* data = entry->payload_data; entry->payload_data = NULL; return data; } void raop_buffer_handle_resends(raop_buffer_t *raop_buffer, raop_resend_cb_t resend_cb, void *opaque) { assert(raop_buffer); assert(resend_cb); if (seqnum_cmp(raop_buffer->first_seqnum, raop_buffer->last_seqnum) < 0) { unsigned short seqnum, count = 0; logger_log(raop_buffer->logger, LOGGER_DEBUG, "raop_buffer_handle_resends first_seqnum=%u last seqnum=%u", raop_buffer->first_seqnum, raop_buffer->last_seqnum); for (seqnum = raop_buffer->first_seqnum; seqnum_cmp(seqnum, raop_buffer->last_seqnum) < 0; seqnum++) { raop_buffer_entry_t *entry = &raop_buffer->entries[seqnum % RAOP_BUFFER_LENGTH]; if (entry->filled) { break; } count++; } if (count){ resend_cb(opaque, raop_buffer->first_seqnum, count); } } } void raop_buffer_flush(raop_buffer_t *raop_buffer, int next_seq) { assert(raop_buffer); for (int i = 0; i < RAOP_BUFFER_LENGTH; i++) { if (raop_buffer->entries[i].payload_data) { free(raop_buffer->entries[i].payload_data); raop_buffer->entries[i].payload_data = NULL; raop_buffer->entries[i].payload_size = 0; } raop_buffer->entries[i].filled = 0; } if (next_seq < 0 || next_seq > 0xffff) { raop_buffer->is_empty = 1; } else { raop_buffer->first_seqnum = next_seq; raop_buffer->last_seqnum = next_seq - 1; } } UxPlay-1.71.1/lib/raop_buffer.h000066400000000000000000000034311473013662600162450ustar00rootroot00000000000000/** * Copyright (C) 2011-2012 Juho Vähä-Herttua * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * *================================================================== * modified by fduncanh 2021-23 */ #ifndef RAOP_BUFFER_H #define RAOP_BUFFER_H #include "logger.h" #include "raop_rtp.h" typedef struct raop_buffer_s raop_buffer_t; typedef int (*raop_resend_cb_t)(void *opaque, unsigned short seqno, unsigned short count); raop_buffer_t *raop_buffer_init(logger_t *logger, const unsigned char *aeskey, const unsigned char *aesiv); int raop_buffer_enqueue(raop_buffer_t *raop_buffer, unsigned char *data, unsigned short datalen, uint64_t *ntp_timestamp, uint64_t *rtp_timestamp, int use_seqnum); void *raop_buffer_dequeue(raop_buffer_t *raop_buffer, unsigned int *length, uint64_t *ntp_timestamp, uint64_t *rtp_timestamp, unsigned short *seqnum, int no_resend); void raop_buffer_handle_resends(raop_buffer_t *raop_buffer, raop_resend_cb_t resend_cb, void *opaque); void raop_buffer_flush(raop_buffer_t *raop_buffer, int next_seq); int raop_buffer_decrypt(raop_buffer_t *raop_buffer, unsigned char *data, unsigned char* output, unsigned int datalen, unsigned int *outputlen); void raop_buffer_destroy(raop_buffer_t *raop_buffer); #endif UxPlay-1.71.1/lib/raop_handlers.h000066400000000000000000001435201473013662600166000ustar00rootroot00000000000000/** * Copyright (C) 2018 Juho Vähä-Herttua * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * *=================================================================== * modfied by fduncanh 2021-2023 */ /* This file should be only included from raop.c as it defines static handler * functions and depends on raop internals */ #include "dnssdint.h" #include "utils.h" #include #include #include #define AUDIO_SAMPLE_RATE 44100 /* all supported AirPlay audio format use this sample rate */ #define SECOND_IN_USECS 1000000 typedef void (*raop_handler_t)(raop_conn_t *, http_request_t *, http_response_t *, char **, int *); static void raop_handler_info(raop_conn_t *conn, http_request_t *request, http_response_t *response, char **response_data, int *response_datalen) { assert(conn->raop->dnssd); plist_t res_node = plist_new_dict(); /* deviceID is the physical hardware address, and will not change */ int hw_addr_raw_len = 0; const char *hw_addr_raw = dnssd_get_hw_addr(conn->raop->dnssd, &hw_addr_raw_len); char *hw_addr = calloc(1, 3 * hw_addr_raw_len); //int hw_addr_len = utils_hwaddr_airplay(hw_addr, 3 * hw_addr_raw_len, hw_addr_raw, hw_addr_raw_len); plist_t device_id_node = plist_new_string(hw_addr); plist_dict_set_item(res_node, "deviceID", device_id_node); /* Persistent Public Key */ int pk_len = 0; char *pk = utils_parse_hex(conn->raop->pk_str, strlen(conn->raop->pk_str), &pk_len); plist_t pk_node = plist_new_data(pk, pk_len); plist_dict_set_item(res_node, "pk", pk_node); /* airplay_txt is from the _airplay._tcp dnssd announuncement, may not be necessary */ int airplay_txt_len = 0; const char *airplay_txt = dnssd_get_airplay_txt(conn->raop->dnssd, &airplay_txt_len); plist_t txt_airplay_node = plist_new_data(airplay_txt, airplay_txt_len); plist_dict_set_item(res_node, "txtAirPlay", txt_airplay_node); uint64_t features = dnssd_get_airplay_features(conn->raop->dnssd); plist_t features_node = plist_new_uint(features); plist_dict_set_item(res_node, "features", features_node); int name_len = 0; const char *name = dnssd_get_name(conn->raop->dnssd, &name_len); plist_t name_node = plist_new_string(name); plist_dict_set_item(res_node, "name", name_node); plist_t audio_latencies_node = plist_new_array(); plist_t audio_latencies_0_node = plist_new_dict(); plist_t audio_latencies_0_output_latency_micros_node = plist_new_bool(0); plist_t audio_latencies_0_type_node = plist_new_uint(100); plist_t audio_latencies_0_audio_type_node = plist_new_string("default"); plist_t audio_latencies_0_input_latency_micros_node = plist_new_uint(0); plist_dict_set_item(audio_latencies_0_node, "type", audio_latencies_0_type_node); plist_dict_set_item(audio_latencies_0_node, "inputLatencyMicros", audio_latencies_0_input_latency_micros_node); plist_dict_set_item(audio_latencies_0_node, "audioType", audio_latencies_0_audio_type_node); plist_dict_set_item(audio_latencies_0_node, "outputLatencyMicros", audio_latencies_0_output_latency_micros_node); plist_array_append_item(audio_latencies_node, audio_latencies_0_node); plist_t audio_latencies_1_node = plist_new_dict(); plist_t audio_latencies_1_output_latency_micros_node = plist_new_bool(0); plist_t audio_latencies_1_type_node = plist_new_uint(101); plist_t audio_latencies_1_audio_type_node = plist_new_string("default"); plist_t audio_latencies_1_input_latency_micros_node = plist_new_uint(0); plist_dict_set_item(audio_latencies_1_node, "type", audio_latencies_1_type_node); plist_dict_set_item(audio_latencies_1_node, "audioType", audio_latencies_1_audio_type_node); plist_dict_set_item(audio_latencies_1_node, "inputLatencyMicros", audio_latencies_1_input_latency_micros_node); plist_dict_set_item(audio_latencies_1_node, "outputLatencyMicros", audio_latencies_1_output_latency_micros_node); plist_array_append_item(audio_latencies_node, audio_latencies_1_node); plist_dict_set_item(res_node, "audioLatencies", audio_latencies_node); plist_t audio_formats_node = plist_new_array(); plist_t audio_format_0_node = plist_new_dict(); plist_t audio_format_0_type_node = plist_new_uint(100); plist_t audio_format_0_audio_input_formats_node = plist_new_uint(0x3fffffc); plist_t audio_format_0_audio_output_formats_node = plist_new_uint(0x3fffffc); plist_dict_set_item(audio_format_0_node, "audioOutputFormats", audio_format_0_audio_output_formats_node); plist_dict_set_item(audio_format_0_node, "type", audio_format_0_type_node); plist_dict_set_item(audio_format_0_node, "audioInputFormats", audio_format_0_audio_input_formats_node); plist_array_append_item(audio_formats_node, audio_format_0_node); plist_t audio_format_1_node = plist_new_dict(); plist_t audio_format_1_type_node = plist_new_uint(101); plist_t audio_format_1_audio_input_formats_node = plist_new_uint(0x3fffffc); plist_t audio_format_1_audio_output_formats_node = plist_new_uint(0x3fffffc); plist_dict_set_item(audio_format_1_node, "audioOutputFormats", audio_format_1_audio_output_formats_node); plist_dict_set_item(audio_format_1_node, "type", audio_format_1_type_node); plist_dict_set_item(audio_format_1_node, "audioInputFormats", audio_format_1_audio_input_formats_node); plist_array_append_item(audio_formats_node, audio_format_1_node); plist_dict_set_item(res_node, "audioFormats", audio_formats_node); plist_t pi_node = plist_new_string(AIRPLAY_PI); plist_dict_set_item(res_node, "pi", pi_node); plist_t vv_node = plist_new_uint(strtol(AIRPLAY_VV, NULL, 10)); plist_dict_set_item(res_node, "vv", vv_node); plist_t status_flags_node = plist_new_uint(68); plist_dict_set_item(res_node, "statusFlags", status_flags_node); plist_t keep_alive_low_power_node = plist_new_uint(1); plist_dict_set_item(res_node, "keepAliveLowPower", keep_alive_low_power_node); plist_t source_version_node = plist_new_string(GLOBAL_VERSION); plist_dict_set_item(res_node, "sourceVersion", source_version_node); plist_t keep_alive_send_stats_as_body_node = plist_new_bool(1); plist_dict_set_item(res_node, "keepAliveSendStatsAsBody", keep_alive_send_stats_as_body_node); plist_t model_node = plist_new_string(GLOBAL_MODEL); plist_dict_set_item(res_node, "model", model_node); plist_t mac_address_node = plist_new_string(hw_addr); plist_dict_set_item(res_node, "macAddress", mac_address_node); plist_t displays_node = plist_new_array(); plist_t displays_0_node = plist_new_dict(); plist_t displays_0_width_physical_node = plist_new_uint(0); plist_t displays_0_height_physical_node = plist_new_uint(0); plist_t displays_0_uuid_node = plist_new_string("e0ff8a27-6738-3d56-8a16-cc53aacee925"); plist_t displays_0_width_node = plist_new_uint(conn->raop->width); plist_t displays_0_height_node = plist_new_uint(conn->raop->height); plist_t displays_0_width_pixels_node = plist_new_uint(conn->raop->width); plist_t displays_0_height_pixels_node = plist_new_uint(conn->raop->height); plist_t displays_0_rotation_node = plist_new_bool(0); /* set to true in AppleTV gen 3 (which has features bit 8 set */ plist_t displays_0_refresh_rate_node = plist_new_real((double) 1.0 / conn->raop->refreshRate); /* set as real 0.166666 = 60hz in AppleTV gen 3 */ plist_t displays_0_max_fps_node = plist_new_uint(conn->raop->maxFPS); plist_t displays_0_overscanned_node = plist_new_bool(conn->raop->overscanned); plist_t displays_0_features = plist_new_uint(14); plist_dict_set_item(displays_0_node, "uuid", displays_0_uuid_node); plist_dict_set_item(displays_0_node, "widthPhysical", displays_0_width_physical_node); plist_dict_set_item(displays_0_node, "heightPhysical", displays_0_height_physical_node); plist_dict_set_item(displays_0_node, "width", displays_0_width_node); plist_dict_set_item(displays_0_node, "height", displays_0_height_node); plist_dict_set_item(displays_0_node, "widthPixels", displays_0_width_pixels_node); plist_dict_set_item(displays_0_node, "heightPixels", displays_0_height_pixels_node); plist_dict_set_item(displays_0_node, "rotation", displays_0_rotation_node); plist_dict_set_item(displays_0_node, "refreshRate", displays_0_refresh_rate_node); plist_dict_set_item(displays_0_node, "maxFPS", displays_0_max_fps_node); plist_dict_set_item(displays_0_node, "overscanned", displays_0_overscanned_node); plist_dict_set_item(displays_0_node, "features", displays_0_features); plist_array_append_item(displays_node, displays_0_node); plist_dict_set_item(res_node, "displays", displays_node); plist_to_bin(res_node, response_data, (uint32_t *) response_datalen); plist_free(res_node); http_response_add_header(response, "Content-Type", "application/x-apple-binary-plist"); free(pk); free(hw_addr); } static void raop_handler_pairpinstart(raop_conn_t *conn, http_request_t *request, http_response_t *response, char **response_data, int *response_datalen) { logger_log(conn->raop->logger, LOGGER_INFO, "client sent PAIR-PIN-START request"); int pin_4; if (conn->raop->pin > 9999) { pin_4 = conn->raop->pin % 10000; } else { pin_4 = random_pin(); if (pin_4 < 0) { logger_log(conn->raop->logger, LOGGER_ERR, "Failed to generate random pin"); } else { conn->raop->pin = (unsigned short) pin_4 % 10000; } } char pin[6]; snprintf(pin, 5, "%04u", pin_4); if (conn->raop->callbacks.display_pin) { conn->raop->callbacks.display_pin(conn->raop->callbacks.cls, pin); } logger_log(conn->raop->logger, LOGGER_INFO, "*** CLIENT MUST NOW ENTER PIN = \"%s\" AS AIRPLAY PASSWORD", pin); *response_data = NULL; response_datalen = 0; } static void raop_handler_pairsetup_pin(raop_conn_t *conn, http_request_t *request, http_response_t *response, char **response_data, int *response_datalen) { const char *request_data = NULL;; int request_datalen = 0; bool data_is_plist = false; bool logger_debug = (logger_get_level(conn->raop->logger) >= LOGGER_DEBUG); request_data = http_request_get_data(request, &request_datalen); logger_log(conn->raop->logger, LOGGER_INFO, "client requested pair-setup-pin, datalen = %d", request_datalen); if (request_datalen > 0) { char *header_str= NULL; http_request_get_header_string(request, &header_str); logger_log(conn->raop->logger, LOGGER_INFO, "request header: %s", header_str); data_is_plist = (strstr(header_str,"apple-binary-plist") != NULL); free(header_str); } if (!data_is_plist) { logger_log(conn->raop->logger, LOGGER_INFO, "did not receive expected plist from client, request_datalen = %d", request_datalen); goto authentication_failed; } /* process the pair-setup-pin request */ plist_t req_root_node = NULL; plist_from_bin(request_data, request_datalen, &req_root_node); plist_t req_method_node = plist_dict_get_item(req_root_node, "method"); plist_t req_user_node = plist_dict_get_item(req_root_node, "user"); plist_t req_pk_node = plist_dict_get_item(req_root_node, "pk"); plist_t req_proof_node = plist_dict_get_item(req_root_node, "proof"); plist_t req_epk_node = plist_dict_get_item(req_root_node, "epk"); plist_t req_authtag_node = plist_dict_get_item(req_root_node, "authTag"); if (PLIST_IS_STRING(req_method_node) && PLIST_IS_STRING(req_user_node)) { /* this is the initial pair-setup-pin request */ const char *salt; char pin[6]; const char *pk; int len_pk, len_salt; char *method = NULL; char *user = NULL; plist_get_string_val(req_method_node, &method); if (strncmp(method, "pin", strlen (method))) { logger_log(conn->raop->logger, LOGGER_ERR, "error, required method is \"pin\", client requested \"%s\"", method); *response_data = NULL; response_datalen = 0; free (method); plist_free (req_root_node); return; } free (method); plist_get_string_val(req_user_node, &user); logger_log(conn->raop->logger, LOGGER_INFO, "pair-setup-pin: device_id = %s", user); snprintf(pin, 6, "%04u", conn->raop->pin % 10000); if (conn->raop->pin < 10000) { conn->raop->pin = 0; } int ret = srp_new_user(conn->session, conn->raop->pairing, (const char *) user, (const char *) pin, &salt, &len_salt, &pk, &len_pk); free(user); plist_free(req_root_node); if (ret < 0) { logger_log(conn->raop->logger, LOGGER_ERR, "failed to create user, err = %d", ret); goto authentication_failed; } plist_t res_root_node = plist_new_dict(); plist_t res_salt_node = plist_new_data(salt, len_salt); plist_t res_pk_node = plist_new_data(pk, len_pk); plist_dict_set_item(res_root_node, "pk", res_pk_node); plist_dict_set_item(res_root_node, "salt", res_salt_node); plist_to_bin(res_root_node, response_data, (uint32_t*) response_datalen); plist_free(res_root_node); http_response_add_header(response, "Content-Type", "application/x-apple-binary-plist"); return; } else if (PLIST_IS_DATA(req_pk_node) && PLIST_IS_DATA(req_proof_node)) { /* this is the second part of pair-setup-pin request */ char *client_pk = NULL; char *client_proof = NULL; unsigned char proof[64]; memset(proof, 0, sizeof(proof)); uint64_t client_pk_len; uint64_t client_proof_len; plist_get_data_val(req_pk_node, &client_pk, &client_pk_len); plist_get_data_val(req_proof_node, &client_proof, &client_proof_len); if (logger_debug) { char *str = utils_data_to_string((const unsigned char *) client_proof, client_proof_len, 20); logger_log(conn->raop->logger, LOGGER_DEBUG, "client SRP6a proof :\n%s", str); free (str); } memcpy(proof, client_proof, (int) client_proof_len); free (client_proof); int ret = srp_validate_proof(conn->session, conn->raop->pairing, (const unsigned char *) client_pk, (int) client_pk_len, proof, (int) client_proof_len, (int) sizeof(proof)); free (client_pk); plist_free(req_root_node); if (ret < 0) { logger_log(conn->raop->logger, LOGGER_ERR, "Client Authentication Failure (client proof not validated)"); goto authentication_failed; } if (logger_debug) { char *str = utils_data_to_string((const unsigned char *) proof, sizeof(proof), 20); logger_log(conn->raop->logger, LOGGER_DEBUG, "server SRP6a proof :\n%s", str); free (str); } plist_t res_root_node = plist_new_dict(); plist_t res_proof_node = plist_new_data((const char *) proof, 20); plist_dict_set_item(res_root_node, "proof", res_proof_node); plist_to_bin(res_root_node, response_data, (uint32_t*) response_datalen); plist_free(res_root_node); http_response_add_header(response, "Content-Type", "application/x-apple-binary-plist"); return; } else if (PLIST_IS_DATA(req_epk_node) && PLIST_IS_DATA(req_authtag_node)) { /* this is the third part of pair-setup-pin request */ char *client_epk = NULL; char *client_authtag = NULL; uint64_t client_epk_len; uint64_t client_authtag_len; unsigned char epk[ED25519_KEY_SIZE]; unsigned char authtag[GCM_AUTHTAG_SIZE]; int ret; plist_get_data_val(req_epk_node, &client_epk, &client_epk_len); plist_get_data_val(req_authtag_node, &client_authtag, &client_authtag_len); if (logger_debug) { char *str = utils_data_to_string((const unsigned char *) client_epk, client_epk_len, 16); logger_log(conn->raop->logger, LOGGER_DEBUG, "client_epk %d:\n%s\n", (int) client_epk_len, str); str = utils_data_to_string((const unsigned char *) client_authtag, client_authtag_len, 16); logger_log(conn->raop->logger, LOGGER_DEBUG, "client_authtag %d:\n%s\n", (int) client_authtag_len, str); free (str); } memcpy(epk, client_epk, ED25519_KEY_SIZE); memcpy(authtag, client_authtag, GCM_AUTHTAG_SIZE); free (client_authtag); free (client_epk); plist_free(req_root_node); ret = srp_confirm_pair_setup(conn->session, conn->raop->pairing, epk, authtag); if (ret < 0) { logger_log(conn->raop->logger, LOGGER_ERR, "pair-pin-setup (step 3): client authentication failed\n"); goto authentication_failed; } else { logger_log(conn->raop->logger, LOGGER_DEBUG, "pair-pin-setup success\n"); } pairing_session_set_setup_status(conn->session); plist_t res_root_node = plist_new_dict(); plist_t res_epk_node = plist_new_data((const char *) epk, 32); plist_t res_authtag_node = plist_new_data((const char *) authtag, 16); plist_dict_set_item(res_root_node, "epk", res_epk_node); plist_dict_set_item(res_root_node, "authTag", res_authtag_node); plist_to_bin(res_root_node, response_data, (uint32_t*) response_datalen); plist_free(res_root_node); http_response_add_header(response, "Content-Type", "application/x-apple-binary-plist"); return; } authentication_failed:; http_response_init(response, "RTSP/1.0", 470, "Client Authentication Failure"); } static void raop_handler_pairsetup(raop_conn_t *conn, http_request_t *request, http_response_t *response, char **response_data, int *response_datalen) { unsigned char public_key[ED25519_KEY_SIZE]; //const char *data; int datalen; //data = http_request_get_data(request, &datalen); if (datalen != 32) { logger_log(conn->raop->logger, LOGGER_ERR, "Invalid pair-setup data"); return; } pairing_get_public_key(conn->raop->pairing, public_key); pairing_session_set_setup_status(conn->session); *response_data = malloc(sizeof(public_key)); if (*response_data) { http_response_add_header(response, "Content-Type", "application/octet-stream"); memcpy(*response_data, public_key, sizeof(public_key)); *response_datalen = sizeof(public_key); } } static void raop_handler_pairverify(raop_conn_t *conn, http_request_t *request, http_response_t *response, char **response_data, int *response_datalen) { bool register_check = false; if (pairing_session_check_handshake_status(conn->session)) { if (conn->raop->use_pin) { pairing_session_set_setup_status(conn->session); register_check = true; } else { return; } } unsigned char public_key[X25519_KEY_SIZE]; unsigned char signature[PAIRING_SIG_SIZE]; const unsigned char *data; int datalen; data = (unsigned char *) http_request_get_data(request, &datalen); if (datalen < 4) { logger_log(conn->raop->logger, LOGGER_ERR, "Invalid pair-verify data"); return; } switch (data[0]) { case 1: if (datalen != 4 + X25519_KEY_SIZE + ED25519_KEY_SIZE) { logger_log(conn->raop->logger, LOGGER_ERR, "Invalid pair-verify data"); return; } /* We can fall through these errors, the result will just be garbage... */ if (pairing_session_handshake(conn->session, data + 4, data + 4 + X25519_KEY_SIZE)) { logger_log(conn->raop->logger, LOGGER_ERR, "Error initializing pair-verify handshake"); } if (pairing_session_get_public_key(conn->session, public_key)) { logger_log(conn->raop->logger, LOGGER_ERR, "Error getting ECDH public key"); } if (pairing_session_get_signature(conn->session, signature)) { logger_log(conn->raop->logger, LOGGER_ERR, "Error getting ED25519 signature"); } if (register_check) { bool registered_client = true; if (conn->raop->callbacks.check_register) { const unsigned char *pk = data + 4 + X25519_KEY_SIZE; char *pk64; ed25519_pk_to_base64(pk, &pk64); registered_client = conn->raop->callbacks.check_register(conn->raop->callbacks.cls, pk64); free (pk64); } if (!registered_client) { return; } } *response_data = malloc(sizeof(public_key) + sizeof(signature)); if (*response_data) { http_response_add_header(response, "Content-Type", "application/octet-stream"); memcpy(*response_data, public_key, sizeof(public_key)); memcpy(*response_data + sizeof(public_key), signature, sizeof(signature)); *response_datalen = sizeof(public_key) + sizeof(signature); } break; case 0: logger_log(conn->raop->logger, LOGGER_DEBUG, "2nd pair-verify step: checking signature"); if (datalen != 4 + PAIRING_SIG_SIZE) { logger_log(conn->raop->logger, LOGGER_ERR, "Invalid pair-verify data"); return; } if (pairing_session_finish(conn->session, data + 4)) { logger_log(conn->raop->logger, LOGGER_ERR, "Incorrect pair-verify signature"); http_response_set_disconnect(response, 1); return; } logger_log(conn->raop->logger, LOGGER_DEBUG, "pair-verify: signature is verified"); http_response_add_header(response, "Content-Type", "application/octet-stream"); break; } } static void raop_handler_fpsetup(raop_conn_t *conn, http_request_t *request, http_response_t *response, char **response_data, int *response_datalen) { const unsigned char *data; int datalen; data = (unsigned char *) http_request_get_data(request, &datalen); if (datalen == 16) { *response_data = malloc(142); if (*response_data) { http_response_add_header(response, "Content-Type", "application/octet-stream"); if (!fairplay_setup(conn->fairplay, data, (unsigned char *) *response_data)) { *response_datalen = 142; } else { // Handle error? free(*response_data); *response_data = NULL; } } } else if (datalen == 164) { *response_data = malloc(32); if (*response_data) { http_response_add_header(response, "Content-Type", "application/octet-stream"); if (!fairplay_handshake(conn->fairplay, data, (unsigned char *) *response_data)) { *response_datalen = 32; } else { // Handle error? free(*response_data); *response_data = NULL; } } } else { logger_log(conn->raop->logger, LOGGER_ERR, "Invalid fp-setup data length"); return; } } static void raop_handler_options(raop_conn_t *conn, http_request_t *request, http_response_t *response, char **response_data, int *response_datalen) { http_response_add_header(response, "Public", "SETUP, RECORD, PAUSE, FLUSH, TEARDOWN, OPTIONS, GET_PARAMETER, SET_PARAMETER"); } static void raop_handler_setup(raop_conn_t *conn, http_request_t *request, http_response_t *response, char **response_data, int *response_datalen) { const char *dacp_id; const char *active_remote_header; bool logger_debug = (logger_get_level(conn->raop->logger) >= LOGGER_DEBUG); const char *data; int data_len; data = http_request_get_data(request, &data_len); dacp_id = http_request_get_header(request, "DACP-ID"); active_remote_header = http_request_get_header(request, "Active-Remote"); if (dacp_id && active_remote_header) { logger_log(conn->raop->logger, LOGGER_DEBUG, "DACP-ID: %s", dacp_id); logger_log(conn->raop->logger, LOGGER_DEBUG, "Active-Remote: %s", active_remote_header); if (conn->raop_rtp) { raop_rtp_remote_control_id(conn->raop_rtp, dacp_id, active_remote_header); } } // Parsing bplist plist_t req_root_node = NULL; plist_from_bin(data, data_len, &req_root_node); plist_t req_ekey_node = plist_dict_get_item(req_root_node, "ekey"); plist_t req_eiv_node = plist_dict_get_item(req_root_node, "eiv"); // For the response plist_t res_root_node = plist_new_dict(); if (PLIST_IS_DATA(req_eiv_node) && PLIST_IS_DATA(req_ekey_node)) { // The first SETUP call that initializes keys and timing unsigned char aesiv[16]; unsigned char aeskey[16]; unsigned char eaeskey[72]; logger_log(conn->raop->logger, LOGGER_DEBUG, "SETUP 1"); // First setup char* eiv = NULL; uint64_t eiv_len = 0; char *deviceID = NULL; char *model = NULL; char *name = NULL; bool admit_client = true; plist_t req_deviceid_node = plist_dict_get_item(req_root_node, "deviceID"); plist_get_string_val(req_deviceid_node, &deviceID); plist_t req_model_node = plist_dict_get_item(req_root_node, "model"); plist_get_string_val(req_model_node, &model); plist_t req_name_node = plist_dict_get_item(req_root_node, "name"); plist_get_string_val(req_name_node, &name); if (conn->raop->callbacks.report_client_request) { conn->raop->callbacks.report_client_request(conn->raop->callbacks.cls, deviceID, model, name, &admit_client); } if (admit_client && deviceID && name && conn->raop->callbacks.register_client) { bool pending_registration; char *client_device_id; char *client_pk; /* encoded as null-terminated base64 string*/ access_client_session_data(conn->session, &client_device_id, &client_pk, &pending_registration); if (pending_registration) { if (client_pk && !strcmp(deviceID, client_device_id)) { conn->raop->callbacks.register_client(conn->raop->callbacks.cls, client_device_id, client_pk, name); } } if (client_pk) { free (client_pk); } } if (deviceID) { free (deviceID); deviceID = NULL; } if (model) { free (model); model = NULL; } if (name) { free (name); name = NULL; } if (admit_client == false) { /* client is not authorized to connect */ plist_free(res_root_node); plist_free(req_root_node); return; } plist_get_data_val(req_eiv_node, &eiv, &eiv_len); memcpy(aesiv, eiv, 16); free(eiv); logger_log(conn->raop->logger, LOGGER_DEBUG, "eiv_len = %llu", eiv_len); if (logger_debug) { char* str = utils_data_to_string(aesiv, 16, 16); logger_log(conn->raop->logger, LOGGER_DEBUG, "16 byte aesiv (needed for AES-CBC audio decryption iv):\n%s", str); free(str); } char* ekey = NULL; uint64_t ekey_len = 0; plist_get_data_val(req_ekey_node, &ekey, &ekey_len); memcpy(eaeskey,ekey,72); free(ekey); logger_log(conn->raop->logger, LOGGER_DEBUG, "ekey_len = %llu", ekey_len); // eaeskey is 72 bytes, aeskey is 16 bytes if (logger_debug) { char *str = utils_data_to_string((unsigned char *) eaeskey, ekey_len, 16); logger_log(conn->raop->logger, LOGGER_DEBUG, "ekey:\n%s", str); free (str); } int ret = fairplay_decrypt(conn->fairplay, (unsigned char*) eaeskey, aeskey); logger_log(conn->raop->logger, LOGGER_DEBUG, "fairplay_decrypt ret = %d", ret); if (logger_debug) { char *str = utils_data_to_string(aeskey, 16, 16); logger_log(conn->raop->logger, LOGGER_DEBUG, "16 byte aeskey (fairplay-decrypted from ekey):\n%s", str); free(str); } const char *user_agent = http_request_get_header(request, "User-Agent"); logger_log(conn->raop->logger, LOGGER_INFO, "Client identified as User-Agent: %s", user_agent); bool old_protocol = false; #ifdef OLD_PROTOCOL_CLIENT_USER_AGENT_LIST /* set in global.h */ if (strstr(OLD_PROTOCOL_CLIENT_USER_AGENT_LIST, user_agent)) old_protocol = true; #endif if (old_protocol) { /* some windows AirPlay-client emulators use old AirPlay 1 protocol with unhashed AES key */ logger_log(conn->raop->logger, LOGGER_INFO, "Client identifed as using old protocol (unhashed) AES audio key)"); } else { unsigned char ecdh_secret[X25519_KEY_SIZE]; if (pairing_get_ecdh_secret_key(conn->session, ecdh_secret)) { /* In this case (legacy) pairing with client was successfully set up and created the shared ecdh_secret: * aeskey must now be hashed with it * * If byte 27 of features ("supports legacy pairing") is turned off, the client does not request pairsetup * and does NOT set up pairing (this eliminates a 5 second delay in connecting with no apparent bad effects). * In this case, ecdh_secret does not exist, so aeskey should NOT be hashed with it. * UxPlay may be able to function with byte 27 turned off because it currently does not support connections * with more than one client at a time. AppleTV supports up to 12 clients, uses pairing to give each a distinct * SessionID and ecdh_secret. * The "old protocol" Windows AirPlay client AirMyPC seems not to respect the byte 27 setting, and always sets * up the ecdh_secret, but decryption fails if aeskey is hashed.*/ if (logger_debug) { char *str = utils_data_to_string(ecdh_secret, X25519_KEY_SIZE, 16); logger_log(conn->raop->logger, LOGGER_DEBUG, "32 byte shared ecdh_secret:\n%s", str); free(str); } memcpy(eaeskey, aeskey, 16); sha_ctx_t *ctx = sha_init(); sha_update(ctx, eaeskey, 16); sha_update(ctx, ecdh_secret, 32); sha_final(ctx, eaeskey, NULL); sha_destroy(ctx); memcpy(aeskey, eaeskey, 16); if (logger_debug) { char *str = utils_data_to_string(aeskey, 16, 16); logger_log(conn->raop->logger, LOGGER_DEBUG, "16 byte aeskey after sha-256 hash with ecdh_secret:\n%s", str); free(str); } } } // Time port plist_t req_is_remote_control_only_node = plist_dict_get_item(req_root_node, "isRemoteControlOnly"); if (req_is_remote_control_only_node) { uint8_t bool_val = 0; plist_get_bool_val(req_is_remote_control_only_node, &bool_val); if (bool_val) { logger_log(conn->raop->logger, LOGGER_ERR, "Client specified AirPlay2 \"Remote Control\" protocol\n" " Only AirPlay v1 protocol (using NTP and timing port) is supported"); } } char *timing_protocol = NULL; timing_protocol_t time_protocol; plist_t req_timing_protocol_node = plist_dict_get_item(req_root_node, "timingProtocol"); plist_get_string_val(req_timing_protocol_node, &timing_protocol); if (timing_protocol) { int string_len = strlen(timing_protocol); if (strncmp(timing_protocol, "NTP", string_len) == 0) { time_protocol = NTP; } else if (strncmp(timing_protocol, "None", string_len) == 0) { time_protocol = TP_NONE; } else { time_protocol = TP_OTHER; } if (time_protocol != NTP) { logger_log(conn->raop->logger, LOGGER_ERR, "Client specified timingProtocol=%s," " but timingProtocol= NTP is required here", timing_protocol); } free (timing_protocol); timing_protocol = NULL; } else { logger_log(conn->raop->logger, LOGGER_DEBUG, "Client did not specify timingProtocol," " old protocol without offset will be used"); time_protocol = TP_UNSPECIFIED; } uint64_t timing_rport = 0; plist_t req_timing_port_node = plist_dict_get_item(req_root_node, "timingPort"); if (req_timing_port_node) { plist_get_uint_val(req_timing_port_node, &timing_rport); } if (timing_rport) { logger_log(conn->raop->logger, LOGGER_DEBUG, "timing_rport = %llu", timing_rport); } else { logger_log(conn->raop->logger, LOGGER_ERR, "Client did not supply timing_rport," " may be using unsupported AirPlay2 \"Remote Control\" protocol"); } unsigned short timing_lport = conn->raop->timing_lport; conn->raop_ntp = NULL; conn->raop_rtp = NULL; conn->raop_rtp_mirror = NULL; char remote[40]; int len = utils_ipaddress_to_string(conn->remotelen, conn->remote, conn->zone_id, remote, (int) sizeof(remote)); if (!len || len > sizeof(remote)) { char *str = utils_data_to_string(conn->remote, conn->remotelen, 16); logger_log(conn->raop->logger, LOGGER_ERR, "failed to extract valid client ip address:\n" "*** UxPlay will be unable to send communications to client.\n" "*** address length %d, zone_id %u address data:\n%sparser returned \"%s\"\n", conn->remotelen, conn->zone_id, str, remote); free(str); } conn->raop_ntp = raop_ntp_init(conn->raop->logger, &conn->raop->callbacks, remote, conn->remotelen, (unsigned short) timing_rport, &time_protocol); raop_ntp_start(conn->raop_ntp, &timing_lport, conn->raop->max_ntp_timeouts); conn->raop_rtp = raop_rtp_init(conn->raop->logger, &conn->raop->callbacks, conn->raop_ntp, remote, conn->remotelen, aeskey, aesiv); conn->raop_rtp_mirror = raop_rtp_mirror_init(conn->raop->logger, &conn->raop->callbacks, conn->raop_ntp, remote, conn->remotelen, aeskey); /* the event port is not used in mirror mode or audio mode */ unsigned short event_port = 0; plist_t res_event_port_node = plist_new_uint(event_port); plist_t res_timing_port_node = plist_new_uint(timing_lport); plist_dict_set_item(res_root_node, "timingPort", res_timing_port_node); plist_dict_set_item(res_root_node, "eventPort", res_event_port_node); logger_log(conn->raop->logger, LOGGER_DEBUG, "eport = %d, tport = %d", event_port, timing_lport); } // Process stream setup requests plist_t req_streams_node = plist_dict_get_item(req_root_node, "streams"); if (PLIST_IS_ARRAY(req_streams_node)) { plist_t res_streams_node = plist_new_array(); int count = plist_array_get_size(req_streams_node); for (int i = 0; i < count; i++) { plist_t req_stream_node = plist_array_get_item(req_streams_node, i); plist_t req_stream_type_node = plist_dict_get_item(req_stream_node, "type"); uint64_t type; plist_get_uint_val(req_stream_type_node, &type); logger_log(conn->raop->logger, LOGGER_DEBUG, "type = %llu", type); switch (type) { case 110: { // Mirroring unsigned short dport = conn->raop->mirror_data_lport; plist_t stream_id_node = plist_dict_get_item(req_stream_node, "streamConnectionID"); uint64_t stream_connection_id; plist_get_uint_val(stream_id_node, &stream_connection_id); logger_log(conn->raop->logger, LOGGER_DEBUG, "streamConnectionID (needed for AES-CTR video decryption" " key and iv): %llu", stream_connection_id); if (conn->raop_rtp_mirror) { raop_rtp_mirror_init_aes(conn->raop_rtp_mirror, &stream_connection_id); raop_rtp_mirror_start(conn->raop_rtp_mirror, &dport, conn->raop->clientFPSdata); logger_log(conn->raop->logger, LOGGER_DEBUG, "Mirroring initialized successfully"); } else { logger_log(conn->raop->logger, LOGGER_ERR, "Mirroring not initialized at SETUP, playing will fail!"); http_response_set_disconnect(response, 1); } plist_t res_stream_node = plist_new_dict(); plist_t res_stream_data_port_node = plist_new_uint(dport); plist_t res_stream_type_node = plist_new_uint(110); plist_dict_set_item(res_stream_node, "dataPort", res_stream_data_port_node); plist_dict_set_item(res_stream_node, "type", res_stream_type_node); plist_array_append_item(res_streams_node, res_stream_node); break; } case 96: { // Audio unsigned short cport = conn->raop->control_lport, dport = conn->raop->data_lport; unsigned short remote_cport = 0; unsigned char ct; unsigned int sr = AUDIO_SAMPLE_RATE; /* all AirPlay audio formats supported so far have sample rate 44.1kHz */ uint64_t uint_val = 0; plist_t req_stream_control_port_node = plist_dict_get_item(req_stream_node, "controlPort"); plist_get_uint_val(req_stream_control_port_node, &uint_val); remote_cport = (unsigned short) uint_val; /* must != 0 to activate audio resend requests */ plist_t req_stream_ct_node = plist_dict_get_item(req_stream_node, "ct"); plist_get_uint_val(req_stream_ct_node, &uint_val); ct = (unsigned char) uint_val; if (conn->raop->callbacks.audio_get_format) { /* get additional audio format parameters */ uint64_t audioFormat; unsigned short spf; bool isMedia; bool usingScreen; uint8_t bool_val = 0; plist_t req_stream_spf_node = plist_dict_get_item(req_stream_node, "spf"); plist_get_uint_val(req_stream_spf_node, &uint_val); spf = (unsigned short) uint_val; plist_t req_stream_audio_format_node = plist_dict_get_item(req_stream_node, "audioFormat"); plist_get_uint_val(req_stream_audio_format_node, &audioFormat); plist_t req_stream_is_media_node = plist_dict_get_item(req_stream_node, "isMedia"); if (req_stream_is_media_node) { plist_get_bool_val(req_stream_is_media_node, &bool_val); isMedia = (bool) bool_val; } else { isMedia = false; } plist_t req_stream_using_screen_node = plist_dict_get_item(req_stream_node, "usingScreen"); if (req_stream_using_screen_node) { plist_get_bool_val(req_stream_using_screen_node, &bool_val); usingScreen = (bool) bool_val; } else { usingScreen = false; } conn->raop->callbacks.audio_get_format(conn->raop->callbacks.cls, &ct, &spf, &usingScreen, &isMedia, &audioFormat); } if (conn->raop_rtp) { raop_rtp_start_audio(conn->raop_rtp, &remote_cport, &cport, &dport, &ct, &sr); logger_log(conn->raop->logger, LOGGER_DEBUG, "RAOP initialized success"); } else { logger_log(conn->raop->logger, LOGGER_ERR, "RAOP not initialized at SETUP, playing will fail!"); http_response_set_disconnect(response, 1); } plist_t res_stream_node = plist_new_dict(); plist_t res_stream_data_port_node = plist_new_uint(dport); plist_t res_stream_control_port_node = plist_new_uint(cport); plist_t res_stream_type_node = plist_new_uint(96); plist_dict_set_item(res_stream_node, "dataPort", res_stream_data_port_node); plist_dict_set_item(res_stream_node, "controlPort", res_stream_control_port_node); plist_dict_set_item(res_stream_node, "type", res_stream_type_node); plist_array_append_item(res_streams_node, res_stream_node); break; } default: logger_log(conn->raop->logger, LOGGER_ERR, "SETUP tries to setup stream of unknown type %llu", type); http_response_set_disconnect(response, 1); break; } } plist_dict_set_item(res_root_node, "streams", res_streams_node); } plist_to_bin(res_root_node, response_data, (uint32_t*) response_datalen); plist_free(res_root_node); plist_free(req_root_node); http_response_add_header(response, "Content-Type", "application/x-apple-binary-plist"); } static void raop_handler_get_parameter(raop_conn_t *conn, http_request_t *request, http_response_t *response, char **response_data, int *response_datalen) { const char *content_type; const char *data; int datalen; content_type = http_request_get_header(request, "Content-Type"); data = http_request_get_data(request, &datalen); if (!strcmp(content_type, "text/parameters")) { const char *current = data; while (current && (datalen - (current - data) > 0)) { const char *next; /* This is a bit ugly, but seems to be how airport works too */ if ((datalen - (current - data) >= 8) && !strncmp(current, "volume\r\n", 8)) { const char volume[] = "volume: 0.0\r\n"; http_response_add_header(response, "Content-Type", "text/parameters"); *response_data = strdup(volume); if (*response_data) { *response_datalen = strlen(*response_data); } return; } for (next = current ; (datalen - (next - data) > 0) ; ++next) if (*next == '\r') break; if ((datalen - (next - data) >= 2) && !strncmp(next, "\r\n", 2)) { if ((next - current) > 0) { logger_log(conn->raop->logger, LOGGER_WARNING, "Found an unknown parameter: %.*s", (next - current), current); } current = next + 2; } else { current = NULL; } } } } static void raop_handler_set_parameter(raop_conn_t *conn, http_request_t *request, http_response_t *response, char **response_data, int *response_datalen) { const char *content_type; const char *data; int datalen; content_type = http_request_get_header(request, "Content-Type"); data = http_request_get_data(request, &datalen); if (!strcmp(content_type, "text/parameters")) { char *datastr; datastr = calloc(1, datalen+1); if (data && datastr && conn->raop_rtp) { memcpy(datastr, data, datalen); if ((datalen >= 8) && !strncmp(datastr, "volume: ", 8)) { float vol = 0.0; sscanf(datastr+8, "%f", &vol); raop_rtp_set_volume(conn->raop_rtp, vol); } else if ((datalen >= 10) && !strncmp(datastr, "progress: ", 10)) { unsigned int start, curr, end; sscanf(datastr+10, "%u/%u/%u", &start, &curr, &end); raop_rtp_set_progress(conn->raop_rtp, start, curr, end); } } else if (!conn->raop_rtp) { logger_log(conn->raop->logger, LOGGER_WARNING, "RAOP not initialized at SET_PARAMETER"); } free(datastr); } else if (!strcmp(content_type, "image/jpeg") || !strcmp(content_type, "image/png")) { logger_log(conn->raop->logger, LOGGER_DEBUG, "Got image data of %d bytes", datalen); if (conn->raop_rtp) { raop_rtp_set_coverart(conn->raop_rtp, data, datalen); } else { logger_log(conn->raop->logger, LOGGER_WARNING, "RAOP not initialized at SET_PARAMETER coverart"); } } else if (!strcmp(content_type, "application/x-dmap-tagged")) { logger_log(conn->raop->logger, LOGGER_DEBUG, "Got metadata of %d bytes", datalen); if (conn->raop_rtp) { raop_rtp_set_metadata(conn->raop_rtp, data, datalen); } else { logger_log(conn->raop->logger, LOGGER_WARNING, "RAOP not initialized at SET_PARAMETER metadata"); } } } static void raop_handler_feedback(raop_conn_t *conn, http_request_t *request, http_response_t *response, char **response_data, int *response_datalen) { logger_log(conn->raop->logger, LOGGER_DEBUG, "raop_handler_feedback"); } static void raop_handler_record(raop_conn_t *conn, http_request_t *request, http_response_t *response, char **response_data, int *response_datalen) { char audio_latency[12]; unsigned int ad = (unsigned int) (((uint64_t) conn->raop->audio_delay_micros) * AUDIO_SAMPLE_RATE / SECOND_IN_USECS); snprintf(audio_latency, sizeof(audio_latency), "%u", ad); logger_log(conn->raop->logger, LOGGER_DEBUG, "raop_handler_record"); http_response_add_header(response, "Audio-Latency", audio_latency); http_response_add_header(response, "Audio-Jack-Status", "connected; type=analog"); } static void raop_handler_flush(raop_conn_t *conn, http_request_t *request, http_response_t *response, char **response_data, int *response_datalen) { const char *rtpinfo; int next_seq = -1; rtpinfo = http_request_get_header(request, "RTP-Info"); if (rtpinfo) { logger_log(conn->raop->logger, LOGGER_DEBUG, "Flush with RTP-Info: %s", rtpinfo); if (!strncmp(rtpinfo, "seq=", 4)) { next_seq = strtol(rtpinfo + 4, NULL, 10); } } if (conn->raop_rtp) { raop_rtp_flush(conn->raop_rtp, next_seq); } else { logger_log(conn->raop->logger, LOGGER_WARNING, "RAOP not initialized at FLUSH"); } } static void raop_handler_teardown(raop_conn_t *conn, http_request_t *request, http_response_t *response, char **response_data, int *response_datalen) { /* get the teardown request type(s): (type 96, 110, or none) */ const char *data; int data_len; bool teardown_96 = false, teardown_110 = false; data = http_request_get_data(request, &data_len); plist_t req_root_node = NULL; plist_from_bin(data, data_len, &req_root_node); char * plist_xml; uint32_t plist_len; plist_to_xml(req_root_node, &plist_xml, &plist_len); logger_log(conn->raop->logger, LOGGER_DEBUG, "%s", plist_xml); free(plist_xml); plist_t req_streams_node = plist_dict_get_item(req_root_node, "streams"); /* Process stream teardown requests */ if (PLIST_IS_ARRAY(req_streams_node)) { uint64_t val; int count = plist_array_get_size(req_streams_node); for (int i = 0; i < count; i++) { plist_t req_stream_node = plist_array_get_item(req_streams_node,0); plist_t req_stream_type_node = plist_dict_get_item(req_stream_node, "type"); plist_get_uint_val(req_stream_type_node, &val); if (val == 96) { teardown_96 = true; } else if (val == 110) { teardown_110 = true; } } } plist_free(req_root_node); if (conn->raop->callbacks.conn_teardown) { conn->raop->callbacks.conn_teardown(conn->raop->callbacks.cls, &teardown_96, &teardown_110); } logger_log(conn->raop->logger, LOGGER_DEBUG, "TEARDOWN request, 96=%d, 110=%d", teardown_96, teardown_110); http_response_add_header(response, "Connection", "close"); if (teardown_96) { if (conn->raop_rtp) { /* Stop our audio RTP session */ raop_rtp_stop(conn->raop_rtp); } } else if (teardown_110) { if (conn->raop_rtp_mirror) { /* Stop our video RTP session */ raop_rtp_mirror_stop(conn->raop_rtp_mirror); } } else { /* Destroy our sessions */ if (conn->raop_rtp) { raop_rtp_destroy(conn->raop_rtp); conn->raop_rtp = NULL; } if (conn->raop_rtp_mirror) { raop_rtp_mirror_destroy(conn->raop_rtp_mirror); conn->raop_rtp_mirror = NULL; } } } UxPlay-1.71.1/lib/raop_ntp.c000066400000000000000000000450551473013662600156000ustar00rootroot00000000000000/* * Copyright (c) 2019 dsafa22 and 2014 Joakim Plate, modified by Florian Draschbacher, * All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * *================================================================= * modified by fduncanh 2021-23 */ // Some of the code in here comes from https://github.com/juhovh/shairplay/pull/25/files #include #include #include #include #include #include #ifdef _WIN32 #define CAST (char *) #else #define CAST #endif #include "raop.h" #include "threads.h" #include "compat.h" #include "netutils.h" #include "byteutils.h" #include "utils.h" #define SECOND_IN_NSECS 1000000000UL #define RAOP_NTP_DATA_COUNT 8 #define RAOP_NTP_PHI_PPM 15ull // PPM #define RAOP_NTP_R_RHO ((1ull << 32) / 1000u) // packet precision #define RAOP_NTP_S_RHO ((1ull << 32) / 1000u) // system clock precision #define RAOP_NTP_MAX_DIST ((1500ull << 32) / 1000u) // maximum allowed distance #define RAOP_NTP_MAX_DISP ((16ull << 32)) // maximum dispersion #define RAOP_NTP_CLOCK_BASE (2208988800ull << 32) typedef struct raop_ntp_data_s { uint64_t time; // The local wall clock time at time of ntp packet arrival uint64_t dispersion; int64_t delay; // The round trip delay int64_t offset; // The difference between remote and local wall clock time } raop_ntp_data_t; struct raop_ntp_s { logger_t *logger; raop_callbacks_t callbacks; int max_ntp_timeouts; thread_handle_t thread; mutex_handle_t run_mutex; mutex_handle_t wait_mutex; cond_handle_t wait_cond; raop_ntp_data_t data[RAOP_NTP_DATA_COUNT]; int data_index; // The clock sync params are periodically updated to the AirPlay client's NTP clock mutex_handle_t sync_params_mutex; int64_t sync_offset; int64_t sync_dispersion; int64_t sync_delay; // Socket address of the AirPlay client struct sockaddr_storage remote_saddr; socklen_t remote_saddr_len; // The remote port of the NTP server on the AirPlay client unsigned short timing_rport; // The local port of the NTP client on the AirPlay server unsigned short timing_lport; /* MUTEX LOCKED VARIABLES START */ /* These variables only edited mutex locked */ int running; int joined; // UDP socket int tsock; timing_protocol_t time_protocol; }; /* * Used for sorting the data array by delay */ static int raop_ntp_compare(const void* av, const void* bv) { const raop_ntp_data_t* a = (const raop_ntp_data_t*)av; const raop_ntp_data_t* b = (const raop_ntp_data_t*)bv; if (a->delay < b->delay) { return -1; } else if(a->delay > b->delay) { return 1; } else { return 0; } } static int raop_ntp_parse_remote(raop_ntp_t *raop_ntp, const char *remote, int remote_addr_len) { int family; int ret; assert(raop_ntp); if (remote_addr_len == 4) { family = AF_INET; } else if (remote_addr_len == 16) { family = AF_INET6; } else { return -1; } logger_log(raop_ntp->logger, LOGGER_DEBUG, "raop_ntp parse remote ip = %s", remote); ret = netutils_parse_address(family, remote, &raop_ntp->remote_saddr, sizeof(raop_ntp->remote_saddr)); if (ret < 0) { return -1; } raop_ntp->remote_saddr_len = ret; return 0; } raop_ntp_t *raop_ntp_init(logger_t *logger, raop_callbacks_t *callbacks, const char *remote, int remote_addr_len, unsigned short timing_rport, timing_protocol_t *time_protocol) { raop_ntp_t *raop_ntp; assert(logger); assert(callbacks); raop_ntp = calloc(1, sizeof(raop_ntp_t)); if (!raop_ntp) { return NULL; } raop_ntp->time_protocol = *time_protocol; raop_ntp->logger = logger; memcpy(&raop_ntp->callbacks, callbacks, sizeof(raop_callbacks_t)); raop_ntp->timing_rport = timing_rport; if (raop_ntp_parse_remote(raop_ntp, remote, remote_addr_len) < 0) { free(raop_ntp); return NULL; } // Set port on the remote address struct ((struct sockaddr_in *) &raop_ntp->remote_saddr)->sin_port = htons(timing_rport); raop_ntp->running = 0; raop_ntp->joined = 1; uint64_t time = raop_ntp_get_local_time(raop_ntp); for (int i = 0; i < RAOP_NTP_DATA_COUNT; ++i) { raop_ntp->data[i].offset = 0ll; raop_ntp->data[i].delay = RAOP_NTP_MAX_DISP; raop_ntp->data[i].dispersion = RAOP_NTP_MAX_DISP; raop_ntp->data[i].time = time; } raop_ntp->sync_delay = 0; raop_ntp->sync_dispersion = 0; raop_ntp->sync_offset = 0; MUTEX_CREATE(raop_ntp->run_mutex); MUTEX_CREATE(raop_ntp->wait_mutex); COND_CREATE(raop_ntp->wait_cond); MUTEX_CREATE(raop_ntp->sync_params_mutex); return raop_ntp; } void raop_ntp_destroy(raop_ntp_t *raop_ntp) { if (raop_ntp) { raop_ntp_stop(raop_ntp); MUTEX_DESTROY(raop_ntp->run_mutex); MUTEX_DESTROY(raop_ntp->wait_mutex); COND_DESTROY(raop_ntp->wait_cond); MUTEX_DESTROY(raop_ntp->sync_params_mutex); free(raop_ntp); } } unsigned short raop_ntp_get_port(raop_ntp_t *raop_ntp) { return raop_ntp->timing_lport; } static int raop_ntp_init_socket(raop_ntp_t *raop_ntp, int use_ipv6) { assert(raop_ntp); unsigned short tport = raop_ntp->timing_lport; int tsock = netutils_init_socket(&tport, use_ipv6, 1); if (tsock == -1) { goto sockets_cleanup; } // We're calling recvfrom without knowing whether there is any data, so we need a timeout uint32_t recv_timeout_msec = 300; #ifdef _WIN32 DWORD tv = recv_timeout_msec; #else struct timeval tv; tv.tv_sec = recv_timeout_msec / (uint32_t) 1000; tv.tv_usec = ((uint32_t) 1000) * (recv_timeout_msec % (uint32_t) 1000); #endif if (setsockopt(tsock, SOL_SOCKET, SO_RCVTIMEO, CAST &tv, sizeof(tv)) < 0) { goto sockets_cleanup; } /* Set socket descriptors */ raop_ntp->tsock = tsock; /* Set port values */ raop_ntp->timing_lport = tport; logger_log(raop_ntp->logger, LOGGER_DEBUG, "raop_ntp local timing port socket %d port UDP %d", tsock, tport); return 0; sockets_cleanup: if (tsock != -1) closesocket(tsock); return -1; } static void raop_ntp_flush_socket(int fd) { #ifdef _WIN32 #define IOCTL ioctlsocket u_long bytes_available = 0; #else #define IOCTL ioctl int bytes_available = 0; #endif while (IOCTL(fd, FIONREAD, &bytes_available) == 0 && bytes_available > 0) { // We are guaranteed that we won't block, because bytes are available. // Read 1 byte. Extra bytes in the datagram will be discarded. char c; int result = recvfrom(fd, &c, sizeof(c), 0, NULL, NULL); if (result < 0) { break; } } } static THREAD_RETVAL raop_ntp_thread(void *arg) { raop_ntp_t *raop_ntp = arg; assert(raop_ntp); unsigned char response[128]; int response_len; unsigned char request[32] = {0x80, 0xd2, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; raop_ntp_data_t data_sorted[RAOP_NTP_DATA_COUNT]; const unsigned two_pow_n[RAOP_NTP_DATA_COUNT] = {2, 4, 8, 16, 32, 64, 128, 256}; int timeout_counter = 0; bool conn_reset = false; bool logger_debug = (logger_get_level(raop_ntp->logger) >= LOGGER_DEBUG); while (1) { MUTEX_LOCK(raop_ntp->run_mutex); if (!raop_ntp->running) { MUTEX_UNLOCK(raop_ntp->run_mutex); break; } MUTEX_UNLOCK(raop_ntp->run_mutex); // Flush the socket in case a super delayed response arrived or something raop_ntp_flush_socket(raop_ntp->tsock); // Send request uint64_t send_time = raop_ntp_get_local_time(raop_ntp); byteutils_put_ntp_timestamp(request, 24, send_time); int send_len = sendto(raop_ntp->tsock, (char *)request, sizeof(request), 0, (struct sockaddr *) &raop_ntp->remote_saddr, raop_ntp->remote_saddr_len); if (logger_debug) { char *str = utils_data_to_string(request, sizeof(request), 16); logger_log(raop_ntp->logger, LOGGER_DEBUG, "\nraop_ntp send time type_t=%d packetlen = %d, now = %8.6f\n%s", request[1] &~0x80, sizeof(request), (double) send_time / SECOND_IN_NSECS, str); free(str); } if (send_len < 0) { int sock_err = SOCKET_GET_ERROR(); logger_log(raop_ntp->logger, LOGGER_ERR, "raop_ntp error sending request. Error %d:%s", sock_err, SOCKET_ERROR_STRING(sock_err)); } else { // Read response response_len = recvfrom(raop_ntp->tsock, (char *)response, sizeof(response), 0, NULL, NULL); if (response_len < 0) { timeout_counter++; char time[30]; int level = (timeout_counter == 1 ? LOGGER_DEBUG : LOGGER_ERR); ntp_timestamp_to_time(send_time, time, sizeof(time)); logger_log(raop_ntp->logger, level, "raop_ntp receive timeout %d (limit %d) (request sent %s)", timeout_counter, raop_ntp->max_ntp_timeouts, time); if (timeout_counter == raop_ntp->max_ntp_timeouts) { conn_reset = true; /* client is no longer responding */ break; } } else { //local time of the server when the NTP response packet returns int64_t t3 = (int64_t) raop_ntp_get_local_time(raop_ntp); timeout_counter = 0; // Local time of the server when the NTP request packet leaves the server int64_t t0 = (int64_t) byteutils_get_ntp_timestamp(response, 8); // Local time of the client when the NTP request packet arrives at the client int64_t t1 = (int64_t) raop_remote_timestamp_to_nano_seconds(raop_ntp, byteutils_get_long_be(response, 16)); // Local time of the client when the response message leaves the client int64_t t2 = (int64_t) raop_remote_timestamp_to_nano_seconds(raop_ntp, byteutils_get_long_be(response, 24)); if (logger_debug) { char *str = utils_data_to_string(response, response_len, 16); logger_log(raop_ntp->logger, LOGGER_DEBUG, "raop_ntp receive time type_t=%d packetlen = %d, now = %8.6f t1 = %8.6f, t2 = %8.6f\n%s", response[1] &~0x80, response_len, (double) t3 / SECOND_IN_NSECS, (double) t1 / SECOND_IN_NSECS, (double) t2 / SECOND_IN_NSECS, str); free(str); } // The iOS client device sends its time in seconds relative to an arbitrary Epoch (the last boot). // For a little bonus confusion, they add SECONDS_FROM_1900_TO_1970. // This means we have to expect some rather huge offset, but its growth or shrink over time should be small. raop_ntp->data_index = (raop_ntp->data_index + 1) % RAOP_NTP_DATA_COUNT; raop_ntp->data[raop_ntp->data_index].time = t3; raop_ntp->data[raop_ntp->data_index].offset = ((t1 - t0) + (t2 - t3)) / 2; raop_ntp->data[raop_ntp->data_index].delay = ((t3 - t0) - (t2 - t1)); raop_ntp->data[raop_ntp->data_index].dispersion = RAOP_NTP_R_RHO + RAOP_NTP_S_RHO + (t3 - t0) * RAOP_NTP_PHI_PPM / SECOND_IN_NSECS; // Sort by delay memcpy(data_sorted, raop_ntp->data, sizeof(data_sorted)); qsort(data_sorted, RAOP_NTP_DATA_COUNT, sizeof(data_sorted[0]), raop_ntp_compare); uint64_t dispersion = 0ull; int64_t offset = data_sorted[0].offset; int64_t delay = data_sorted[RAOP_NTP_DATA_COUNT - 1].delay; // Calculate dispersion for(int i = 0; i < RAOP_NTP_DATA_COUNT; ++i) { unsigned long long disp = raop_ntp->data[i].dispersion + (t3 - raop_ntp->data[i].time) * RAOP_NTP_PHI_PPM / SECOND_IN_NSECS; dispersion += disp / two_pow_n[i]; } MUTEX_LOCK(raop_ntp->sync_params_mutex); int64_t correction = offset - raop_ntp->sync_offset; raop_ntp->sync_offset = offset; raop_ntp->sync_dispersion = dispersion; raop_ntp->sync_delay = delay; MUTEX_UNLOCK(raop_ntp->sync_params_mutex); logger_log(raop_ntp->logger, LOGGER_DEBUG, "raop_ntp sync correction = %lld", correction); } } // Sleep for 3 seconds struct timespec wait_time; MUTEX_LOCK(raop_ntp->wait_mutex); clock_gettime(CLOCK_REALTIME, &wait_time); wait_time.tv_sec += 3; pthread_cond_timedwait(&raop_ntp->wait_cond, &raop_ntp->wait_mutex, &wait_time); MUTEX_UNLOCK(raop_ntp->wait_mutex); } // Ensure running reflects the actual state MUTEX_LOCK(raop_ntp->run_mutex); raop_ntp->running = false; MUTEX_UNLOCK(raop_ntp->run_mutex); logger_log(raop_ntp->logger, LOGGER_DEBUG, "raop_ntp exiting thread"); if (conn_reset && raop_ntp->callbacks.conn_reset) { const bool video_reset = false; /* leave "frozen video" in place */ raop_ntp->callbacks.conn_reset(raop_ntp->callbacks.cls, timeout_counter, video_reset); } return 0; } void raop_ntp_start(raop_ntp_t *raop_ntp, unsigned short *timing_lport, int max_ntp_timeouts) { logger_log(raop_ntp->logger, LOGGER_DEBUG, "raop_ntp starting time"); int use_ipv6 = 0; assert(raop_ntp); assert(timing_lport); raop_ntp->max_ntp_timeouts = max_ntp_timeouts; raop_ntp->timing_lport = *timing_lport; MUTEX_LOCK(raop_ntp->run_mutex); if (raop_ntp->running || !raop_ntp->joined) { MUTEX_UNLOCK(raop_ntp->run_mutex); return; } /* Initialize ports and sockets */ if (raop_ntp->remote_saddr.ss_family == AF_INET6) { use_ipv6 = 1; } //use_ipv6 = 0; if (raop_ntp_init_socket(raop_ntp, use_ipv6) < 0) { logger_log(raop_ntp->logger, LOGGER_ERR, "raop_ntp initializing timing socket failed"); MUTEX_UNLOCK(raop_ntp->run_mutex); return; } *timing_lport = raop_ntp->timing_lport; /* Create the thread and initialize running values */ raop_ntp->running = 1; raop_ntp->joined = 0; THREAD_CREATE(raop_ntp->thread, raop_ntp_thread, raop_ntp); MUTEX_UNLOCK(raop_ntp->run_mutex); } void raop_ntp_stop(raop_ntp_t *raop_ntp) { assert(raop_ntp); /* Check that we are running and thread is not * joined (should never be while still running) */ MUTEX_LOCK(raop_ntp->run_mutex); if (!raop_ntp->running || raop_ntp->joined) { MUTEX_UNLOCK(raop_ntp->run_mutex); return; } raop_ntp->running = 0; MUTEX_UNLOCK(raop_ntp->run_mutex); logger_log(raop_ntp->logger, LOGGER_DEBUG, "raop_ntp stopping time thread"); MUTEX_LOCK(raop_ntp->wait_mutex); COND_SIGNAL(raop_ntp->wait_cond); MUTEX_UNLOCK(raop_ntp->wait_mutex); if (raop_ntp->tsock != -1) { closesocket(raop_ntp->tsock); raop_ntp->tsock = -1; } THREAD_JOIN(raop_ntp->thread); logger_log(raop_ntp->logger, LOGGER_DEBUG, "raop_ntp stopped time thread"); /* Mark thread as joined */ MUTEX_LOCK(raop_ntp->run_mutex); raop_ntp->joined = 1; MUTEX_UNLOCK(raop_ntp->run_mutex); } /** * Converts from a little endian ntp timestamp to nano seconds since the Unix epoch. * Does the same thing as byteutils_get_ntp_timestamp, except its input is an uint64_t * and expected to already be in little endian. * Please note this just converts to a different representation, the clock remains the * same. */ uint64_t raop_ntp_timestamp_to_nano_seconds(uint64_t ntp_timestamp, bool account_for_epoch_diff) { uint64_t seconds = ((ntp_timestamp >> 32) & 0xffffffff) - (account_for_epoch_diff ? SECONDS_FROM_1900_TO_1970 : 0); uint64_t fraction = (ntp_timestamp & 0xffffffff); return (seconds * SECOND_IN_NSECS) + ((fraction * SECOND_IN_NSECS) >> 32); } uint64_t raop_remote_timestamp_to_nano_seconds(raop_ntp_t *raop_ntp, uint64_t timestamp) { uint64_t seconds = ((timestamp >> 32) & 0xffffffff); if (raop_ntp->time_protocol == NTP) seconds -= SECONDS_FROM_1900_TO_1970; uint64_t fraction = (timestamp & 0xffffffff); return (seconds * SECOND_IN_NSECS) + ((fraction * SECOND_IN_NSECS) >> 32); } /** * Returns the current time in nano seconds according to the local wall clock. * The system Unix time is used as the local wall clock. */ uint64_t raop_ntp_get_local_time(raop_ntp_t *raop_ntp) { struct timespec time; clock_gettime(CLOCK_REALTIME, &time); return ((uint64_t) time.tv_nsec) + (uint64_t) time.tv_sec * SECOND_IN_NSECS; } /** * Returns the current time in nano seconds according to the remote wall clock. */ uint64_t raop_ntp_get_remote_time(raop_ntp_t *raop_ntp) { MUTEX_LOCK(raop_ntp->sync_params_mutex); int64_t offset = raop_ntp->sync_offset; MUTEX_UNLOCK(raop_ntp->sync_params_mutex); return (uint64_t) ((int64_t) raop_ntp_get_local_time(raop_ntp) + offset); } /** * Returns the local wall clock time in nano seconds for the given point in remote clock time */ uint64_t raop_ntp_convert_remote_time(raop_ntp_t *raop_ntp, uint64_t remote_time) { MUTEX_LOCK(raop_ntp->sync_params_mutex); int64_t offset = raop_ntp->sync_offset; MUTEX_UNLOCK(raop_ntp->sync_params_mutex); return (uint64_t) ((int64_t) remote_time - offset); } /** * Returns the remote wall clock time in nano seconds for the given point in local clock time */ uint64_t raop_ntp_convert_local_time(raop_ntp_t *raop_ntp, uint64_t local_time) { MUTEX_LOCK(raop_ntp->sync_params_mutex); int64_t offset = raop_ntp->sync_offset; MUTEX_UNLOCK(raop_ntp->sync_params_mutex); return (uint64_t) ((int64_t) local_time + offset); } UxPlay-1.71.1/lib/raop_ntp.h000066400000000000000000000032251473013662600155760ustar00rootroot00000000000000/* * Copyright (c) 2019 dsafa22, modified by Florian Draschbacher, * All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * *================================================================= * modified by fduncanh 2021-2023 */ #ifndef RAOP_NTP_H #define RAOP_NTP_H #include #include #include "logger.h" typedef struct raop_ntp_s raop_ntp_t; typedef enum timing_protocol_e { NTP, TP_NONE, TP_OTHER, TP_UNSPECIFIED } timing_protocol_t; void raop_ntp_start(raop_ntp_t *raop_ntp, unsigned short *timing_lport, int max_ntp_timeouts); void raop_ntp_stop(raop_ntp_t *raop_ntp); unsigned short raop_ntp_get_port(raop_ntp_t *raop_ntp); void raop_ntp_destroy(raop_ntp_t *raop_rtp); uint64_t raop_ntp_timestamp_to_nano_seconds(uint64_t ntp_timestamp, bool account_for_epoch_diff); uint64_t raop_remote_timestamp_to_nano_seconds(raop_ntp_t *raop_ntp, uint64_t timestamp); uint64_t raop_ntp_get_local_time(raop_ntp_t *raop_ntp); uint64_t raop_ntp_get_remote_time(raop_ntp_t *raop_ntp); uint64_t raop_ntp_convert_remote_time(raop_ntp_t *raop_ntp, uint64_t remote_time); uint64_t raop_ntp_convert_local_time(raop_ntp_t *raop_ntp, uint64_t local_time); #endif //RAOP_NTP_H UxPlay-1.71.1/lib/raop_rtp.c000066400000000000000000001012731473013662600155770ustar00rootroot00000000000000/** * Copyright (C) 2011-2012 Juho Vähä-Herttua * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * *================================================================= * modified by fduncanh 2021-2023 */ #include #include #include #include #include #include #include "raop_rtp.h" #include "raop.h" #include "raop_buffer.h" #include "netutils.h" #include "compat.h" #include "logger.h" #include "byteutils.h" #include "mirror_buffer.h" #include "stream.h" #include "utils.h" #define NO_FLUSH (-42) #define SECOND_IN_NSECS 1000000000 #define RAOP_RTP_SYNC_DATA_COUNT 8 #define SEC SECOND_IN_NSECS #define DELAY_AAC 0.275 //empirical, matches audio latency of about -0.25 sec after first clock sync event /* note: it is unclear what will happen in the unlikely event that this code is running at the time of the unix-time * epoch event on 2038-01-19 at 3:14:08 UTC ! (but Apple will surely have removed AirPlay "legacy pairing" by then!) */ typedef struct raop_rtp_sync_data_s { uint64_t ntp_time; // The local wall clock time (unix time in usec) at the time of rtp_time uint64_t rtp_time; // The remote rtp clock time corresponding to ntp_time } raop_rtp_sync_data_t; struct raop_rtp_s { logger_t *logger; raop_callbacks_t callbacks; // Time and sync raop_ntp_t *ntp; double rtp_clock_rate; int64_t rtp_sync_offset; raop_rtp_sync_data_t sync_data[RAOP_RTP_SYNC_DATA_COUNT]; int sync_data_index; uint64_t ntp_start_time; uint64_t rtp_start_time; uint64_t rtp_time; bool rtp_clock_started; // Transmission Stats, could be used if a playout buffer is needed // float interarrival_jitter; // As defined by RTP RFC 3550, Section 6.4.1 // unsigned int last_packet_transit_time; //int transit = (packet_receive_time - packet_send_time); // int d = transit - last_packet_transit_time; // if (d < 0) d = -d; // interarrival_jitter = (1.f / 16.f) * ((double) d - interarrival_jitter); /* Buffer to handle all resends */ raop_buffer_t *buffer; /* Remote address as sockaddr */ struct sockaddr_storage remote_saddr; socklen_t remote_saddr_len; /* MUTEX LOCKED VARIABLES START */ /* These variables only edited mutex locked */ int running; int joined; float volume; int volume_changed; unsigned char *metadata; int metadata_len; unsigned char *coverart; int coverart_len; char *dacp_id; char *active_remote_header; unsigned int progress_start; unsigned int progress_curr; unsigned int progress_end; int progress_changed; int flush; thread_handle_t thread; mutex_handle_t run_mutex; /* MUTEX LOCKED VARIABLES END */ /* Remote control and timing ports */ unsigned short control_rport; /* Sockets for control and data */ int csock, dsock; /* Local control, timing and data ports */ unsigned short control_lport; unsigned short data_lport; /* Initialized after the first control packet */ struct sockaddr_storage control_saddr; socklen_t control_saddr_len; unsigned short control_seqnum; /* audio compression type: ct = 2 (ALAC), ct = 8 (AAC_ELD) (ct = 4 would be AAC-MAIN) */ unsigned char ct; }; static int raop_rtp_parse_remote(raop_rtp_t *raop_rtp, const char *remote, int remotelen) { int family; int ret; assert(raop_rtp); if (remotelen == 4) { family = AF_INET; } else if (remotelen == 16) { family = AF_INET6; } else { return -1; } logger_log(raop_rtp->logger, LOGGER_DEBUG, "raop_rtp parse remote ip = %s", remote); ret = netutils_parse_address(family, remote, &raop_rtp->remote_saddr, sizeof(raop_rtp->remote_saddr)); if (ret < 0) { return -1; } raop_rtp->remote_saddr_len = ret; return 0; } raop_rtp_t * raop_rtp_init(logger_t *logger, raop_callbacks_t *callbacks, raop_ntp_t *ntp, const char *remote, int remotelen, const unsigned char *aeskey, const unsigned char *aesiv) { raop_rtp_t *raop_rtp; assert(logger); assert(callbacks); raop_rtp = calloc(1, sizeof(raop_rtp_t)); if (!raop_rtp) { return NULL; } raop_rtp->logger = logger; raop_rtp->ntp = ntp; raop_rtp->rtp_sync_offset = 0; raop_rtp->sync_data_index = 0; for (int i = 0; i < RAOP_RTP_SYNC_DATA_COUNT; ++i) { raop_rtp->sync_data[i].ntp_time = 0; raop_rtp->sync_data[i].rtp_time = 0; } raop_rtp->ntp_start_time = 0; raop_rtp->rtp_start_time = 0; raop_rtp->rtp_clock_started = false; raop_rtp->dacp_id = NULL; raop_rtp->active_remote_header = NULL; raop_rtp->metadata = NULL; raop_rtp->coverart = NULL; memcpy(&raop_rtp->callbacks, callbacks, sizeof(raop_callbacks_t)); raop_rtp->buffer = raop_buffer_init(logger, aeskey, aesiv); if (!raop_rtp->buffer) { free(raop_rtp); return NULL; } if (raop_rtp_parse_remote(raop_rtp, remote, remotelen) < 0) { free(raop_rtp); return NULL; } raop_rtp->running = 0; raop_rtp->joined = 1; raop_rtp->flush = NO_FLUSH; MUTEX_CREATE(raop_rtp->run_mutex); return raop_rtp; } void raop_rtp_destroy(raop_rtp_t *raop_rtp) { if (raop_rtp) { raop_rtp_stop(raop_rtp); MUTEX_DESTROY(raop_rtp->run_mutex); raop_buffer_destroy(raop_rtp->buffer); free(raop_rtp->metadata); free(raop_rtp->coverart); free(raop_rtp->dacp_id); free(raop_rtp->active_remote_header); free(raop_rtp); } } static int raop_rtp_resend_callback(void *opaque, unsigned short seqnum, unsigned short count) { raop_rtp_t *raop_rtp = opaque; unsigned char packet[8]; unsigned short ourseqnum; struct sockaddr *addr; socklen_t addrlen; int ret; addr = (struct sockaddr *)&raop_rtp->control_saddr; addrlen = raop_rtp->control_saddr_len; logger_log(raop_rtp->logger, LOGGER_DEBUG, "raop_rtp got resend request %d %d", seqnum, count); ourseqnum = raop_rtp->control_seqnum++; /* Fill the request buffer */ packet[0] = 0x80; packet[1] = 0x55|0x80; packet[2] = (ourseqnum >> 8); packet[3] = ourseqnum; packet[4] = (seqnum >> 8); packet[5] = seqnum; packet[6] = (count >> 8); packet[7] = count; ret = sendto(raop_rtp->csock, (const char *)packet, sizeof(packet), 0, addr, addrlen); if (ret == -1) { logger_log(raop_rtp->logger, LOGGER_WARNING, "raop_rtp resend failed: %d", SOCKET_GET_ERROR()); } return 0; } static int raop_rtp_init_sockets(raop_rtp_t *raop_rtp, int use_ipv6) { assert(raop_rtp); unsigned short cport = raop_rtp->control_lport; unsigned short dport = raop_rtp->data_lport; int csock = netutils_init_socket(&cport, use_ipv6, 1); int dsock = netutils_init_socket(&dport, use_ipv6, 1); if (csock == -1 || dsock == -1) { goto sockets_cleanup; } /* Set socket descriptors */ raop_rtp->csock = csock; raop_rtp->dsock = dsock; /* Set port values */ raop_rtp->control_lport = cport; raop_rtp->data_lport = dport; logger_log(raop_rtp->logger, LOGGER_DEBUG, "raop_rtp local control port socket %d port UDP %d", csock, cport); logger_log(raop_rtp->logger, LOGGER_DEBUG, "raop_rtp local data port socket %d port UDP %d", dsock, dport); return 0; sockets_cleanup: if (csock != -1) closesocket(csock); if (dsock != -1) closesocket(dsock); return -1; } static int raop_rtp_process_events(raop_rtp_t *raop_rtp, void *cb_data) { int flush; float volume; int volume_changed; unsigned char *metadata; int metadata_len; unsigned char *coverart; int coverart_len; char *dacp_id; char *active_remote_header; unsigned int progress_start; unsigned int progress_curr; unsigned int progress_end; int progress_changed; assert(raop_rtp); MUTEX_LOCK(raop_rtp->run_mutex); if (!raop_rtp->running) { MUTEX_UNLOCK(raop_rtp->run_mutex); return 1; } /* Read the volume level */ volume = raop_rtp->volume; volume_changed = raop_rtp->volume_changed; raop_rtp->volume_changed = 0; /* Read the flush value */ flush = raop_rtp->flush; raop_rtp->flush = NO_FLUSH; /* Read the metadata */ metadata = raop_rtp->metadata; metadata_len = raop_rtp->metadata_len; raop_rtp->metadata = NULL; raop_rtp->metadata_len = 0; /* Read the coverart */ coverart = raop_rtp->coverart; coverart_len = raop_rtp->coverart_len; raop_rtp->coverart = NULL; raop_rtp->coverart_len = 0; /* Read DACP remote control data */ dacp_id = raop_rtp->dacp_id; active_remote_header = raop_rtp->active_remote_header; raop_rtp->dacp_id = NULL; raop_rtp->active_remote_header = NULL; /* Read the progress values */ progress_start = raop_rtp->progress_start; progress_curr = raop_rtp->progress_curr; progress_end = raop_rtp->progress_end; progress_changed = raop_rtp->progress_changed; raop_rtp->progress_changed = 0; MUTEX_UNLOCK(raop_rtp->run_mutex); /* Call set_volume callback if changed */ if (volume_changed) { //raop_buffer_flush(raop_rtp->buffer, flush); /* seems to be unnecessary, may cause audio artefacts */ if (raop_rtp->callbacks.audio_set_volume) { raop_rtp->callbacks.audio_set_volume(raop_rtp->callbacks.cls, volume); } } /* Handle flush if requested */ if (flush != NO_FLUSH) { if (raop_rtp->callbacks.audio_flush) { raop_rtp->callbacks.audio_flush(raop_rtp->callbacks.cls); } } if (metadata != NULL) { if (raop_rtp->callbacks.audio_set_metadata) { raop_rtp->callbacks.audio_set_metadata(raop_rtp->callbacks.cls, metadata, metadata_len); } free(metadata); metadata = NULL; } if (coverart != NULL) { if (raop_rtp->callbacks.audio_set_coverart) { raop_rtp->callbacks.audio_set_coverart(raop_rtp->callbacks.cls, coverart, coverart_len); } free(coverart); coverart = NULL; } if (dacp_id && active_remote_header) { if (raop_rtp->callbacks.audio_remote_control_id) { raop_rtp->callbacks.audio_remote_control_id(raop_rtp->callbacks.cls, dacp_id, active_remote_header); } free(dacp_id); free(active_remote_header); dacp_id = NULL; active_remote_header = NULL; } if (progress_changed) { if (raop_rtp->callbacks.audio_set_progress) { raop_rtp->callbacks.audio_set_progress(raop_rtp->callbacks.cls, progress_start, progress_curr, progress_end); } } return 0; } void raop_rtp_sync_clock(raop_rtp_t *raop_rtp, uint64_t *ntp_time, uint64_t *rtp_time) { /* ntp_time = (uint64_t)(((int64_t)(raop_rtp->rtp_clock_rate * rtp_time)) + raop_rtp->rtp_sync_offset) */ int latest, valid_data_count = 0; uint64_t ntp_sum = 0, rtp_sum = 0; double offset = ((double) *ntp_time) - raop_rtp->rtp_clock_rate * *rtp_time; int64_t correction = 0; raop_rtp->sync_data_index = (raop_rtp->sync_data_index + 1) % RAOP_RTP_SYNC_DATA_COUNT; latest = raop_rtp->sync_data_index; raop_rtp->sync_data[latest].rtp_time = *rtp_time; raop_rtp->sync_data[latest].ntp_time = *ntp_time; for (int i = 0; i < RAOP_RTP_SYNC_DATA_COUNT; i++) { if (raop_rtp->sync_data[i].ntp_time == 0) continue; valid_data_count++; if (i == latest) continue; ntp_sum += *ntp_time - raop_rtp->sync_data[i].ntp_time; rtp_sum += *rtp_time - raop_rtp->sync_data[i].rtp_time; } if (valid_data_count > 1) { correction -= raop_rtp->rtp_sync_offset; offset += (((double) ntp_sum) - raop_rtp->rtp_clock_rate * rtp_sum) / valid_data_count; } raop_rtp->rtp_sync_offset = (int64_t) offset; correction += raop_rtp->rtp_sync_offset; logger_log(raop_rtp->logger, LOGGER_DEBUG, "dataset %d raop_rtp sync correction=%lld, rtp_sync_offset = %lld ", valid_data_count, correction, raop_rtp->rtp_sync_offset); } uint64_t rtp64_time (raop_rtp_t *raop_rtp, const uint32_t *rtp32) { /* convert from 32-bit to 64-bit rtp time: * the rtp_time 32-bit epoch at 44.1kHz has length of about 27 hours * using 64-bit rtp time avoids any epoch issues. * initial call sets epoch to 1; subsequent calls maintain consistent epoch. * (assumes successive calls are close in time) */ if (raop_rtp->rtp_clock_started) { uint32_t diff1 = *rtp32 - ((uint32_t) raop_rtp->rtp_time); uint32_t diff2 = ((uint32_t) raop_rtp->rtp_time) - *rtp32; if (diff1 <= diff2) { raop_rtp->rtp_time += (uint64_t) diff1; } else { raop_rtp->rtp_time -= (uint64_t) diff2; } } else { raop_rtp->rtp_time = (0x01ULL << 32 ) + (uint64_t) *rtp32; raop_rtp->rtp_start_time = raop_rtp->rtp_time; raop_rtp->rtp_clock_started = true; } //assert(*rtp32 == (uint32_t) raop_rtp->rtp_time); return raop_rtp->rtp_time; } static THREAD_RETVAL raop_rtp_thread_udp(void *arg) { raop_rtp_t *raop_rtp = arg; unsigned char packet[RAOP_PACKET_LEN]; unsigned int packetlen; struct sockaddr_storage saddr; socklen_t saddrlen; bool got_remote_control_saddr = false; /* for initial rtp to ntp conversions */ bool have_synced = false; bool no_data_yet = true; unsigned char no_data_marker[] = {0x00, 0x68, 0x34, 0x00 }; int rtp_count = 0; double sync_adjustment = 0; unsigned short seqnum1 = 0, seqnum2 = 0; assert(raop_rtp); bool logger_debug = (logger_get_level(raop_rtp->logger) >= LOGGER_DEBUG); raop_rtp->ntp_start_time = raop_ntp_get_local_time(raop_rtp->ntp); raop_rtp->rtp_clock_started = false; for (int i = 0; i < RAOP_RTP_SYNC_DATA_COUNT; i++) { raop_rtp->sync_data[i].ntp_time = 0; } int no_resend = (raop_rtp->control_rport == 0); /* true when control_rport is not set */ logger_log(raop_rtp->logger, LOGGER_DEBUG, "raop_rtp start_time = %8.6f (raop_rtp audio)", ((double) raop_rtp->ntp_start_time) / SEC); while(1) { fd_set rfds; struct timeval tv; int nfds, ret; /* Check if we are still running and process callbacks */ if (raop_rtp_process_events(raop_rtp, NULL)) { break; } /* Set timeout value to 5ms */ tv.tv_sec = 0; tv.tv_usec = 5000; /* Get the correct nfds value */ nfds = raop_rtp->csock+1; if (raop_rtp->dsock >= nfds) nfds = raop_rtp->dsock+1; /* Set rfds and call select */ FD_ZERO(&rfds); FD_SET(raop_rtp->csock, &rfds); FD_SET(raop_rtp->dsock, &rfds); ret = select(nfds, &rfds, NULL, NULL, &tv); if (ret == 0) { /* Timeout happened */ continue; } else if (ret == -1) { logger_log(raop_rtp->logger, LOGGER_ERR, "raop_rtp error in select"); break; } if (FD_ISSET(raop_rtp->csock, &rfds)) { if (got_remote_control_saddr== false) { saddrlen = sizeof(saddr); packetlen = recvfrom(raop_rtp->csock, (char *)packet, sizeof(packet), 0, (struct sockaddr *)&saddr, &saddrlen); if (packetlen > 0) { memcpy(&raop_rtp->control_saddr, &saddr, saddrlen); raop_rtp->control_saddr_len = saddrlen; got_remote_control_saddr = true; } } else { packetlen = recvfrom(raop_rtp->csock, (char *)packet, sizeof(packet), 0, NULL, NULL); } int type_c = packet[1] & ~0x80; logger_log(raop_rtp->logger, LOGGER_DEBUG, "\nraop_rtp type_c 0x%02x, packetlen = %d", type_c, packetlen); if (type_c == 0x56 && packetlen >= 8) { /* Handle resent data packet, which begins at offset 4 of these packets */ unsigned char *resent_packet = &packet[4]; unsigned int resent_packetlen = packetlen - 4; unsigned short seqnum = byteutils_get_short_be(resent_packet, 2); if (resent_packetlen >= 12) { uint32_t timestamp = byteutils_get_int_be(resent_packet, 4); uint64_t rtp_time = rtp64_time(raop_rtp, ×tamp); uint64_t ntp_time = 0; if (have_synced) { ntp_time = (uint64_t) (raop_rtp->rtp_sync_offset + (int64_t) (raop_rtp->rtp_clock_rate * rtp_time)); } logger_log(raop_rtp->logger, LOGGER_DEBUG, "raop_rtp resent audio packet: seqnum=%u", seqnum); int result = raop_buffer_enqueue(raop_rtp->buffer, resent_packet, resent_packetlen, &ntp_time, &rtp_time, 1); assert(result >= 0); } else if (logger_debug) { /* type_c = 0x56 packets with length 8 have been reported */ char *str = utils_data_to_string(packet, packetlen, 16); logger_log(raop_rtp->logger, LOGGER_DEBUG, "Received empty resent audio packet length %d, seqnum=%u:\n%s", packetlen, seqnum, str); free (str); } } else if (type_c == 0x54 && packetlen >= 20) { /* packet[0] = 0x90 (first sync ?) or 0x80 (subsequent ones) * packet[1] = 0xd4, (0xd4 && ~0x80 = type 0x54) * packet[2:3] = 0x00 0x04 * packet[4:7] : sync_rtp (big-endian uint32_t) * packet[8:15]: remote ntp timestamp (big-endian uint64_t) * packet[16:20]: next_rtp (big-endian uint32_t) * next_rtp = sync_rtp + 7497 = 441 * 17 (0.17 sec) for AAC-ELD * next_rtp = sync_rtp + 77175 = 441 * 175 (1.75 sec) for ALAC */ // The unit for the rtp clock is 1 / sample rate = 1 / 44100 uint32_t sync_rtp = byteutils_get_int_be(packet, 4); uint64_t sync_rtp64 = rtp64_time(raop_rtp, &sync_rtp); if (have_synced == false) { logger_log(raop_rtp->logger, LOGGER_DEBUG, "first audio rtp sync"); have_synced = true; } uint64_t sync_ntp_raw = byteutils_get_long_be(packet, 8); uint64_t sync_ntp_remote = raop_remote_timestamp_to_nano_seconds(raop_rtp->ntp, sync_ntp_raw); if (logger_debug) { uint64_t sync_ntp_local = raop_ntp_convert_remote_time(raop_rtp->ntp, sync_ntp_remote); char *str = utils_data_to_string(packet, packetlen, 20); logger_log(raop_rtp->logger, LOGGER_DEBUG, "raop_rtp sync: client ntp=%8.6f, ntp = %8.6f, ntp_start_time %8.6f\nts_client = %8.6f sync_rtp=%u\n%s", (double) sync_ntp_remote / SEC, (double) sync_ntp_local / SEC, (double) raop_rtp->ntp_start_time / SEC, (double) sync_ntp_remote / SEC, sync_rtp, str); free(str); } raop_rtp_sync_clock(raop_rtp, &sync_ntp_remote, &sync_rtp64); } else if (logger_debug) { char *str = utils_data_to_string(packet, packetlen, 16); logger_log(raop_rtp->logger, LOGGER_DEBUG, "raop_rtp unknown udp control packet\n%s", str); free(str); } } /* rtp audio data packets: * packet[0] 0x80 * packet[1] 0x60 = 96 * packet[2:3] seqnum (big-endian unsigned short) * packet[4:7] rtp timestamp (big-endian unsigned int) * packet[8:11] 0x00 0x00 0x00 0x00 * packet[12:packetlen - 1] encrypted audio payload * For (AAC-ELD only), the payload of initial packets at the start of * the stream may be replaced by a 4-byte "no_data_marker" 0x00 0x68 0x34 0x00 */ /* consecutive AAC-ELD rtp timestamps differ by spf = 480 * consecutive ALAC rtp timestamps differ by spf = 352 * both have PCM uncompressed sampling rate = 441000 Hz */ /* clock time in microseconds advances at (rtp_timestamp * 1000000)/44100 between frames */ /* every AAC-ELD packet is sent three times: 0 0 1 0 1 2 1 2 3 2 3 4 ... * (after decoding AAC-ELD into PCM, the sound frame is three times bigger) * ALAC packets are sent once only 0 1 2 3 4 5 ... */ /* When the AAC-ELD audio stream starts, the initial packets are length-16 packets with * a four-byte "no_data_marker" 0x00 0x68 0x34 0x00 replacing the payload. * The 12-byte packetheader contains a secnum and rtp_timestamp, and each packets is sent * three times; the secnum and rtp_timestamp increment according to the same pattern as * AAC-ELD packets with audio content.*/ /* When the ALAC audio stream starts, the initial packets are length-44 packets with * the same 32-byte encrypted payload which after decryption is the beginning of a * 32-byte ALAC packet, presumably with format information, but not actual audio data. * The secnum and rtp_timestamp in the packet header increment according to the same * pattern as ALAC packets with audio content */ /* The first ALAC packet with data seems to be decoded just before the first sync event * so its dequeuing should be delayed until the first rtp sync has occurred */ if (FD_ISSET(raop_rtp->dsock, &rfds)) { //logger_log(raop_rtp->logger, LOGGER_INFO, "Would have data packet in queue"); // Receiving audio data here saddrlen = sizeof(saddr); packetlen = recvfrom(raop_rtp->dsock, (char *)packet, sizeof(packet), 0, NULL, NULL); // rtp payload type //int type_d = packet[1] & ~0x80; //logger_log(raop_rtp->logger, LOGGER_DEBUG, "raop_rtp_thread_udp type_d 0x%02x, packetlen = %d", type_d, packetlen); if (packetlen < 12) { if (logger_debug) { char *str = utils_data_to_string(packet, packetlen, 16); logger_log(raop_rtp->logger, LOGGER_DEBUG, "Received short type_d = 0x%2x packet with length %d:\n%s", packet[1] & ~0x80, packetlen, str); free (str); } continue; } uint32_t rtp_timestamp = byteutils_get_int_be(packet, 4); uint64_t rtp_time = rtp64_time(raop_rtp, &rtp_timestamp); uint64_t ntp_time = 0; if (raop_rtp->ct == 2 && packetlen == 44) continue; /* ignore the ALAC packets with format information only. */ if (have_synced) { ntp_time = (uint64_t) (raop_rtp->rtp_sync_offset + (int64_t) (raop_rtp->rtp_clock_rate * rtp_time)); } else if (packetlen == 16 && memcmp(packet + 12, no_data_marker, 4) == 0) { /* use the special "no_data" packet to help determine an initial offset before the first rtp sync. * until the first rtp sync occurs, we don't know the exact client ntp timestamp that matches the client rtp timestamp */ if (no_data_yet) { int64_t sync_ntp = ((int64_t) raop_ntp_get_local_time(raop_rtp->ntp)) - ((int64_t) raop_rtp->ntp_start_time) ; int64_t sync_rtp = ((int64_t) rtp_time) - ((int64_t) raop_rtp->rtp_start_time); unsigned short seqnum = byteutils_get_short_be(packet, 2); if (rtp_count == 0) { sync_adjustment = ((double) sync_ntp); rtp_count = 1; seqnum1 = seqnum; seqnum2 = seqnum; } if (seqnum2 != seqnum) { /* for AAC-ELD only use copy 1 of the 3 copies of each frame */ rtp_count++; sync_adjustment += (((double) sync_ntp) - raop_rtp->rtp_clock_rate * sync_rtp - sync_adjustment) / rtp_count; } seqnum2 = seqnum1; seqnum1 = seqnum; } continue; } else { no_data_yet = false; } int result = raop_buffer_enqueue(raop_rtp->buffer, packet, packetlen, &ntp_time, &rtp_time, 1); assert(result >= 0); if (raop_rtp->ct == 2 && !have_synced) { /* in ALAC Audio-only mode wait until the first sync before dequeing */ continue; } else { // Render continuous buffer entries void *payload = NULL; unsigned int payload_size; unsigned short seqnum; uint64_t rtp64_timestamp; uint64_t ntp_timestamp; while ((payload = raop_buffer_dequeue(raop_rtp->buffer, &payload_size, &ntp_timestamp, &rtp64_timestamp, &seqnum, no_resend))) { audio_decode_struct audio_data; audio_data.rtp_time = rtp64_timestamp; audio_data.seqnum = seqnum; audio_data.data_len = payload_size; audio_data.data = payload; audio_data.ct = raop_rtp->ct; if (have_synced) { if (ntp_timestamp == 0) { ntp_timestamp = (uint64_t) (raop_rtp->rtp_sync_offset + (int64_t) (raop_rtp->rtp_clock_rate * rtp64_timestamp)); } audio_data.ntp_time_remote = ntp_timestamp; audio_data.ntp_time_local = raop_ntp_convert_remote_time(raop_rtp->ntp, audio_data.ntp_time_remote); audio_data.sync_status = 1; } else { double elapsed_time = raop_rtp->rtp_clock_rate * (rtp64_timestamp - raop_rtp->rtp_start_time) + sync_adjustment + DELAY_AAC * SECOND_IN_NSECS; audio_data.ntp_time_local = raop_rtp->ntp_start_time + (uint64_t) elapsed_time; audio_data.ntp_time_remote = raop_ntp_convert_local_time(raop_rtp->ntp, audio_data.ntp_time_local); audio_data.sync_status = 0; } raop_rtp->callbacks.audio_process(raop_rtp->callbacks.cls, raop_rtp->ntp, &audio_data); free(payload); if (logger_debug) { uint64_t ntp_now = raop_ntp_get_local_time(raop_rtp->ntp); int64_t latency = ((int64_t) ntp_now) - ((int64_t) audio_data.ntp_time_local); logger_log(raop_rtp->logger, LOGGER_DEBUG, "raop_rtp audio: now = %8.6f, ntp = %8.6f, latency = %8.6f, rtp_time=%u seqnum = %u", (double) ntp_now / SEC, (double) audio_data.ntp_time_local / SEC, (double) latency / SEC, (uint32_t) rtp64_timestamp, seqnum); } } /* Handle possible resend requests */ if (!no_resend) { raop_buffer_handle_resends(raop_rtp->buffer, raop_rtp_resend_callback, raop_rtp); } } } } // Ensure running reflects the actual state MUTEX_LOCK(raop_rtp->run_mutex); raop_rtp->running = false; MUTEX_UNLOCK(raop_rtp->run_mutex); logger_log(raop_rtp->logger, LOGGER_DEBUG, "raop_rtp exiting thread"); return 0; } // Start rtp service, using two udp ports void raop_rtp_start_audio(raop_rtp_t *raop_rtp, unsigned short *control_rport, unsigned short *control_lport, unsigned short *data_lport, unsigned char *ct, unsigned int *sr) { logger_log(raop_rtp->logger, LOGGER_INFO, "raop_rtp starting audio"); int use_ipv6 = 0; assert(raop_rtp); MUTEX_LOCK(raop_rtp->run_mutex); if (raop_rtp->running || !raop_rtp->joined) { MUTEX_UNLOCK(raop_rtp->run_mutex); return; } raop_rtp->ct = *ct; raop_rtp->rtp_clock_rate = SECOND_IN_NSECS / *sr; /* Initialize ports and sockets */ raop_rtp->control_lport = *control_lport; raop_rtp->data_lport = *data_lport; raop_rtp->control_rport = *control_rport; if (raop_rtp->remote_saddr.ss_family == AF_INET6) { use_ipv6 = 1; } //use_ipv6 = 0; if (raop_rtp_init_sockets(raop_rtp, use_ipv6) < 0) { logger_log(raop_rtp->logger, LOGGER_ERR, "raop_rtp initializing sockets failed"); MUTEX_UNLOCK(raop_rtp->run_mutex); return; } *control_lport = raop_rtp->control_lport; *data_lport = raop_rtp->data_lport; /* Create the thread and initialize running values */ raop_rtp->running = 1; raop_rtp->joined = 0; THREAD_CREATE(raop_rtp->thread, raop_rtp_thread_udp, raop_rtp); MUTEX_UNLOCK(raop_rtp->run_mutex); } void raop_rtp_set_volume(raop_rtp_t *raop_rtp, float volume) { assert(raop_rtp); if (volume > 0.0f) { volume = 0.0f; } else if (volume < -144.0f) { volume = -144.0f; } /* Set volume in thread instead */ MUTEX_LOCK(raop_rtp->run_mutex); raop_rtp->volume = volume; raop_rtp->volume_changed = 1; MUTEX_UNLOCK(raop_rtp->run_mutex); } void raop_rtp_set_metadata(raop_rtp_t *raop_rtp, const char *data, int datalen) { unsigned char *metadata; assert(raop_rtp); if (datalen <= 0) { return; } metadata = malloc(datalen); assert(metadata); memcpy(metadata, data, datalen); /* Set metadata in thread instead */ MUTEX_LOCK(raop_rtp->run_mutex); raop_rtp->metadata = metadata; raop_rtp->metadata_len = datalen; MUTEX_UNLOCK(raop_rtp->run_mutex); } void raop_rtp_set_coverart(raop_rtp_t *raop_rtp, const char *data, int datalen) { unsigned char *coverart; assert(raop_rtp); if (datalen <= 0) { return; } coverart = malloc(datalen); assert(coverart); memcpy(coverart, data, datalen); /* Set coverart in thread instead */ MUTEX_LOCK(raop_rtp->run_mutex); raop_rtp->coverart = coverart; raop_rtp->coverart_len = datalen; MUTEX_UNLOCK(raop_rtp->run_mutex); } void raop_rtp_remote_control_id(raop_rtp_t *raop_rtp, const char *dacp_id, const char *active_remote_header) { assert(raop_rtp); if (!dacp_id || !active_remote_header) { return; } /* Set dacp stuff in thread instead */ MUTEX_LOCK(raop_rtp->run_mutex); if (raop_rtp->dacp_id) { free(raop_rtp->dacp_id); } raop_rtp->dacp_id = strdup(dacp_id); if (raop_rtp->active_remote_header) { free(raop_rtp->active_remote_header); } raop_rtp->active_remote_header = strdup(active_remote_header); MUTEX_UNLOCK(raop_rtp->run_mutex); } void raop_rtp_set_progress(raop_rtp_t *raop_rtp, unsigned int start, unsigned int curr, unsigned int end) { assert(raop_rtp); /* Set progress in thread instead */ MUTEX_LOCK(raop_rtp->run_mutex); raop_rtp->progress_start = start; raop_rtp->progress_curr = curr; raop_rtp->progress_end = end; raop_rtp->progress_changed = 1; MUTEX_UNLOCK(raop_rtp->run_mutex); } void raop_rtp_flush(raop_rtp_t *raop_rtp, int next_seq) { assert(raop_rtp); /* Call flush in thread instead */ MUTEX_LOCK(raop_rtp->run_mutex); raop_rtp->flush = next_seq; MUTEX_UNLOCK(raop_rtp->run_mutex); } void raop_rtp_stop(raop_rtp_t *raop_rtp) { assert(raop_rtp); /* Check that we are running and thread is not * joined (should never be while still running) */ MUTEX_LOCK(raop_rtp->run_mutex); if (!raop_rtp->running || raop_rtp->joined) { MUTEX_UNLOCK(raop_rtp->run_mutex); return; } raop_rtp->running = 0; MUTEX_UNLOCK(raop_rtp->run_mutex); /* Join the thread */ THREAD_JOIN(raop_rtp->thread); if (raop_rtp->csock != -1) closesocket(raop_rtp->csock); if (raop_rtp->dsock != -1) closesocket(raop_rtp->dsock); /* Flush buffer into initial state */ raop_buffer_flush(raop_rtp->buffer, -1); /* Mark thread as joined */ MUTEX_LOCK(raop_rtp->run_mutex); raop_rtp->joined = 1; MUTEX_UNLOCK(raop_rtp->run_mutex); } int raop_rtp_is_running(raop_rtp_t *raop_rtp) { assert(raop_rtp); MUTEX_LOCK(raop_rtp->run_mutex); int running = raop_rtp->running; MUTEX_UNLOCK(raop_rtp->run_mutex); return running; } UxPlay-1.71.1/lib/raop_rtp.h000066400000000000000000000037161473013662600156070ustar00rootroot00000000000000/** * Copyright (C) 2011-2012 Juho Vähä-Herttua * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * *================================================================== * modified by fduncanh 2021-2023 */ #ifndef RAOP_RTP_H #define RAOP_RTP_H /* For raop_callbacks_t */ #include "raop.h" #include "logger.h" #include "raop_ntp.h" #define RAOP_AESIV_LEN 16 #define RAOP_AESKEY_LEN 16 #define RAOP_PACKET_LEN 32768 typedef struct raop_rtp_s raop_rtp_t; raop_rtp_t *raop_rtp_init(logger_t *logger, raop_callbacks_t *callbacks, raop_ntp_t *ntp, const char *remote, int remotelen, const unsigned char *aeskey, const unsigned char *aesiv); void raop_rtp_start_audio(raop_rtp_t *raop_rtp, unsigned short *control_rport, unsigned short *control_lport, unsigned short *data_lport, unsigned char *ct, unsigned int *sr); void raop_rtp_set_volume(raop_rtp_t *raop_rtp, float volume); void raop_rtp_set_metadata(raop_rtp_t *raop_rtp, const char *data, int datalen); void raop_rtp_set_coverart(raop_rtp_t *raop_rtp, const char *data, int datalen); void raop_rtp_remote_control_id(raop_rtp_t *raop_rtp, const char *dacp_id, const char *active_remote_header); void raop_rtp_set_progress(raop_rtp_t *raop_rtp, unsigned int start, unsigned int curr, unsigned int end); void raop_rtp_flush(raop_rtp_t *raop_rtp, int next_seq); void raop_rtp_stop(raop_rtp_t *raop_rtp); int raop_rtp_is_running(raop_rtp_t *raop_rtp); void raop_rtp_destroy(raop_rtp_t *raop_rtp); #endif UxPlay-1.71.1/lib/raop_rtp_mirror.c000066400000000000000000001246661473013662600172040ustar00rootroot00000000000000/* * Copyright (c) 2019 dsafa22, All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * *================================================================== * modified by fduncanh 2021-2023 */ #include "raop_rtp_mirror.h" #include #include #include #include #include #include #ifdef _WIN32 #include #else #include #endif #include "raop.h" #include "netutils.h" #include "compat.h" #include "logger.h" #include "byteutils.h" #include "mirror_buffer.h" #include "stream.h" #include "utils.h" #include "plist/plist.h" #ifdef _WIN32 #define CAST (char *) /* are these keepalive settings for WIN32 correct? */ /* (taken from https://github.com/wegank/ludimus) */ #define TCP_KEEPALIVE 3 #define TCP_KEEPCNT 16 #define TCP_KEEPIDLE TCP_KEEPALIVE #define TCP_KEEPINTVL 17 #else #define CAST #endif #define SECOND_IN_NSECS 1000000000UL #define SEC SECOND_IN_NSECS /* for MacOS, where SOL_TCP and TCP_KEEPIDLE are not defined */ #if !defined(SOL_TCP) && defined(IPPROTO_TCP) #define SOL_TCP IPPROTO_TCP #endif #if !defined(TCP_KEEPIDLE) && defined(TCP_KEEPALIVE) #define TCP_KEEPIDLE TCP_KEEPALIVE #endif //struct h264codec_s { // unsigned char compatibility; // short pps_size; // short sps_size; // unsigned char level; // unsigned char number_of_pps; // unsigned char* picture_parameter_set; // unsigned char profile_high; // unsigned char reserved_3_and_sps; // unsigned char reserved_6_and_nal; // unsigned char* sequence_parameter_set; // unsigned char version; //}; struct raop_rtp_mirror_s { logger_t *logger; raop_callbacks_t callbacks; raop_ntp_t *ntp; /* mirror buffer for decryption */ mirror_buffer_t *buffer; /* Remote address as sockaddr */ struct sockaddr_storage remote_saddr; socklen_t remote_saddr_len; /* MUTEX LOCKED VARIABLES START */ /* These variables only edited mutex locked */ int running; int joined; int flush; thread_handle_t thread_mirror; mutex_handle_t run_mutex; /* MUTEX LOCKED VARIABLES END */ int mirror_data_sock; unsigned short mirror_data_lport; /* switch for displaying client FPS data */ uint8_t show_client_FPS_data; }; static int raop_rtp_mirror_parse_remote(raop_rtp_mirror_t *raop_rtp_mirror, const char *remote, int remotelen) { int family; int ret; assert(raop_rtp_mirror); if (remotelen == 4) { family = AF_INET; } else if (remotelen == 16) { family = AF_INET6; } else { return -1; } logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror parse remote ip = %s", remote); ret = netutils_parse_address(family, remote, &raop_rtp_mirror->remote_saddr, sizeof(raop_rtp_mirror->remote_saddr)); if (ret < 0) { return -1; } raop_rtp_mirror->remote_saddr_len = ret; return 0; } #define NO_FLUSH (-42) raop_rtp_mirror_t *raop_rtp_mirror_init(logger_t *logger, raop_callbacks_t *callbacks, raop_ntp_t *ntp, const char *remote, int remotelen, const unsigned char *aeskey) { raop_rtp_mirror_t *raop_rtp_mirror; assert(logger); assert(callbacks); raop_rtp_mirror = calloc(1, sizeof(raop_rtp_mirror_t)); if (!raop_rtp_mirror) { return NULL; } raop_rtp_mirror->logger = logger; raop_rtp_mirror->ntp = ntp; memcpy(&raop_rtp_mirror->callbacks, callbacks, sizeof(raop_callbacks_t)); raop_rtp_mirror->buffer = mirror_buffer_init(logger, aeskey); if (!raop_rtp_mirror->buffer) { free(raop_rtp_mirror); return NULL; } if (raop_rtp_mirror_parse_remote(raop_rtp_mirror, remote, remotelen) < 0) { free(raop_rtp_mirror); return NULL; } raop_rtp_mirror->running = 0; raop_rtp_mirror->joined = 1; raop_rtp_mirror->flush = NO_FLUSH; MUTEX_CREATE(raop_rtp_mirror->run_mutex); return raop_rtp_mirror; } void raop_rtp_mirror_init_aes(raop_rtp_mirror_t *raop_rtp_mirror, uint64_t *streamConnectionID) { mirror_buffer_init_aes(raop_rtp_mirror->buffer, streamConnectionID); } #define RAOP_PACKET_LEN 32768 /** * Mirror */ static THREAD_RETVAL raop_rtp_mirror_thread(void *arg) { raop_rtp_mirror_t *raop_rtp_mirror = arg; assert(raop_rtp_mirror); int stream_fd = -1; unsigned char packet[128]; memset(packet, 0 , 128); unsigned char* sps_pps = NULL; bool prepend_sps_pps = false; int sps_pps_len = 0; unsigned char* payload = NULL; unsigned int readstart = 0; bool conn_reset = false; uint64_t ntp_timestamp_nal = 0; uint64_t ntp_timestamp_raw = 0; uint64_t ntp_timestamp_remote = 0; uint64_t ntp_timestamp_local = 0; unsigned char nal_start_code[4] = { 0x00, 0x00, 0x00, 0x01 }; bool logger_debug = (logger_get_level(raop_rtp_mirror->logger) >= LOGGER_DEBUG); bool h265_video = false; video_codec_t codec; const char h264[] = "h264"; const char h265[] = "h265"; bool unsupported_codec = false; bool video_stream_suspended = false; while (1) { fd_set rfds; struct timeval tv; int nfds, ret; MUTEX_LOCK(raop_rtp_mirror->run_mutex); if (!raop_rtp_mirror->running) { MUTEX_UNLOCK(raop_rtp_mirror->run_mutex); logger_log(raop_rtp_mirror->logger, LOGGER_INFO, "raop_rtp_mirror->running is no longer true"); break; } MUTEX_UNLOCK(raop_rtp_mirror->run_mutex); /* Set timeout valu to 5ms */ tv.tv_sec = 0; tv.tv_usec = 5000; /* Get the correct nfds value and set rfds */ FD_ZERO(&rfds); if (stream_fd == -1) { FD_SET(raop_rtp_mirror->mirror_data_sock, &rfds); nfds = raop_rtp_mirror->mirror_data_sock+1; } else { FD_SET(stream_fd, &rfds); nfds = stream_fd+1; } ret = select(nfds, &rfds, NULL, NULL, &tv); if (ret == 0) { /* Timeout happened */ continue; } else if (ret == -1) { logger_log(raop_rtp_mirror->logger, LOGGER_ERR, "raop_rtp_mirror error in select"); break; } if (stream_fd == -1 && (raop_rtp_mirror && raop_rtp_mirror->mirror_data_sock >= 0) && FD_ISSET(raop_rtp_mirror->mirror_data_sock, &rfds)) { struct sockaddr_storage saddr; socklen_t saddrlen; logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror accepting client"); saddrlen = sizeof(saddr); stream_fd = accept(raop_rtp_mirror->mirror_data_sock, (struct sockaddr *)&saddr, &saddrlen); if (stream_fd == -1) { int sock_err = SOCKET_GET_ERROR(); logger_log(raop_rtp_mirror->logger, LOGGER_ERR, "raop_rtp_mirror error in accept %d %s", sock_err, SOCKET_ERROR_STRING(sock_err)); break; } // We're calling recv for a certain amount of data, so we need a timeout struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 5000; if (setsockopt(stream_fd, SOL_SOCKET, SO_RCVTIMEO, CAST &tv, sizeof(tv)) < 0) { int sock_err = SOCKET_GET_ERROR(); logger_log(raop_rtp_mirror->logger, LOGGER_ERR, "raop_rtp_mirror could not set stream socket timeout %d %s", sock_err, SOCKET_ERROR_STRING(sock_err)); break; } int option; option = 1; if (setsockopt(stream_fd, SOL_SOCKET, SO_KEEPALIVE, CAST &option, sizeof(option)) < 0) { int sock_err = SOCKET_GET_ERROR(); logger_log(raop_rtp_mirror->logger, LOGGER_WARNING, "raop_rtp_mirror could not set stream socket keepalive %d %s", sock_err, SOCKET_ERROR_STRING(sock_err)); } option = 60; if (setsockopt(stream_fd, SOL_TCP, TCP_KEEPIDLE, CAST &option, sizeof(option)) < 0) { int sock_err = SOCKET_GET_ERROR(); logger_log(raop_rtp_mirror->logger, LOGGER_WARNING, "raop_rtp_mirror could not set stream socket keepalive time %d %s", sock_err, SOCKET_ERROR_STRING(sock_err)); } option = 10; if (setsockopt(stream_fd, SOL_TCP, TCP_KEEPINTVL, CAST &option, sizeof(option)) < 0) { int sock_err = SOCKET_GET_ERROR(); logger_log(raop_rtp_mirror->logger, LOGGER_WARNING, "raop_rtp_mirror could not set stream socket keepalive interval %d %s", sock_err, SOCKET_ERROR_STRING(sock_err)); } option = 6; if (setsockopt(stream_fd, SOL_TCP, TCP_KEEPCNT, CAST &option, sizeof(option)) < 0) { int sock_err = SOCKET_GET_ERROR(); logger_log(raop_rtp_mirror->logger, LOGGER_WARNING, "raop_rtp_mirror could not set stream socket keepalive probes %d %s", sock_err, SOCKET_ERROR_STRING(sock_err)); } readstart = 0; } if (stream_fd != -1 && FD_ISSET(stream_fd, &rfds)) { // The first 128 bytes are some kind of header for the payload that follows while (payload == NULL && readstart < 128) { unsigned char* pos = packet + readstart; ret = recv(stream_fd, CAST pos, 128 - readstart, 0); if (ret <= 0) break; readstart = readstart + ret; } if (payload == NULL && ret == 0) { logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror tcp socket was closed by client (recv returned 0); got %d bytes of 128 byte header",readstart); FD_CLR(stream_fd, &rfds); stream_fd = -1; continue; } else if (payload == NULL && ret == -1) { int sock_err = SOCKET_GET_ERROR(); if (sock_err == SOCKET_ERRORNAME(EAGAIN) || sock_err == SOCKET_ERRORNAME(EWOULDBLOCK)) continue; // Timeouts can happen even if the connection is fine logger_log(raop_rtp_mirror->logger, LOGGER_ERR, "raop_rtp_mirror error in header recv: %d %s", sock_err, SOCKET_ERROR_STRING(sock_err)); if (sock_err == SOCKET_ERRORNAME(ECONNRESET)) conn_reset = true;; break; } /*packet[0:3] contains the payload size */ int payload_size = byteutils_get_int(packet, 0); char packet_description[13] = {0}; char *p = packet_description; int n = sizeof(packet_description); for (int i = 4; i < 8; i++) { snprintf(p, n, "%2.2x ", (unsigned int) packet[i]); n -= 3; p += 3; } ntp_timestamp_raw = byteutils_get_long(packet, 8); ntp_timestamp_remote = raop_ntp_timestamp_to_nano_seconds(ntp_timestamp_raw, false); /* packet[4] + packet[5] identify the payload type: values seen are: * * 0x00 0x00: encrypted packet containing a non-IDR type 1 VCL NAL unit * * 0x00 0x10: encrypted packet containing an IDR type 5 VCL NAL unit * * 0x01 0x00: unencrypted packet containing a type 7 SPS NAL + a type 8 PPS NAL unit * * 0x02 0x00: unencrypted packet (old protocol) no payload, sent once every second * * 0x05 0x00 unencrypted packet with a "streaming report", sent once per second. */ /* packet[6] + packet[7] may list a payload "option": values seen are: * * 0x00 0x00 : encrypted and "streaming report" packets * * 0x1e 0x00 : old protocol (seen in AirMyPC) no-payload once-per-second packets * * 0x16 0x01 : seen in most unencrypted h264 SPS+PPS packets * * 0x56 0x01 : unencrypted h264 SPS+PPS packets (video stream stops, client sleeps) * * 0x1e 0x01 : unencrypted h265/HEVC SPS+PPS packets * 0x5e 0x01 : unencrypted h265 SPS+PPS packets (video stream stops, client sleeps) */ /* unencrypted packets with a SPS and a PPS NAL are sent initially, and also when a * * change in video format (e.g. width, height) subsequently occurs. They seem always * * to be followed by a packet with a type 5 encrypted IDR VCL NAL, with an identical * * timestamp. On M1/M2 Mac clients, this type 5 NAL is prepended with a type 6 SEI * * NAL unit. Here we prepend the SPS+PPS NALs to the next encrypted packet, which * * always has the same timestamp, and is (almost?) always an IDR NAL unit. */ /* Unencrypted SPS/PPS packets also have image-size data in (parts of) packet[16:127] */ /* "streaming report" packets have no timestamp in packet[8:15] */ if (payload == NULL) { payload = malloc(payload_size); readstart = 0; } while (readstart < payload_size) { // Payload data unsigned char *pos = payload + readstart; ret = recv(stream_fd, CAST pos, payload_size - readstart, 0); if (ret <= 0) break; readstart = readstart + ret; } if (ret == 0) { logger_log(raop_rtp_mirror->logger, LOGGER_ERR, "raop_rtp_mirror tcp socket was closed by client (recv returned 0)"); break; } else if (ret == -1) { int sock_err = SOCKET_GET_ERROR(); if (sock_err == SOCKET_ERRORNAME(EAGAIN) || sock_err == SOCKET_ERRORNAME(EWOULDBLOCK)) continue; // Timeouts can happen even if the connection is fine logger_log(raop_rtp_mirror->logger, LOGGER_ERR, "raop_rtp_mirror error in recv: %d %s", sock_err, SOCKET_ERROR_STRING(sock_err)); if (errno == SOCKET_ERRORNAME(ECONNRESET)) conn_reset = true; break; } switch (packet[4]) { case 0x00: // Normal video data (VCL NAL) // Conveniently, the video data is already stamped with the remote wall clock time, // so no additional clock syncing needed. The only thing odd here is that the video // ntp time stamps don't include the SECONDS_FROM_1900_TO_1970, so it's really just // counting nano seconds since last boot. ntp_timestamp_local = raop_ntp_convert_remote_time(raop_rtp_mirror->ntp, ntp_timestamp_remote); if (logger_debug) { uint64_t ntp_now = raop_ntp_get_local_time(raop_rtp_mirror->ntp); int64_t latency = ((int64_t) ntp_now) - ((int64_t) ntp_timestamp_local); logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp video: now = %8.6f, ntp = %8.6f, latency = %8.6f, ts = %8.6f, %s %s", (double) ntp_now / SEC, (double) ntp_timestamp_local / SEC, (double) latency / SEC, (double) ntp_timestamp_remote / SEC, packet_description, h265_video ? h265 : h264); } unsigned char* payload_out; unsigned char* payload_decrypted; /* * nal_types:1 Coded non-partitioned slice of a non-IDR picture * 5 Coded non-partitioned slice of an IDR picture * 6 Supplemental enhancement information (SEI) * 7 Sequence parameter set (SPS) * 8 Picture parameter set (PPS) * * if a previous unencrypted packet contains an SPS (type 7) and PPS (type 8) NAL which has not * yet been sent, it should be prepended to the current NAL. The M1 Macs have increased the h264 level, * and now the first encrypted packet after the unencrypted SPS+PPS packet may also contain a SEI (type 6) NAL * prepended to its VCL NAL. * * The flag prepend_sps_pps = true will signal that the previous packet contained a SPS NAL + a PPS NAL, * that has not yet been sent. This will trigger prepending it to the current NAL, and the prepend_sps_pps * flag will be set to false after it has been prepended. */ if (prepend_sps_pps & (ntp_timestamp_raw != ntp_timestamp_nal)) { logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror: prepended sps_pps timestamp does not match timestamp of " "video payload\n%llu\n%llu , discarding", ntp_timestamp_raw, ntp_timestamp_nal); free (sps_pps); sps_pps = NULL; prepend_sps_pps = false; } if (prepend_sps_pps) { assert(sps_pps); payload_out = (unsigned char*) malloc(payload_size + sps_pps_len); payload_decrypted = payload_out + sps_pps_len; memcpy(payload_out, sps_pps, sps_pps_len); free (sps_pps); sps_pps = NULL; } else { payload_out = (unsigned char*) malloc(payload_size); payload_decrypted = payload_out; } // Decrypt data mirror_buffer_decrypt(raop_rtp_mirror->buffer, payload, payload_decrypted, payload_size); // It seems the AirPlay protocol prepends NALs with their size, which we're replacing with the 4-byte // start code for the NAL Byte-Stream Format. bool valid_data = true; int nalu_size = 0; int nalus_count = 0; while (nalu_size < payload_size) { int nc_len = byteutils_get_int_be(payload_decrypted, nalu_size); if (nc_len < 0 || nalu_size + 4 > payload_size) { valid_data = false; break; } memcpy(payload_decrypted + nalu_size, nal_start_code, 4); nalu_size += 4; nalus_count++; /* first bit of h264 nalu MUST be 0 ("forbidden_zero_bit") */ if (payload_decrypted[nalu_size] & 0x80) { valid_data = false; break; } int nalu_type; if (h265_video) { nalu_type = payload_decrypted[nalu_size] & 0x7e >> 1;; //logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG," h265 video, NALU type %d, size %d", nalu_type, nc_len); } else { nalu_type = payload_decrypted[nalu_size] & 0x1f; int ref_idc = (payload_decrypted[nalu_size] >> 5); switch (nalu_type) { case 14: /* Prefix NALu , seen before all VCL Nalu's in AirMyPc */ case 5: /*IDR, slice_layer_without_partitioning */ case 1: /*non-IDR, slice_layer_without_partitioning */ break; case 2: /* slice data partition A */ case 3: /* slice data partition B */ case 4: /* slice data partition C */ logger_log(raop_rtp_mirror->logger, LOGGER_INFO, "unexpected partitioned VCL NAL unit: nalu_type = %d, ref_idc = %d, nalu_size = %d," "processed bytes %d, payloadsize = %d nalus_count = %d", nalu_type, ref_idc, nc_len, nalu_size, payload_size, nalus_count); break; case 6: if (logger_debug) { char *str = utils_data_to_string(payload_decrypted + nalu_size, nc_len, 16); logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror SEI NAL size = %d", nc_len); logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror h264 Supplemental Enhancement Information:\n%s", str); free(str); } break; case 7: if (logger_debug) { char *str = utils_data_to_string(payload_decrypted + nalu_size, nc_len, 16); logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror SPS NAL size = %d", nc_len); logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror h264 Sequence Parameter Set:\n%s", str); free(str); } break; case 8: if (logger_debug) { char *str = utils_data_to_string(payload_decrypted + nalu_size, nc_len, 16); logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror PPS NAL size = %d", nc_len); logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror h264 Picture Parameter Set :\n%s", str); free(str); } break; default: logger_log(raop_rtp_mirror->logger, LOGGER_INFO, "unexpected non-VCL NAL unit: nalu_type = %d, ref_idc = %d, nalu_size = %d," "processed bytes %d, payloadsize = %d nalus_count = %d", nalu_type, ref_idc, nc_len, nalu_size, payload_size, nalus_count); break; } } nalu_size += nc_len; } if (nalu_size != payload_size) valid_data = false; if(!valid_data) { logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "nalu marked as invalid"); payload_out[0] = 1; /* mark video data as invalid h264 (failed decryption) */ } payload_decrypted = NULL; video_decode_struct video_data; video_data.is_h265 = h265_video; video_data.ntp_time_local = ntp_timestamp_local; video_data.ntp_time_remote = ntp_timestamp_remote; video_data.nal_count = nalus_count; /*nal_count will be the number of nal units in the packet */ video_data.data_len = payload_size; video_data.data = payload_out; if (prepend_sps_pps) { video_data.data_len += sps_pps_len; video_data.nal_count += 2; if (h265_video) { video_data.nal_count++; } prepend_sps_pps = false; } raop_rtp_mirror->callbacks.video_process(raop_rtp_mirror->callbacks.cls, raop_rtp_mirror->ntp, &video_data); free(payload_out); break; case 0x01: /* 128-byte observed packet header structure bytes 0-15: length + timestamp bytes 16-19 float width_source (value is x.0000, x = unsigned short) bytes 20-23 float height_source (value is x.0000, x = unsigned short) bytes 24-39 all 0x0 bytes 40-43 float width_source (value is x.0000, x = unsigned short) bytes 44-47 float height_source (value is x.0000, x = unsigned short) bytes 48-51 ??? float "other_w" (value seems to be x.0000, x = unsigned short) bytes 48-51 ??? float "other_h" (value seems to be x.0000, x = unsigned short) bytes 56-59 width bytes 60-63 height bytes 64-127 all 0x0 */ // The information in the payload contains an SPS and a PPS NAL // The sps_pps is not encrypted logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "\nReceived unencrypted codec packet from client:" " payload_size %d header %s ts_client = %8.6f", payload_size, packet_description, (double) ntp_timestamp_remote / SEC); if (!video_stream_suspended && (packet[6] == 0x56 || packet[6] == 0x5e)) { video_stream_suspended = true; raop_rtp_mirror->callbacks.video_pause(raop_rtp_mirror->callbacks.cls); } else if (video_stream_suspended && (packet[6] == 0x16 || packet[6] == 0x1e)) { raop_rtp_mirror->callbacks.video_resume(raop_rtp_mirror->callbacks.cls); video_stream_suspended = false; } codec = VIDEO_CODEC_UNKNOWN; assert (raop_rtp_mirror->callbacks.video_set_codec); ntp_timestamp_nal = ntp_timestamp_raw; /* these "floats" are in fact integers that fit into unsigned shorts */ float width_0 = byteutils_get_float(packet, 16); float height_0 = byteutils_get_float(packet, 20); float width_source = byteutils_get_float(packet, 40); // duplication of width_0 float height_source = byteutils_get_float(packet, 44); // duplication of height_0 float unknown_w = byteutils_get_float(packet, 48); float unknown_h = byteutils_get_float(packet, 52); float width = byteutils_get_float(packet, 56); float height = byteutils_get_float(packet, 60); if (width != width_0 || height != height_0) { logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror: Unexpected : data %f," " %f != width_source = %f, height_source = %f", width_0, height_0, width_source, height_source); } logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror: unidentified extra header data %f, %f", unknown_w, unknown_h); if (raop_rtp_mirror->callbacks.video_report_size) { raop_rtp_mirror->callbacks.video_report_size(raop_rtp_mirror->callbacks.cls, &width_source, &height_source, &width, &height); } logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror width_source = %f height_source = %f width = %f height = %f", width_source, height_source, width, height); if (payload_size == 0) { logger_log(raop_rtp_mirror->logger, LOGGER_ERR, "raop_rtp_mirror: received type 0x01 packet with no payload:\n" "this indicates non-h264 video but Airplay features bit 42 (SupportsScreenMultiCodec) is not set\n" "use startup option \"-h265\" to set this bit and support h265 (4K) video"); unsupported_codec = true; break; } if (sps_pps) { free(sps_pps); sps_pps = NULL; } /* test for a H265 VPS/SPS/PPS */ unsigned char hvc1[] = { 0x68, 0x76, 0x63, 0x31 }; if (!memcmp(payload + 4, hvc1, 4)) { /* hvc1 HECV detected */ codec = VIDEO_CODEC_H265; h265_video = true; raop_rtp_mirror->callbacks.video_set_codec(raop_rtp_mirror->callbacks.cls, codec); unsigned char vps_start_code[] = { 0xa0, 0x00, 0x01, 0x00 }; unsigned char sps_start_code[] = { 0xa1, 0x00, 0x01, 0x00 }; unsigned char pps_start_code[] = { 0xa2, 0x00, 0x01, 0x00 }; unsigned char *vps; short vps_size; unsigned char *sps; short sps_size; unsigned char *pps; short pps_size; unsigned char * ptr = payload + 0x75; if (memcmp(ptr, vps_start_code, 4)) { logger_log(raop_rtp_mirror->logger, LOGGER_ERR, "non-conforming HEVC VPS/SPS/PPS payload (VPS)"); raop_rtp_mirror->callbacks.video_pause(raop_rtp_mirror->callbacks.cls); break; } vps_size = byteutils_get_short_be(ptr, 3); ptr += 5; vps = ptr; if (logger_debug) { char *str = utils_data_to_string(vps, vps_size, 16); logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "h265 vps size %d\n%s",vps_size, str); free(str); } ptr += vps_size; if (memcmp(ptr, sps_start_code, 4)) { logger_log(raop_rtp_mirror->logger, LOGGER_ERR, "non-conforming HEVC VPS/SPS/PPS payload (SPS)"); raop_rtp_mirror->callbacks.video_pause(raop_rtp_mirror->callbacks.cls); break; } sps_size = byteutils_get_short_be(ptr, 3); ptr += 5; sps = ptr; if (logger_debug) { char *str = utils_data_to_string(sps, sps_size, 16); logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "h265 sps size %d\n%s",vps_size, str); free(str); } ptr += sps_size; if (memcmp(ptr, pps_start_code, 4)) { logger_log(raop_rtp_mirror->logger, LOGGER_ERR, "non-conforming HEVC VPS/SPS/PPS payload (PPS)"); raop_rtp_mirror->callbacks.video_pause(raop_rtp_mirror->callbacks.cls); break; } pps_size = byteutils_get_short_be(ptr, 3); ptr += 5; pps = ptr; if (logger_debug) { char *str = utils_data_to_string(pps, pps_size, 16); logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "h265 pps size %d\n%s",pps_size, str); free(str); } sps_pps_len = vps_size + sps_size + pps_size + 12; sps_pps = (unsigned char*) malloc(sps_pps_len); assert(sps_pps); ptr = sps_pps; memcpy(ptr, nal_start_code, 4); ptr += 4; memcpy(ptr, vps, vps_size); ptr += vps_size; memcpy(ptr, nal_start_code, 4); ptr += 4; memcpy(ptr, sps, sps_size); ptr += sps_size; memcpy(ptr, nal_start_code, 4); ptr += 4; memcpy(ptr, pps, pps_size); } else { codec = VIDEO_CODEC_H264; h265_video = false; raop_rtp_mirror->callbacks.video_set_codec(raop_rtp_mirror->callbacks.cls, codec); short sps_size = byteutils_get_short_be(payload,6); unsigned char *sequence_parameter_set = payload + 8; short pps_size = byteutils_get_short_be(payload, sps_size + 9); unsigned char *picture_parameter_set = payload + sps_size + 11; int data_size = 6; if (logger_debug) { char *str = utils_data_to_string(payload, data_size, 16); logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror: SPS+PPS header size = %d", data_size); logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror h264 SPS+PPS header:\n%s", str); free(str); str = utils_data_to_string(sequence_parameter_set, sps_size,16); logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror SPS NAL size = %d", sps_size); logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror h264 Sequence Parameter Set:\n%s", str); free(str); str = utils_data_to_string(picture_parameter_set, pps_size, 16); logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror PPS NAL size = %d", pps_size); logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror h264 Picture Parameter Set:\n%s", str); free(str); } data_size = payload_size - sps_size - pps_size - 11; if (data_size > 0 && logger_debug) { char *str = utils_data_to_string (picture_parameter_set + pps_size, data_size, 16); logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "remainder size = %d", data_size); logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "remainder of SPS+PPS packet:\n%s", str); free(str); } else if (data_size < 0) { logger_log(raop_rtp_mirror->logger, LOGGER_ERR, " pps_sps error: packet remainder size = %d < 0", data_size); } // Copy the sps and pps into a buffer to prepend to the next NAL unit. sps_pps_len = sps_size + pps_size + 8; sps_pps = (unsigned char*) malloc(sps_pps_len); assert(sps_pps); memcpy(sps_pps, nal_start_code, 4); memcpy(sps_pps + 4, sequence_parameter_set, sps_size); memcpy(sps_pps + sps_size + 4, nal_start_code, 4); memcpy(sps_pps + sps_size + 8, payload + sps_size + 11, pps_size); } prepend_sps_pps = true; // h264codec_t h264; // h264.version = payload[0]; // h264.profile_high = payload[1]; // h264.compatibility = payload[2]; // h264.level = payload[3]; // h264.reserved_6_and_nal = payload[4]; // h264.reserved_3_and_sps = payload[5]; // h264.sps_size = sps_size; // h264.sequence_parameter_set = malloc(h264.sps_size); // memcpy(h264.sequence_parameter_set, sequence_parameter_set, sps_size); // h264.number_of_pps = payload[h264.sps_size + 8]; // h264.pps_size = pps_size; // h264.picture_parameter_set = malloc(h264.pps_size); // memcpy(h264.picture_parameter_set, picture_parameter_set, pps_size); break; case 0x02: logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "\nReceived old-protocol once-per-second packet from client:" " payload_size %d header %s ts_raw = %llu", payload_size, packet_description, ntp_timestamp_raw); /* "old protocol" (used by AirMyPC), rest of 128-byte packet is empty */ case 0x05: logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "\nReceived video streaming performance info packet from client:" " payload_size %d header %s ts_raw = %llu", payload_size, packet_description, ntp_timestamp_raw); /* payloads with packet[4] = 0x05 have no timestamp, and carry video info from the client as a binary plist * * Sometimes (e.g, when the client has a locked screen), there is a 25kB trailer attached to the packet. * * This 25000 Byte trailer with unidentified content seems to be the same data each time it is sent. */ if (payload_size && raop_rtp_mirror->show_client_FPS_data) { //char *str = utils_data_to_string(packet, 128, 16); //logger_log(raop_rtp_mirror->logger, LOGGER_WARNING, "type 5 video packet header:\n%s", str); //free (str); int plist_size = payload_size; if (payload_size > 25000) { plist_size = payload_size - 25000; if (logger_debug) { char *str = utils_data_to_string(payload + plist_size, 16, 16); logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "video_info packet had 25kB trailer; first 16 bytes are:\n%s", str); free(str); } } if (plist_size) { char *plist_xml; uint32_t plist_len; plist_t root_node = NULL; plist_from_bin((char *) payload, plist_size, &root_node); plist_to_xml(root_node, &plist_xml, &plist_len); logger_log(raop_rtp_mirror->logger, LOGGER_INFO, "%s", plist_xml); free(plist_xml); } } break; default: logger_log(raop_rtp_mirror->logger, LOGGER_WARNING, "\nReceived unexpected TCP packet from client, " "size %d, %s ts_raw = %llu", payload_size, packet_description, ntp_timestamp_raw); break; } free(payload); payload = NULL; memset(packet, 0, 128); readstart = 0; if (unsupported_codec) { break; } } } /* Close the stream file descriptor */ if (stream_fd != -1) { closesocket(stream_fd); } // Ensure running reflects the actual state MUTEX_LOCK(raop_rtp_mirror->run_mutex); raop_rtp_mirror->running = false; MUTEX_UNLOCK(raop_rtp_mirror->run_mutex); logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror exiting TCP thread"); if (conn_reset && raop_rtp_mirror->callbacks.conn_reset) { const bool video_reset = false; /* leave "frozen video" showing */ raop_rtp_mirror->callbacks.conn_reset(raop_rtp_mirror->callbacks.cls, 0, video_reset); } if (unsupported_codec) { closesocket(raop_rtp_mirror->mirror_data_sock); raop_rtp_mirror_stop(raop_rtp_mirror); raop_rtp_mirror->callbacks.video_reset(raop_rtp_mirror->callbacks.cls); } return 0; } static int raop_rtp_mirror_init_socket(raop_rtp_mirror_t *raop_rtp_mirror, int use_ipv6) { assert(raop_rtp_mirror); unsigned short dport = raop_rtp_mirror->mirror_data_lport; int dsock = netutils_init_socket(&dport, use_ipv6, 0); if (dsock == -1) { goto sockets_cleanup; } /* Listen to the data socket if using TCP */ if (listen(dsock, 1) < 0) { goto sockets_cleanup; } /* Set socket descriptors */ raop_rtp_mirror->mirror_data_sock = dsock; /* Set port values */ raop_rtp_mirror->mirror_data_lport = dport; logger_log(raop_rtp_mirror->logger, LOGGER_DEBUG, "raop_rtp_mirror local data port socket %d port TCP %d", dsock, dport); return 0; sockets_cleanup: if (dsock != -1) closesocket(dsock); return -1; } void raop_rtp_mirror_start(raop_rtp_mirror_t *raop_rtp_mirror, unsigned short *mirror_data_lport, uint8_t show_client_FPS_data) { logger_log(raop_rtp_mirror->logger, LOGGER_INFO, "raop_rtp_mirror starting mirroring"); int use_ipv6 = 0; assert(raop_rtp_mirror); assert(mirror_data_lport); raop_rtp_mirror->show_client_FPS_data = show_client_FPS_data; MUTEX_LOCK(raop_rtp_mirror->run_mutex); if (raop_rtp_mirror->running || !raop_rtp_mirror->joined) { MUTEX_UNLOCK(raop_rtp_mirror->run_mutex); return; } if (raop_rtp_mirror->remote_saddr.ss_family == AF_INET6) { use_ipv6 = 1; } //use_ipv6 = 0; raop_rtp_mirror->mirror_data_lport = *mirror_data_lport; if (raop_rtp_mirror_init_socket(raop_rtp_mirror, use_ipv6) < 0) { logger_log(raop_rtp_mirror->logger, LOGGER_ERR, "raop_rtp_mirror initializing socket failed"); MUTEX_UNLOCK(raop_rtp_mirror->run_mutex); return; } *mirror_data_lport = raop_rtp_mirror->mirror_data_lport; /* Create the thread and initialize running values */ raop_rtp_mirror->running = 1; raop_rtp_mirror->joined = 0; THREAD_CREATE(raop_rtp_mirror->thread_mirror, raop_rtp_mirror_thread, raop_rtp_mirror); MUTEX_UNLOCK(raop_rtp_mirror->run_mutex); } void raop_rtp_mirror_stop(raop_rtp_mirror_t *raop_rtp_mirror) { assert(raop_rtp_mirror); /* Check that we are running and thread is not * joined (should never be while still running) */ MUTEX_LOCK(raop_rtp_mirror->run_mutex); if (!raop_rtp_mirror->running || raop_rtp_mirror->joined) { MUTEX_UNLOCK(raop_rtp_mirror->run_mutex); return; } raop_rtp_mirror->running = 0; MUTEX_UNLOCK(raop_rtp_mirror->run_mutex); if (raop_rtp_mirror->mirror_data_sock != -1) { closesocket(raop_rtp_mirror->mirror_data_sock); raop_rtp_mirror->mirror_data_sock = -1; } /* Join the thread */ THREAD_JOIN(raop_rtp_mirror->thread_mirror); /* Mark thread as joined */ MUTEX_LOCK(raop_rtp_mirror->run_mutex); raop_rtp_mirror->joined = 1; MUTEX_UNLOCK(raop_rtp_mirror->run_mutex); } void raop_rtp_mirror_destroy(raop_rtp_mirror_t *raop_rtp_mirror) { if (raop_rtp_mirror) { raop_rtp_mirror_stop(raop_rtp_mirror); MUTEX_DESTROY(raop_rtp_mirror->run_mutex); mirror_buffer_destroy(raop_rtp_mirror->buffer); free(raop_rtp_mirror); } } UxPlay-1.71.1/lib/raop_rtp_mirror.h000066400000000000000000000027111473013662600171730ustar00rootroot00000000000000/* * Copyright (c) 2019 dsafa22, All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * *================================================================= * modified by fduncanh 2021-2023 */ #ifndef RAOP_RTP_MIRROR_H #define RAOP_RTP_MIRROR_H #include #include "raop.h" #include "logger.h" typedef struct raop_rtp_mirror_s raop_rtp_mirror_t; typedef struct h264codec_s h264codec_t; raop_rtp_mirror_t *raop_rtp_mirror_init(logger_t *logger, raop_callbacks_t *callbacks, raop_ntp_t *ntp, const char *remote, int remotelen, const unsigned char *aeskey); void raop_rtp_mirror_init_aes(raop_rtp_mirror_t *raop_rtp_mirror, uint64_t *streamConnectionID); void raop_rtp_mirror_start(raop_rtp_mirror_t *raop_rtp_mirror, unsigned short *mirror_data_lport, uint8_t show_client_FPS_data); void raop_rtp_mirror_stop(raop_rtp_mirror_t *raop_rtp_mirror); void raop_rtp_mirror_destroy(raop_rtp_mirror_t *raop_rtp_mirror); #endif //RAOP_RTP_MIRROR_H UxPlay-1.71.1/lib/sockets.h000066400000000000000000000025551473013662600154340ustar00rootroot00000000000000/** * Copyright (C) 2011-2012 Juho Vähä-Herttua * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. */ #ifndef SOCKETS_H #define SOCKETS_H #if defined(WIN32) char *wsa_strerror(int errnum); typedef int socklen_t; #ifndef SHUT_RD # define SHUT_RD SD_RECEIVE #endif #ifndef SHUT_WR # define SHUT_WR SD_SEND #endif #ifndef SHUT_RDWR # define SHUT_RDWR SD_BOTH #endif #define SOCKET_GET_ERROR() WSAGetLastError() #define SOCKET_SET_ERROR(value) WSASetLastError(value) #define SOCKET_ERRORNAME(name) WSA##name #define SOCKET_ERROR_STRING(errnum) wsa_strerror(errnum) #define WSAEAGAIN WSAEWOULDBLOCK #define WSAENOMEM WSA_NOT_ENOUGH_MEMORY #else #define closesocket close #define ioctlsocket ioctl #define SOCKET_GET_ERROR() (errno) #define SOCKET_SET_ERROR(value) (errno = (value)) #define SOCKET_ERRORNAME(name) name #define SOCKET_ERROR_STRING(errnum) strerror(errnum) #endif #endif UxPlay-1.71.1/lib/srp.c000066400000000000000000001073171473013662600145620ustar00rootroot00000000000000/* * Secure Remote Password 6a implementation * Copyright (c) 2010 Tom Cocagne. All rights reserved. * https://github.com/cocagne/csrp * * The MIT License (MIT) * * Copyright (c) 2013 Tom Cocagne * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is furnished to do * so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * *=========================================================================== * updated (2023) by fduncanh to replace deprecated openssl SHA* hash functions * modified (2023) by fduncanh for use with Apple's pair-setup-pin protocol */ #define APPLE_VARIANT #ifdef WIN32 # include # include #else # include #endif #include #include #include #include #include #include #include #include #include #include #include "srp.h" static int g_initialized = 0; typedef struct { BIGNUM * N; BIGNUM * g; } NGConstant; struct NGHex { const char * n_hex; const char * g_hex; }; /* All constants here were pulled from Appendix A of RFC 5054 */ static struct NGHex global_Ng_constants[] = { #if 0 /* begin removed section 1 */ { /* 1024 */ "EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C9C256576D674DF7496" "EA81D3383B4813D692C6E0E0D5D8E250B98BE48E495C1D6089DAD15DC7D7B46154D6B6CE8E" "F4AD69B15D4982559B297BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA" "9AFD5138FE8376435B9FC61D2FC0EB06E3", "2" }, { /* 1536 */ "9DEF3CAFB939277AB1F12A8617A47BBBDBA51DF499AC4C80BEEEA961" "4B19CC4D5F4F5F556E27CBDE51C6A94BE4607A291558903BA0D0F843" "80B655BB9A22E8DCDF028A7CEC67F0D08134B1C8B97989149B609E0B" "E3BAB63D47548381DBC5B1FC764E3F4B53DD9DA1158BFD3E2B9C8CF5" "6EDF019539349627DB2FD53D24B7C48665772E437D6C7F8CE442734A" "F7CCB7AE837C264AE3A9BEB87F8A2FE9B8B5292E5A021FFF5E91479E" "8CE7A28C2442C6F315180F93499A234DCF76E3FED135F9BB", "2" }, #endif /* end removed section 1 */ { /* 2048 */ "AC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4" "A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF60" "95179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF" "747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B907" "8717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB37861" "60279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DB" "FBB694B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F9E4AFF73", "2" }, #if 0 /* begin removed section 2 */ { /* 3072 */ "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B" "139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485" "B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1F" "E649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23" "DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32" "905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF69558" "17183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521" "ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D7" "1E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B1817" "7B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82" "D120A93AD2CAFFFFFFFFFFFFFFFF", "5" }, { /* 4096 */ "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B" "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9" "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6" "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8" "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D" "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C" "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718" "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D" "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D" "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226" "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C" "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC" "E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26" "99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB" "04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2" "233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127" "D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199" "FFFFFFFFFFFFFFFF", "5" }, { /* 6144 */ "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B" "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9" "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6" "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8" "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D" "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C" "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718" "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D" "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D" "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226" "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C" "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC" "E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26" "99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB" "04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2" "233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127" "D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406" "AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918" "DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B33205151" "2BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03" "F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97F" "BEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58B" "B7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632" "387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E" "6DCC4024FFFFFFFFFFFFFFFF", "5" }, { /* 8192 */ "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B" "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9" "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6" "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8" "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D" "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C" "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718" "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D" "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D" "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226" "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C" "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC" "E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26" "99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB" "04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2" "233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127" "D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406" "AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918" "DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B33205151" "2BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03" "F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97F" "BEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58B" "B7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632" "387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E" "6DBE115974A3926F12FEE5E438777CB6A932DF8CD8BEC4D073B931BA" "3BC832B68D9DD300741FA7BF8AFC47ED2576F6936BA424663AAB639C" "5AE4F5683423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9" "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B4BCBC886" "2F8385DDFA9D4B7FA2C087E879683303ED5BDD3A062B3CF5B3A278A6" "6D2A13F83F44F82DDF310EE074AB6A364597E899A0255DC164F31CC5" "0846851DF9AB48195DED7EA1B1D510BD7EE74D73FAF36BC31ECFA268" "359046F4EB879F924009438B481C6CD7889A002ED5EE382BC9190DA6" "FC026E479558E4475677E9AA9E3050E2765694DFC81F56E880B96E71" "60C980DD98EDD3DFFFFFFFFFFFFFFFFF", "13" }, #endif /* end removed section 2 */ {0,0} /* null sentinel */ }; static NGConstant * new_ng( SRP_NGType ng_type, const char * n_hex, const char * g_hex ) { NGConstant * ng = (NGConstant *) malloc( sizeof(NGConstant) ); ng->N = BN_new(); ng->g = BN_new(); if( !ng || !ng->N || !ng->g ) return 0; if ( ng_type != SRP_NG_CUSTOM ) { int idx = ng_type; if ( ng_type > SRP_NG_CUSTOM ) idx -= 1; n_hex = global_Ng_constants[ idx ].n_hex; g_hex = global_Ng_constants[ idx ].g_hex; } BN_hex2bn( &ng->N, n_hex ); BN_hex2bn( &ng->g, g_hex ); return ng; } static void delete_ng( NGConstant * ng ) { if (ng) { BN_free( ng->N ); BN_free( ng->g ); ng->N = 0; ng->g = 0; free(ng); } } typedef struct HashCTX_s { EVP_MD_CTX *digest_ctx; } HashCTX_t; struct SRPVerifier { SRP_HashAlgorithm hash_alg; NGConstant *ng; const char * username; const unsigned char * bytes_B; int authenticated; int rfc5054; unsigned char M [SHA512_DIGEST_LENGTH]; unsigned char H_AMK [SHA512_DIGEST_LENGTH]; #ifdef APPLE_VARIANT unsigned char session_key [2 * SHA512_DIGEST_LENGTH]; #else unsigned char session_key [SHA512_DIGEST_LENGTH]; #endif }; #if 0 /*begin removed section 3*/ struct SRPUser { SRP_HashAlgorithm hash_alg; NGConstant *ng; BIGNUM *a; BIGNUM *A; BIGNUM *S; const unsigned char * bytes_A; int authenticated; int rfc5054; const char * username; const unsigned char * password; int password_len; unsigned char M [SHA512_DIGEST_LENGTH]; unsigned char H_AMK [SHA512_DIGEST_LENGTH]; #ifdef APPLE_VARIANT unsigned char session_key [2 * SHA512_DIGEST_LENGTH]; #else unsigned char session_key [SHA512_DIGEST_LENGTH]; #endif }; #endif /*end removed section 3*/ static void handle_error(const char* location) { long error = ERR_get_error(); const char* error_str = ERR_error_string(error, NULL); fprintf(stderr, "SRP error at %s: %s\n", location, error_str); exit(EXIT_FAILURE); } static void hash_destroy( HashCTX_t *ctx) { if (ctx) { EVP_MD_CTX_free(ctx->digest_ctx); free(ctx); } } static HashCTX_t *hash_create() { HashCTX_t *ctx = (HashCTX_t *) malloc(sizeof(HashCTX_t)); assert(ctx != NULL); ctx->digest_ctx = EVP_MD_CTX_new(); assert(ctx->digest_ctx != NULL); return ctx; } int hash_reset( HashCTX_t *ctx) { return EVP_MD_CTX_reset( ctx->digest_ctx); } static int hash_init( SRP_HashAlgorithm alg, HashCTX_t *ctx) { int ret; switch (alg) { case SRP_SHA1 : ret = EVP_DigestInit_ex(ctx->digest_ctx, EVP_sha1(), NULL); break; case SRP_SHA224 : ret = EVP_DigestInit_ex(ctx->digest_ctx, EVP_sha224(), NULL); break; case SRP_SHA256 : ret = EVP_DigestInit_ex(ctx->digest_ctx, EVP_sha256(), NULL); break; case SRP_SHA384 : ret = EVP_DigestInit_ex(ctx->digest_ctx, EVP_sha384(), NULL); break; case SRP_SHA512 : ret = EVP_DigestInit_ex(ctx->digest_ctx, EVP_sha512(), NULL); break; default: return -1; } return ret; } static int hash_update( SRP_HashAlgorithm alg, HashCTX_t *ctx, const void *data, size_t len ) { int ret = EVP_DigestUpdate(ctx->digest_ctx, data, len); if (!ret) { handle_error(__func__); } return ret; } static int hash_final( SRP_HashAlgorithm alg, HashCTX_t *ctx, unsigned char *md, unsigned int *md_len ) { int ret = EVP_DigestFinal_ex(ctx->digest_ctx, md, md_len); if (!ret) { handle_error(__func__); } return ret; } static unsigned char * hash( SRP_HashAlgorithm alg, const unsigned char *d, size_t n, unsigned char *md ) { switch (alg) { case SRP_SHA1 : return SHA1( d, n, md ); case SRP_SHA224: return SHA224( d, n, md ); case SRP_SHA256: return SHA256( d, n, md ); case SRP_SHA384: return SHA384( d, n, md ); case SRP_SHA512: return SHA512( d, n, md ); default: return 0; }; } static int hash_length( SRP_HashAlgorithm alg ) { switch (alg) { case SRP_SHA1 : return SHA_DIGEST_LENGTH; case SRP_SHA224: return SHA224_DIGEST_LENGTH; case SRP_SHA256: return SHA256_DIGEST_LENGTH; case SRP_SHA384: return SHA384_DIGEST_LENGTH; case SRP_SHA512: return SHA512_DIGEST_LENGTH; default: return -1; }; } static BIGNUM * H_nn_orig( SRP_HashAlgorithm alg, const BIGNUM * n1, const BIGNUM * n2 ) { unsigned char buff[ SHA512_DIGEST_LENGTH ]; int len_n1 = BN_num_bytes(n1); int len_n2 = BN_num_bytes(n2); int nbytes = len_n1 + len_n2; unsigned char * bin = (unsigned char *) malloc( nbytes ); if (!bin) return 0; BN_bn2bin(n1, bin); BN_bn2bin(n2, bin + len_n1); hash( alg, bin, nbytes, buff ); free(bin); return BN_bin2bn(buff, hash_length(alg), NULL); } static BIGNUM * H_nn_rfc5054( SRP_HashAlgorithm alg, const BIGNUM * N, const BIGNUM * n1, const BIGNUM * n2 ) { unsigned char buff[ SHA512_DIGEST_LENGTH ]; int len_N = BN_num_bytes(N); int len_n1 = BN_num_bytes(n1); int len_n2 = BN_num_bytes(n2); int nbytes = len_N * 2; unsigned char * bin = (unsigned char *) malloc( nbytes ); if (!bin) return 0; if (len_n1 > len_N || len_n2 > len_N) return 0; memset(bin, 0, nbytes); BN_bn2bin(n1, bin + (len_N - len_n1)); BN_bn2bin(n2, bin + (len_N + len_N - len_n2)); hash( alg, bin, nbytes, buff ); free(bin); return BN_bin2bn(buff, hash_length(alg), NULL); } static BIGNUM * H_ns( SRP_HashAlgorithm alg, const BIGNUM * n, const unsigned char * bytes, int len_bytes ) { unsigned char buff[ SHA512_DIGEST_LENGTH ]; int len_n = BN_num_bytes(n); int nbytes = len_n + len_bytes; unsigned char * bin = (unsigned char *) malloc( nbytes ); if (!bin) return 0; BN_bn2bin(n, bin); memcpy( bin + len_n, bytes, len_bytes ); hash( alg, bin, nbytes, buff ); free(bin); return BN_bin2bn(buff, hash_length(alg), NULL); } static BIGNUM * calculate_x( SRP_HashAlgorithm alg, const BIGNUM * salt, const char * username, const unsigned char * password, int password_len ) { unsigned char ucp_hash[SHA512_DIGEST_LENGTH]; unsigned int ucp_hash_len; HashCTX_t *ctx = hash_create(); hash_init( alg, ctx); hash_update( alg, ctx, username, strlen(username) ); hash_update( alg, ctx, ":", 1 ); hash_update( alg, ctx, password, password_len ); hash_final( alg, ctx, ucp_hash, &ucp_hash_len ); hash_destroy ( ctx); return H_ns( alg, salt, ucp_hash, hash_length(alg) ); } static void update_hash_n( SRP_HashAlgorithm alg, HashCTX_t *ctx, const BIGNUM * n ) { unsigned long len = BN_num_bytes(n); unsigned char * n_bytes = (unsigned char *) malloc( len ); if (!n_bytes) return; BN_bn2bin(n, n_bytes); hash_update(alg, ctx, n_bytes, len); free(n_bytes); } static void hash_num( SRP_HashAlgorithm alg, const BIGNUM * n, unsigned char * dest ) { int nbytes = BN_num_bytes(n); unsigned char * bin = (unsigned char *) malloc( nbytes ); if(!bin) return; BN_bn2bin(n, bin); hash( alg, bin, nbytes, dest ); free(bin); } #ifdef APPLE_VARIANT /* added for compatibility with Apple's modified srp * see https://htmlpreview.github.io/?https://github.com/philippe44/RAOP-Player/blob/master/doc/auth_protocol.html */ static int hash_session_key( SRP_HashAlgorithm alg, const BIGNUM * n, unsigned char * dest ) { HashCTX_t *ctx; int nbytes = BN_num_bytes(n); unsigned char * bin = (unsigned char *) malloc( nbytes ); unsigned char fourbytes[4] = { 0 }; //Apple's modified SRP protocol unsigned int len1, len2; if(!bin) return -1; BN_bn2bin(n, bin); ctx = hash_create(); hash_init(alg, ctx); hash_update( alg, ctx, bin, nbytes); hash_update( alg, ctx, fourbytes, sizeof(fourbytes)); hash_final( alg, ctx, dest, &len1); hash_reset( ctx); fourbytes[3] = 1; hash_init(alg, ctx); hash_update( alg, ctx, bin, nbytes); hash_update( alg, ctx, fourbytes, sizeof(fourbytes)); hash_final( alg, ctx, dest + len1, &len2); hash_destroy( ctx); free(bin); return len1 + len2; } #endif static void calculate_M( SRP_HashAlgorithm alg, NGConstant *ng, unsigned char * dest, const char * I, const BIGNUM * s, const BIGNUM * A, const BIGNUM * B, const unsigned char * K ) { unsigned char H_N[ SHA512_DIGEST_LENGTH ]; unsigned char H_g[ SHA512_DIGEST_LENGTH ]; unsigned char H_I[ SHA512_DIGEST_LENGTH ]; unsigned char H_xor[ SHA512_DIGEST_LENGTH ]; unsigned int dest_len; HashCTX_t *ctx; int i = 0; int hash_len = hash_length(alg); hash_num( alg, ng->N, H_N ); hash_num( alg, ng->g, H_g ); hash(alg, (const unsigned char *)I, strlen(I), H_I); for (i=0; i < hash_len; i++ ) H_xor[i] = H_N[i] ^ H_g[i]; ctx = hash_create(); hash_init( alg, ctx); hash_update( alg, ctx, H_xor, hash_len ); hash_update( alg, ctx, H_I, hash_len ); update_hash_n( alg, ctx, s ); update_hash_n( alg, ctx, A ); update_hash_n( alg, ctx, B ); #ifdef APPLE_VARIANT /* Apple's SRP session key length is 2 x hash_len */ hash_update( alg, ctx, K, 2 * hash_len ); #else hash_update( alg, ctx, K, hash_len ); #endif hash_final( alg, ctx, dest, &dest_len ); hash_destroy ( ctx); } static void calculate_H_AMK( SRP_HashAlgorithm alg, unsigned char *dest, const BIGNUM * A, const unsigned char * M, const unsigned char * K ) { HashCTX_t *ctx; unsigned int dest_len; ctx = hash_create(); hash_init( alg, ctx); update_hash_n( alg, ctx, A ); hash_update( alg, ctx, M, hash_length(alg) ); #ifdef APPLE_VARIANT hash_update( alg, ctx, K, 2 * hash_length(alg) ); #else hash_update( alg, ctx, K, hash_length(alg) ); #endif hash_final( alg, ctx, dest, &dest_len ); hash_destroy ( ctx); } static void init_random() { if (g_initialized) return; #ifdef WIN32 HCRYPTPROV wctx; #else FILE *fp = 0; #endif unsigned char buff[64]; #ifdef WIN32 CryptAcquireContext(&wctx, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); CryptGenRandom(wctx, sizeof(buff), (BYTE*) buff); CryptReleaseContext(wctx, 0); g_initialized = 1; #else fp = fopen("/dev/urandom", "r"); if (fp) { size_t count = fread(buff, sizeof(buff), 1, fp); fclose(fp); if (count == 1) { g_initialized = 1; } } #endif if (g_initialized) RAND_seed( buff, sizeof(buff) ); } /*********************************************************************************************************** * * Exported Functions * ***********************************************************************************************************/ void srp_random_seed( const unsigned char * random_data, int data_length ) { g_initialized = 1; if (random_data) RAND_seed( random_data, data_length ); } void srp_create_salted_verification_key( SRP_HashAlgorithm alg, SRP_NGType ng_type, const char * username, const unsigned char * password, int len_password, const unsigned char ** bytes_s, int * len_s, const unsigned char ** bytes_v, int * len_v, const char * n_hex, const char * g_hex ) { BIGNUM * s = BN_new(); BIGNUM * v = BN_new(); BIGNUM * x = 0; BN_CTX * ctx = BN_CTX_new(); NGConstant * ng = new_ng( ng_type, n_hex, g_hex ); if( !s || !v || !ctx || !ng ) goto cleanup_and_exit; init_random(); /* Only happens once */ #ifdef APPLE_VARIANT //use a 16 byte salt BN_rand(s, 128, -1, 0); #else BN_rand(s, 32, -1, 0); #endif x = calculate_x( alg, s, username, password, len_password ); if( !x ) goto cleanup_and_exit; BN_mod_exp(v, ng->g, x, ng->N, ctx); *len_s = BN_num_bytes(s); *len_v = BN_num_bytes(v); *bytes_s = (const unsigned char *) malloc( *len_s ); *bytes_v = (const unsigned char *) malloc( *len_v ); if (!bytes_s || !bytes_v) goto cleanup_and_exit; BN_bn2bin(s, (unsigned char *) *bytes_s); BN_bn2bin(v, (unsigned char *) *bytes_v); cleanup_and_exit: delete_ng( ng ); BN_free(s); BN_free(v); BN_free(x); BN_CTX_free(ctx); } #ifdef APPLE_VARIANT /* Out: bytes_B, len_B, bytes_b, len_b * On failure, bytes_B and bytes_b will be set to NULL * len_B and len_will be set to 0 */ void srp_create_server_ephemeral_key( SRP_HashAlgorithm alg, SRP_NGType ng_type, const unsigned char * bytes_v, int len_v, const unsigned char * bytes_b, int len_b, const unsigned char ** bytes_B, int * len_B, const char * n_hex, const char * g_hex, int rfc5054_compat ) { BIGNUM *v = BN_bin2bn(bytes_v, len_v, NULL); BIGNUM *tmp1 = BN_new(); BIGNUM *tmp2 = BN_new(); BIGNUM *B = BN_new(); BIGNUM *b = BN_new(); BIGNUM *k = 0; BN_CTX *ctx = BN_CTX_new(); NGConstant *ng = new_ng( ng_type, n_hex, g_hex ); *len_B = 0; *bytes_B = 0; if( !v || !B || !b || !tmp1 || !tmp2 || !ctx || !ng ) goto cleanup_and_exit; b = BN_bin2bn(bytes_b, len_b, NULL); if (rfc5054_compat) k = H_nn_rfc5054(alg, ng->N, ng->N, ng->g); else k = H_nn_orig(alg, ng->N, ng->g); if(!k) goto cleanup_and_exit; /* B = kv + g^b */ if (rfc5054_compat) { BN_mod_mul(tmp1, k, v, ng->N, ctx); BN_mod_exp(tmp2, ng->g, b, ng->N, ctx); BN_mod_add(B, tmp1, tmp2, ng->N, ctx); } else { BN_mul(tmp1, k, v, ctx); BN_mod_exp(tmp2, ng->g, b, ng->N, ctx); BN_add(B, tmp1, tmp2); } *len_B = BN_num_bytes(B); *bytes_B = (const unsigned char *)malloc( *len_B ); BN_bn2bin( B, (unsigned char *) *bytes_B ); cleanup_and_exit: BN_free(v); if (k) BN_free(k); BN_free(B); BN_free(b); BN_free(tmp1); BN_free(tmp2); BN_CTX_free(ctx); } #endif /* Out: bytes_B, len_B. * * On failure, bytes_B will be set to NULL and len_B will be set to 0 */ struct SRPVerifier * srp_verifier_new( SRP_HashAlgorithm alg, SRP_NGType ng_type, const char * username, const unsigned char * bytes_s, int len_s, const unsigned char * bytes_v, int len_v, const unsigned char * bytes_A, int len_A, #ifdef APPLE_VARIANT const unsigned char * bytes_b, int len_b, #endif const unsigned char ** bytes_B, int * len_B, const char * n_hex, const char * g_hex, int rfc5054_compat ) { BIGNUM *s = BN_bin2bn(bytes_s, len_s, NULL); BIGNUM *v = BN_bin2bn(bytes_v, len_v, NULL); BIGNUM *A = BN_bin2bn(bytes_A, len_A, NULL); BIGNUM *u = 0; BIGNUM *B = BN_new(); BIGNUM *S = BN_new(); BIGNUM *b = BN_new(); BIGNUM *k = 0; BIGNUM *tmp1 = BN_new(); BIGNUM *tmp2 = BN_new(); BN_CTX *ctx = BN_CTX_new(); int ulen = strlen(username) + 1; NGConstant *ng = new_ng( ng_type, n_hex, g_hex ); struct SRPVerifier *ver = 0; *len_B = 0; *bytes_B = 0; if( !s || !v || !A || !B || !S || !b || !tmp1 || !tmp2 || !ctx || !ng ) goto cleanup_and_exit; ver = (struct SRPVerifier *) malloc( sizeof(struct SRPVerifier) ); if (!ver) goto cleanup_and_exit; init_random(); /* Only happens once */ ver->username = (char *) malloc( ulen ); ver->hash_alg = alg; ver->ng = ng; if (!ver->username) { free(ver); ver = 0; goto cleanup_and_exit; } memcpy( (char*)ver->username, username, ulen ); ver->authenticated = 0; ver->rfc5054 = rfc5054_compat; /* SRP-6a safety check */ BN_mod(tmp1, A, ng->N, ctx); if ( !BN_is_zero(tmp1) ) { #ifdef APPLE_VARIANT if ( !len_b || !bytes_b) { #endif BN_rand(b, 256, -1, 0); #ifdef APPLE_VARIANT } else { b = BN_bin2bn(bytes_b, len_b, NULL); } #endif if (rfc5054_compat) k = H_nn_rfc5054(alg, ng->N, ng->N, ng->g); else k = H_nn_orig(alg, ng->N, ng->g); if(!k) { free(ver); ver = 0; goto cleanup_and_exit; } /* B = kv + g^b */ if (rfc5054_compat) { BN_mod_mul(tmp1, k, v, ng->N, ctx); BN_mod_exp(tmp2, ng->g, b, ng->N, ctx); BN_mod_add(B, tmp1, tmp2, ng->N, ctx); } else { BN_mul(tmp1, k, v, ctx); BN_mod_exp(tmp2, ng->g, b, ng->N, ctx); BN_add(B, tmp1, tmp2); } if (rfc5054_compat) u = H_nn_rfc5054(alg, ng->N, A, B); else u = H_nn_orig(alg, A, B); if(!u) { free(ver); ver = 0; goto cleanup_and_exit; } /* S = (A *(v^u)) ^ b */ BN_mod_exp(tmp1, v, u, ng->N, ctx); BN_mul(tmp2, A, tmp1, ctx); BN_mod_exp(S, tmp2, b, ng->N, ctx); #ifdef APPLE_VARIANT hash_session_key(alg, S, ver->session_key); #else hash_num(alg, S, ver->session_key); #endif calculate_M( alg, ng, ver->M, username, s, A, B, ver->session_key ); calculate_H_AMK( alg, ver->H_AMK, A, ver->M, ver->session_key ); *len_B = BN_num_bytes(B); *bytes_B = (const unsigned char *)malloc( *len_B ); if( !((const unsigned char *)*bytes_B) ) { free( (void*) ver->username ); free( ver ); ver = 0; *len_B = 0; goto cleanup_and_exit; } BN_bn2bin( B, (unsigned char *) *bytes_B ); ver->bytes_B = *bytes_B; } else { free(ver); ver = 0; } cleanup_and_exit: BN_free(s); BN_free(v); BN_free(A); if (u) BN_free(u); if (k) BN_free(k); BN_free(B); BN_free(S); BN_free(b); BN_free(tmp1); BN_free(tmp2); BN_CTX_free(ctx); return ver; } void srp_verifier_delete( struct SRPVerifier * ver ) { if (ver) { delete_ng( ver->ng ); free( (char *) ver->username ); free( (unsigned char *) ver->bytes_B ); memset(ver, 0, sizeof(*ver)); free( ver ); } } int srp_verifier_is_authenticated( struct SRPVerifier * ver ) { return ver->authenticated; } const char * srp_verifier_get_username( struct SRPVerifier * ver ) { return ver->username; } const unsigned char * srp_verifier_get_session_key( struct SRPVerifier * ver, int * key_length ) { if (key_length) #ifdef APPLE_VARIANT *key_length = 2 * hash_length( ver->hash_alg ); #else *key_length = hash_length( ver->hash_alg ); #endif return ver->session_key; } int srp_verifier_get_session_key_length( struct SRPVerifier * ver ) { #ifdef APPLE_VARIANT return 2 * hash_length( ver->hash_alg ); #else return hash_length( ver->hash_alg ); #endif } /* user_M must be exactly SHA512_DIGEST_LENGTH bytes in size */ void srp_verifier_verify_session( struct SRPVerifier * ver, const unsigned char * user_M, const unsigned char ** bytes_HAMK ) { if ( memcmp( ver->M, user_M, hash_length(ver->hash_alg) ) == 0 ) { ver->authenticated = 1; *bytes_HAMK = ver->H_AMK; } else *bytes_HAMK = NULL; } /*******************************************************************************/ #if 0 /*begin removed section 4 */ struct SRPUser * srp_user_new( SRP_HashAlgorithm alg, SRP_NGType ng_type, const char * username, const unsigned char * bytes_password, int len_password, const char * n_hex, const char * g_hex, int rfc5054_compat ) { struct SRPUser *usr = (struct SRPUser *) malloc( sizeof(struct SRPUser) ); int ulen = strlen(username) + 1; if (!usr) goto err_exit; init_random(); /* Only happens once */ usr->hash_alg = alg; usr->ng = new_ng( ng_type, n_hex, g_hex ); usr->a = BN_new(); usr->A = BN_new(); usr->S = BN_new(); if (!usr->ng || !usr->a || !usr->A || !usr->S) goto err_exit; usr->username = (const char *) malloc(ulen); usr->password = (const unsigned char *) malloc(len_password); usr->password_len = len_password; if (!usr->username || !usr->password) goto err_exit; memcpy((char *)usr->username, username, ulen); memcpy((char *)usr->password, bytes_password, len_password); usr->authenticated = 0; usr->rfc5054 = rfc5054_compat; usr->bytes_A = 0; return usr; err_exit: if (usr) { BN_free(usr->a); BN_free(usr->A); BN_free(usr->S); if (usr->username) free((void*)usr->username); if (usr->password) { memset((void*)usr->password, 0, usr->password_len); free((void*)usr->password); } free(usr); } return 0; } void srp_user_delete( struct SRPUser * usr ) { if( usr ) { BN_free( usr->a ); BN_free( usr->A ); BN_free( usr->S ); delete_ng( usr->ng ); memset((void*)usr->password, 0, usr->password_len); free((char *)usr->username); free((char *)usr->password); if (usr->bytes_A) free( (char *)usr->bytes_A ); memset(usr, 0, sizeof(*usr)); free( usr ); } } int srp_user_is_authenticated( struct SRPUser * usr) { return usr->authenticated; } const char * srp_user_get_username( struct SRPUser * usr ) { return usr->username; } const unsigned char * srp_user_get_session_key( struct SRPUser * usr, int * key_length ) { if (key_length) #ifdef APPLE_VARIANT *key_length = 2 * hash_length( usr->hash_alg ); #else *key_length = hash_length( usr->hash_alg ); #endif return usr->session_key; } int srp_user_get_session_key_length( struct SRPUser * usr ) { #ifdef APPLE_VARIANT return 2 * hash_length( usr->hash_alg ); #else return hash_length( usr->hash_alg ); #endif } /* Output: username, bytes_A, len_A */ void srp_user_start_authentication( struct SRPUser * usr, const char ** username, const unsigned char ** bytes_A, int * len_A ) { BN_CTX *ctx = BN_CTX_new(); BN_rand(usr->a, 256, -1, 0); BN_mod_exp(usr->A, usr->ng->g, usr->a, usr->ng->N, ctx); BN_CTX_free(ctx); *len_A = BN_num_bytes(usr->A); *bytes_A = (const unsigned char *)malloc( *len_A ); if (!*bytes_A) { *len_A = 0; *bytes_A = 0; *username = 0; return; } BN_bn2bin( usr->A, (unsigned char *) *bytes_A ); usr->bytes_A = *bytes_A; *username = usr->username; } /* Output: bytes_M. Buffer length is SHA512_DIGEST_LENGTH */ void srp_user_process_challenge( struct SRPUser * usr, const unsigned char * bytes_s, int len_s, const unsigned char * bytes_B, int len_B, const unsigned char ** bytes_M, int * len_M) { BIGNUM *s = BN_bin2bn(bytes_s, len_s, NULL); BIGNUM *B = BN_bin2bn(bytes_B, len_B, NULL); BIGNUM *u = 0; BIGNUM *x = 0; BIGNUM *k = 0; BIGNUM *v = BN_new(); BIGNUM *tmp1 = BN_new(); BIGNUM *tmp2 = BN_new(); BIGNUM *tmp3 = BN_new(); BN_CTX *ctx = BN_CTX_new(); *len_M = 0; *bytes_M = 0; if( !s || !B || !v || !tmp1 || !tmp2 || !tmp3 || !ctx ) goto cleanup_and_exit; if (usr->rfc5054) u = H_nn_rfc5054(usr->hash_alg, usr->ng->N, usr->A, B); else u = H_nn_orig(usr->hash_alg, usr->A, B); if (!u) goto cleanup_and_exit; x = calculate_x( usr->hash_alg, s, usr->username, usr->password, usr->password_len ); if (!x) goto cleanup_and_exit; if (usr->rfc5054) k = H_nn_rfc5054(usr->hash_alg, usr->ng->N, usr->ng->N, usr->ng->g); else k = H_nn_orig(usr->hash_alg, usr->ng->N, usr->ng->g); if (!k) goto cleanup_and_exit; /* SRP-6a safety check */ if ( !BN_is_zero(B) && !BN_is_zero(u) ) { BN_mod_exp(v, usr->ng->g, x, usr->ng->N, ctx); /* S = (B - k*(g^x)) ^ (a + ux) */ BN_mul(tmp1, u, x, ctx); BN_add(tmp2, usr->a, tmp1); /* tmp2 = (a + ux) */ BN_mod_exp(tmp1, usr->ng->g, x, usr->ng->N, ctx); BN_mul(tmp3, k, tmp1, ctx); /* tmp3 = k*(g^x) */ BN_sub(tmp1, B, tmp3); /* tmp1 = (B - K*(g^x)) */ BN_mod_exp(usr->S, tmp1, tmp2, usr->ng->N, ctx); #ifdef APPLE_VARIANT hash_session_key(usr->hash_alg, usr->S, usr->session_key); #else hash_num(usr->hash_alg, usr->S, usr->session_key); #endif calculate_M( usr->hash_alg, usr->ng, usr->M, usr->username, s, usr->A, B, usr->session_key ); calculate_H_AMK( usr->hash_alg, usr->H_AMK, usr->A, usr->M, usr->session_key ); *bytes_M = usr->M; if (len_M) *len_M = hash_length( usr->hash_alg ); } else { *bytes_M = NULL; if (len_M) *len_M = 0; } cleanup_and_exit: BN_free(s); BN_free(B); BN_free(u); BN_free(x); BN_free(k); BN_free(v); BN_free(tmp1); BN_free(tmp2); BN_free(tmp3); BN_CTX_free(ctx); } void srp_user_verify_session( struct SRPUser * usr, const unsigned char * bytes_HAMK ) { if ( memcmp( usr->H_AMK, bytes_HAMK, hash_length(usr->hash_alg) ) == 0 ) usr->authenticated = 1; } #endif /*end removed section 4 */ UxPlay-1.71.1/lib/srp.h000066400000000000000000000236731473013662600145710ustar00rootroot00000000000000/* * Secure Remote Password 6a implementation * Copyright (c) 2010 Tom Cocagne. All rights reserved. * https://github.com/cocagne/csrp * * The MIT License (MIT) * * Copyright (c) 2014 Tom Cocagne * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is furnished to do * so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * *=========================================================================== * updated (2023) by fduncanh to replace deprecated openssl SHA* hash functions * modified (2023) by fduncanh for use with Apple's pair-setup-pin protocol */ /* * * Purpose: This is a direct implementation of the Secure Remote Password * Protocol version 6a as described by * http://srp.stanford.edu/design.html * * Author: tom.cocagne@gmail.com (Tom Cocagne) * * Dependencies: OpenSSL (and Advapi32.lib on Windows) * * Usage: Refer to test_srp.c for a demonstration * * Notes: * This library allows multiple combinations of hashing algorithms and * prime number constants. For authentication to succeed, the hash and * prime number constants must match between * srp_create_salted_verification_key(), srp_user_new(), * and srp_verifier_new(). A recommended approach is to determine the * desired level of security for an application and globally define the * hash and prime number constants to the predetermined values. * * As one might suspect, more bits means more security. As one might also * suspect, more bits also means more processing time. The test_srp.c * program can be easily modified to profile various combinations of * hash & prime number pairings. */ #ifndef SRP_H #define SRP_H #define APPLE_VARIANT struct SRPVerifier; #if 0 /*begin removed section 1*/ struct SRPUser; #endif /*end removed section 1*/ typedef enum { #if 0 /* begin removed section 2*/ SRP_NG_1024, SRP_NG_1536, #endif /* end removed section 2*/ SRP_NG_2048, #if 0 /* begin removed section 3*/ SRP_NG_3072, SRP_NG_4096, SRP_NG_6144, SRP_NG_8192, #endif /* end removed section 3*/ SRP_NG_CUSTOM } SRP_NGType; typedef enum { SRP_SHA1, SRP_SHA224, SRP_SHA256, SRP_SHA384, SRP_SHA512 } SRP_HashAlgorithm; /* This library will automatically seed the OpenSSL random number generator * using cryptographically sound random data on Windows & Linux. If this is * undesirable behavior or the host OS does not provide a /dev/urandom file, * this function may be called to seed the random number generator with * alternate data. * * The random data should include at least as many bits of entropy as the * largest hash function used by the application. So, for example, if a * 512-bit hash function is used, the random data requies at least 512 * bits of entropy. * * Passing a null pointer to this function will cause this library to skip * seeding the random number generator. This is only legitimate if it is * absolutely known that the OpenSSL random number generator has already * been sufficiently seeded within the running application. * * Notes: * * This function is optional on Windows & Linux and mandatory on all * other platforms. */ void srp_random_seed( const unsigned char * random_data, int data_length ); /* Out: bytes_s, len_s, bytes_v, len_v * * The caller is responsible for freeing the memory allocated for bytes_s and bytes_v * * The n_hex and g_hex parameters should be 0 unless SRP_NG_CUSTOM is used for ng_type. * If provided, they must contain ASCII text of the hexidecimal notation. * */ void srp_create_salted_verification_key( SRP_HashAlgorithm alg, SRP_NGType ng_type, const char * username, const unsigned char * password, int len_password, const unsigned char ** bytes_s, int * len_s, const unsigned char ** bytes_v, int * len_v, const char * n_hex, const char * g_hex ); #ifdef APPLE_VARIANT /* Out: bytes_B, len_B * On failure, bytes_B will be set to NULL and len_B will be set to 0 * * The n_hex and g_hex parameters should be 0 unless SRP_NG_CUSTOM is used for ng_type * * bytes_b should be a pointer to a cryptographically secure random array of length * len_b bytes (for example, produced with OpenSSL's RAND_bytes(bytes_b, len_b)). */ void srp_create_server_ephemeral_key( SRP_HashAlgorithm alg, SRP_NGType ng_type, const unsigned char * bytes_v, int len_v, const unsigned char * bytes_b, int len_b, const unsigned char ** bytes_B, int * len_B, const char * n_hex, const char * g_hex, int rfc5054_compat ); #endif /* Out: bytes_B, len_B. * * On failure, bytes_B will be set to NULL and len_B will be set to 0 * * The n_hex and g_hex parameters should be 0 unless SRP_NG_CUSTOM is used for ng_type * * If rfc5054_compat is non-zero the resulting verifier will be RFC 5054 compaliant. This * breaks compatibility with previous versions of the csrp library but is recommended * for new code. */ struct SRPVerifier * srp_verifier_new( SRP_HashAlgorithm alg, SRP_NGType ng_type, const char * username, const unsigned char * bytes_s, int len_s, const unsigned char * bytes_v, int len_v, const unsigned char * bytes_A, int len_A, #ifdef APPLE_VARIANT const unsigned char * bytes_b, int len_b, #endif const unsigned char ** bytes_B, int * len_B, const char * n_hex, const char * g_hex, int rfc5054_compat ); void srp_verifier_delete( struct SRPVerifier * ver ); int srp_verifier_is_authenticated( struct SRPVerifier * ver ); const char * srp_verifier_get_username( struct SRPVerifier * ver ); /* key_length may be null */ const unsigned char * srp_verifier_get_session_key( struct SRPVerifier * ver, int * key_length ); int srp_verifier_get_session_key_length( struct SRPVerifier * ver ); /* user_M must be exactly srp_verifier_get_session_key_length() bytes in size */ /* (in APPLE_VARIANT case, session_key_length is DOUBLE the length of user_M) */ void srp_verifier_verify_session( struct SRPVerifier * ver, const unsigned char * user_M, const unsigned char ** bytes_HAMK ); /*******************************************************************************/ /* The n_hex and g_hex parameters should be 0 unless SRP_NG_CUSTOM is used for ng_type * * If rfc5054_compat is non-zero the resulting verifier will be RFC 5054 compaliant. This * breaks compatibility with previous versions of the csrp library but is recommended * for new code. */ #if 0 /*begin removed section 4 */ struct SRPUser * srp_user_new( SRP_HashAlgorithm alg, SRP_NGType ng_type, const char * username, const unsigned char * bytes_password, int len_password, const char * n_hex, const char * g_hex, int rfc5054_compat ); void srp_user_delete( struct SRPUser * usr ); int srp_user_is_authenticated( struct SRPUser * usr); const char * srp_user_get_username( struct SRPUser * usr ); /* key_length may be null */ const unsigned char * srp_user_get_session_key( struct SRPUser * usr, int * key_length ); int srp_user_get_session_key_length( struct SRPUser * usr ); /* Output: username, bytes_A, len_A */ void srp_user_start_authentication( struct SRPUser * usr, const char ** username, const unsigned char ** bytes_A, int * len_A ); /* Output: bytes_M, len_M (len_M may be null and will always be * srp_user_get_session_key_length() bytes in size) */ /* (in APPLE_VARIANT case, session_key_length is DOUBLE the length of bytes_M) */ void srp_user_process_challenge( struct SRPUser * usr, const unsigned char * bytes_s, int len_s, const unsigned char * bytes_B, int len_B, const unsigned char ** bytes_M, int * len_M ); /* bytes_HAMK must be exactly srp_user_get_session_key_length() bytes in size */ /* (in APPLE_VARIANT case, session_key_length is DOUBLE the length of bytes_HAMK) */ void srp_user_verify_session( struct SRPUser * usr, const unsigned char * bytes_HAMK ); #endif /*end removed section 4*/ #endif /* Include Guard */ UxPlay-1.71.1/lib/stream.h000066400000000000000000000023261473013662600152500ustar00rootroot00000000000000/* * Copyright (c) 2019 dsafa22, All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * *================================================================= * modified by fduncanh 2022-2023 */ #ifndef AIRPLAYSERVER_STREAM_H #define AIRPLAYSERVER_STREAM_H #include #include typedef struct { bool is_h265; int nal_count; unsigned char *data; int data_len; uint64_t ntp_time_local; uint64_t ntp_time_remote; } video_decode_struct; typedef struct { unsigned char *data; unsigned char ct; int data_len; int sync_status; uint64_t ntp_time_local; uint64_t ntp_time_remote; uint64_t rtp_time; unsigned short seqnum; } audio_decode_struct; #endif //AIRPLAYSERVER_STREAM_H UxPlay-1.71.1/lib/threads.h000066400000000000000000000030721473013662600154060ustar00rootroot00000000000000/** * Copyright (C) 2011-2012 Juho Vähä-Herttua * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * *================================================================= * modified by fduncanh 2022 */ #ifndef THREADS_H #define THREADS_H /* Always use pthread library */ #include #include #define sleepms(x) usleep((x)*1000) typedef pthread_t thread_handle_t; #define THREAD_RETVAL void * #define THREAD_CREATE(handle, func, arg) \ if (pthread_create(&(handle), NULL, func, arg)) handle = 0 #define THREAD_JOIN(handle) pthread_join(handle, NULL) typedef pthread_mutex_t mutex_handle_t; typedef pthread_cond_t cond_handle_t; #define MUTEX_CREATE(handle) pthread_mutex_init(&(handle), NULL) #define MUTEX_LOCK(handle) pthread_mutex_lock(&(handle)) #define MUTEX_UNLOCK(handle) pthread_mutex_unlock(&(handle)) #define MUTEX_DESTROY(handle) pthread_mutex_destroy(&(handle)) #define COND_CREATE(handle) pthread_cond_init(&(handle), NULL) #define COND_SIGNAL(handle) pthread_cond_signal(&(handle)) #define COND_DESTROY(handle) pthread_cond_destroy(&(handle)) #endif /* THREADS_H */ UxPlay-1.71.1/lib/utils.c000066400000000000000000000204031473013662600151040ustar00rootroot00000000000000/** * Copyright (C) 2011-2012 Juho Vähä-Herttua * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * *================================================================= * modified by fduncanh 2021-2022 */ #include #include #include #include #include #include #define SECOND_IN_NSECS 1000000000UL char * utils_strsep(char **stringp, const char *delim) { char *original; char *strptr; if (*stringp == NULL) { return NULL; } original = *stringp; strptr = strstr(*stringp, delim); if (strptr == NULL) { *stringp = NULL; return original; } *strptr = '\0'; *stringp = strptr+strlen(delim); return original; } int utils_read_file(char **dst, const char *filename) { FILE *stream; int filesize; char *buffer; int read_bytes; /* Open stream for reading */ stream = fopen(filename, "rb"); if (!stream) { return -1; } /* Find out file size */ fseek(stream, 0, SEEK_END); filesize = ftell(stream); fseek(stream, 0, SEEK_SET); /* Allocate one extra byte for zero */ buffer = malloc(filesize+1); if (!buffer) { fclose(stream); return -2; } /* Read data in a loop to buffer */ read_bytes = 0; do { int ret = fread(buffer+read_bytes, 1, filesize-read_bytes, stream); if (ret == 0) { break; } read_bytes += ret; } while (read_bytes < filesize); /* Add final null byte and close stream */ buffer[read_bytes] = '\0'; fclose(stream); /* If read didn't finish, return error */ if (read_bytes != filesize) { free(buffer); return -3; } /* Return buffer */ *dst = buffer; return filesize; } int utils_hwaddr_raop(char *str, int strlen, const char *hwaddr, int hwaddrlen) { int i,j; /* Check that our string is long enough */ if (strlen == 0 || strlen < 2*hwaddrlen+1) return -1; /* Convert hardware address to hex string */ for (i=0,j=0; i>4) & 0x0f; int lo = hwaddr[i] & 0x0f; if (hi < 10) str[j++] = '0' + hi; else str[j++] = 'A' + hi-10; if (lo < 10) str[j++] = '0' + lo; else str[j++] = 'A' + lo-10; } /* Add string terminator */ str[j++] = '\0'; return j; } int utils_hwaddr_airplay(char *str, int strlen, const char *hwaddr, int hwaddrlen) { int i,j; /* Check that our string is long enough */ if (strlen == 0 || strlen < 2*hwaddrlen+hwaddrlen) return -1; /* Convert hardware address to hex string */ for (i=0,j=0; i>4) & 0x0f; int lo = hwaddr[i] & 0x0f; if (hi < 10) str[j++] = '0' + hi; else str[j++] = 'a' + hi-10; if (lo < 10) str[j++] = '0' + lo; else str[j++] = 'a' + lo-10; str[j++] = ':'; } /* Add string terminator */ if (j != 0) j--; str[j++] = '\0'; return j; } char *utils_parse_hex(const char *str, int str_len, int *data_len) { assert(str_len % 2 == 0); char *data = malloc(str_len / 2); for (int i = 0; i < (str_len / 2); i++) { char c_1 = str[i * 2]; if (c_1 >= 97 && c_1 <= 102) { c_1 -= (97 - 10); } else if (c_1 >= 65 && c_1 <= 70) { c_1 -= (65 - 10); } else if (c_1 >= 48 && c_1 <= 57) { c_1 -= 48; } else { free(data); return NULL; } char c_2 = str[(i * 2) + 1]; if (c_2 >= 97 && c_2 <= 102) { c_2 -= (97 - 10); } else if (c_2 >= 65 && c_2 <= 70) { c_2 -= (65 - 10); } else if (c_2 >= 48 && c_2 <= 57) { c_2 -= 48; } else { free(data); return NULL; } data[i] = (c_1 << 4) | c_2; } *data_len = (str_len / 2); return data; } char *utils_pk_to_string(const unsigned char *pk, int pk_len) { char *pk_str = (char *) malloc(2*pk_len + 1); char* pos = pk_str; for (int i = 0; i < pk_len; i++) { snprintf(pos, 3, "%2.2x", *(pk + i)); pos +=2; } return pk_str; } char *utils_data_to_string(const unsigned char *data, int datalen, int chars_per_line) { assert(datalen >= 0); assert(chars_per_line > 0); int len = 3*datalen + 1; if (datalen > chars_per_line) { len += (datalen-1)/chars_per_line; } char *str = (char *) calloc(len + 1, sizeof(char)); assert(str); char *p = str; int n = len + 1; for (int i = 0; i < datalen; i++) { if (i > 0 && i % chars_per_line == 0) { snprintf(p, n, "\n"); n--; p++; } snprintf(p, n, "%2.2x ", (unsigned int) data[i]); n -= 3; p += 3; } snprintf(p, n, "\n"); n--; p++; assert(p == &(str[len])); assert(len == strlen(str)); return str; } char *utils_data_to_text(const char *data, int datalen) { char *ptr = (char *) calloc(datalen + 1, sizeof(char)); assert(ptr); strncpy(ptr, data, datalen); char *p = ptr; while (p) { p = strchr(p, '\r'); /* replace occurences of '\r' by ' ' */ if (p) *p = ' '; } return ptr; } void ntp_timestamp_to_time(uint64_t ntp_timestamp, char *timestamp, size_t maxsize) { time_t rawtime = (time_t) (ntp_timestamp / SECOND_IN_NSECS); struct tm ts = *localtime(&rawtime); assert(maxsize > 29); #ifdef _WIN32 /*modification for compiling for Windows */ strftime(timestamp, 20, "%Y-%m-%d %H:%M:%S", &ts); #else strftime(timestamp, 20, "%F %T", &ts); #endif snprintf(timestamp + 19, 11,".%9.9lu", (unsigned long) ntp_timestamp % SECOND_IN_NSECS); } void ntp_timestamp_to_seconds(uint64_t ntp_timestamp, char *timestamp, size_t maxsize) { time_t rawtime = (time_t) (ntp_timestamp / SECOND_IN_NSECS); struct tm ts = *localtime(&rawtime); assert(maxsize > 12); strftime(timestamp, 3, "%S", &ts); snprintf(timestamp + 2, 11,".%9.9lu", (unsigned long) ntp_timestamp % SECOND_IN_NSECS); } int utils_ipaddress_to_string(int addresslen, const unsigned char *address, unsigned int zone_id, char *string, int sizeof_string) { int ret = 0; unsigned char ipv6_link_local_prefix[] = { 0xfe, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; assert(sizeof_string > 0); assert(string); if (addresslen != 4 && addresslen != 16) { //invalid address length (only ipv4 and ipv6 allowed) string[0] = '\0'; } if (addresslen == 4) { /* IPV4 */ ret = snprintf(string, sizeof_string, "%d.%d.%d.%d", address[0], address[1], address[2], address[3]); } else if (zone_id) { /* IPV6 link-local */ if (memcmp(address, ipv6_link_local_prefix, 8)) { string[0] = '\0'; //only link-local ipv6 addresses can have a zone_id } else { ret = snprintf(string, sizeof_string, "fe80::%02x%02x:%02x%02x:%02x%02x:%02x%02x%%%u", address[8], address[9], address[10], address[11], address[12], address[13], address[14], address[15], zone_id); } } else { /* IPV6 standard*/ ret = snprintf(string, sizeof_string, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", address[0], address[1], address[2], address[3], address[4], address[5], address[6], address[7], address[8], address[9], address[10], address[11], address[12], address[13], address[14], address[15]); } return ret; } const char *gmt_time_string() { static char date_buf[64]; memset(date_buf, 0, 64); time_t now = time(0); if (strftime(date_buf, 63, "%c GMT", gmtime(&now))) return date_buf; else return ""; } UxPlay-1.71.1/lib/utils.h000066400000000000000000000031731473013662600151160ustar00rootroot00000000000000/** * Copyright (C) 2011-2012 Juho Vähä-Herttua * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * *================================================================== * modified by fduncanh 2021-2022 */ #ifndef UTILS_H #define UTILS_H #include char *utils_strsep(char **stringp, const char *delim); int utils_read_file(char **dst, const char *pemstr); int utils_hwaddr_raop(char *str, int strlen, const char *hwaddr, int hwaddrlen); int utils_hwaddr_airplay(char *str, int strlen, const char *hwaddr, int hwaddrlen); char *utils_parse_hex(const char *str, int str_len, int *data_len); char *utils_pk_to_string(const unsigned char *pk, int pk_len); char *utils_data_to_string(const unsigned char *data, int datalen, int chars_per_line); char *utils_data_to_text(const char *data, int datalen); void ntp_timestamp_to_time(uint64_t ntp_timestamp, char *timestamp, size_t maxsize); void ntp_timestamp_to_seconds(uint64_t ntp_timestamp, char *timestamp, size_t maxsize); const char *gmt_time_string(); int utils_ipaddress_to_string(int addresslen, const unsigned char *address, unsigned int zone_id, char *string, int len); #endif UxPlay-1.71.1/renderers/000077500000000000000000000000001473013662600150245ustar00rootroot00000000000000UxPlay-1.71.1/renderers/CMakeLists.txt000066400000000000000000000071411473013662600175670ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.5) if (APPLE ) set( ENV{PKG_CONFIG_PATH} "/Library/FrameWorks/GStreamer.framework/Libraries/pkgconfig" ) # GStreamer.framework, preferred set( ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:/usr/local/lib/pkgconfig" ) # Brew or self-installed gstreamer set( ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:/opt/homebrew/lib/pkgconfig" ) # Brew, M1/M2 macs set( ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:$ENV{HOMEBREW_PREFIX}/lib/pkgconfig" ) # Brew, using prefix set( ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:/opt/local/lib/pkgconfig/" ) # MacPorts message( "PKG_CONFIG_PATH (Apple, renderers) = " $ENV{PKG_CONFIG_PATH} ) find_program( PKG_CONFIG_EXECUTABLE pkg-config PATHS /Library/FrameWorks/GStreamer.framework/Commands ) set(PKG_CONFIG_EXECUTABLE ${PKG_CONFIG_EXECUTABLE} --define-prefix ) else() if ( DEFINED ENV{GSTREAMER_ROOT_DIR} ) if ( EXISTS "$ENV{GSTREAMER_ROOT_DIR}/pkgconfig" ) message ( STATUS "*** Using GSTREAMER_ROOT_DIR = " $ENV{GSTREAMER_ROOT_DIR} ) set( ENV{PKG_CONFIG_PATH} "$ENV{GSTREAMER_ROOT_DIR}/pkgconfig:$ENV{PKG_CONFIG_PATH}" ) endif() endif() set( ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:/usr/local/lib/pkgconfig" ) # standard location for self-installed gstreamer endif() find_package( PkgConfig REQUIRED ) if ( X11_FOUND ) message (STATUS "Will use X_DISPLAY_FIX" ) add_definitions( -DX_DISPLAY_FIX ) pkg_check_modules (GST120 gstreamer-1.0>=1.20) if ( GST120_FOUND ) message( "-- ZOOMFIX will NOT be applied as Gstreamer version is >= 1.20" ) else() message( "-- Failure to find Gstreamer >= 1.20 is NOT an error!" ) message( "-- ZOOMFIX will be applied as Gstreamer version is < 1.20" ) add_definitions( -DZOOM_WINDOW_NAME_FIX ) endif() endif() pkg_check_modules(GST REQUIRED gstreamer-1.0>=1.4 gstreamer-sdp-1.0>=1.4 gstreamer-video-1.0>=1.4 gstreamer-app-1.0>=1.4 ) add_library( renderers STATIC audio_renderer.c video_renderer.c ) target_link_libraries ( renderers PUBLIC airplay ) # hacks to fix cmake confusion due to links in path with macOS FrameWorks if( GST_INCLUDE_DIRS MATCHES "/Library/FrameWorks/GStreamer.framework/include" ) set( GST_INCLUDE_DIRS "/Library/FrameWorks/GStreamer.framework/Headers") message( STATUS "GST_INCLUDE_DIRS" ${GST_INCLUDE_DIRS} ) # fix to use -DGST_MACOS for "Official" GStreamer >= 1.22 packages pkg_check_modules ( GST122 gstreamer-1.0>=1.22 ) if ( GST122_FOUND ) set( GST_MACOS "1" CACHE STRING "define GST_MACOS in uxplay.cpp" ) endif() endif() # set GST_MACOS for all Apple when GStreamer >= 1.24 if ( APPLE AND NOT GST_MACOS ) pkg_check_modules ( GST124 gstreamer-1.0>=1.24 ) if ( GST124_FOUND ) set( GST_MACOS "1" CACHE STRING "define GST_MACOS in uxplay.cpp" ) endif() endif() target_include_directories ( renderers PUBLIC ${GST_INCLUDE_DIRS} ) if( GST_LIBRARY_DIRS MATCHES "/Library/FrameWorks/GStreamer.framework/lib" ) set( GST_LIBRARY_DIRS "/Library/FrameWorks/GStreamer.framework/Libraries") message( STATUS "GST_LIBRARY_DIRS" ${GST_LIBRARY_DIRS} ) target_link_libraries( renderers PUBLIC ${GST_LIBRARIES} ) if( CMAKE_VERSION VERSION_LESS "3.13" ) message( FATAL_ERROR "This macOS build needs cmake >= 3.13" ) endif() target_link_directories ( renderers PUBLIC ${GST_LIBRARY_DIRS} ) elseif( CMAKE_VERSION VERSION_LESS "3.12" ) target_link_libraries ( renderers PUBLIC ${GST_LIBRARIES} ) else() target_link_libraries( renderers PUBLIC ${GST_LINK_LIBRARIES} ) endif() UxPlay-1.71.1/renderers/audio_renderer.c000066400000000000000000000341271473013662600201660ustar00rootroot00000000000000/** * RPiPlay - An open-source AirPlay mirroring server for Raspberry Pi * Copyright (C) 2019 Florian Draschbacher * Modified for: * UxPlay - An open-source AirPlay mirroring server * Copyright (C) 2021-23 F. Duncanh * * 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, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include "audio_renderer.h" #define SECOND_IN_NSECS 1000000000UL #define NFORMATS 2 /* set to 4 to enable AAC_LD and PCM: allowed, but never seen in real-world use */ static GstClockTime gst_audio_pipeline_base_time = GST_CLOCK_TIME_NONE; static logger_t *logger = NULL; const char * format[NFORMATS]; static const gchar *avdec_aac = "avdec_aac"; static const gchar *avdec_alac = "avdec_alac"; static gboolean aac = FALSE; static gboolean alac = FALSE; static gboolean render_audio = FALSE; static gboolean async = FALSE; static gboolean vsync = FALSE; static gboolean sync = FALSE; typedef struct audio_renderer_s { GstElement *appsrc; GstElement *pipeline; GstElement *volume; unsigned char ct; } audio_renderer_t ; static audio_renderer_t *renderer_type[NFORMATS]; static audio_renderer_t *renderer = NULL; /* GStreamer Caps strings for Airplay-defined audio compression types (ct) */ /* ct = 1; linear PCM (uncompressed): 44100/16/2, S16LE */ static const char lpcm_caps[]="audio/x-raw,rate=(int)44100,channels=(int)2,format=S16LE,layout=interleaved"; /* ct = 2; codec_data is ALAC magic cookie: 44100/16/2 spf = 352 */ static const char alac_caps[] = "audio/x-alac,mpegversion=(int)4,channnels=(int)2,rate=(int)44100,stream-format=raw,codec_data=(buffer)" "00000024""616c6163""00000000""00000160""0010280a""0e0200ff""00000000""00000000""0000ac44"; /* ct = 4; codec_data from MPEG v4 ISO 14996-3 Section 1.6.2.1: AAC-LC 44100/2 spf = 1024 */ static const char aac_lc_caps[] ="audio/mpeg,mpegversion=(int)4,channnels=(int)2,rate=(int)44100,stream-format=raw,codec_data=(buffer)1210"; /* ct = 8; codec_data from MPEG v4 ISO 14996-3 Section 1.6.2.1: AAC_ELD 44100/2 spf = 480 */ static const char aac_eld_caps[] ="audio/mpeg,mpegversion=(int)4,channnels=(int)2,rate=(int)44100,stream-format=raw,codec_data=(buffer)f8e85000"; static gboolean check_plugins (void) { gboolean ret; GstRegistry *registry; const gchar *needed[] = { "app", "libav", "playback", "autodetect", "videoparsersbad", NULL}; const gchar *gst[] = {"plugins-base", "libav", "plugins-base", "plugins-good", "plugins-bad", NULL}; registry = gst_registry_get (); ret = TRUE; for (int i = 0; i < g_strv_length ((gchar **) needed); i++) { GstPlugin *plugin; plugin = gst_registry_find_plugin (registry, needed[i]); if (!plugin) { g_print ("Required gstreamer plugin '%s' not found\n" "Missing plugin is contained in '[GStreamer 1.x]-%s'\n",needed[i], gst[i]); ret = FALSE; continue; } gst_object_unref (plugin); plugin = NULL; } if (ret == FALSE) { g_print ("\nif the plugin is installed, but not found, your gstreamer registry may have been corrupted.\n" "to rebuild it when gstreamer next starts, clear your gstreamer cache with:\n" "\"rm -rf ~/.cache/gstreamer-1.0\"\n\n"); } return ret; } static gboolean check_plugin_feature (const gchar *needed_feature) { gboolean ret; GstPluginFeature *plugin_feature; GstRegistry *registry = gst_registry_get (); ret = TRUE; plugin_feature = gst_registry_find_feature (registry, needed_feature, GST_TYPE_ELEMENT_FACTORY); if (!plugin_feature) { g_print ("Required gstreamer libav plugin feature '%s' not found:\n\n" "This may be missing because the FFmpeg package used by GStreamer-1.x-libav is incomplete.\n" "(Some distributions provide an incomplete FFmpeg due to License or Patent issues:\n" "in such cases a complete version for that distribution is usually made available elsewhere)\n", needed_feature); ret = FALSE; } else { gst_object_unref (plugin_feature); plugin_feature = NULL; } if (ret == FALSE) { g_print ("\nif the plugin feature is installed, but not found, your gstreamer registry may have been corrupted.\n" "to rebuild it when gstreamer next starts, clear your gstreamer cache with:\n" "\"rm -rf ~/.cache/gstreamer-1.0\"\n\n"); } return ret; } bool gstreamer_init(){ gst_init(NULL,NULL); return (bool) check_plugins (); } void audio_renderer_init(logger_t *render_logger, const char* audiosink, const bool* audio_sync, const bool* video_sync) { GError *error = NULL; GstCaps *caps = NULL; GstClock *clock = gst_system_clock_obtain(); g_object_set(clock, "clock-type", GST_CLOCK_TYPE_REALTIME, NULL); logger = render_logger; aac = check_plugin_feature (avdec_aac); alac = check_plugin_feature (avdec_alac); for (int i = 0; i < NFORMATS ; i++) { renderer_type[i] = (audio_renderer_t *) calloc(1,sizeof(audio_renderer_t)); g_assert(renderer_type[i]); GString *launch = g_string_new("appsrc name=audio_source ! "); g_string_append(launch, "queue ! "); switch (i) { case 0: /* AAC-ELD */ case 2: /* AAC-LC */ if (aac) g_string_append(launch, "avdec_aac ! "); break; case 1: /* ALAC */ if (alac) g_string_append(launch, "avdec_alac ! "); break; case 3: /*PCM*/ break; default: break; } g_string_append (launch, "audioconvert ! "); g_string_append (launch, "audioresample ! "); /* wasapisink must resample from 44.1 kHz to 48 kHz */ g_string_append (launch, "volume name=volume ! level ! "); g_string_append (launch, audiosink); switch(i) { case 1: /*ALAC*/ if (*audio_sync) { g_string_append (launch, " sync=true"); async = TRUE; } else { g_string_append (launch, " sync=false"); async = FALSE; } break; default: if (*video_sync) { g_string_append (launch, " sync=true"); vsync = TRUE; } else { g_string_append (launch, " sync=false"); vsync = FALSE; } break; } renderer_type[i]->pipeline = gst_parse_launch(launch->str, &error); if (error) { g_error ("gst_parse_launch error (audio %d):\n %s\n", i+1, error->message); g_clear_error (&error); } g_assert (renderer_type[i]->pipeline); gst_pipeline_use_clock(GST_PIPELINE_CAST(renderer_type[i]->pipeline), clock); renderer_type[i]->appsrc = gst_bin_get_by_name (GST_BIN (renderer_type[i]->pipeline), "audio_source"); renderer_type[i]->volume = gst_bin_get_by_name (GST_BIN (renderer_type[i]->pipeline), "volume"); switch (i) { case 0: caps = gst_caps_from_string(aac_eld_caps); renderer_type[i]->ct = 8; format[i] = "AAC-ELD 44100/2"; break; case 1: caps = gst_caps_from_string(alac_caps); renderer_type[i]->ct = 2; format[i] = "ALAC 44100/16/2"; break; case 2: caps = gst_caps_from_string(aac_lc_caps); renderer_type[i]->ct = 4; format[i] = "AAC-LC 44100/2"; break; case 3: caps = gst_caps_from_string(lpcm_caps); renderer_type[i]->ct = 1; format[i] = "PCM 44100/16/2 S16LE"; break; default: break; } logger_log(logger, LOGGER_DEBUG, "Audio format %d: %s",i+1,format[i]); logger_log(logger, LOGGER_DEBUG, "GStreamer audio pipeline %d: \"%s\"", i+1, launch->str); g_string_free(launch, TRUE); g_object_set(renderer_type[i]->appsrc, "caps", caps, "stream-type", 0, "is-live", TRUE, "format", GST_FORMAT_TIME, NULL); gst_caps_unref(caps); g_object_unref(clock); } } void audio_renderer_stop() { if (renderer) { gst_app_src_end_of_stream(GST_APP_SRC(renderer->appsrc)); gst_element_set_state (renderer->pipeline, GST_STATE_NULL); renderer = NULL; } } static void get_renderer_type(unsigned char *ct, int *id) { render_audio = FALSE; *id = -1; for (int i = 0; i < NFORMATS; i++) { if (renderer_type[i]->ct == *ct) { *id = i; break; } } switch (*id) { case 2: case 0: if (aac) { render_audio = TRUE; } else { logger_log(logger, LOGGER_INFO, "*** GStreamer libav plugin feature avdec_aac is missing, cannot decode AAC audio"); } sync = vsync; break; case 1: if (alac) { render_audio = TRUE; } else { logger_log(logger, LOGGER_INFO, "*** GStreamer libav plugin feature avdec_alac is missing, cannot decode ALAC audio"); } sync = async; break; case 3: render_audio = TRUE; sync = FALSE; break; default: break; } } void audio_renderer_start(unsigned char *ct) { int id = -1; get_renderer_type(ct, &id); if (id >= 0 && renderer) { if(*ct != renderer->ct) { gst_app_src_end_of_stream(GST_APP_SRC(renderer->appsrc)); gst_element_set_state (renderer->pipeline, GST_STATE_NULL); logger_log(logger, LOGGER_INFO, "changed audio connection, format %s", format[id]); renderer = renderer_type[id]; gst_element_set_state (renderer->pipeline, GST_STATE_PLAYING); gst_audio_pipeline_base_time = gst_element_get_base_time(renderer->appsrc); } } else if (id >= 0) { logger_log(logger, LOGGER_INFO, "start audio connection, format %s", format[id]); renderer = renderer_type[id]; gst_element_set_state (renderer->pipeline, GST_STATE_PLAYING); gst_audio_pipeline_base_time = gst_element_get_base_time(renderer->appsrc); } else { logger_log(logger, LOGGER_ERR, "unknown audio compression type ct = %d", *ct); } } void audio_renderer_render_buffer(unsigned char* data, int *data_len, unsigned short *seqnum, uint64_t *ntp_time) { GstBuffer *buffer; bool valid; if (!render_audio) return; /* do nothing unless render_audio == TRUE */ GstClockTime pts = (GstClockTime) *ntp_time ; /* now in nsecs */ //GstClockTimeDiff latency = GST_CLOCK_DIFF(gst_element_get_current_clock_time (renderer->appsrc), pts); if (sync) { if (pts >= gst_audio_pipeline_base_time) { pts -= gst_audio_pipeline_base_time; } else { logger_log(logger, LOGGER_ERR, "*** invalid ntp_time < gst_audio_pipeline_base_time\n%8.6f ntp_time\n%8.6f base_time", ((double) *ntp_time) / SECOND_IN_NSECS, ((double) gst_audio_pipeline_base_time) / SECOND_IN_NSECS); return; } } if (data_len == 0 || renderer == NULL) return; /* all audio received seems to be either ct = 8 (AAC_ELD 44100/2 spf 460 ) AirPlay Mirror protocol * * or ct = 2 (ALAC 44100/16/2 spf 352) AirPlay protocol. * * first byte data[0] of ALAC frame is 0x20, * * first byte of AAC_ELD is 0x8c, 0x8d or 0x8e: 0x100011(00,01,10) in modern devices * * but is 0x80, 0x81 or 0x82: 0x100000(00,01,10) in ios9, ios10 devices * * first byte of AAC_LC should be 0xff (ADTS) (but has never been seen). */ buffer = gst_buffer_new_allocate(NULL, *data_len, NULL); g_assert(buffer != NULL); //g_print("audio latency %8.6f\n", (double) latency / SECOND_IN_NSECS); if (sync) { GST_BUFFER_PTS(buffer) = pts; } gst_buffer_fill(buffer, 0, data, *data_len); switch (renderer->ct){ case 8: /*AAC-ELD*/ switch (data[0]){ case 0x8c: case 0x8d: case 0x8e: case 0x80: case 0x81: case 0x82: valid = true; break; default: valid = false; break; } break; case 2: /*ALAC*/ valid = (data[0] == 0x20); break; case 4: /*AAC_LC */ valid = (data[0] == 0xff ); break; default: valid = true; break; } if (valid) { gst_app_src_push_buffer(GST_APP_SRC(renderer->appsrc), buffer); } else { logger_log(logger, LOGGER_ERR, "*** ERROR invalid audio frame (compression_type %d) skipped ", renderer->ct); logger_log(logger, LOGGER_ERR, "*** first byte of invalid frame was 0x%2.2x ", (unsigned int) data[0]); } } void audio_renderer_set_volume(double volume) { volume = (volume > 10.0) ? 10.0 : volume; volume = (volume < 0.0) ? 0.0 : volume; g_object_set(renderer->volume, "volume", volume, NULL); } void audio_renderer_flush() { } void audio_renderer_destroy() { audio_renderer_stop(); for (int i = 0; i < NFORMATS ; i++ ) { gst_object_unref (renderer_type[i]->volume); renderer_type[i]->volume = NULL; gst_object_unref (renderer_type[i]->appsrc); renderer_type[i]->appsrc = NULL; gst_object_unref (renderer_type[i]->pipeline); renderer_type[i]->pipeline = NULL; free(renderer_type[i]); } } UxPlay-1.71.1/renderers/audio_renderer.h000066400000000000000000000031371473013662600201700ustar00rootroot00000000000000/** * RPiPlay - An open-source AirPlay mirroring server for Raspberry Pi * Copyright (C) 2019 Florian Draschbacher * Modified for: * UxPlay - An open-source AirPlay mirroring server * Copyright (C) 2021-23 F. Duncanh * * 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, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef AUDIO_RENDERER_H #define AUDIO_RENDERER_H #ifdef __cplusplus extern "C" { #endif #include #include #include #include "../lib/logger.h" bool gstreamer_init(); void audio_renderer_init(logger_t *logger, const char* audiosink, const bool *audio_sync, const bool *video_sync); void audio_renderer_start(unsigned char* compression_type); void audio_renderer_stop(); void audio_renderer_render_buffer(unsigned char* data, int *data_len, unsigned short *seqnum, uint64_t *ntp_time); void audio_renderer_set_volume(double volume); void audio_renderer_flush(); void audio_renderer_destroy(); #ifdef __cplusplus } #endif #endif //AUDIO_RENDERER_H UxPlay-1.71.1/renderers/video_renderer.c000066400000000000000000000760201473013662600201710ustar00rootroot00000000000000/** * RPiPlay - An open-source AirPlay mirroring server for Raspberry Pi * Copyright (C) 2019 Florian Draschbacher * Modified for: * UxPlay - An open-source AirPlay mirroring server * Copyright (C) 2021-24 F. Duncanh * * 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, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include "video_renderer.h" #define SECOND_IN_NSECS 1000000000UL #ifdef X_DISPLAY_FIX #include #include "x_display_fix.h" static bool fullscreen = false; static bool alt_keypress = false; static unsigned char X11_search_attempts; #endif static GstClockTime gst_video_pipeline_base_time = GST_CLOCK_TIME_NONE; static logger_t *logger = NULL; static unsigned short width, height, width_source, height_source; /* not currently used */ static bool first_packet = false; static bool sync = false; static bool auto_videosink = true; static bool hls_video = false; #ifdef X_DISPLAY_FIX static bool use_x11 = false; #endif static bool logger_debug = false; static bool video_terminate = false; #define NCODECS 2 /* renderers for h264 and h265 */ struct video_renderer_s { GstElement *appsrc, *pipeline; GstBus *bus; const char *codec; bool autovideo, state_pending; int id; gboolean terminate; gint64 duration; gint buffering_level; #ifdef X_DISPLAY_FIX bool use_x11; const char * server_name; X11_Window_t * gst_window; #endif }; static video_renderer_t *renderer = NULL; static video_renderer_t *renderer_type[NCODECS] = {0}; static int n_renderers = NCODECS; static char h264[] = "h264"; static char h265[] = "h265"; static char hls[] = "hls"; static void append_videoflip (GString *launch, const videoflip_t *flip, const videoflip_t *rot) { /* videoflip image transform */ switch (*flip) { case INVERT: switch (*rot) { case LEFT: g_string_append(launch, "videoflip video-direction=GST_VIDEO_ORIENTATION_90R ! "); break; case RIGHT: g_string_append(launch, "videoflip video-direction=GST_VIDEO_ORIENTATION_90L ! "); break; default: g_string_append(launch, "videoflip video-direction=GST_VIDEO_ORIENTATION_180 ! "); break; } break; case HFLIP: switch (*rot) { case LEFT: g_string_append(launch, "videoflip video-direction=GST_VIDEO_ORIENTATION_UL_LR ! "); break; case RIGHT: g_string_append(launch, "videoflip video-direction=GST_VIDEO_ORIENTATION_UR_LL ! "); break; default: g_string_append(launch, "videoflip video-direction=GST_VIDEO_ORIENTATION_HORIZ ! "); break; } break; case VFLIP: switch (*rot) { case LEFT: g_string_append(launch, "videoflip video-direction=GST_VIDEO_ORIENTATION_UR_LL ! "); break; case RIGHT: g_string_append(launch, "videoflip video-direction=GST_VIDEO_ORIENTATION_UL_LR ! "); break; default: g_string_append(launch, "videoflip video-direction=GST_VIDEO_ORIENTATION_VERT ! "); break; } break; default: switch (*rot) { case LEFT: g_string_append(launch, "videoflip video-direction=GST_VIDEO_ORIENTATION_90L ! "); break; case RIGHT: g_string_append(launch, "videoflip video-direction=GST_VIDEO_ORIENTATION_90R ! "); break; default: break; } break; } } /* apple uses colorimetry=1:3:5:1 * * (not recognized by v4l2 plugin in Gstreamer < 1.20.4) * * See .../gst-libs/gst/video/video-color.h in gst-plugins-base * * range = 1 -> GST_VIDEO_COLOR_RANGE_0_255 ("full RGB") * * matrix = 3 -> GST_VIDEO_COLOR_MATRIX_BT709 * * transfer = 5 -> GST_VIDEO_TRANSFER_BT709 * * primaries = 1 -> GST_VIDEO_COLOR_PRIMARIES_BT709 * * closest used by GStreamer < 1.20.4 is BT709, 2:3:5:1 with * * * range = 2 -> GST_VIDEO_COLOR_RANGE_16_235 ("limited RGB") */ static const char h264_caps[]="video/x-h264,stream-format=(string)byte-stream,alignment=(string)au"; static const char h265_caps[]="video/x-h265,stream-format=(string)byte-stream,alignment=(string)au"; void video_renderer_size(float *f_width_source, float *f_height_source, float *f_width, float *f_height) { width_source = (unsigned short) *f_width_source; height_source = (unsigned short) *f_height_source; width = (unsigned short) *f_width; height = (unsigned short) *f_height; logger_log(logger, LOGGER_DEBUG, "begin video stream wxh = %dx%d; source %dx%d", width, height, width_source, height_source); } GstElement *make_video_sink(const char *videosink, const char *videosink_options) { /* used to build a videosink for playbin, using the user-specified string "videosink" */ GstElement *video_sink = gst_element_factory_make(videosink, "videosink"); if (!video_sink) { return NULL; } /* process the video_sink_optons */ size_t len = strlen(videosink_options); if (!len) { return video_sink; } char *options = (char *) malloc(len + 1); strncpy(options, videosink_options, len + 1); /* remove any extension begining with "!" */ char *end = strchr(options, '!'); if (end) { *end = '\0'; } /* add any fullscreen options "property=pval" included in string videosink_options*/ /* OK to use strtok_r in Windows with MSYS2 (POSIX); use strtok_s for MSVC */ char *token; char *text = options; while((token = strtok_r(text, " ", &text))) { char *pval = strchr(token, '='); if (pval) { *pval = '\0'; pval++; const gchar *property_name = (const gchar *) token; const gchar *value = (const gchar *) pval; g_print("playbin_videosink property: \"%s\" \"%s\"\n", property_name, value); gst_util_set_object_arg(G_OBJECT (video_sink), property_name, value); } } free(options); return video_sink; } void video_renderer_init(logger_t *render_logger, const char *server_name, videoflip_t videoflip[2], const char *parser, const char *decoder, const char *converter, const char *videosink, const char *videosink_options, bool initial_fullscreen, bool video_sync, bool h265_support, const char *uri) { GError *error = NULL; GstCaps *caps = NULL; hls_video = (uri != NULL); /* videosink choices that are auto */ auto_videosink = (strstr(videosink, "autovideosink") || strstr(videosink, "fpsdisplaysink")); logger = render_logger; logger_debug = (logger_get_level(logger) >= LOGGER_DEBUG); video_terminate = false; /* this call to g_set_application_name makes server_name appear in the X11 display window title bar, */ /* (instead of the program name uxplay taken from (argv[0]). It is only set one time. */ const gchar *appname = g_get_application_name(); if (!appname || strcmp(appname,server_name)) g_set_application_name(server_name); appname = NULL; /* the renderer for hls video will only be built if a HLS uri is provided in * the call to video_renderer_init, in which case the h264 and 265 mirror-mode * renderers will not be built. This is because it appears that we cannot * put playbin into GST_STATE_READY before knowing the uri (?), so cannot use a * unified renderer structure with h264, h265 and hls */ if (hls_video) { n_renderers = 1; } else { n_renderers = h265_support ? 2 : 1; } g_assert (n_renderers <= NCODECS); for (int i = 0; i < n_renderers; i++) { g_assert (i < 2); renderer_type[i] = (video_renderer_t *) calloc(1, sizeof(video_renderer_t)); g_assert(renderer_type[i]); renderer_type[i]->autovideo = auto_videosink; renderer_type[i]->id = i; renderer_type[i]->bus = NULL; if (hls_video) { /* use playbin3 to play HLS video: replace "playbin3" by "playbin" to use playbin2 */ renderer_type[i]->pipeline = gst_element_factory_make("playbin3", "hls-playbin3"); g_assert(renderer_type[i]->pipeline); renderer_type[i]->appsrc = NULL; renderer_type[i]->codec = hls; /* if we are not using autovideosink, build a videossink based on the stricng "videosink" */ if(strcmp(videosink, "autovideosink")) { GstElement *playbin_videosink = make_video_sink(videosink, videosink_options); if (!playbin_videosink) { logger_log(logger, LOGGER_ERR, "video_renderer_init: failed to create playbin_videosink"); } else { logger_log(logger, LOGGER_DEBUG, "video_renderer_init: create playbin_videosink at %p", playbin_videosink); g_object_set(G_OBJECT (renderer_type[i]->pipeline), "video-sink", playbin_videosink, NULL); } } g_object_set (G_OBJECT (renderer_type[i]->pipeline), "uri", uri, NULL); } else { switch (i) { case 0: renderer_type[i]->codec = h264; caps = gst_caps_from_string(h264_caps); break; case 1: renderer_type[i]->codec = h265; caps = gst_caps_from_string(h265_caps); break; default: g_assert(0); } GString *launch = g_string_new("appsrc name=video_source ! "); g_string_append(launch, "queue ! "); g_string_append(launch, parser); g_string_append(launch, " ! "); g_string_append(launch, decoder); g_string_append(launch, " ! "); append_videoflip(launch, &videoflip[0], &videoflip[1]); g_string_append(launch, converter); g_string_append(launch, " ! "); g_string_append(launch, "videoscale ! "); g_string_append(launch, videosink); g_string_append(launch, " name="); g_string_append(launch, videosink); g_string_append(launch, "_"); g_string_append(launch, renderer_type[i]->codec); g_string_append(launch, videosink_options); if (video_sync) { g_string_append(launch, " sync=true"); sync = true; } else { g_string_append(launch, " sync=false"); sync = false; } if (!strcmp(renderer_type[i]->codec, h264)) { char *pos = launch->str; while ((pos = strstr(pos,h265))){ pos +=3; *pos = '4'; } } else if (!strcmp(renderer_type[i]->codec, h265)) { char *pos = launch->str; while ((pos = strstr(pos,h264))){ pos +=3; *pos = '5'; } } logger_log(logger, LOGGER_DEBUG, "GStreamer video pipeline %d:\n\"%s\"", i + 1, launch->str); renderer_type[i]->pipeline = gst_parse_launch(launch->str, &error); if (error) { g_error ("get_parse_launch error (video) :\n %s\n",error->message); g_clear_error (&error); } g_assert (renderer_type[i]->pipeline); GstClock *clock = gst_system_clock_obtain(); g_object_set(clock, "clock-type", GST_CLOCK_TYPE_REALTIME, NULL); gst_pipeline_use_clock(GST_PIPELINE_CAST(renderer_type[i]->pipeline), clock); renderer_type[i]->appsrc = gst_bin_get_by_name (GST_BIN (renderer_type[i]->pipeline), "video_source"); g_assert(renderer_type[i]->appsrc); g_object_set(renderer_type[i]->appsrc, "caps", caps, "stream-type", 0, "is-live", TRUE, "format", GST_FORMAT_TIME, NULL); g_string_free(launch, TRUE); gst_caps_unref(caps); gst_object_unref(clock); } #ifdef X_DISPLAY_FIX use_x11 = (strstr(videosink, "xvimagesink") || strstr(videosink, "ximagesink") || auto_videosink); fullscreen = initial_fullscreen; renderer_type[i]->server_name = server_name; renderer_type[i]->gst_window = NULL; renderer_type[i]->use_x11 = false; X11_search_attempts = 0; if (use_x11) { if (i == 0) { renderer_type[0]->gst_window = (X11_Window_t *) calloc(1, sizeof(X11_Window_t)); g_assert(renderer_type[0]->gst_window); get_X11_Display(renderer_type[0]->gst_window); if (renderer_type[0]->gst_window->display) { renderer_type[i]->use_x11 = true; } else { free(renderer_type[0]->gst_window); renderer_type[0]->gst_window = NULL; } } else if (renderer_type[0]->use_x11) { renderer_type[i]->gst_window = (X11_Window_t *) calloc(1, sizeof(X11_Window_t)); g_assert(renderer_type[i]->gst_window); memcpy(renderer_type[i]->gst_window, renderer_type[0]->gst_window, sizeof(X11_Window_t)); renderer_type[i]->use_x11 = true; } } #endif gst_element_set_state (renderer_type[i]->pipeline, GST_STATE_READY); GstState state; if (gst_element_get_state (renderer_type[i]->pipeline, &state, NULL, 100 * GST_MSECOND)) { if (state == GST_STATE_READY) { logger_log(logger, LOGGER_DEBUG, "Initialized GStreamer video renderer %d", i + 1); if (hls_video && i == 0) { renderer = renderer_type[i]; } } else { logger_log(logger, LOGGER_ERR, "Failed to initialize GStreamer video renderer %d", i + 1); } } else { logger_log(logger, LOGGER_ERR, "Failed to initialize GStreamer video renderer %d", i + 1); } } } void video_renderer_pause() { if (!renderer) { return; } logger_log(logger, LOGGER_DEBUG, "video renderer paused"); gst_element_set_state(renderer->pipeline, GST_STATE_PAUSED); } void video_renderer_resume() { if (!renderer) { return; } gst_element_set_state (renderer->pipeline, GST_STATE_PLAYING); GstState state; /* wait with timeout 100 msec for pipeline to change state from PAUSED to PLAYING */ gst_element_get_state(renderer->pipeline, &state, NULL, 100 * GST_MSECOND); const gchar *state_name = gst_element_state_get_name(state); logger_log(logger, LOGGER_DEBUG, "video renderer resumed: state %s", state_name); if (renderer->appsrc) { gst_video_pipeline_base_time = gst_element_get_base_time(renderer->appsrc); } } void video_renderer_start() { if (hls_video) { renderer->bus = gst_element_get_bus(renderer->pipeline); gst_element_set_state (renderer->pipeline, GST_STATE_PLAYING); return; } /* when not hls, start both h264 and h265 pipelines; will shut down the "wrong" one when we know the codec */ for (int i = 0; i < n_renderers; i++) { gst_element_set_state (renderer_type[i]->pipeline, GST_STATE_PLAYING); if (renderer_type[i]->appsrc) { gst_video_pipeline_base_time = gst_element_get_base_time(renderer_type[i]->appsrc); } renderer_type[i]->bus = gst_element_get_bus(renderer_type[i]->pipeline); } renderer = NULL; first_packet = true; #ifdef X_DISPLAY_FIX X11_search_attempts = 0; #endif } /* used to find any X11 Window used by the playbin (HLS) pipeline after it starts playing. * if use_x11 is true, called every 100 ms after playbin state is READY until the x11 window is found*/ bool waiting_for_x11_window() { if (!hls_video) { return false; } #ifdef X_DISPLAY_FIX if (use_x11 && renderer->gst_window) { get_x_window(renderer->gst_window, renderer->server_name); if (!renderer->gst_window->window) { return true; /* window still not found */ } } #endif return false; } void video_renderer_render_buffer(unsigned char* data, int *data_len, int *nal_count, uint64_t *ntp_time) { GstBuffer *buffer; GstClockTime pts = (GstClockTime) *ntp_time; /*now in nsecs */ //GstClockTimeDiff latency = GST_CLOCK_DIFF(gst_element_get_current_clock_time (renderer->appsrc), pts); if (sync) { if (pts >= gst_video_pipeline_base_time) { pts -= gst_video_pipeline_base_time; } else { logger_log(logger, LOGGER_ERR, "*** invalid ntp_time < gst_video_pipeline_base_time\n%8.6f ntp_time\n%8.6f base_time", ((double) *ntp_time) / SECOND_IN_NSECS, ((double) gst_video_pipeline_base_time) / SECOND_IN_NSECS); return; } } g_assert(data_len != 0); /* first four bytes of valid h264 video data are 0x00, 0x00, 0x00, 0x01. * * nal_count is the number of NAL units in the data: short SPS, PPS, SEI NALs * * may precede a VCL NAL. Each NAL starts with 0x00 0x00 0x00 0x01 and is * * byte-aligned: the first byte of invalid data (decryption failed) is 0x01 */ if (data[0]) { logger_log(logger, LOGGER_ERR, "*** ERROR decryption of video packet failed "); } else { if (first_packet) { logger_log(logger, LOGGER_INFO, "Begin streaming to GStreamer video pipeline"); first_packet = false; } buffer = gst_buffer_new_allocate(NULL, *data_len, NULL); g_assert(buffer != NULL); //g_print("video latency %8.6f\n", (double) latency / SECOND_IN_NSECS); if (sync) { GST_BUFFER_PTS(buffer) = pts; } gst_buffer_fill(buffer, 0, data, *data_len); gst_app_src_push_buffer (GST_APP_SRC(renderer->appsrc), buffer); #ifdef X_DISPLAY_FIX if (renderer->gst_window && !(renderer->gst_window->window) && renderer->use_x11) { X11_search_attempts++; logger_log(logger, LOGGER_DEBUG, "Looking for X11 UxPlay Window, attempt %d", (int) X11_search_attempts); get_x_window(renderer->gst_window, renderer->server_name); if (renderer->gst_window->window) { logger_log(logger, LOGGER_INFO, "\n*** X11 Windows: Use key F11 or (left Alt)+Enter to toggle full-screen mode\n"); if (fullscreen) { set_fullscreen(renderer->gst_window, &fullscreen); } } } #endif } } void video_renderer_flush() { } void video_renderer_stop() { if (renderer) { if (renderer->appsrc) { gst_app_src_end_of_stream (GST_APP_SRC(renderer->appsrc)); } gst_element_set_state (renderer->pipeline, GST_STATE_NULL); //gst_element_set_state (renderer->playbin, GST_STATE_NULL); } } static void video_renderer_destroy_h26x(video_renderer_t *renderer) { if (renderer) { GstState state; gst_element_get_state(renderer->pipeline, &state, NULL, 100 * GST_MSECOND); if (state != GST_STATE_NULL) { if (!hls_video) { gst_app_src_end_of_stream (GST_APP_SRC(renderer->appsrc)); } gst_element_set_state (renderer->pipeline, GST_STATE_NULL); } gst_object_unref(renderer->bus); if (renderer->appsrc) { gst_object_unref (renderer->appsrc); } gst_object_unref (renderer->pipeline); #ifdef X_DISPLAY_FIX if (renderer->gst_window) { free(renderer->gst_window); renderer->gst_window = NULL; } #endif free (renderer); renderer = NULL; } } void video_renderer_destroy() { for (int i = 0; i < n_renderers; i++) { if (renderer_type[i]) { video_renderer_destroy_h26x(renderer_type[i]); } } } gboolean gstreamer_pipeline_bus_callback(GstBus *bus, GstMessage *message, void *loop) { /* identify which pipeline sent the message */ int type = -1; for (int i = 0 ; i < n_renderers ; i ++ ) { if (renderer_type[i]->bus == bus) { type = i; break; } } g_assert(type != -1); if (logger_debug) { g_print("GStreamer %s bus message: %s %s\n", renderer_type[type]->codec, GST_MESSAGE_SRC_NAME(message), GST_MESSAGE_TYPE_NAME(message)); } if (logger_debug && hls_video) { gint64 pos; gst_element_query_position (renderer_type[type]->pipeline, GST_FORMAT_TIME, &pos); if (GST_CLOCK_TIME_IS_VALID(pos)) { g_print("GStreamer bus message %s %s; position: %" GST_TIME_FORMAT "\n", GST_MESSAGE_SRC_NAME(message), GST_MESSAGE_TYPE_NAME(message), GST_TIME_ARGS(pos)); } else { g_print("GStreamer bus message %s %s; position: none\n", GST_MESSAGE_SRC_NAME(message), GST_MESSAGE_TYPE_NAME(message)); } } switch (GST_MESSAGE_TYPE (message)) { case GST_MESSAGE_DURATION: renderer_type[type]->duration = GST_CLOCK_TIME_NONE; break; case GST_MESSAGE_BUFFERING: if (hls_video) { gint percent = -1; gst_message_parse_buffering(message, &percent); if (percent >= 0) { renderer_type[type]->buffering_level = percent; logger_log(logger, LOGGER_DEBUG, "Buffering :%u percent done", percent); if (percent < 100) { gst_element_set_state (renderer_type[type]->pipeline, GST_STATE_PAUSED); } else { gst_element_set_state (renderer_type[type]->pipeline, GST_STATE_PLAYING); } } } break; case GST_MESSAGE_ERROR: { GError *err; gchar *debug; gboolean flushing; gst_message_parse_error (message, &err, &debug); logger_log(logger, LOGGER_INFO, "GStreamer error: %s %s", GST_MESSAGE_SRC_NAME(message),err->message); if (!hls_video && strstr(err->message,"Internal data stream error")) { logger_log(logger, LOGGER_INFO, "*** This is a generic GStreamer error that usually means that GStreamer\n" "*** was unable to construct a working video pipeline.\n\n" "*** If you are letting the default autovideosink select the videosink,\n" "*** GStreamer may be trying to use non-functional hardware h264 video decoding.\n" "*** Try using option -avdec to force software decoding or use -vs \n" "*** to select a videosink of your choice (see \"man uxplay\").\n\n" "*** Raspberry Pi models 4B and earlier using Video4Linux2 may need \"-bt709\" uxplay option"); } g_error_free (err); g_free (debug); if (renderer_type[type]->appsrc) { gst_app_src_end_of_stream (GST_APP_SRC(renderer_type[type]->appsrc)); } gst_bus_set_flushing(bus, TRUE); gst_element_set_state (renderer_type[type]->pipeline, GST_STATE_READY); renderer_type[type]->terminate = TRUE; g_main_loop_quit( (GMainLoop *) loop); break; } case GST_MESSAGE_EOS: /* end-of-stream */ logger_log(logger, LOGGER_INFO, "GStreamer: End-Of-Stream"); if (hls_video) { gst_bus_set_flushing(bus, TRUE); gst_element_set_state (renderer_type[type]->pipeline, GST_STATE_READY); renderer_type[type]->terminate = TRUE; g_main_loop_quit( (GMainLoop *) loop); } break; case GST_MESSAGE_STATE_CHANGED: if (renderer_type[type]->state_pending && strstr(GST_MESSAGE_SRC_NAME(message), "pipeline")) { GstState state; gst_element_get_state(renderer_type[type]->pipeline, &state, NULL, 100 * GST_MSECOND); if (state == GST_STATE_NULL) { gst_element_set_state(renderer_type[type]->pipeline, GST_STATE_PLAYING); } else if (state == GST_STATE_PLAYING) { renderer_type[type]->state_pending = false; } } if (renderer_type[type]->autovideo) { char *sink = strstr(GST_MESSAGE_SRC_NAME(message), "-actual-sink-"); if (sink) { sink += strlen("-actual-sink-"); if (strstr(GST_MESSAGE_SRC_NAME(message), renderer_type[type]->codec)) { logger_log(logger, LOGGER_DEBUG, "GStreamer: automatically-selected videosink" " (renderer %d: %s) is \"%ssink\"", renderer_type[type]->id + 1, renderer_type[type]->codec, sink); #ifdef X_DISPLAY_FIX renderer_type[type]->use_x11 = (strstr(sink, "ximage") || strstr(sink, "xvimage")); #endif renderer_type[type]->autovideo = false; } } } break; #ifdef X_DISPLAY_FIX case GST_MESSAGE_ELEMENT: if (renderer_type[type]->gst_window && renderer_type[type]->gst_window->window) { GstNavigationMessageType message_type = gst_navigation_message_get_type (message); if (message_type == GST_NAVIGATION_MESSAGE_EVENT) { GstEvent *event = NULL; if (gst_navigation_message_parse_event (message, &event)) { GstNavigationEventType event_type = gst_navigation_event_get_type (event); const gchar *key; switch (event_type) { case GST_NAVIGATION_EVENT_KEY_PRESS: if (gst_navigation_event_parse_key_event (event, &key)) { if ((strcmp (key, "F11") == 0) || (alt_keypress && strcmp (key, "Return") == 0)) { fullscreen = !(fullscreen); set_fullscreen(renderer_type[type]->gst_window, &fullscreen); } else if (strcmp (key, "Alt_L") == 0) { alt_keypress = true; } } break; case GST_NAVIGATION_EVENT_KEY_RELEASE: if (gst_navigation_event_parse_key_event (event, &key)) { if (strcmp (key, "Alt_L") == 0) { alt_keypress = false; } } default: break; } } if (event) { gst_event_unref (event); } } } break; #endif default: /* unhandled message */ break; } return TRUE; } void video_renderer_choose_codec (bool video_is_h265) { g_assert(!hls_video); /* set renderer to h264 or h265, depending on pps/sps received by raop_rtp_mirror */ video_renderer_t *renderer_new = video_is_h265 ? renderer_type[1] : renderer_type[0]; if (renderer == renderer_new) { return; } video_renderer_t *renderer_prev = renderer; renderer = renderer_new; gst_video_pipeline_base_time = gst_element_get_base_time(renderer->appsrc); /* it seems unlikely that the codec will change between h264 and h265 during a connection, * but in case it does, we set the previous renderer to GST_STATE_NULL, detect * when this is finished by listening for the bus message, and then reset it to * GST_STATE_READY, so it can be reused if the codec changes again. */ if (renderer_prev) { gst_app_src_end_of_stream (GST_APP_SRC(renderer_prev->appsrc)); gst_bus_set_flushing(renderer_prev->bus, TRUE); /* set state of previous renderer to GST_STATE_NULL to (hopefully?) close its video window */ gst_element_set_state (renderer_prev->pipeline, GST_STATE_NULL); renderer_prev->state_pending = true; // will set state to PLAYING once state is NULL } } unsigned int video_reset_callback(void * loop) { if (video_terminate) { video_terminate = false; if (renderer->appsrc) { gst_app_src_end_of_stream (GST_APP_SRC(renderer->appsrc)); } gboolean flushing = TRUE; gst_bus_set_flushing(renderer->bus, flushing); gst_element_set_state (renderer->pipeline, GST_STATE_NULL); g_main_loop_quit( (GMainLoop *) loop); } return (unsigned int) TRUE; } bool video_get_playback_info(double *duration, double *position, float *rate) { gint64 pos = 0; GstState state; *duration = 0.0; *position = -1.0; *rate = 0.0f; if (!renderer) { return true; } gst_element_get_state(renderer->pipeline, &state, NULL, 0); *rate = 0.0f; switch (state) { case GST_STATE_PLAYING: *rate = 1.0f; default: break; } if (!GST_CLOCK_TIME_IS_VALID(renderer->duration)) { if (!gst_element_query_duration (renderer->pipeline, GST_FORMAT_TIME, &renderer->duration)) { return true; } } *duration = ((double) renderer->duration) / GST_SECOND; if (*duration) { if (gst_element_query_position (renderer->pipeline, GST_FORMAT_TIME, &pos) && GST_CLOCK_TIME_IS_VALID(pos)) { *position = ((double) pos) / GST_SECOND; } } logger_log(logger, LOGGER_DEBUG, "********* video_get_playback_info: position %" GST_TIME_FORMAT " duration %" GST_TIME_FORMAT " %s *********", GST_TIME_ARGS (pos), GST_TIME_ARGS (renderer->duration), gst_element_state_get_name(state)); return true; } void video_renderer_seek(float position) { double pos = (double) position; pos *= GST_SECOND; gint64 seek_position = (gint64) pos; seek_position = seek_position < 1000 ? 1000 : seek_position; seek_position = seek_position > renderer->duration - 1000 ? renderer->duration - 1000: seek_position; g_print("SCRUB: seek to %f secs = %" GST_TIME_FORMAT ", duration = %" GST_TIME_FORMAT "\n", position, GST_TIME_ARGS(seek_position), GST_TIME_ARGS(renderer->duration)); gboolean result = gst_element_seek_simple(renderer->pipeline, GST_FORMAT_TIME, (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT), seek_position); if (result) { g_print("seek succeeded\n"); gst_element_set_state (renderer->pipeline, GST_STATE_PLAYING); } else { g_print("seek failed\n"); } } unsigned int video_renderer_listen(void *loop, int id) { g_assert(id >= 0 && id < n_renderers); return (unsigned int) gst_bus_add_watch(renderer_type[id]->bus,(GstBusFunc) gstreamer_pipeline_bus_callback, (gpointer) loop); } UxPlay-1.71.1/renderers/video_renderer.h000066400000000000000000000047131473013662600201760ustar00rootroot00000000000000/** * RPiPlay - An open-source AirPlay mirroring server for Raspberry Pi * Copyright (C) 2019 Florian Draschbacher * Modified for: * UxPlay - An open-source AirPlay mirroring server * Copyright (C) 2021-23 F. Duncanh * * 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, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* * H264 renderer using gstreamer */ #ifndef VIDEO_RENDERER_H #define VIDEO_RENDERER_H #ifdef __cplusplus extern "C" { #endif #include #include #include #include "../lib/logger.h" typedef enum videoflip_e { NONE, LEFT, RIGHT, INVERT, VFLIP, HFLIP, } videoflip_t; typedef struct video_renderer_s video_renderer_t; void video_renderer_init (logger_t *logger, const char *server_name, videoflip_t videoflip[2], const char *parser, const char *decoder, const char *converter, const char *videosink, const char *videosink_options, bool initial_fullscreen, bool video_sync, bool h265_support, const char *uri); void video_renderer_start (); void video_renderer_stop (); void video_renderer_pause (); void video_renderer_seek(float position); void video_renderer_resume (); bool video_renderer_is_paused(); void video_renderer_render_buffer (unsigned char* data, int *data_len, int *nal_count, uint64_t *ntp_time); void video_renderer_flush (); unsigned int video_renderer_listen(void *loop, int id); void video_renderer_destroy (); void video_renderer_size(float *width_source, float *height_source, float *width, float *height); bool waiting_for_x11_window(); bool video_get_playback_info(double *duration, double *position, float *rate); void video_renderer_choose_codec(bool is_h265); unsigned int video_renderer_listen(void *loop, int id); unsigned int video_reset_callback(void *loop); #ifdef __cplusplus } #endif #endif //VIDEO_RENDERER_H UxPlay-1.71.1/renderers/x_display_fix.h000066400000000000000000000072251473013662600200450ustar00rootroot00000000000000/** * RPiPlay - An open-source AirPlay mirroring server for Raspberry Pi * Copyright (C) 2019 Florian Draschbacher * Modified for: * UxPlay - An open-source AirPlay mirroring server * Copyright (C) 2021-23 F. Duncanh * * * 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, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* based on code from David Ventura https://github.com/DavidVentura/UxPlay */ /* This file should be only included from video_renderer.c as it defines static * functions and depends on video_renderer internals */ #ifndef X_DISPLAY_FIX_H #define X_DISPLAY_FIX_H #ifdef __cplusplus extern "C" { #endif #include #include #include #include struct X11_Window_s { Display * display; Window window; } typedef X11_Window_t; static void get_X11_Display(X11_Window_t * X11) { X11->display = XOpenDisplay(NULL); X11->window = (Window) NULL; } static Window enum_windows(const char * str, Display * display, Window window, int depth) { int i; XTextProperty text; XGetWMName(display, window, &text); char* name = NULL; XFetchName(display, window, &name); if (name != 0 && strcmp(str, name) == 0) { return window; } Window _root, parent; Window* children = NULL; unsigned int n; XQueryTree(display, window, &_root, &parent, &children, &n); if (children != NULL) { for (i = 0; i < n; i++) { Window w = enum_windows(str, display, children[i], depth + 1); if (w) return w; } XFree(children); } return (Window) NULL; } int X11_error_catcher( Display *disp, XErrorEvent *xe ) { // do nothing return 0; } static void get_x_window(X11_Window_t * X11, const char * name) { Window root = XDefaultRootWindow(X11->display); XSetErrorHandler(X11_error_catcher); X11->window = enum_windows(name, X11->display, root, 0); XSetErrorHandler(NULL); #ifdef ZOOM_WINDOW_NAME_FIX if (X11->window) { Atom _NET_WM_NAME = XInternAtom(X11->display, "_NET_WM_NAME", 0); Atom UTF8_STRING = XInternAtom(X11->display, "UTF8_STRING", 0); XChangeProperty(X11->display, X11->window, _NET_WM_NAME, UTF8_STRING, 8, 0, (const unsigned char *) name, strlen(name)); XSync(X11->display, False); } #endif } static void set_fullscreen(X11_Window_t * X11, bool * fullscreen) { XClientMessageEvent msg = { .type = ClientMessage, .display = X11->display, .window = X11->window, .message_type = XInternAtom(X11->display, "_NET_WM_STATE", True), .format = 32, .data = { .l = { *fullscreen, XInternAtom(X11->display, "_NET_WM_STATE_FULLSCREEN", True), None, 0, 1 }} }; XSendEvent(X11->display, XRootWindow(X11->display, XDefaultScreen(X11->display)), False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent*) &msg); XSync(X11->display, False); } #ifdef __cplusplus } #endif #endif UxPlay-1.71.1/uxplay.1000066400000000000000000000136001473013662600144370ustar00rootroot00000000000000.TH UXPLAY "1" "December 2024" "1.71" "User Commands" .SH NAME uxplay \- start AirPlay server .SH SYNOPSIS .B uxplay [\fI\,-n name\/\fR] [\fI\,-s wxh\/\fR] [\fI\,-p \/\fR[\fI\,n\/\fR]] [more \fI OPTIONS \/\fR ...] .SH DESCRIPTION UxPlay 1.71: An open\-source AirPlay mirroring (+ audio streaming) server: .SH OPTIONS .TP .B \fB\-n\fR name Specify the network name of the AirPlay server .TP \fB\-nh\fR Do \fBNOT\fR append "@\fIhostname\fR" at end of AirPlay server name .TP \fB\-h265\fR Support h265 (4K) video (with h265 versions of h264 plugins) .TP \fB\-hls\fR Support HTTP Live Streaming (currently YouTube video only) .TP \fB\-pin\fI[xxxx]\fRUse a 4-digit pin code to control client access (default: no) .IP without option, pin is random: optionally use fixed pin xxxx. .TP \fB\-reg\fI [fn]\fR Keep a register in $HOME/.uxplay.register to verify returning .IP client pin-registration; (option: use file "fn" for this) .TP \fB\-vsync\fI[x]\fR Mirror mode: sync audio to video using timestamps (default) .IP \fIx\fR is optional audio delay: millisecs, decimal, can be neg. .TP \fB\-vsync\fR no Switch off audio/(server)video timestamp synchronization. .TP \fB\-async\fR[\fIx\fR] Audio-Only mode: sync audio to client video (default: no). .TP \fB\-async\fR no Switch off audio/(client)video timestamp synchronization. .TP \fB\-db\fI l[:h]\fR Set minumum volume attenuation to l dB (decibels, negative); .IP optional: set maximum to h dB (+ or -); default -30.0:0.0 .PP .TP \fB\-taper\fR Use a "tapered" AirPlay volume-control profile. .TP \fB\-s\fR wxh[@r]Request to client for video display resolution [refresh_rate] .IP default 1920x1080[@60] (or 3840x2160[@60] with -h265 option). .PP .TP \fB\-o\fR Set display "overscanned" mode on (not usually needed) .TP \fB-fs\fR Full-screen (only works with X11, Wayland, VAAPI, D3D11) .TP \fB\-p\fR Use legacy ports UDP 6000:6001:7011 TCP 7000:7001:7100 .TP \fB\-p\fR n Use TCP and UDP ports n,n+1,n+2. range 1024\-65535 .IP use "\-p n1,n2,n3" to set each port, "n1,n2" for n3 = n2+1 .IP "\-p tcp n" or "\-p udp n" sets TCP or UDP ports separately. .PP .TP \fB\-avdec\fR Force software h264 video decoding with libav decoder. .TP \fB\-vp\fI prs \fR Choose GStreamer h264 parser; default "h264parse" .TP \fB\-vd\fI dec \fR Choose GStreamer h264 decoder; default "decodebin" .IP choices: (software) avdec_h264; (hardware) v4l2h264dec, .IP nvdec, nvh264dec, vaapih264dec, vtdec, ... .TP \fB\-vc\fI cnv \fR Choose GStreamer videoconverter; default "videoconvert" .IP another choice when using v4l2h264dec: v4l2convert. .TP \fB\-vs\fI sink\fR Choose the GStreamer videosink; default "autovideosink" .IP choices: ximagesink,xvimagesink,vaapisink,glimagesink, .IP gtksink,waylandsink,osxvideosink,kmssink,d3d11videosink,... .PP .TP \fB\-vs\fR 0 Streamed audio only, with no video display window. .TP \fB\-v4l2\fR Use Video4Linux2 for GPU hardware h264 video decoding. .TP \fB\-bt709\fR Sometimes needed for Raspberry Pi models using Video4Linux2. .TP \fB\-as\fI sink\fR Choose the GStreamer audiosink; default "autoaudiosink" .IP choices:pulsesink,alsasink,pipewiresink,osssink,oss4sink, .IP jackaudiosink,osxaudiosink,wasapisink,directsoundsink,.. .PP .TP \fB\-as\fR 0 (or \fB\-a\fR) Turn audio off, streamed video only. .TP \fB\-al\fR x Audio latency in seconds (default 0.25) reported to client. .TP \fB\-ca\fI fn \fR In Airplay Audio (ALAC) mode, write cover-art to file fn. .TP \fB\-reset\fR n Reset after 3n seconds client silence (default 5, 0=never). .TP \fB\-nofreeze\fR Do NOT leave frozen screen in place after reset. .TP \fB\-nc\fR Do NOT close video window when client stops mirroring .TP \fB\-nohold\fR Drop current connection when new client connects. .TP \fB\-restrict\fR Restrict clients to those specified by "-allow deviceID". .IP Uxplay displays deviceID when a client attempts to connect. .IP Use "-restrict no" for no client restrictions (default). .PP \fB\-allow\fR id Permit deviceID = id to connect if restrictions are imposed. .TP \fB\-block\fR id Always block connections from deviceID = id. .TP \fB\-FPSdata\fR Show video-streaming performance reports sent by client. .TP \fB\-fps\fR n Set maximum allowed streaming framerate, default 30 .TP \fB\-f\fR {H|V|I}Horizontal|Vertical flip, or both=Inversion=rotate 180 deg .TP \fB\-r\fR {R|L} Rotate 90 degrees Right (cw) or Left (ccw) .TP \fB\-m\fI [mac]\fR Set MAC address (also Device ID); use for concurrent UxPlays .IP if mac xx:xx:xx:xx:xx:xx is not given, a random MAC is used. .PP .TP \fB\-key\fI [fn]\fR Store private key in $HOME/.uxplay.pem (or in file "fn") .PP .TP \fB\-dacp\fI [fn]\fRExport client DACP information to file $HOME/.uxplay.dacp .IP (option to use file "fn" instead); used for client remote. .PP .TP \fB\-vdmp\fR [n] Dump h264 video output to "fn.h264"; fn="videodump", change .IP with "-vdmp [n] filename". If [n] is given, file fn.x.h264 .IP x=1,2,.. opens whenever a new SPS/PPS NAL arrives, and <=n .IP NAL units are dumped. .PP .TP \fB\-admp\fR [n] Dump audio output to "fn.x.fmt", fmt ={aac, alac, aud}, x .IP =1,2,..; fn="audiodump"; change with "-admp [n] filename". .IP x increases when audio format changes. If n is given, <= n .IP audio packets are dumped. "aud"= unknown format. .PP .TP \fB\-d\fR Enable debug logging .TP \fB\-v\fR Displays version information .TP \fB\-h\fR Displays help information .SH FILES Options in one of $UXPLAYRC, or ~/.uxplayrc, or ~/.config/uxplayrc .TP are applied first (command-line options may modify them). Format: .TP one option per line,\fI no\fR initial "-"; lines beginning with "#" ignored. .SH AUTHORS .TP Various, see website or distribution. .SH COPYRIGHT .TP Various, see website or distribution. License: GPL v3+: .TP GNU GPL version 3 or later. (some parts LGPL v.2.1+ or MIT). .SH SEE ALSO .TP Website: UxPlay-1.71.1/uxplay.cpp000066400000000000000000002561051473013662600150720ustar00rootroot00000000000000/** * RPiPlay - An open-source AirPlay mirroring server for Raspberry Pi * Copyright (C) 2019 Florian Draschbacher * Modified extensively to become * UxPlay - An open-souce AirPlay mirroring server. * Modifications Copyright (C) 2021-23 F. Duncanh * * 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, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef _WIN32 /*modifications for Windows compilation */ #include #include #include #include #else #include #include #include #include #include #include # ifdef __linux__ # include # else # include # endif #endif #include "lib/raop.h" #include "lib/stream.h" #include "lib/logger.h" #include "lib/dnssd.h" #include "renderers/video_renderer.h" #include "renderers/audio_renderer.h" #define VERSION "1.71" #define SECOND_IN_USECS 1000000 #define SECOND_IN_NSECS 1000000000UL #define DEFAULT_NAME "UxPlay" #define DEFAULT_DEBUG_LOG false #define LOWEST_ALLOWED_PORT 1024 #define HIGHEST_PORT 65535 #define NTP_TIMEOUT_LIMIT 5 #define BT709_FIX "capssetter caps=\"video/x-h264, colorimetry=bt709\"" static std::string server_name = DEFAULT_NAME; static dnssd_t *dnssd = NULL; static raop_t *raop = NULL; static logger_t *render_logger = NULL; static bool audio_sync = false; static bool video_sync = true; static int64_t audio_delay_alac = 0; static int64_t audio_delay_aac = 0; static bool relaunch_video = false; static bool reset_loop = false; static unsigned int open_connections= 0; static std::string videosink = "autovideosink"; static std::string videosink_options = ""; static videoflip_t videoflip[2] = { NONE , NONE }; static bool use_video = true; static unsigned char compression_type = 0; static std::string audiosink = "autoaudiosink"; static int audiodelay = -1; static bool use_audio = true; static bool new_window_closing_behavior = true; static bool close_window; static std::string video_parser = "h264parse"; static std::string video_decoder = "decodebin"; static std::string video_converter = "videoconvert"; static bool show_client_FPS_data = false; static unsigned int max_ntp_timeouts = NTP_TIMEOUT_LIMIT; static FILE *video_dumpfile = NULL; static std::string video_dumpfile_name = "videodump"; static int video_dump_limit = 0; static int video_dumpfile_count = 0; static int video_dump_count = 0; static bool dump_video = false; static unsigned char mark[] = { 0x00, 0x00, 0x00, 0x01 }; static FILE *audio_dumpfile = NULL; static std::string audio_dumpfile_name = "audiodump"; static int audio_dump_limit = 0; static int audio_dumpfile_count = 0; static int audio_dump_count = 0; static bool dump_audio = false; static unsigned char audio_type = 0x00; static unsigned char previous_audio_type = 0x00; static bool fullscreen = false; static std::string coverart_filename = ""; static bool do_append_hostname = true; static bool use_random_hw_addr = false; static unsigned short display[5] = {0}, tcp[3] = {0}, udp[3] = {0}; static bool debug_log = DEFAULT_DEBUG_LOG; static int log_level = LOGGER_INFO; static bool bt709_fix = false; static int nohold = 0; static bool nofreeze = false; static unsigned short raop_port; static unsigned short airplay_port; static uint64_t remote_clock_offset = 0; static std::vector allowed_clients; static std::vector blocked_clients; static bool restrict_clients; static bool setup_legacy_pairing = false; static bool require_password = false; static unsigned short pin = 0; static std::string keyfile = ""; static std::string mac_address = ""; static std::string dacpfile = ""; static bool registration_list = false; static std::string pairing_register = ""; static std::vector registered_keys; static double db_low = -30.0; static double db_high = 0.0; static bool taper_volume = false; static bool h265_support = false; static int n_renderers = 0; static bool hls_support = false; static std::string url = ""; static guint gst_x11_window_id = 0; static guint gst_hls_position_id = 0; static bool preserve_connections = false; /* logging */ static void log(int level, const char* format, ...) { va_list vargs; if (level > log_level) return; switch (level) { case 0: case 1: case 2: case 3: printf("*** ERROR: "); break; case 4: printf("*** WARNING: "); break; default: break; } va_start(vargs, format); vprintf(format, vargs); printf("\n"); va_end(vargs); } #define LOGD(...) log(LOGGER_DEBUG, __VA_ARGS__) #define LOGI(...) log(LOGGER_INFO, __VA_ARGS__) #define LOGW(...) log(LOGGER_WARNING, __VA_ARGS__) #define LOGE(...) log(LOGGER_ERR, __VA_ARGS__) static bool file_has_write_access (const char * filename) { bool exists = false; bool write = false; #ifdef _WIN32 if ((exists = _access(filename, 0) != -1)) { write = (_access(filename, 2) != -1); } #else if ((exists = access(filename, F_OK) != -1)) { write = (access(filename, W_OK) != -1); } #endif if (!exists) { FILE *fp = fopen(filename, "w"); if (fp) { write = true; fclose(fp); remove(filename); } } return write; } /* 95 byte png file with a 1x1 white square (single pixel): placeholder for coverart*/ static const unsigned char empty_image[] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x00, 0x00, 0x00, 0x25, 0xdb, 0x56, 0xca, 0x00, 0x00, 0x00, 0x03, 0x50, 0x4c, 0x54, 0x45, 0x00, 0x00, 0x00, 0xa7, 0x7a, 0x3d, 0xda, 0x00, 0x00, 0x00, 0x01, 0x74, 0x52, 0x4e, 0x53, 0x00, 0x40, 0xe6, 0xd8, 0x66, 0x00, 0x00, 0x00, 0x0a, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0x60, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0xe2, 0x21, 0xbc, 0x33, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; static size_t write_coverart(const char *filename, const void *image, size_t len) { FILE *fp = fopen(filename, "wb"); size_t count = fwrite(image, 1, len, fp); fclose(fp); return count; } static char *create_pin_display(char *pin_str, int margin, int gap) { char *ptr; char num[2] = { 0 }; int w = 10; int h = 8; char digits[10][8][11] = { "0821111380", "2114005113", "1110000111", "1110000111", "1110000111", "1110000111", "5113002114", "0751111470", "0002111000", "0021111000", "0000111000", "0000111000", "0000111000", "0000111000", "0000111000", "0011111110", "0811112800", "2114005113", "0000000111", "0000082114", "0862111470", "2114700000", "1117000000", "1111111111", "0821111380", "2114005113", "0000082114", "0000111170", "0000075130", "1110000111", "5113002114", "0751111470", "0000211110", "0001401110", "0021401110", "0214001110", "2110001110", "1111111111", "0000001110", "0000001110", "1111111110", "1110000000", "1110000000", "1112111380", "0000075113", "0000000111", "5113002114", "0711114700", "0821111380", "2114005113", "1110000000", "1112111380", "1114075113", "1110000111", "5113002114", "0751111470", "1111111111", "0000002114", "0000021140", "0000211400", "0002114000", "0021140000", "0211400000", "2114000000", "0831111280", "2114002114", "5113802114", "0751111170", "8214775138", "1110000111", "5113002114", "0751111470", "0821111380", "2114005113", "1110000111", "5113802111", "0751114111", "0000000111", "5113002114", "0751111470" }; char pixels[9] = { ' ', '8', 'd', 'b', 'P', 'Y', 'o', '"', '.' }; /* Ascii art used here is derived from the FIGlet font "collosal" */ int pin_val = (int) strtoul(pin_str, &ptr, 10); if (*ptr) { return NULL; } int len = strlen(pin_str); int *pin = (int *) calloc( len, sizeof(int)); if(!pin) { return NULL; } for (int i = 0; i < len; i++) { pin[len - 1 - i] = pin_val % 10; pin_val = pin_val / 10; } int size = 4 + h*(margin + len*(w + gap + 1)); char *pin_image = (char *) calloc(size, sizeof(char)); if (!pin_image) { return NULL; } char *pos = pin_image; snprintf(pos, 2, "\n"); pos++; for (int i = 0; i < h; i++) { for (int j = 0; j < margin; j++) { snprintf(pos, 2, " "); pos++; } for (int j = 0; j < len; j++) { int l = pin[j]; char *p = digits[l][i]; for (int k = 0; k < w; k++) { char *ptr; strncpy(num, p++, 1); int r = (int) strtoul(num, &ptr, 10); snprintf(pos, 2, "%c", pixels[r]); pos++; } for (int n=0; n < gap ; n++) { snprintf(pos, 2, " "); pos++; } } snprintf(pos, 2, "\n"); pos++; } snprintf(pos, 2, "\n"); return pin_image; } static void dump_audio_to_file(unsigned char *data, int datalen, unsigned char type) { if (!audio_dumpfile && audio_type != previous_audio_type) { char suffix[20]; std::string fn = audio_dumpfile_name; previous_audio_type = audio_type; audio_dumpfile_count++; audio_dump_count = 0; /* type 0x20 is lossless ALAC, type 0x80 is compressed AAC-ELD, type 0x10 is "other" */ if (audio_type == 0x20) { snprintf(suffix, sizeof(suffix), ".%d.alac", audio_dumpfile_count); } else if (audio_type == 0x80) { snprintf(suffix, sizeof(suffix), ".%d.aac", audio_dumpfile_count); } else { snprintf(suffix, sizeof(suffix), ".%d.aud", audio_dumpfile_count); } fn.append(suffix); audio_dumpfile = fopen(fn.c_str(),"w"); if (audio_dumpfile == NULL) { LOGE("could not open file %s for dumping audio frames",fn.c_str()); } } if (audio_dumpfile) { fwrite(data, 1, datalen, audio_dumpfile); if (audio_dump_limit) { audio_dump_count++; if (audio_dump_count == audio_dump_limit) { fclose(audio_dumpfile); audio_dumpfile = NULL; } } } } static void dump_video_to_file(unsigned char *data, int datalen) { /* SPS NAL has (data[4] & 0x1f) = 0x07 */ if ((data[4] & 0x1f) == 0x07 && video_dumpfile && video_dump_limit) { fwrite(mark, 1, sizeof(mark), video_dumpfile); fclose(video_dumpfile); video_dumpfile = NULL; video_dump_count = 0; } if (!video_dumpfile) { std::string fn = video_dumpfile_name; if (video_dump_limit) { char suffix[20]; video_dumpfile_count++; snprintf(suffix, sizeof(suffix), ".%d", video_dumpfile_count); fn.append(suffix); } fn.append(".h264"); video_dumpfile = fopen (fn.c_str(),"w"); if (video_dumpfile == NULL) { LOGE("could not open file %s for dumping h264 frames",fn.c_str()); } } if (video_dumpfile) { if (video_dump_limit == 0) { fwrite(data, 1, datalen, video_dumpfile); } else if (video_dump_count < video_dump_limit) { video_dump_count++; fwrite(data, 1, datalen, video_dumpfile); } } } static gboolean reset_callback(gpointer loop) { if (reset_loop) { g_main_loop_quit((GMainLoop *) loop); } return TRUE; } static gboolean x11_window_callback(gpointer loop) { /* called while trying to find an x11 window used by playbin (HLS mode) */ if (waiting_for_x11_window()) { return TRUE; } g_source_remove(gst_x11_window_id); gst_x11_window_id = 0; return FALSE; } static gboolean sigint_callback(gpointer loop) { relaunch_video = false; g_main_loop_quit((GMainLoop *) loop); return TRUE; } static gboolean sigterm_callback(gpointer loop) { relaunch_video = false; g_main_loop_quit((GMainLoop *) loop); return TRUE; } #ifdef _WIN32 struct signal_handler { GSourceFunc handler; gpointer user_data; }; static std::unordered_map u = {}; static void SignalHandler(int signum) { if (signum == SIGTERM || signum == SIGINT) { u[signum].handler(u[signum].user_data); } } static guint g_unix_signal_add(gint signum, GSourceFunc handler, gpointer user_data) { u[signum] = signal_handler{handler, user_data}; (void) signal(signum, SignalHandler); return 0; } #endif static void main_loop() { guint gst_bus_watch_id[2] = { 0 }; g_assert(n_renderers <= 2); GMainLoop *loop = g_main_loop_new(NULL,FALSE); relaunch_video = false; if (use_video) { relaunch_video = true; if (url.empty()) { n_renderers = h265_support ? 2 : 1; gst_x11_window_id = 0; } else { /* hls video will be rendered */ n_renderers = 1; url.erase(); gst_x11_window_id = g_timeout_add(100, (GSourceFunc) x11_window_callback, (gpointer) loop); } for (int i = 0; i < n_renderers; i++) { gst_bus_watch_id[i] = (guint) video_renderer_listen((void *)loop, i); } } guint reset_watch_id = g_timeout_add(100, (GSourceFunc) reset_callback, (gpointer) loop); guint video_reset_watch_id = g_timeout_add(100, (GSourceFunc) video_reset_callback, (gpointer) loop); guint sigterm_watch_id = g_unix_signal_add(SIGTERM, (GSourceFunc) sigterm_callback, (gpointer) loop); guint sigint_watch_id = g_unix_signal_add(SIGINT, (GSourceFunc) sigint_callback, (gpointer) loop); g_main_loop_run(loop); for (int i = 0; i < n_renderers; i++) { if (gst_bus_watch_id[i] > 0) g_source_remove(gst_bus_watch_id[i]); } if (gst_x11_window_id > 0) g_source_remove(gst_x11_window_id); if (sigint_watch_id > 0) g_source_remove(sigint_watch_id); if (sigterm_watch_id > 0) g_source_remove(sigterm_watch_id); if (reset_watch_id > 0) g_source_remove(reset_watch_id); if (video_reset_watch_id > 0) g_source_remove(video_reset_watch_id); g_main_loop_unref(loop); } static int parse_hw_addr (std::string str, std::vector &hw_addr) { for (int i = 0; i < (int) str.length(); i += 3) { hw_addr.push_back((char) stol(str.substr(i), NULL, 16)); } return 0; } static const char *get_homedir() { const char *homedir = getenv("XDG_CONFIG_HOMEDIR"); if (homedir == NULL) { homedir = getenv("HOME"); } #ifndef _WIN32 if (homedir == NULL){ homedir = getpwuid(getuid())->pw_dir; } #endif return homedir; } static std::string find_uxplay_config_file() { std::string no_config_file = ""; const char *homedir = NULL; const char *uxplayrc = NULL; std::string config0, config1, config2; struct stat sb; uxplayrc = getenv("UXPLAYRC"); /* first look for $UXPLAYRC */ if (uxplayrc) { config0 = uxplayrc; if (stat(config0.c_str(), &sb) == 0) return config0; } homedir = get_homedir(); if (homedir) { config1 = homedir; config1.append("/.uxplayrc"); if (stat(config1.c_str(), &sb) == 0) return config1; /* look for ~/.uxplayrc */ config2 = homedir; config2.append("/.config/uxplayrc"); /* look for ~/.config/uxplayrc */ if (stat(config2.c_str(), &sb) == 0) return config2; } return no_config_file; } static std::string find_mac () { /* finds the MAC address of a network interface * * in a Windows, Linux, *BSD or macOS system. */ std::string mac = ""; char str[3]; #ifdef _WIN32 ULONG buflen = sizeof(IP_ADAPTER_ADDRESSES); PIP_ADAPTER_ADDRESSES addresses = (IP_ADAPTER_ADDRESSES*) malloc(buflen); if (addresses == NULL) { return mac; } if (GetAdaptersAddresses(AF_UNSPEC, 0, NULL, addresses, &buflen) == ERROR_BUFFER_OVERFLOW) { free(addresses); addresses = (IP_ADAPTER_ADDRESSES*) malloc(buflen); if (addresses == NULL) { return mac; } } if (GetAdaptersAddresses(AF_UNSPEC, 0, NULL, addresses, &buflen) == NO_ERROR) { for (PIP_ADAPTER_ADDRESSES address = addresses; address != NULL; address = address->Next) { if (address->PhysicalAddressLength != 6 /* MAC has 6 octets */ || (address->IfType != 6 && address->IfType != 71) /* Ethernet or Wireless interface */ || address->OperStatus != 1) { /* interface is up */ continue; } mac.erase(); for (int i = 0; i < 6; i++) { snprintf(str, sizeof(str), "%02x", int(address->PhysicalAddress[i])); mac = mac + str; if (i < 5) mac = mac + ":"; } break; } } free(addresses); return mac; #else struct ifaddrs *ifap, *ifaptr; int non_null_octets = 0; unsigned char octet[6]; if (getifaddrs(&ifap) == 0) { for(ifaptr = ifap; ifaptr != NULL; ifaptr = ifaptr->ifa_next) { if(ifaptr->ifa_addr == NULL) continue; #ifdef __linux__ if (ifaptr->ifa_addr->sa_family != AF_PACKET) continue; struct sockaddr_ll *s = (struct sockaddr_ll*) ifaptr->ifa_addr; for (int i = 0; i < 6; i++) { if ((octet[i] = s->sll_addr[i]) != 0) non_null_octets++; } #else /* macOS and *BSD */ if (ifaptr->ifa_addr->sa_family != AF_LINK) continue; unsigned char *ptr = (unsigned char *) LLADDR((struct sockaddr_dl *) ifaptr->ifa_addr); for (int i= 0; i < 6 ; i++) { if ((octet[i] = *ptr) != 0) non_null_octets++; ptr++; } #endif if (non_null_octets) { mac.erase(); for (int i = 0; i < 6 ; i++) { snprintf(str, sizeof(str), "%02x", octet[i]); mac = mac + str; if (i < 5) mac = mac + ":"; } break; } } } freeifaddrs(ifap); #endif return mac; } #define MULTICAST 0 #define LOCAL 1 #define OCTETS 6 static bool validate_mac(char * mac_address) { char c; if (strlen(mac_address) != 17) return false; for (int i = 0; i < 17; i++) { c = *(mac_address + i); if (i % 3 == 2) { if (c != ':') return false; } else { if (c < '0') return false; if (c > '9' && c < 'A') return false; if (c > 'F' && c < 'a') return false; if (c > 'f') return false; } } return true; } static std::string random_mac () { char str[3]; int octet = rand() % 64; octet = (octet << 1) + LOCAL; octet = (octet << 1) + MULTICAST; snprintf(str,3,"%02x",octet); std::string mac_address(str); for (int i = 1; i < OCTETS; i++) { mac_address = mac_address + ":"; octet = rand() % 256; snprintf(str,3,"%02x",octet); mac_address = mac_address + str; } return mac_address; } static void print_info (char *name) { printf("UxPlay %s: An open-source AirPlay mirroring server.\n", VERSION); printf("=========== Website: https://github.com/FDH2/UxPlay ==========\n"); printf("Usage: %s [-n name] [-s wxh] [-p [n]] [(other options)]\n", name); printf("Options:\n"); printf("-n name Specify the network name of the AirPlay server\n"); printf("-nh Do not add \"@hostname\" at the end of AirPlay server name\n"); printf("-h265 Support h265 (4K) video (with h265 versions of h264 plugins)\n"); printf("-hls Support HTTP Live Streaming (currently Youtube video only) \n"); printf("-pin[xxxx]Use a 4-digit pin code to control client access (default: no)\n"); printf(" default pin is random: optionally use fixed pin xxxx\n"); printf("-reg [fn] Keep a register in $HOME/.uxplay.register to verify returning\n"); printf(" client pin-registration; (option: use file \"fn\" for this)\n"); printf("-vsync [x]Mirror mode: sync audio to video using timestamps (default)\n"); printf(" x is optional audio delay: millisecs, decimal, can be neg.\n"); printf("-vsync no Switch off audio/(server)video timestamp synchronization \n"); printf("-async [x]Audio-Only mode: sync audio to client video (default: no)\n"); printf("-async no Switch off audio/(client)video timestamp synchronization\n"); printf("-db l[:h] Set minimum volume attenuation to l dB (decibels, negative);\n"); printf(" optional: set maximum to h dB (+ or -) default: -30.0:0.0 dB\n"); printf("-taper Use a \"tapered\" AirPlay volume-control profile\n"); printf("-s wxh[@r]Request to client for video display resolution [refresh_rate]\n"); printf(" default 1920x1080[@60] (or 3840x2160[@60] with -h265 option)\n"); printf("-o Set display \"overscanned\" mode on (not usually needed)\n"); printf("-fs Full-screen (only works with X11, Wayland, VAAPI, D3D11)\n"); printf("-p Use legacy ports UDP 6000:6001:7011 TCP 7000:7001:7100\n"); printf("-p n Use TCP and UDP ports n,n+1,n+2. range %d-%d\n", LOWEST_ALLOWED_PORT, HIGHEST_PORT); printf(" use \"-p n1,n2,n3\" to set each port, \"n1,n2\" for n3 = n2+1\n"); printf(" \"-p tcp n\" or \"-p udp n\" sets TCP or UDP ports separately\n"); printf("-avdec Force software h264 video decoding with libav decoder\n"); printf("-vp ... Choose the GSteamer h264 parser: default \"h264parse\"\n"); printf("-vd ... Choose the GStreamer h264 decoder; default \"decodebin\"\n"); printf(" choices: (software) avdec_h264; (hardware) v4l2h264dec,\n"); printf(" nvdec, nvh264dec, vaapih64dec, vtdec,etc.\n"); printf(" choices: avdec_h264,vaapih264dec,nvdec,nvh264dec,v4l2h264dec\n"); printf("-vc ... Choose the GStreamer videoconverter; default \"videoconvert\"\n"); printf(" another choice when using v4l2h264dec: v4l2convert\n"); printf("-vs ... Choose the GStreamer videosink; default \"autovideosink\"\n"); printf(" some choices: ximagesink,xvimagesink,vaapisink,glimagesink,\n"); printf(" gtksink,waylandsink,osxvideosink,kmssink,d3d11videosink etc.\n"); printf("-vs 0 Streamed audio only, with no video display window\n"); printf("-v4l2 Use Video4Linux2 for GPU hardware h264 decoding\n"); printf("-bt709 Sometimes needed for Raspberry Pi models using Video4Linux2 \n"); printf("-as ... Choose the GStreamer audiosink; default \"autoaudiosink\"\n"); printf(" some choices:pulsesink,alsasink,pipewiresink,jackaudiosink,\n"); printf(" osssink,oss4sink,osxaudiosink,wasapisink,directsoundsink.\n"); printf("-as 0 (or -a) Turn audio off, streamed video only\n"); printf("-al x Audio latency in seconds (default 0.25) reported to client.\n"); printf("-ca In Airplay Audio (ALAC) mode, write cover-art to file \n"); printf("-reset n Reset after 3n seconds client silence (default %d, 0=never)\n", NTP_TIMEOUT_LIMIT); printf("-nofreeze Do NOT leave frozen screen in place after reset\n"); printf("-nc Do NOT Close video window when client stops mirroring\n"); printf("-nohold Drop current connection when new client connects.\n"); printf("-restrict Restrict clients to those specified by \"-allow \"\n"); printf(" UxPlay displays deviceID when a client attempts to connect\n"); printf(" Use \"-restrict no\" for no client restrictions (default)\n"); printf("-allow Permit deviceID = to connect if restrictions are imposed\n"); printf("-block Always block connections from deviceID = \n"); printf("-FPSdata Show video-streaming performance reports sent by client.\n"); printf("-fps n Set maximum allowed streaming framerate, default 30\n"); printf("-f {H|V|I}Horizontal|Vertical flip, or both=Inversion=rotate 180 deg\n"); printf("-r {R|L} Rotate 90 degrees Right (cw) or Left (ccw)\n"); printf("-m [mac] Set MAC address (also Device ID);use for concurrent UxPlays\n"); printf(" if mac xx:xx:xx:xx:xx:xx is not given, a random MAC is used\n"); printf("-key [fn] Store private key in $HOME/.uxplay.pem (or in file \"fn\")\n"); printf("-dacp [fn]Export client DACP information to file $HOME/.uxplay.dacp\n"); printf(" (option to use file \"fn\" instead); used for client remote\n"); printf("-vdmp [n] Dump h264 video output to \"fn.h264\"; fn=\"videodump\",change\n"); printf(" with \"-vdmp [n] filename\". If [n] is given, file fn.x.h264\n"); printf(" x=1,2,.. opens whenever a new SPS/PPS NAL arrives, and <=n\n"); printf(" NAL units are dumped.\n"); printf("-admp [n] Dump audio output to \"fn.x.fmt\", fmt ={aac, alac, aud}, x\n"); printf(" =1,2,..; fn=\"audiodump\"; change with \"-admp [n] filename\".\n"); printf(" x increases when audio format changes. If n is given, <= n\n"); printf(" audio packets are dumped. \"aud\"= unknown format.\n"); printf("-d Enable debug logging\n"); printf("-v Displays version information\n"); printf("-h Displays this help\n"); printf("Startup options in $UXPLAYRC, ~/.uxplayrc, or ~/.config/uxplayrc are\n"); printf("applied first (command-line options may modify them): format is one \n"); printf("option per line, no initial \"-\"; lines starting with \"#\" are ignored.\n"); } static bool option_has_value(const int i, const int argc, std::string option, const char *next_arg) { if (i >= argc - 1 || next_arg[0] == '-') { LOGE("invalid: \"%s\" had no argument", option.c_str()); return false; } return true; } static bool get_display_settings (std::string value, unsigned short *w, unsigned short *h, unsigned short *r) { // assume str = wxh@r is valid if w and h are positive decimal integers // with no more than 4 digits, r < 256 (stored in one byte). char *end; std::size_t pos = value.find_first_of("x"); if (pos == std::string::npos) return false; std::string str1 = value.substr(pos+1); value.erase(pos); if (value.length() == 0 || value.length() > 4 || value[0] == '-') return false; *w = (unsigned short) strtoul(value.c_str(), &end, 10); if (*end || *w == 0) return false; pos = str1.find_first_of("@"); if(pos != std::string::npos) { std::string str2 = str1.substr(pos+1); if (str2.length() == 0 || str2.length() > 3 || str2[0] == '-') return false; *r = (unsigned short) strtoul(str2.c_str(), &end, 10); if (*end || *r == 0 || *r > 255) return false; str1.erase(pos); } if (str1.length() == 0 || str1.length() > 4 || str1[0] == '-') return false; *h = (unsigned short) strtoul(str1.c_str(), &end, 10); if (*end || *h == 0) return false; return true; } static bool get_value (const char *str, unsigned int *n) { // if n > 0 str must be a positive decimal <= input value *n // if n = 0, str must be a non-negative decimal if (strlen(str) == 0 || strlen(str) > 10 || str[0] == '-') return false; char *end; unsigned long l = strtoul(str, &end, 10); if (*end) return false; if (*n && (l == 0 || l > *n)) return false; *n = (unsigned int) l; return true; } static bool get_ports (int nports, std::string option, const char * value, unsigned short * const port) { /*valid entries are comma-separated values port_1,port_2,...,port_r, 0 < r <= nports */ /*where ports are distinct, and are in the allowed range. */ /*missing values are consecutive to last given value (at least one value needed). */ char *end; unsigned long l; std::size_t pos; std::string val(value), str; for (int i = 0; i <= nports ; i++) { if(i == nports) break; pos = val.find_first_of(','); str = val.substr(0,pos); if(str.length() == 0 || str.length() > 5 || str[0] == '-') break; l = strtoul(str.c_str(), &end, 10); if (*end || l < LOWEST_ALLOWED_PORT || l > HIGHEST_PORT) break; *(port + i) = (unsigned short) l; for (int j = 0; j < i ; j++) { if( *(port + j) == *(port + i)) break; } if(pos == std::string::npos) { if (nports + *(port + i) > i + 1 + HIGHEST_PORT) break; for (int j = i + 1; j < nports; j++) { *(port + j) = *(port + j - 1) + 1; } return true; } val.erase(0, pos+1); } LOGE("invalid \"%s %s\", all %d ports must be in range [%d,%d]", option.c_str(), value, nports, LOWEST_ALLOWED_PORT, HIGHEST_PORT); return false; } static bool get_videoflip (const char *str, videoflip_t *videoflip) { if (strlen(str) > 1) return false; switch (str[0]) { case 'I': *videoflip = INVERT; break; case 'H': *videoflip = HFLIP; break; case 'V': *videoflip = VFLIP; break; default: return false; } return true; } static bool get_videorotate (const char *str, videoflip_t *videoflip) { if (strlen(str) > 1) return false; switch (str[0]) { case 'L': *videoflip = LEFT; break; case 'R': *videoflip = RIGHT; break; default: return false; } return true; } static void append_hostname(std::string &server_name) { #ifdef _WIN32 /*modification for compilation on Windows */ char buffer[256] = ""; unsigned long size = sizeof(buffer); if (GetComputerNameA(buffer, &size)) { std::string name = server_name; name.append("@"); name.append(buffer); server_name = name; } #else struct utsname buf; if (!uname(&buf)) { std::string name = server_name; name.append("@"); name.append(buf.nodename); server_name = name; } #endif } static void parse_arguments (int argc, char *argv[]) { // Parse arguments for (int i = 1; i < argc; i++) { std::string arg(argv[i]); if (arg == "-allow") { if (!option_has_value(i, argc, arg, argv[i+1])) exit(1); i++; allowed_clients.push_back(argv[i]); } else if (arg == "-block") { if (!option_has_value(i, argc, arg, argv[i+1])) exit(1); i++; blocked_clients.push_back(argv[i]); } else if (arg == "-restrict") { if (i < argc - 1) { if (strlen(argv[i+1]) == 2 && strncmp(argv[i+1], "no", 2) == 0) { restrict_clients = false; i++; continue; } } restrict_clients = true; } else if (arg == "-n") { if (!option_has_value(i, argc, arg, argv[i+1])) exit(1); server_name = std::string(argv[++i]); } else if (arg == "-nh") { do_append_hostname = false; } else if (arg == "-async") { audio_sync = true; if (i < argc - 1) { if (strlen(argv[i+1]) == 2 && strncmp(argv[i+1], "no", 2) == 0) { audio_sync = false; i++; continue; } char *end; int n = (int) (strtof(argv[i + 1], &end) * 1000); if (*end == '\0') { i++; if (n > -SECOND_IN_USECS && n < SECOND_IN_USECS) { audio_delay_alac = n * 1000; /* units are nsecs */ } else { fprintf(stderr, "invalid -async %s: requested delays must be smaller than +/- 1000 millisecs\n", argv[i] ); exit (1); } } } } else if (arg == "-vsync") { video_sync = true; if (i < argc - 1) { if (strlen(argv[i+1]) == 2 && strncmp(argv[i+1], "no", 2) == 0) { video_sync = false; i++; continue; } char *end; int n = (int) (strtof(argv[i + 1], &end) * 1000); if (*end == '\0') { i++; if (n > -SECOND_IN_USECS && n < SECOND_IN_USECS) { audio_delay_aac = n * 1000; /* units are nsecs */ } else { fprintf(stderr, "invalid -vsync %s: requested delays must be smaller than +/- 1000 millisecs\n", argv[i]); exit (1); } } } } else if (arg == "-s") { if (!option_has_value(i, argc, argv[i], argv[i+1])) exit(1); std::string value(argv[++i]); if (!get_display_settings(value, &display[0], &display[1], &display[2])) { fprintf(stderr, "invalid \"-s %s\"; -s wxh : max w,h=9999; -s wxh@r : max r=255\n", argv[i]); exit(1); } } else if (arg == "-fps") { if (!option_has_value(i, argc, arg, argv[i+1])) exit(1); unsigned int n = 255; if (!get_value(argv[++i], &n)) { fprintf(stderr, "invalid \"-fps %s\"; -fps n : max n=255, default n=30\n", argv[i]); exit(1); } display[3] = (unsigned short) n; } else if (arg == "-o") { display[4] = 1; } else if (arg == "-f") { if (!option_has_value(i, argc, arg, argv[i+1])) exit(1); if (!get_videoflip(argv[++i], &videoflip[0])) { fprintf(stderr,"invalid \"-f %s\" , unknown flip type, choices are H, V, I\n",argv[i]); exit(1); } } else if (arg == "-r") { if (!option_has_value(i, argc, arg, argv[i+1])) exit(1); if (!get_videorotate(argv[++i], &videoflip[1])) { fprintf(stderr,"invalid \"-r %s\" , unknown rotation type, choices are R, L\n",argv[i]); exit(1); } } else if (arg == "-p") { if (i == argc - 1 || argv[i + 1][0] == '-') { tcp[0] = 7100; tcp[1] = 7000; tcp[2] = 7001; udp[0] = 7011; udp[1] = 6001; udp[2] = 6000; continue; } std::string value(argv[++i]); if (value == "tcp") { arg.append(" tcp"); if(!get_ports(3, arg, argv[++i], tcp)) exit(1); } else if (value == "udp") { arg.append( " udp"); if(!get_ports(3, arg, argv[++i], udp)) exit(1); } else { if(!get_ports(3, arg, argv[i], tcp)) exit(1); for (int j = 1; j < 3; j++) { udp[j] = tcp[j]; } } } else if (arg == "-m") { if (i < argc - 1 && *argv[i+1] != '-') { if (validate_mac(argv[++i])) { mac_address.erase(); mac_address = argv[i]; use_random_hw_addr = false; } else { fprintf(stderr,"invalid mac address \"%s\": address must have form" " \"xx:xx:xx:xx:xx:xx\", x = 0-9, A-F or a-f\n", argv[i]); exit(1); } } else { use_random_hw_addr = true; } } else if (arg == "-a") { use_audio = false; } else if (arg == "-d") { debug_log = !debug_log; } else if (arg == "-h" || arg == "--help" || arg == "-?" || arg == "-help") { print_info(argv[0]); exit(0); } else if (arg == "-v") { printf("UxPlay version %s; for help, use option \"-h\"\n", VERSION); exit(0); } else if (arg == "-vp") { if (!option_has_value(i, argc, arg, argv[i+1])) exit(1); video_parser.erase(); video_parser.append(argv[++i]); } else if (arg == "-vd") { if (!option_has_value(i, argc, arg, argv[i+1])) exit(1); video_decoder.erase(); video_decoder.append(argv[++i]); } else if (arg == "-vc") { if (!option_has_value(i, argc, arg, argv[i+1])) exit(1); video_converter.erase(); video_converter.append(argv[++i]); } else if (arg == "-vs") { if (!option_has_value(i, argc, arg, argv[i+1])) exit(1); videosink.erase(); videosink.append(argv[++i]); std::size_t pos = videosink.find(" "); if (pos != std::string::npos) { videosink_options.erase(); videosink_options = videosink.substr(pos); videosink.erase(pos); } } else if (arg == "-as") { if (!option_has_value(i, argc, arg, argv[i+1])) exit(1); audiosink.erase(); audiosink.append(argv[++i]); } else if (arg == "-t") { fprintf(stderr,"The uxplay option \"-t\" has been removed: it was a workaround for an Avahi issue.\n"); fprintf(stderr,"The correct solution is to open network port UDP 5353 in the firewall for mDNS queries\n"); exit(1); } else if (arg == "-nc") { new_window_closing_behavior = false; } else if (arg == "-avdec") { video_parser.erase(); video_parser = "h264parse"; video_decoder.erase(); video_decoder = "avdec_h264"; video_converter.erase(); video_converter = "videoconvert"; } else if (arg == "-v4l2") { video_decoder.erase(); video_decoder = "v4l2h264dec"; video_converter.erase(); video_converter = "v4l2convert"; } else if (arg == "-rpi" || arg == "-rpifb" || arg == "-rpigl" || arg == "-rpiwl") { fprintf(stderr,"*** -rpi* options do not apply to Raspberry Pi model 5, and have been removed\n"); fprintf(stderr," For models 3 and 4, use their equivalents, if needed:\n"); fprintf(stderr," -rpi was equivalent to \"-v4l2\"\n"); fprintf(stderr," -rpifb was equivalent to \"-v4l2 -vs kmssink\"\n"); fprintf(stderr," -rpigl was equivalent to \"-v4l2 -vs glimagesink\"\n"); fprintf(stderr," -rpiwl was equivalent to \"-v4l2 -vs waylandsink\"\n"); fprintf(stderr," for GStreamer < 1.22, \"-bt709\" may also be needed\n"); exit(1); } else if (arg == "-fs" ) { fullscreen = true; } else if (arg == "-FPSdata") { show_client_FPS_data = true; } else if (arg == "-reset") { max_ntp_timeouts = 0; if (!get_value(argv[++i], &max_ntp_timeouts)) { fprintf(stderr, "invalid \"-reset %s\"; -reset n must have n >= 0, default n = %d\n", argv[i], NTP_TIMEOUT_LIMIT); exit(1); } } else if (arg == "-vdmp") { dump_video = true; if (i < argc - 1 && *argv[i+1] != '-') { unsigned int n = 0; if (get_value (argv[++i], &n)) { if (n == 0) { fprintf(stderr, "invalid \"-vdmp 0 %s\"; -vdmp n needs a non-zero value of n\n", argv[i]); exit(1); } video_dump_limit = n; if (option_has_value(i, argc, arg, argv[i+1])) { video_dumpfile_name.erase(); video_dumpfile_name.append(argv[++i]); } } else { video_dumpfile_name.erase(); video_dumpfile_name.append(argv[i]); } const char *fn = video_dumpfile_name.c_str(); if (!file_has_write_access(fn)) { fprintf(stderr, "%s cannot be written to:\noption \"-vdmp \" must be to a file with write access\n", fn); exit(1); } } } else if (arg == "-admp") { dump_audio = true; if (i < argc - 1 && *argv[i+1] != '-') { unsigned int n = 0; if (get_value (argv[++i], &n)) { if (n == 0) { fprintf(stderr, "invalid \"-admp 0 %s\"; -admp n needs a non-zero value of n\n", argv[i]); exit(1); } audio_dump_limit = n; if (option_has_value(i, argc, arg, argv[i+1])) { audio_dumpfile_name.erase(); audio_dumpfile_name.append(argv[++i]); } } else { audio_dumpfile_name.erase(); audio_dumpfile_name.append(argv[i]); } const char *fn = audio_dumpfile_name.c_str(); if (!file_has_write_access(fn)) { fprintf(stderr, "%s cannot be written to:\noption \"-admp \" must be to a file with write access\n", fn); exit(1); } } } else if (arg == "-ca" ) { if (option_has_value(i, argc, arg, argv[i+1])) { coverart_filename.erase(); coverart_filename.append(argv[++i]); const char *fn = coverart_filename.c_str(); if (!file_has_write_access(fn)) { fprintf(stderr, "%s cannot be written to:\noption \"-ca \" must be to a file with write access\n", fn); exit(1); } } else { fprintf(stderr,"option -ca must be followed by a filename for cover-art output\n"); exit(1); } } else if (arg == "-bt709") { bt709_fix = true; } else if (arg == "-nohold") { nohold = 1; } else if (arg == "-al") { int n; char *end; if (i < argc - 1 && *argv[i+1] != '-') { n = (int) (strtof(argv[++i], &end) * SECOND_IN_USECS); if (*end == '\0' && n >=0 && n <= 10 * SECOND_IN_USECS) { audiodelay = n; continue; } } fprintf(stderr, "invalid -al %s: value must be a decimal time offset in seconds, range [0,10]\n" "(like 5 or 4.8, which will be converted to a whole number of microseconds)\n", argv[i]); exit(1); } else if (arg == "-pin") { setup_legacy_pairing = true; require_password = true; if (i < argc - 1 && *argv[i+1] != '-') { unsigned int n = 9999; if (!get_value(argv[++i], &n)) { fprintf(stderr, "invalid \"-pin %s\"; -pin nnnn : max nnnn=9999, (4 digits)\n", argv[i]); exit(1); } pin = n + 10000; } } else if (arg == "-reg") { registration_list = true; pairing_register.erase(); if (i < argc - 1 && *argv[i+1] != '-') { pairing_register.append(argv[++i]); const char * fn = pairing_register.c_str(); if (!file_has_write_access(fn)) { fprintf(stderr, "%s cannot be written to:\noption \"-key \" must be to a file with write access\n", fn); exit(1); } } } else if (arg == "-key") { keyfile.erase(); if (i < argc - 1 && *argv[i+1] != '-') { keyfile.append(argv[++i]); const char * fn = keyfile.c_str(); if (!file_has_write_access(fn)) { fprintf(stderr, "%s cannot be written to:\noption \"-key \" must be to a file with write access\n", fn); exit(1); } } else { // fprintf(stderr, "option \"-key \" requires a path to a file for persistent key storage\n"); // exit(1); keyfile.erase(); keyfile.append("0"); } } else if (arg == "-dacp") { dacpfile.erase(); if (i < argc - 1 && *argv[i+1] != '-') { dacpfile.append(argv[++i]); const char *fn = dacpfile.c_str(); if (!file_has_write_access(fn)) { fprintf(stderr, "%s cannot be written to:\noption \"-dacp \" must be to a file with write access\n", fn); exit(1); } } else { dacpfile.append(get_homedir()); dacpfile.append("/.uxplay.dacp"); } } else if (arg == "-taper") { taper_volume = true; } else if (arg == "-db") { bool db_bad = true; double db1, db2; char *start = NULL; if ( i < argc -1) { char *end1, *end2; start = argv[i+1]; db1 = strtod(start, &end1); if (end1 > start && *end1 == ':') { db2 = strtod(++end1, &end2); if ( *end2 == '\0' && end2 > end1 && db1 < 0 && db1 < db2) { db_bad = false; } } else if (*end1 =='\0' && end1 > start && db1 < 0 ) { db_bad = false; db2 = 0.0; } } if (db_bad) { fprintf(stderr, "invalid %s %s: db value must be \"low\" or \"low:high\", low < 0 and high > low are decibel gains\n", argv[i], start); exit(1); } i++; db_low = db1; db_high = db2; printf("db range %f:%f\n", db_low, db_high); } else if (arg == "-hls") { hls_support = true; } else if (arg == "-h265") { h265_support = true; } else if (arg == "-nofreeze") { nofreeze = true; } else { fprintf(stderr, "unknown option %s, stopping (for help use option \"-h\")\n",argv[i]); exit(1); } } } static void process_metadata(int count, const char *dmap_tag, const unsigned char* metadata, int datalen) { int dmap_type = 0; /* DMAP metadata items can be strings (dmap_type = 9); other types are byte, short, int, long, date, and list. * * The DMAP item begins with a 4-character (4-letter) "dmap_tag" string that identifies the type. */ if (debug_log) { printf("%d: dmap_tag [%s], %d\n", count, dmap_tag, datalen); } /* UTF-8 String-type DMAP tags seen in Apple Music Radio are processed here. * * (DMAP tags "asal", "asar", "ascp", "asgn", "minm" ). TODO expand this */ if (datalen == 0) { return; } if (dmap_tag[0] == 'a' && dmap_tag[1] == 's') { dmap_type = 9; switch (dmap_tag[2]) { case 'a': switch (dmap_tag[3]) { case 'a': printf("Album artist: "); /*asaa*/ break; case 'l': printf("Album: "); /*asal*/ break; case 'r': printf("Artist: "); /*asar*/ break; default: dmap_type = 0; break; } break; case 'c': switch (dmap_tag[3]) { case 'm': printf("Comment: "); /*ascm*/ break; case 'n': printf("Content description: "); /*ascn*/ break; case 'p': printf("Composer: "); /*ascp*/ break; case 't': printf("Category: "); /*asct*/ break; default: dmap_type = 0; break; } break; case 's': switch (dmap_tag[3]) { case 'a': printf("Sort Artist: "); /*assa*/ break; case 'c': printf("Sort Composer: "); /*assc*/ break; case 'l': printf("Sort Album artist: "); /*assl*/ break; case 'n': printf("Sort Name: "); /*assn*/ break; case 's': printf("Sort Series: "); /*asss*/ break; case 'u': printf("Sort Album: "); /*assu*/ break; default: dmap_type = 0; break; } break; default: if (strcmp(dmap_tag, "asdt") == 0) { printf("Description: "); } else if (strcmp (dmap_tag, "asfm") == 0) { printf("Format: "); } else if (strcmp (dmap_tag, "asgn") == 0) { printf("Genre: "); } else if (strcmp (dmap_tag, "asky") == 0) { printf("Keywords: "); } else if (strcmp (dmap_tag, "aslc") == 0) { printf("Long Content Description: "); } else { dmap_type = 0; } break; } } else if (strcmp (dmap_tag, "minm") == 0) { dmap_type = 9; printf("Title: "); } if (dmap_type == 9) { char *str = (char *) calloc(1, datalen + 1); memcpy(str, metadata, datalen); printf("%s", str); free(str); } else if (debug_log) { for (int i = 0; i < datalen; i++) { if (i > 0 && i % 16 == 0) printf("\n"); printf("%2.2x ", (int) metadata[i]); } } printf("\n"); } static int parse_dmap_header(const unsigned char *metadata, char *tag, int *len) { const unsigned char *header = metadata; bool istag = true; for (int i = 0; i < 4; i++) { tag[i] = (char) *header; if (!isalpha(tag[i])) { istag = false; } header++; } *len = 0; for (int i = 0; i < 4; i++) { *len <<= 8; *len += (int) *header; header++; } if (!istag || *len < 0) { return 1; } return 0; } static int register_dnssd() { int dnssd_error; uint64_t features; if ((dnssd_error = dnssd_register_raop(dnssd, raop_port))) { if (dnssd_error == -65537) { LOGE("No DNS-SD Server found (DNSServiceRegister call returned kDNSServiceErr_Unknown)"); } else if (dnssd_error == -65548) { LOGE("DNSServiceRegister call returned kDNSServiceErr_NameConflict"); LOGI("Is another instance of %s running with the same DeviceID (MAC address) or using same network ports?", DEFAULT_NAME); LOGI("Use options -m ... and -p ... to allow multiple instances of %s to run concurrently", DEFAULT_NAME); } else { LOGE("dnssd_register_raop failed with error code %d\n" "mDNS Error codes are in range FFFE FF00 (-65792) to FFFE FFFF (-65537) " "(see Apple's dns_sd.h)", dnssd_error); } return -3; } if ((dnssd_error = dnssd_register_airplay(dnssd, airplay_port))) { LOGE("dnssd_register_airplay failed with error code %d\n" "mDNS Error codes are in range FFFE FF00 (-65792) to FFFE FFFF (-65537) " "(see Apple's dns_sd.h)", dnssd_error); return -4; } LOGD("register_dnssd: advertised AirPlay service with \"Features\" code = 0x%llX", dnssd_get_airplay_features(dnssd)); return 0; } static void unregister_dnssd() { if (dnssd) { dnssd_unregister_raop(dnssd); dnssd_unregister_airplay(dnssd); } return; } static void stop_dnssd() { if (dnssd) { unregister_dnssd(); dnssd_destroy(dnssd); dnssd = NULL; return; } } static int start_dnssd(std::vector hw_addr, std::string name) { int dnssd_error; int require_pw = (require_password ? 1 : 0); if (dnssd) { LOGE("start_dnssd error: dnssd != NULL"); return 2; } dnssd = dnssd_init(name.c_str(), strlen(name.c_str()), hw_addr.data(), hw_addr.size(), &dnssd_error, require_pw); if (dnssd_error) { LOGE("Could not initialize dnssd library!: error %d", dnssd_error); return 1; } /* after dnssd starts, reset the default feature set here * (overwrites features set in dnssdint.h) * default: FEATURES_1 = 0x5A7FFEE6, FEATURES_2 = 0 */ dnssd_set_airplay_features(dnssd, 0, 0); // AirPlay video supported dnssd_set_airplay_features(dnssd, 1, 1); // photo supported dnssd_set_airplay_features(dnssd, 2, 1); // video protected with FairPlay DRM dnssd_set_airplay_features(dnssd, 3, 0); // volume control supported for videos dnssd_set_airplay_features(dnssd, 4, 0); // http live streaming (HLS) supported dnssd_set_airplay_features(dnssd, 5, 1); // slideshow supported dnssd_set_airplay_features(dnssd, 6, 1); // dnssd_set_airplay_features(dnssd, 7, 1); // mirroring supported dnssd_set_airplay_features(dnssd, 8, 0); // screen rotation supported dnssd_set_airplay_features(dnssd, 9, 1); // audio supported dnssd_set_airplay_features(dnssd, 10, 1); // dnssd_set_airplay_features(dnssd, 11, 1); // audio packet redundancy supported dnssd_set_airplay_features(dnssd, 12, 1); // FaiPlay secure auth supported dnssd_set_airplay_features(dnssd, 13, 1); // photo preloading supported dnssd_set_airplay_features(dnssd, 14, 1); // Authentication bit 4: FairPlay authentication dnssd_set_airplay_features(dnssd, 15, 1); // Metadata bit 1 support: Artwork dnssd_set_airplay_features(dnssd, 16, 1); // Metadata bit 2 support: Soundtrack Progress dnssd_set_airplay_features(dnssd, 17, 1); // Metadata bit 0 support: Text (DAACP) "Now Playing" info. dnssd_set_airplay_features(dnssd, 18, 1); // Audio format 1 support: dnssd_set_airplay_features(dnssd, 19, 1); // Audio format 2 support: must be set for AirPlay 2 multiroom audio dnssd_set_airplay_features(dnssd, 20, 1); // Audio format 3 support: must be set for AirPlay 2 multiroom audio dnssd_set_airplay_features(dnssd, 21, 1); // Audio format 4 support: dnssd_set_airplay_features(dnssd, 22, 1); // Authentication type 4: FairPlay authentication dnssd_set_airplay_features(dnssd, 23, 0); // Authentication type 1: RSA Authentication dnssd_set_airplay_features(dnssd, 24, 0); // dnssd_set_airplay_features(dnssd, 25, 1); // dnssd_set_airplay_features(dnssd, 26, 0); // Has Unified Advertiser info dnssd_set_airplay_features(dnssd, 27, 1); // Supports Legacy Pairing dnssd_set_airplay_features(dnssd, 28, 1); // dnssd_set_airplay_features(dnssd, 29, 0); // dnssd_set_airplay_features(dnssd, 30, 1); // RAOP support: with this bit set, the AirTunes service is not required. dnssd_set_airplay_features(dnssd, 31, 0); // /* bits 32-63: see https://emanualcozzi.net/docs/airplay2/features dnssd_set_airplay_features(dnssd, 32, 0); // isCarPlay when ON,; Supports InitialVolume when OFF dnssd_set_airplay_features(dnssd, 33, 0); // Supports Air Play Video Play Queue dnssd_set_airplay_features(dnssd, 34, 0); // Supports Air Play from cloud (requires that bit 6 is ON) dnssd_set_airplay_features(dnssd, 35, 0); // Supports TLS_PSK dnssd_set_airplay_features(dnssd, 36, 0); // dnssd_set_airplay_features(dnssd, 37, 0); // dnssd_set_airplay_features(dnssd, 38, 0); // Supports Unified Media Control (CoreUtils Pairing and Encryption) dnssd_set_airplay_features(dnssd, 39, 0); // dnssd_set_airplay_features(dnssd, 40, 0); // Supports Buffered Audio dnssd_set_airplay_features(dnssd, 41, 0); // Supports PTP dnssd_set_airplay_features(dnssd, 42, 0); // Supports Screen Multi Codec (allows h265 video) dnssd_set_airplay_features(dnssd, 43, 0); // Supports System Pairing dnssd_set_airplay_features(dnssd, 44, 0); // is AP Valeria Screen Sender dnssd_set_airplay_features(dnssd, 45, 0); // dnssd_set_airplay_features(dnssd, 46, 0); // Supports HomeKit Pairing and Access Control dnssd_set_airplay_features(dnssd, 47, 0); // dnssd_set_airplay_features(dnssd, 48, 0); // Supports CoreUtils Pairing and Encryption dnssd_set_airplay_features(dnssd, 49, 0); // dnssd_set_airplay_features(dnssd, 50, 0); // Metadata bit 3: "Now Playing" info sent by bplist not DAACP test dnssd_set_airplay_features(dnssd, 51, 0); // Supports Unified Pair Setup and MFi Authentication dnssd_set_airplay_features(dnssd, 52, 0); // Supports Set Peers Extended Message dnssd_set_airplay_features(dnssd, 53, 0); // dnssd_set_airplay_features(dnssd, 54, 0); // Supports AP Sync dnssd_set_airplay_features(dnssd, 55, 0); // Supports WoL dnssd_set_airplay_features(dnssd, 56, 0); // Supports Wol dnssd_set_airplay_features(dnssd, 57, 0); // dnssd_set_airplay_features(dnssd, 58, 0); // Supports Hangdog Remote Control dnssd_set_airplay_features(dnssd, 59, 0); // Supports AudioStreamConnection setup dnssd_set_airplay_features(dnssd, 60, 0); // Supports Audo Media Data Control dnssd_set_airplay_features(dnssd, 61, 0); // Supports RFC2198 redundancy */ /* needed for HLS video support */ dnssd_set_airplay_features(dnssd, 0, (int) hls_support); dnssd_set_airplay_features(dnssd, 4, (int) hls_support); // not sure about this one (bit 8, screen rotation supported): //dnssd_set_airplay_features(dnssd, 8, (int) hls_support); /* needed for h265 video support */ dnssd_set_airplay_features(dnssd, 42, (int) h265_support); /* bit 27 of Features determines whether the AirPlay2 client-pairing protocol will be used (1) or not (0) */ dnssd_set_airplay_features(dnssd, 27, (int) setup_legacy_pairing); return 0; } static bool check_client(char *deviceid) { bool ret = false; int list = allowed_clients.size(); for (int i = 0; i < list ; i++) { if (!strcmp(deviceid,allowed_clients[i].c_str())) { ret = true; break; } } return ret; } static bool check_blocked_client(char *deviceid) { bool ret = false; int list = blocked_clients.size(); for (int i = 0; i < list ; i++) { if (!strcmp(deviceid,blocked_clients[i].c_str())) { ret = true; break; } } return ret; } // Server callbacks extern "C" void video_reset(void *cls) { LOGD("video_reset"); url.erase(); reset_loop = true; remote_clock_offset = 0; relaunch_video = true; } extern "C" void video_set_codec(void *cls, video_codec_t codec) { if (use_video) { bool video_is_h265 = (codec == VIDEO_CODEC_H265); video_renderer_choose_codec(video_is_h265); } } extern "C" void display_pin(void *cls, char *pin) { int margin = 10; int spacing = 3; char *image = create_pin_display(pin, margin, spacing); if (!image) { LOGE("create_pin_display could not create pin image, pin = %s", pin); } else { LOGI("%s\n",image); free (image); } } extern "C" void export_dacp(void *cls, const char *active_remote, const char *dacp_id) { if (dacpfile.length()) { FILE *fp = fopen(dacpfile.c_str(), "w"); if (fp) { fprintf(fp,"%s\n%s\n", dacp_id, active_remote); fclose(fp); } else { LOGE("failed to open DACP export file \"%s\"", dacpfile.c_str()); } } } extern "C" void conn_init (void *cls) { open_connections++; LOGD("Open connections: %i", open_connections); //video_renderer_update_background(1); } extern "C" void conn_destroy (void *cls) { //video_renderer_update_background(-1); open_connections--; LOGD("Open connections: %i", open_connections); if (open_connections == 0) { remote_clock_offset = 0; if (use_audio) { audio_renderer_stop(); } if (dacpfile.length()) { remove (dacpfile.c_str()); } } } extern "C" void conn_reset (void *cls, int timeouts, bool reset_video) { LOGI("***ERROR lost connection with client (network problem?)"); if (timeouts) { LOGI(" Client no-response limit of %d timeouts (%d seconds) reached:", timeouts, 3*timeouts); LOGI(" Sometimes the network connection may recover after a longer delay:\n" " the default timeout limit n = %d can be changed with the \"-reset n\" option", NTP_TIMEOUT_LIMIT); } if (!nofreeze) { close_window = reset_video; /* leave "frozen" window open if reset_video is false */ } raop_stop(raop); reset_loop = true; } extern "C" void conn_teardown(void *cls, bool *teardown_96, bool *teardown_110) { if (*teardown_110 && close_window) { reset_loop = true; } } extern "C" void report_client_request(void *cls, char *deviceid, char * model, char *name, bool * admit) { LOGI("connection request from %s (%s) with deviceID = %s\n", name, model, deviceid); if (restrict_clients) { *admit = check_client(deviceid); if (*admit == false) { LOGI("client connections have been restricted to those with listed deviceID,\nuse \"-allow %s\" to allow this client to connect.\n", deviceid); } } else { *admit = true; } if (check_blocked_client(deviceid)) { *admit = false; LOGI("*** attempt to connect by blocked client (clientID %s): DENIED\n", deviceid); } } extern "C" void audio_process (void *cls, raop_ntp_t *ntp, audio_decode_struct *data) { if (dump_audio) { dump_audio_to_file(data->data, data->data_len, (data->data)[0] & 0xf0); } if (use_audio) { if (!remote_clock_offset) { remote_clock_offset = data->ntp_time_local - data->ntp_time_remote; } data->ntp_time_remote = data->ntp_time_remote + remote_clock_offset; switch (data->ct) { case 2: if (audio_delay_alac) { data->ntp_time_remote = (uint64_t) ((int64_t) data->ntp_time_remote + audio_delay_alac); } break; case 4: case 8: if (audio_delay_aac) { data->ntp_time_remote = (uint64_t) ((int64_t) data->ntp_time_remote + audio_delay_aac); } break; default: break; } audio_renderer_render_buffer(data->data, &(data->data_len), &(data->seqnum), &(data->ntp_time_remote)); } } extern "C" void video_process (void *cls, raop_ntp_t *ntp, video_decode_struct *data) { if (dump_video) { dump_video_to_file(data->data, data->data_len); } if (use_video) { if (!remote_clock_offset) { remote_clock_offset = data->ntp_time_local - data->ntp_time_remote; } data->ntp_time_remote = data->ntp_time_remote + remote_clock_offset; video_renderer_render_buffer(data->data, &(data->data_len), &(data->nal_count), &(data->ntp_time_remote)); } } extern "C" void video_pause (void *cls) { if (use_video) { video_renderer_pause(); } } extern "C" void video_resume (void *cls) { if (use_video) { video_renderer_resume(); } } extern "C" void audio_flush (void *cls) { if (use_audio) { audio_renderer_flush(); } } extern "C" void video_flush (void *cls) { if (use_video) { video_renderer_flush(); } } extern "C" void audio_set_volume (void *cls, float volume) { double db, db_flat, frac, gst_volume; if (!use_audio) { return; } /* convert from AirPlay dB volume in range {-30dB : 0dB}, to GStreamer volume */ if (volume == -144.0f) { /* AirPlay "mute" signal */ frac = 0.0; } else if (volume < -30.0f) { LOGE(" invalid AirPlay volume %f", volume); frac = 0.0; } else if (volume > 0.0f) { LOGE(" invalid AirPlay volume %f", volume); frac = 1.0; } else if (volume == -30.0f) { frac = 0.0; } else if (volume == 0.0f) { frac = 1.0; } else { frac = (double) ( (30.0f + volume) / 30.0f); frac = (frac > 1.0) ? 1.0 : frac; } /* frac is length of volume slider as fraction of max length */ /* also (steps/16) where steps is number of discrete steps above mute (16 = full volume) */ if (frac == 0.0) { gst_volume = 0.0; } else { /* flat rescaling of decibel range from {-30dB : 0dB} to {db_low : db_high} */ db_flat = db_low + (db_high-db_low) * frac; if (taper_volume) { /* taper the volume reduction by the (rescaled) Airplay {-30:0} range so each reduction of * the remaining slider length by 50% reduces the perceived volume by 50% (-10dB gain) * (This is the "dasl-tapering" scheme offered by shairport-sync) */ db = db_high + 10.0 * (log10(frac) / log10(2.0)); db = (db > db_flat) ? db : db_flat; } else { db = db_flat; } /* conversion from (gain) decibels to GStreamer's linear volume scale */ gst_volume = pow(10.0, 0.05*db); } audio_renderer_set_volume(gst_volume); } extern "C" void audio_get_format (void *cls, unsigned char *ct, unsigned short *spf, bool *usingScreen, bool *isMedia, uint64_t *audioFormat) { unsigned char type; LOGI("ct=%d spf=%d usingScreen=%d isMedia=%d audioFormat=0x%lx",*ct, *spf, *usingScreen, *isMedia, (unsigned long) *audioFormat); switch (*ct) { case 2: type = 0x20; break; case 8: type = 0x80; break; default: type = 0x10; break; } if (audio_dumpfile && type != audio_type) { fclose(audio_dumpfile); audio_dumpfile = NULL; } audio_type = type; if (use_audio) { audio_renderer_start(ct); } if (coverart_filename.length()) { write_coverart(coverart_filename.c_str(), (const void *) empty_image, sizeof(empty_image)); } } extern "C" void video_report_size(void *cls, float *width_source, float *height_source, float *width, float *height) { if (use_video) { video_renderer_size(width_source, height_source, width, height); } } extern "C" void audio_set_coverart(void *cls, const void *buffer, int buflen) { if (buffer && coverart_filename.length()) { write_coverart(coverart_filename.c_str(), buffer, buflen); LOGI("coverart size %d written to %s", buflen, coverart_filename.c_str()); } } extern "C" void audio_set_progress(void *cls, unsigned int start, unsigned int curr, unsigned int end) { int duration = (int) (end - start)/44100; int position = (int) (curr - start)/44100; int remain = duration - position; printf("audio progress (min:sec): %d:%2.2d; remaining: %d:%2.2d; track length %d:%2.2d\n", position/60, position%60, remain/60, remain%60, duration/60, duration%60); } extern "C" void audio_set_metadata(void *cls, const void *buffer, int buflen) { char dmap_tag[5] = {0x0}; const unsigned char *metadata = (const unsigned char *) buffer; int datalen; int count = 0; printf("==============Audio Metadata=============\n"); if (buflen < 8) { LOGE("received invalid metadata, length %d < 8", buflen); return; } else if (parse_dmap_header(metadata, dmap_tag, &datalen)) { LOGE("received invalid metadata, tag [%s] datalen %d", dmap_tag, datalen); return; } metadata += 8; buflen -= 8; if (strcmp(dmap_tag, "mlit") != 0 || datalen != buflen) { LOGE("received metadata with tag %s, but is not a DMAP listingitem, or datalen = %d != buflen %d", dmap_tag, datalen, buflen); return; } while (buflen >= 8) { count++; if (parse_dmap_header(metadata, dmap_tag, &datalen)) { LOGE("received metadata with invalid DMAP header: tag = [%s], datalen = %d", dmap_tag, datalen); return; } metadata += 8; buflen -= 8; process_metadata(count, (const char *) dmap_tag, metadata, datalen); metadata += datalen; buflen -= datalen; } if (buflen != 0) { LOGE("%d bytes of metadata were not processed", buflen); } } extern "C" void register_client(void *cls, const char *device_id, const char *client_pk, const char *client_name) { if (!registration_list) { /* we are not maintaining a list of registered clients */ return; } LOGI("registered new client: %s DeviceID = %s PK = \n%s", client_name, device_id, client_pk); registered_keys.push_back(client_pk); if (strlen(pairing_register.c_str())) { FILE *fp = fopen(pairing_register.c_str(), "a"); if (fp) { fprintf(fp, "%s,%s,%s\n", client_pk, device_id, client_name); fclose(fp); } } } extern "C" bool check_register(void *cls, const char *client_pk) { if (!registration_list) { /* we are not maintaining a list of registered clients */ return true; } LOGD("check returning client's pairing registration"); std::string pk = client_pk; if (std::find(registered_keys.rbegin(), registered_keys.rend(), pk) != registered_keys.rend()) { LOGD("registration found: PK=%s", client_pk); return true; } else { LOGE("returning client's pairing registration not found: PK=%s", client_pk); return false; } } /* control callbacks for video player (unimplemented) */ extern "C" void on_video_play(void *cls, const char* location, const float start_position) { /* start_position needs to be implemented */ url.erase(); url.append(location); reset_loop = true; relaunch_video = true; preserve_connections = true; LOGD("********************on_video_play: location = %s***********************", url.c_str()); } extern "C" void on_video_scrub(void *cls, const float position) { LOGI("on_video_scrub: position = %7.5f\n", position); video_renderer_seek(position); } extern "C" void on_video_rate(void *cls, const float rate) { LOGI("on_video_rate = %7.5f\n", rate); if (rate == 1.0f) { video_renderer_resume(); } else if (rate == 0.0f) { video_renderer_pause(); } else { LOGI("on_video_rate: ignoring unexpected value rate = %f\n", rate); } } extern "C" void on_video_stop(void *cls) { LOGI("on_video_stop\n"); } extern "C" void on_video_acquire_playback_info (void *cls, playback_info_t *playback_info) { int buffering_level; LOGD("on_video_acquire_playback info\n"); bool still_playing = video_get_playback_info(&playback_info->duration, &playback_info->position, &playback_info->rate); LOGD("on_video_acquire_playback info done\n"); if (!still_playing) { LOGI(" video has finished, %f", playback_info->position); playback_info->position = -1.0; playback_info->duration = -1.0; video_renderer_stop(); } } extern "C" void log_callback (void *cls, int level, const char *msg) { switch (level) { case LOGGER_DEBUG: { LOGD("%s", msg); break; } case LOGGER_WARNING: { LOGW("%s", msg); break; } case LOGGER_INFO: { LOGI("%s", msg); break; } case LOGGER_ERR: { LOGE("%s", msg); break; } default: break; } } static int start_raop_server (unsigned short display[5], unsigned short tcp[3], unsigned short udp[3], bool debug_log) { raop_callbacks_t raop_cbs; memset(&raop_cbs, 0, sizeof(raop_cbs)); raop_cbs.conn_init = conn_init; raop_cbs.conn_destroy = conn_destroy; raop_cbs.conn_reset = conn_reset; raop_cbs.conn_teardown = conn_teardown; raop_cbs.audio_process = audio_process; raop_cbs.video_process = video_process; raop_cbs.audio_flush = audio_flush; raop_cbs.video_flush = video_flush; raop_cbs.video_pause = video_pause; raop_cbs.video_resume = video_resume; raop_cbs.audio_set_volume = audio_set_volume; raop_cbs.audio_get_format = audio_get_format; raop_cbs.video_report_size = video_report_size; raop_cbs.audio_set_metadata = audio_set_metadata; raop_cbs.audio_set_coverart = audio_set_coverart; raop_cbs.audio_set_progress = audio_set_progress; raop_cbs.report_client_request = report_client_request; raop_cbs.display_pin = display_pin; raop_cbs.register_client = register_client; raop_cbs.check_register = check_register; raop_cbs.export_dacp = export_dacp; raop_cbs.video_reset = video_reset; raop_cbs.video_set_codec = video_set_codec; raop_cbs.on_video_play = on_video_play; raop_cbs.on_video_scrub = on_video_scrub; raop_cbs.on_video_rate = on_video_rate; raop_cbs.on_video_stop = on_video_stop; raop_cbs.on_video_acquire_playback_info = on_video_acquire_playback_info; raop = raop_init(&raop_cbs); if (raop == NULL) { LOGE("Error initializing raop!"); return -1; } raop_set_log_callback(raop, log_callback, NULL); raop_set_log_level(raop, log_level); /* set nohold = 1 to allow capture by new client */ if (raop_init2(raop, nohold, mac_address.c_str(), keyfile.c_str())){ LOGE("Error initializing raop (2)!"); free (raop); return -1; } /* write desired display pixel width, pixel height, refresh_rate, max_fps, overscanned. */ /* use 0 for default values 1920,1080,60,30,0; these are sent to the Airplay client */ if (display[0]) raop_set_plist(raop, "width", (int) display[0]); if (display[1]) raop_set_plist(raop, "height", (int) display[1]); if (display[2]) raop_set_plist(raop, "refreshRate", (int) display[2]); if (display[3]) raop_set_plist(raop, "maxFPS", (int) display[3]); if (display[4]) raop_set_plist(raop, "overscanned", (int) display[4]); if (show_client_FPS_data) raop_set_plist(raop, "clientFPSdata", 1); raop_set_plist(raop, "max_ntp_timeouts", max_ntp_timeouts); if (audiodelay >= 0) raop_set_plist(raop, "audio_delay_micros", audiodelay); if (require_password) raop_set_plist(raop, "pin", (int) pin); if (hls_support) raop_set_plist(raop, "hls", 1); /* network port selection (ports listed as "0" will be dynamically assigned) */ raop_set_tcp_ports(raop, tcp); raop_set_udp_ports(raop, udp); raop_port = raop_get_port(raop); raop_start(raop, &raop_port); raop_set_port(raop, raop_port); /* use raop_port for airplay_port (instead of tcp[2]) */ airplay_port = raop_port; if (dnssd) { raop_set_dnssd(raop, dnssd); } else { LOGE("raop_set failed to set dnssd"); return -2; } return 0; } static void stop_raop_server () { if (raop) { raop_destroy(raop); raop = NULL; } return; } static void read_config_file(const char * filename, const char * uxplay_name) { std::string config_file = filename; std::string option_char = "-"; std::vector options; options.push_back(uxplay_name); std::ifstream file(config_file); if (file.is_open()) { fprintf(stdout,"UxPlay: reading configuration from %s\n", config_file.c_str()); std::string line; while (std::getline(file, line)) { if (line[0] == '#') continue; // first process line into separate option items with '\0' as delimiter bool is_part_of_item, in_quotes; char endchar; is_part_of_item = false; for (int i = 0; i < (int) line.size(); i++) { if (is_part_of_item == false) { if (line[i] == ' ') { line[i] = '\0'; } else { // start of new item is_part_of_item = true; switch (line[i]) { case '\'': case '\"': endchar = line[i]; line[i] = '\0'; in_quotes = true; break; default: in_quotes = false; endchar = ' '; break; } } } else { /* previous character was inside this item */ if (line[i] == endchar) { if (in_quotes) { /* cases where endchar is inside quoted item */ if (i > 0 && line[i - 1] == '\\') continue; if (i + 1 < (int) line.size() && line[i + 1] != ' ') continue; } line[i] = '\0'; is_part_of_item = false; } } } // now tokenize the processed line std::istringstream iss(line); std::string token; bool first = true; while (std::getline(iss, token, '\0')) { if (token.size() > 0) { if (first) { options.push_back(option_char + token.c_str()); first = false; } else { options.push_back(token.c_str()); } } } } file.close(); } else { fprintf(stderr,"UxPlay: failed to open configuration file at %s\n", config_file.c_str()); } if (options.size() > 1) { int argc = options.size(); char **argv = (char **) malloc(sizeof(char*) * argc); for (int i = 0; i < argc; i++) { argv[i] = (char *) options[i].c_str(); } parse_arguments (argc, argv); free (argv); } } #ifdef GST_MACOS /* workaround for GStreamer >= 1.22 "Official Builds" on macOS */ #include #include void real_main (int argc, char *argv[]); int main (int argc, char *argv[]) { LOGI("*=== Using gst_macos_main wrapper for GStreamer >= 1.22 on macOS ===*"); return gst_macos_main ((GstMainFunc) real_main, argc, argv , NULL); } void real_main (int argc, char *argv[]) { #else int main (int argc, char *argv[]) { #endif std::vector server_hw_addr; std::string config_file = ""; #ifdef SUPPRESS_AVAHI_COMPAT_WARNING // suppress avahi_compat nag message. avahi emits a "nag" warning (once) // if getenv("AVAHI_COMPAT_NOWARN") returns null. static char avahi_compat_nowarn[] = "AVAHI_COMPAT_NOWARN=1"; if (!getenv("AVAHI_COMPAT_NOWARN")) putenv(avahi_compat_nowarn); #endif config_file = find_uxplay_config_file(); if (config_file.length()) { read_config_file(config_file.c_str(), argv[0]); } parse_arguments (argc, argv); log_level = (debug_log ? LOGGER_DEBUG : LOGGER_INFO); #ifdef _WIN32 /* use utf-8 terminal output; don't buffer stdout in WIN32 when debug_log = false */ SetConsoleOutputCP(CP_UTF8); if (!debug_log) { setbuf(stdout, NULL); } #endif LOGI("UxPlay %s: An Open-Source AirPlay mirroring and audio-streaming server.", VERSION); if (audiosink == "0") { use_audio = false; dump_audio = false; } if (dump_video) { if (video_dump_limit > 0) { LOGI("dump video using \"-vdmp %d %s\"", video_dump_limit, video_dumpfile_name.c_str()); } else { LOGI("dump video using \"-vdmp %s\"", video_dumpfile_name.c_str()); } } if (dump_audio) { if (audio_dump_limit > 0) { LOGI("dump audio using \"-admp %d %s\"", audio_dump_limit, audio_dumpfile_name.c_str()); } else { LOGI("dump audio using \"-admp %s\"", audio_dumpfile_name.c_str()); } } #if __APPLE__ /* force use of -nc option on macOS */ LOGI("macOS detected: using -nc option as workaround for GStreamer problem"); new_window_closing_behavior = false; #endif if (videosink == "0") { use_video = false; videosink.erase(); videosink.append("fakesink"); videosink_options.erase(); LOGI("video_disabled"); display[3] = 1; /* set fps to 1 frame per sec when no video will be shown */ } if (fullscreen && use_video) { if (videosink == "waylandsink" || videosink == "vaapisink") { videosink_options.append(" fullscreen=true"); } } if (videosink == "d3d11videosink" && videosink_options.empty() && use_video) { if (fullscreen) { videosink_options.append(" fullscreen-toggle-mode=GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_PROPERTY fullscreen=true "); } else { videosink_options.append(" fullscreen-toggle-mode=GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_ALT_ENTER "); } LOGI("d3d11videosink is being used with option fullscreen-toggle-mode=alt-enter\n" "Use Alt-Enter key combination to toggle into/out of full-screen mode"); } if (bt709_fix && use_video) { video_parser.append(" ! "); video_parser.append(BT709_FIX); } if (require_password && registration_list) { if (pairing_register == "") { const char * homedir = get_homedir(); if (homedir) { pairing_register = homedir; pairing_register.append("/.uxplay.register"); } } } /* read in public keys that were previously registered with pair-setup-pin */ if (require_password && registration_list && strlen(pairing_register.c_str())) { size_t len = 0; std::string key; int clients = 0; std::ifstream file(pairing_register); if (file.is_open()) { std::string line; while (std::getline(file, line)) { /*32 bytes pk -> base64 -> strlen(pk64) = 44 chars = line[0:43]; add '\0' at line[44] */ line[44] = '\0'; std::string pk = line.c_str(); registered_keys.push_back(key.assign(pk)); clients ++; } if (clients) { LOGI("Register %s lists %d pin-registered clients", pairing_register.c_str(), clients); } file.close(); } } if (require_password && keyfile == "0") { const char * homedir = get_homedir(); if (homedir) { keyfile.erase(); keyfile = homedir; keyfile.append("/.uxplay.pem"); } else { LOGE("could not determine $HOME: public key wiil not be saved, and so will not be persistent"); } } if (keyfile != "") { LOGI("public key storage (for persistence) is in %s", keyfile.c_str()); } if (do_append_hostname) { append_hostname(server_name); } if (!gstreamer_init()) { LOGE ("stopping"); exit (1); } render_logger = logger_init(); logger_set_callback(render_logger, log_callback, NULL); logger_set_level(render_logger, log_level); if (use_audio) { audio_renderer_init(render_logger, audiosink.c_str(), &audio_sync, &video_sync); } else { LOGI("audio_disabled"); } if (use_video) { video_renderer_init(render_logger, server_name.c_str(), videoflip, video_parser.c_str(), video_decoder.c_str(), video_converter.c_str(), videosink.c_str(), videosink_options.c_str(), fullscreen, video_sync, h265_support, NULL); video_renderer_start(); } if (udp[0]) { LOGI("using network ports UDP %d %d %d TCP %d %d %d", udp[0], udp[1], udp[2], tcp[0], tcp[1], tcp[2]); } if (!use_random_hw_addr) { if (strlen(mac_address.c_str()) == 0) { mac_address = find_mac(); LOGI("using system MAC address %s",mac_address.c_str()); } else { LOGI("using user-set MAC address %s",mac_address.c_str()); } } if (mac_address.empty()) { srand(time(NULL) * getpid()); mac_address = random_mac(); LOGI("using randomly-generated MAC address %s",mac_address.c_str()); } parse_hw_addr(mac_address, server_hw_addr); if (coverart_filename.length()) { LOGI("any AirPlay audio cover-art will be written to file %s",coverart_filename.c_str()); write_coverart(coverart_filename.c_str(), (const void *) empty_image, sizeof(empty_image)); } /* set default resolutions for h264 or h265*/ if (!display[0] && !display[1]) { if (h265_support) { display[0] = 3840; display[1] = 2160; } else { display[0] = 1920; display[1] = 1080; } } restart: if (start_dnssd(server_hw_addr, server_name)) { goto cleanup; } if (start_raop_server(display, tcp, udp, debug_log)) { stop_dnssd(); goto cleanup; } if (register_dnssd()) { stop_raop_server(); stop_dnssd(); goto cleanup; } reconnect: compression_type = 0; close_window = new_window_closing_behavior; main_loop(); if (relaunch_video || reset_loop) { if(reset_loop) { reset_loop = false; } else { raop_stop(raop); } if (use_audio) audio_renderer_stop(); if (use_video && (close_window || preserve_connections)) { video_renderer_destroy(); if (!preserve_connections) { raop_destroy_airplay_video(raop); url.erase(); raop_remove_known_connections(raop); } preserve_connections = false; const char *uri = (url.empty() ? NULL : url.c_str()); video_renderer_init(render_logger, server_name.c_str(), videoflip, video_parser.c_str(), video_decoder.c_str(), video_converter.c_str(), videosink.c_str(), videosink_options.c_str(), fullscreen, video_sync, h265_support, uri); video_renderer_start(); } if (relaunch_video) { unsigned short port = raop_get_port(raop); raop_start(raop, &port); raop_set_port(raop, port); goto reconnect; } else { LOGI("Re-launching RAOP server..."); stop_raop_server(); stop_dnssd(); goto restart; } } else { LOGI("Stopping..."); stop_raop_server(); stop_dnssd(); } cleanup: if (use_audio) { audio_renderer_destroy(); } if (use_video) { video_renderer_destroy(); } logger_destroy(render_logger); render_logger = NULL; if(audio_dumpfile) { fclose(audio_dumpfile); } if (video_dumpfile) { fwrite(mark, 1, sizeof(mark), video_dumpfile); fclose(video_dumpfile); } if (coverart_filename.length()) { remove (coverart_filename.c_str()); } } UxPlay-1.71.1/uxplay.spec000066400000000000000000000077251473013662600152440ustar00rootroot00000000000000Name: uxplay Version: 1.71.1 Release: 1%{?dist} %global gittag v%{version} Summary: AirPlay-Mirror and AirPlay-Audio server License: GPLv3+ URL: https://github.com/FDH2/UxPlay Source0: https://github.com/FDH2/UxPlay/archive/%{gittag}/%{name}-%{version}.tar.gz Packager: UxPlay maintainer BuildRequires: cmake >= 3.5 BuildRequires: make BuildRequires: gcc BuildRequires: gcc-c++ Requires: avahi #RedHat and clones %if %{defined fedora} || %{defined rhel} BuildRequires: pkgconf BuildRequires: openssl-devel >= 3.0 BuildRequires: libplist-devel >= 2.0 BuildRequires: avahi-compat-libdns_sd-devel BuildRequires: gstreamer1-devel BuildRequires: gstreamer1-plugins-base-devel Requires: openssl-libs >= 3.0 Requires: libplist >= 2.0 Requires: gstreamer1-plugins-base Requires: gstreamer1-plugins-good Requires: gstreamer1-plugins-bad-free Requires: gstreamer1-libav %define cmake_builddir redhat-linux-build %endif #SUSE %if "%{_host_vendor}" == "suse" BuildRequires: pkg-config BuildRequires: libopenssl-3-devel BuildRequires: libplist-2_0-devel BuildRequires: avahi-compat-mDNSResponder-devel BuildRequires: gstreamer-devel BuildRequires: gstreamer-plugins-base-devel Requires: libopenssl3 Requires: libplist-2_0-3 Requires: gstreamer-plugins-base Requires: gstreamer-plugins-good Requires: gstreamer-plugins-bad Requires: gstreamer-plugins-libav %endif #Mageia, OpenMandriva, PCLinuxOS (Mandriva/Mandrake descendents) %if "%{_host_vendor}" == "mageia" || %{defined omvver} || "%{_host_vendor}" == "mandriva" %if "%{_host_vendor}" == "mandriva" # host_vendor = "mandriva" identifies PCLinuxOS. # As of 07/2023, PCLinuxOS does not seem to supply openssl >= 3.0. # Note that UxPlay does not have a "GPL exception" allowing it to be # distributed in binary form when linked to openssl < 3.0, unless that # OpenSSL < 3.0 qualifies as a "system library". BuildRequires: pkgconfig BuildRequires: %{mklibname openssl-devel} >= 1.1.1 Requires: %{mklibname openssl1.1.0} %else BuildRequires: pkgconf BuildRequires: %{mklibname openssl-devel} >= 3.0 %if %{defined omvver} Requires: openssl >= 3.0 %else Requires: %{mklibname openssl3} %endif %endif BuildRequires: %{mklibname plist-devel} >= 2.0 BuildRequires: %{mklibname avahi-compat-libdns_sd-devel} %if %{defined omvver} BuildRequires: %{mklibname gstreamer-devel} BuildRequires: %{mklibname gst-plugins-base1.0-devel} Requires: %{mklibname plist} >= 2.0 %else BuildRequires: %{mklibname gstreamer1.0-devel} BuildRequires: %{mklibname gstreamer-plugins-base1.0-devel} Requires: %{mklibname plist2.0_3} %endif Requires: gstreamer1.0-plugins-base Requires: gstreamer1.0-plugins-good Requires: gstreamer1.0-plugins-bad Requires: gstreamer1.0-libav %endif %description An AirPlay2 Mirror and AirPlay2 Audio (but not Video) server that provides screen-mirroring (with audio) of iOS/MacOS clients in a display window on the server host (which can be shared using a screen-sharing application); Apple Lossless Audio (ALAC) (e.g.,iTunes) can be streamed from client to server in non-mirror mode %prep %autosetup -n UxPlay-%{version} # if you are building for a distribution, add cmake option -DNO_MARCH_NATIVE=ON %cmake -DCMAKE_INSTALL_DOCDIR=%{_docdir}/%{name} %build %if %{defined cmake_builddir} cd %{cmake_builddir} %else cd build %endif %make_build %install %if %{defined cmake_builddir} cd %{cmake_builddir} %else cd build %endif %make_install %files %{_bindir}/uxplay %{_mandir}/man1/uxplay.1* %doc %{_docdir}/%{name}/README.txt %{_docdir}/%{name}/README.html %{_docdir}/%{name}/README.md %license %{_docdir}/%{name}/LICENSE %{_docdir}/%{name}/llhttp/LICENSE-MIT %changelog * Fri Nov 15 2024 UxPlay maintainer Initial uxplay.spec: tested on Fedora 38, Rocky Linux 9.2, OpenSUSE Leap 15.5, Mageia 9, OpenMandriva ROME, PCLinuxOS -