From cfdde9f1e8b2dfc4a154657611b033f61e30d473 Mon Sep 17 00:00:00 2001 From: Lanchon Date: Wed, 9 Aug 2017 06:26:31 -0300 Subject: [PATCH] Fork multidexlib2 from its DexPatcher-tool subproject to a separate repo Source: https://github.com/DexPatcher/dexpatcher-tool/tree/0589091706fb14dad26416b143cfb285c95c1126/multidexlib2 --- .gitignore | 7 + .idea/codeStyleSettings.xml | 31 + .idea/compiler.xml | 19 + .idea/copyright/Default.xml | 6 + .idea/copyright/profiles_settings.xml | 3 + .idea/gradle.xml | 17 + .idea/misc.xml | 12 + .idea/modules.xml | 10 + .idea/modules/dexpatcher-multidexlib2.iml | 13 + .../modules/dexpatcher-multidexlib2_main.iml | 18 + .../modules/dexpatcher-multidexlib2_test.iml | 20 + .idea/uiDesigner.xml | 124 ++++ .idea/vcs.xml | 6 + LICENSE.txt | 674 ++++++++++++++++++ NOTICE.txt | 17 + build.gradle | 119 ++++ gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 53324 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 164 +++++ gradlew.bat | 90 +++ .../com/google/common/io/ByteStreamsHack.java | 34 + .../AbstractMultiDexContainer.java | 75 ++ .../multidexlib2/BasicDexFileNamer.java | 60 ++ .../multidexlib2/BasicMultiDexFile.java | 53 ++ .../multidexlib2/DexFileNameComparator.java | 38 + .../multidexlib2/DexFileNameIterator.java | 61 ++ .../lanchon/multidexlib2/DexFileNamer.java | 20 + src/main/java/lanchon/multidexlib2/DexIO.java | 186 +++++ .../DexPoolOverflowException.java | 19 + .../lanchon/multidexlib2/DexVersionMap.java | 47 ++ .../multidexlib2/DirectoryDexContainer.java | 39 + .../DuplicateEntryNameException.java | 19 + .../multidexlib2/DuplicateTypeException.java | 19 + .../EmptyMultiDexContainerException.java | 19 + .../MultiDexContainerBackedDexFile.java | 61 ++ .../MultiDexDetectedException.java | 19 + .../java/lanchon/multidexlib2/MultiDexIO.java | 125 ++++ .../lanchon/multidexlib2/OpcodeUtils.java | 44 ++ .../java/lanchon/multidexlib2/RawDexIO.java | 80 +++ .../multidexlib2/SingletonDexContainer.java | 37 + .../multidexlib2/ZipFileDexContainer.java | 65 ++ src/main/resources/LICENSE.txt | 674 ++++++++++++++++++ 42 files changed, 3150 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/codeStyleSettings.xml create mode 100644 .idea/compiler.xml create mode 100644 .idea/copyright/Default.xml create mode 100644 .idea/copyright/profiles_settings.xml create mode 100644 .idea/gradle.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/modules/dexpatcher-multidexlib2.iml create mode 100644 .idea/modules/dexpatcher-multidexlib2_main.iml create mode 100644 .idea/modules/dexpatcher-multidexlib2_test.iml create mode 100644 .idea/uiDesigner.xml create mode 100644 .idea/vcs.xml create mode 100644 LICENSE.txt create mode 100644 NOTICE.txt create mode 100644 build.gradle create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat create mode 100644 src/main/java/com/google/common/io/ByteStreamsHack.java create mode 100644 src/main/java/lanchon/multidexlib2/AbstractMultiDexContainer.java create mode 100644 src/main/java/lanchon/multidexlib2/BasicDexFileNamer.java create mode 100644 src/main/java/lanchon/multidexlib2/BasicMultiDexFile.java create mode 100644 src/main/java/lanchon/multidexlib2/DexFileNameComparator.java create mode 100644 src/main/java/lanchon/multidexlib2/DexFileNameIterator.java create mode 100644 src/main/java/lanchon/multidexlib2/DexFileNamer.java create mode 100644 src/main/java/lanchon/multidexlib2/DexIO.java create mode 100644 src/main/java/lanchon/multidexlib2/DexPoolOverflowException.java create mode 100644 src/main/java/lanchon/multidexlib2/DexVersionMap.java create mode 100644 src/main/java/lanchon/multidexlib2/DirectoryDexContainer.java create mode 100644 src/main/java/lanchon/multidexlib2/DuplicateEntryNameException.java create mode 100644 src/main/java/lanchon/multidexlib2/DuplicateTypeException.java create mode 100644 src/main/java/lanchon/multidexlib2/EmptyMultiDexContainerException.java create mode 100644 src/main/java/lanchon/multidexlib2/MultiDexContainerBackedDexFile.java create mode 100644 src/main/java/lanchon/multidexlib2/MultiDexDetectedException.java create mode 100644 src/main/java/lanchon/multidexlib2/MultiDexIO.java create mode 100644 src/main/java/lanchon/multidexlib2/OpcodeUtils.java create mode 100644 src/main/java/lanchon/multidexlib2/RawDexIO.java create mode 100644 src/main/java/lanchon/multidexlib2/SingletonDexContainer.java create mode 100644 src/main/java/lanchon/multidexlib2/ZipFileDexContainer.java create mode 100644 src/main/resources/LICENSE.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..edab483 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +/.gradle/ +/.idea/workspace.xml +/.idea/libraries + +/build/ + +/gradle.properties diff --git a/.idea/codeStyleSettings.xml b/.idea/codeStyleSettings.xml new file mode 100644 index 0000000..260f59a --- /dev/null +++ b/.idea/codeStyleSettings.xml @@ -0,0 +1,31 @@ + + + + + + \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..97dd42a --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/copyright/Default.xml b/.idea/copyright/Default.xml new file mode 100644 index 0000000..7fe6f41 --- /dev/null +++ b/.idea/copyright/Default.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..53f7074 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..80c5a8a --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..b280a94 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..60b4372 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/dexpatcher-multidexlib2.iml b/.idea/modules/dexpatcher-multidexlib2.iml new file mode 100644 index 0000000..2e4a4fe --- /dev/null +++ b/.idea/modules/dexpatcher-multidexlib2.iml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/dexpatcher-multidexlib2_main.iml b/.idea/modules/dexpatcher-multidexlib2_main.iml new file mode 100644 index 0000000..4e64cdc --- /dev/null +++ b/.idea/modules/dexpatcher-multidexlib2_main.iml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/dexpatcher-multidexlib2_test.iml b/.idea/modules/dexpatcher-multidexlib2_test.iml new file mode 100644 index 0000000..a36a84f --- /dev/null +++ b/.idea/modules/dexpatcher-multidexlib2_test.iml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..e96534f --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/NOTICE.txt b/NOTICE.txt new file mode 100644 index 0000000..2b38921 --- /dev/null +++ b/NOTICE.txt @@ -0,0 +1,17 @@ +******************************************************************** +multidexlib2 - Copyright 2015, 2016 Rodrigo Balerdi +(GNU General Public License version 3 or later) +******************************************************************** +multidexlib2 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. + +multidexlib2 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 multidexlib2. If not, see . +******************************************************************** diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..ae71ef7 --- /dev/null +++ b/build.gradle @@ -0,0 +1,119 @@ +/* + * DexPatcher - Copyright 2015, 2016 Rodrigo Balerdi + * (GNU General Public License version 3 or later) + * + * DexPatcher 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. + */ + +plugins { + id 'java' + id 'signing' + id 'maven' +} + +def dexlib2Version = '2.2.0' +def multidexlib2VersionSuffix = '' + +group = 'com.github.lanchon.dexpatcher' +version = dexlib2Version + multidexlib2VersionSuffix + +sourceCompatibility = '1.7' + +repositories { + jcenter() + + // Use local fork of dexlib2: + // (https://github.com/DexPatcher/dexlib2-fork-for-dexpatcher) + //flatDir dirs: '../dexlib2-fork-for-dexpatcher/dexlib2/build/libs' + //flatDir dirs: '../dexlib2-fork-for-dexpatcher/util/build/libs' +} + +dependencies { + compile 'org.smali:dexlib2:' + dexlib2Version + + // Use local fork of dexlib2: + //compile 'org.smali:dexlib2:2.1.3-dexpatcher' + //compile 'org.smali:util:2.1.3-dexpatcher' + //compile 'com.google.guava:guava:18.0' +} + +compileJava { + options.compilerArgs << '-Xlint:unchecked' << '-Xlint:deprecation' +} + +Manifest sharedManifest = manifest { + attributes( + 'Implementation-Title': 'multidexlib2', + 'Implementation-Version': version + ) +} + +jar { + manifest.from sharedManifest +} + +task sourcesJar(type: Jar) { + classifier = 'sources' + from sourceSets.main.allSource + manifest.from sharedManifest +} + +task javadocJar(type: Jar) { + classifier = 'javadoc' + from javadoc + manifest.from sharedManifest +} + +artifacts { + archives sourcesJar + archives javadocJar +} + +signing { + sign configurations.archives +} + +uploadArchives { + repositories.mavenDeployer { + pom.project { + name 'multidexlib2' + description 'Multi-dex extensions for dexlib2.' + url 'https://github.com/DexPatcher/multidexlib2' + + scm { + connection 'scm:git:git://github.com/DexPatcher/multidexlib2.git' + developerConnection 'scm:git:ssh://github.com:DexPatcher/multidexlib2.git' + url 'https://github.com/DexPatcher/multidexlib2/tree/master' + } + + licenses { + license { + name 'GNU General Public License (version 3 or later)' + url 'https://www.gnu.org/licenses/gpl.txt' + } + } + + developers { + developer { + name 'Lanchon' + url 'https://github.com/Lanchon' + } + } + } + + repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") { + authentication userName: ossrhUsername, password: ossrhPassword + } + + snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") { + authentication userName: ossrhUsername, password: ossrhPassword + } + + beforeDeployment { + signing.signPom(it) + } + } +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..3baa851b28c65f87dd36a6748e1a85cf360c1301 GIT binary patch literal 53324 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

*Ou)7mZ_?&1& z&e&!u&@94-=zm+q5;#4GP=A;{4|HYXi{V&`z&dImq$h}6i!*LPRgj31Wa6vg8uP(A ziXg@(h~lJw7b8k32g*?ktFVl@l1r(>CngG~N;fS)7Ly6t$iz3psb~hB+5G)CDrBzu z3r&ES@hok9!TwXX&3vYI6aRv8{=bP2rvHq1{ypB6GIsczS@qS95cXAkZQbK-9`P>iX}%^=l4H7rl4Mkno6jXdd9hD@uKa*(=pRElXU zur<=9(oH%1f$}a)db1}Ao*Cr+vvp0!&fDjE=3rrfWcX3;2qVTdYr~&Dd0|S7>SPU& z0R_t@uWd0hFJ~z(YwrH@9eR*0+ZLp@zdth2cVZ*I#e0V7$;!i4zb&ohDVZTy+nK(l za2=418RI}{Z3YH7rQ=1GS=*41LA2l0;i=gySaTSeZ^N*ULLHrBZOW8xn?~C}?NmKS z=OUykw$&=YCM^krgjuXMEf)E$lX=+<7&krJNDb_R!)0F7F54rKV``Wo{b6S8Ls?sf zKge?Ky1nR$E!Bj&PQUFo!L6gUyL5=4>^>s?GdA&yG}gg3mOM!?MPNePL0;5*10+U# zh@mM}PJ>`Dje+~=9OZ=>*Z7?3(3kUz@U-X{n6ffT&%R?M5T2RT*hXQ+BKq9Y)&C&9 zH$A20(C24(ZkZY%Ra#|xI3}1*+)KtXi}XziQLPE6-mY>K^v~KdH64lWDw3bYFrp(4 zb;>S3Zw`mj8cR*>&dFzLCsgGvVwM07uzKmO_LDc;3KtfR6AK(?m;AN5xB4e8>cbQ_ z(g`XJ;Hng66;g+!;H{Bxc;MRTF9lU=BM6KVC*k?|LHg)~hp6az2dwCMhd(13?@EH| z)cj%`!5|cOR6yuc(zJx=OJeLD(CTP6KRGUyyn)RwCtYE(xjj;zQ^dRusA)-q$KB*i zBte#6O!6nx$k_FMGPZ6u-5HG1q0lMIhqWg7Hw$9V6dVHOfXpX=W@C7TT&i_~jcf;aB3N#Ga=Qr*+|3_# z;Q5U32OzfO&2b;S9O+x0^Y?ROYP@`NWBI^gzMV0iV(4%Ais^@!0YxjqfeyuOqvDU zP|%MUj31FaGd4usP}e1W?7Jh=?pUaooq}m4&&gYwW1SxlEcJfb(uET4x~?+GGAYw3 z{PIlMXz>F!EPIwP@cnK0Pybfp&D5#!_v{Ax8`Tm1Xa6SWX!+mKTWHdU%2(U}QIniiD{EbV7V{_aM<~wl5aB22XHoQND?Ex; zQ+#f&>n(TQZ<-(9-|z5yNQy~Pdln#RPP9Ka%PEwD>BRKIc}2EToQQ-I=8VGQ${;+k z*PsVCSO;0QPT?9Zq_5Kr?0x&O8}$bd>dFQMJa;PmlN30*T1zuWD@~zzxuQGDMnVdf zTJZJf@!gGFj*E(7CAO41TWej*hLPCqa|)EMb1MkdhSlix&pTp`&*>ACa303RmV4l6 z5!CVmwLt+RCVn4k?mm8e$EhQ_Eum4ExouPmWGfV=023`dQP$-3^AMFoR89AxN1o(g zwDx5i2u~I`{PqB|*<2nRL6)I4m2W!)F*zJ;ywU^_9TC zb}(r3g*t}7CRe9ag;stiWM1G`b)cEIy=27LzO+8N0@{#X1>z6bvn{-wL3Ej$qDf$# zA_mjPnUAw*p)^lRE!|K}XaiEI?cm9PHN0HJJ(10l9g^HuNu4EGFZ%AZ1-Jzpp3nt$ zs$%Q~*-#$zo~^rs=Rd&zR7sOpYudBFP!b0L2#Df8tE7^#o0YJutGT_&e;>3d8gGWU ztH^&Cq;#~a?deQ;jik)wP>F#nw@2*d4^nAcQNWUEhZRIHnlUcJQyRM(3p9N?_@4~P@OpXhzQXwl@_ zQKf!~=tSy4cYI5Z7muZ<{_go1?^(Y!g_NL6Q%tL4{<;ijl-}Lo-VW9?xq-@D zE}otSQYO`Lg@@Zlb9BbUNv1L5g{`>gC+w^FHitRB9bgMSsr;i%)`R%4YhtVM$z{Es z)wQ#Wd8C}9!g_JO;V5AB;M(e!)64IMOgr;S>K_)(tJ5OGE8?DRcl137-4RavcK&tf z;PlhYZskOsrMx523}O<$*)F5-Jt~Hn?0%F?5bA+1s5ey`alD;e^#pV2nituO^^?_6vhk$cB1m(X+QAHor1zAb{y2r@Sm|I-Ssne?Mu)cb0@+?%NK0(zOm$$2DLM>IV zZHMk-lNfrgicTNcz4L_kyw3zwiuq}7xpQy|!Lx6fJ_OH$Lo*W+>|8-)+x3jc7(t~p; z(^`FDam-zpNO~|aL5mfj>&Zh!eXitSP23)AnT6v3D?0g|V;uLu3;|0xs5Pn4-B;80 zP~Y~;*0)00>HW_mb|0l#&x>7-)(k%0+s~NFrZ+I?gxtNhIwcn+9IaxNnM(%#kfhZS za5FMOpm4IL@0kd*R`W)cns+Z#OXop`?ZmYCsGi_Bp2Klm-KN!HvnVI2apJN@k3QR6 zISbv76aqptz`ck#Bai&^XCpp-cV}LZ{U|$!zrpDhO4F$WA&?oi<*T||uA$NO*$8Pn z5cutBCA@U4V7+C|L7acQOR}$B6dvK>MNc;R%)T1@L{;tuc`Wmc5TS?{5@BKSo6IZI z2v^k4`~LpJCA95yEU6MhQQg4_L=;TeYoCn#71@qu z3+m0QNE0Oh8>rc0z#_XC1Hhx8cFb@d2jQBeRYeq1QwKflP?F0nj7!bA888#I|Is=6 zd_MAW?z5nDsAPsYs;RQQe)$gS4M+MitB@BcVtvKPS32P>;ERPUyzpyqQkI zUyUA+XJEmw;dMdL!VsUTTK@{9PsEN|`~a6Z<{GNBjBg;*S3-xG<- zo}Fzib`VVX{OgvD{0{CT&(8h<0(|H8E;}19BCj(H z(#36!pH<9}zl*B}g`{u?=bZ<#(#wgmEow;S6OMKH55V#bPW8Lie=EirPZHAf#;oz< z{Ef~Zw)chk8_I_{EbdMW@-1T&H$xAuBg*WIYRz%uJFej=IXgV}HDUmGlFHmo1oaf={j*ZMl$AT83sgsm8fcNixQ z61;T$8dCfn6VZj4XJYgf>CH@{SdC7U%yO@i?z~2IoC&?Uvh*C)nvH+!b3sc>%d&>8 z;T>SqSRxz!2}VX2GfYQO)fV*^)r@##Di-(mA9`p6V>tM0!6XAT~M>P?sfS01{&RmYdAWL7%s zO|!!=-u)H{#T<_w2F{$7E&frFmp1O&5$>BBor9lmQv389#=Dko&(%vkaQ65&h*y=W zmwRApFy_cbiFJIbGF3G)%;|@B%_AGN-_L=(2iK;&RcT4tz?s9R1v{v_&~D}Z6`-2q z`+yy?+35u}a4%R#^;eS6O|ykopqkTbV4M9Y^d01Ujs4AmwAVM4w|2Qqn$Rbp7U!;k z0wDWS55cf6yVnlUqiec71`hG6$**qJTx4X5N+&uY{Ccv?SFW2A+G1&{Y`8fEhvbpO z2MhiKhYZ|P1MNA=NCWJ>s#lx0Zk-(gdVvm|ecSXP_!!#@4o=6;=7I|M#gWqG zEKc?s#|}5q?a~&x(CM_xuE)%9g3D^_78HwWSMbHxcP~2Yb7tEp0%_p~+YG-1FUzt7 zqs)0cMYk0!x=<-PiwOYgmuQrmwK-N?0p4RpLWJJWrta8A!f$D_gx_Ns?pL=Z%^c5AJI(9NO5+c5ShMd>sjF{PcrE6cjaX^3biN#>nV^Oz{kSH`+R zweXec<)kE$L&bYw9;{sNZh%&ebSZ20IFCwYu$33jppX=M0%Qw^)`@!l9&?~*p~e8c z4M!*%V3Jj^dGsy{7eW#Tvt~lo#txIq-)OXB?K;LS1-FZK&`wo*WxYdz5Uqf!&LRD? zwXm-?u@yAFX#U935MhXlw`rU-8$}{w!M&IyL6yQ()0^oYNa3_@ zX|hcX>juvssSHr}yRL{u5DwURUWV#@76=q>b1Ma5awjv&6p*Q0ex{jAU$@qBZ@9xC zHTHNs-mo#{Ly)4!D%iDpk|3_&T3v>hU`b}`!bkKOv;et~bI~y3Q(3gz@KL}e0QTR` zpqi7I(&x_Jq|xr0OyI|le$tn)vQ+VFYIbXGrd)<_t`x&(><9Ra$($o^E`pDH(IB(f zdBw5%bj8G*hg>8782X8(wz#z)Usb88NOnSO(HhsB#c49c6mMBbZN<)O+LqX!inRvCY>Nni>IiqO|((H zI)tjc-FOAP1Eqp<=GI2ae~RTUO2RPi;XV<~m0VvipFEFhHiQNE{j|QPn*jc^r;r*V zHA0OuI**rpk1VL=p6V>xQ{duozMMcbxk3wBv3k;HS%VB1!6jDpA-NY5SjWS?=B$7S&6IPD3~K@N{T4lcFbVYHe&^RyajCSbprb$tYd;{TL+ESKz76 zBlkt~l^sy9K*V3P;Qol6Qd?lF?h`_welF2V5Iw5qG*LKP*_`E|bnf$BJ z%;P2`+X)=mM|gizy*Ie8@ImuUA?4*>e~jVAJb1vf>XZGubK>PLAm#ShQOY%M;w1_N zvHX+h3l8_!+(Ar5y17J*-GD{sm7gvpeVfMINgCOy?S6a0l8LjdsIbksh1{a4e|lkNSWW2Q234g`(|7OI!ZZWp#a&CfP?ZwWdxt*qDN8Px}5-+wBN03>|+Q zx^2pCyn6MLUm7_CVH=rCHJKS9&M1YXc&Mr5nYn>h=OGZ$YgY@CEwN&JmFJl$Qsl!1 z3h?Umk=7lLXhsu5!rTX$eW9Ra?rb)-&}F|culi^3&A zPd<*#sr2BP2YsCl4`gh zS*pRL9Iioq#V2S6$H$>9N9n`67Y$0QD8Dxfc!REEIF^r!Q|WkzmI;c2_g7LCS@|b?rzuWsb$jsoQ2zJvtcq^6& z&P&4l(Kz0{f1>G|^(1M__0ko3%Q{bpmz-|1x`I58wzPjaeuX=3Os*)Amw(9q5vd7A zh37nhr|?6?dVP#H=$w?|7_X@;wUeN_CCPfk?Of|dOkh4nWFM;GdQeoOr@(|Q(0hF{ zbUUy80o$QPRb!@y?DzTkp4q#&Sx{e#74M?vi&SGLK@K5`CxjI7Z@YZVr-rn1?O`BcjqxJiKeVXowe`U zJy-A5k|vQRD~Q#{Ns--B&LkJ>dOYXa)-sW3#Z=^^T$X%1ZJif)oB(&Bgk~|L%q$TdJDVGrtU{Ne zf}_pi&uIc{{lE5NxF=6r!!Kga*v{&T@s?lp zQRS%n=9Reg6@jGA%r*gtEM3B7s)Q-X$^zi$GM$m>wIiAY{+TexUNJ8s+_syF*@@Sb zu~S|OzqWACDVlxn-0`Wr?z1%ogusu3(X43kI5P|gh@O~Y80)y?WW0}!A5t{&OQFN; z5b{KQao*-;hGk+(7qH`v38qU?x^tvCO^de*q}%3d#GbRphMu#eQY`x-^avgUa(e>_ z5>BANrGB}piwnx@g;}V`z9q2%GbY*g2s;X*ubfPp%G4l!9R~LbXKrW^Jc9qGrLBZ0 zFV8FGmmH3ZiEo1ANey-(H>)YcR)ZhMTyv>)Z#O^I6E`eo6fX4R$?BE!6($#wJ>ytg z4Q@GhOVGN~j&7gqJkQoyE6R7z&w9*)}IrAl9 z3ikzctB*NPdT~2c520U^_3s8)6@d)-C6Dl(ai4{5E7hEHUrZ<@5LE>Eki^4c8{)gg zpiH*J;%z2b<2)m8mZn_j>7J0cMlJoifVKm|qON`ZgFNr2hVAJ^Lk$S$k8 zQ4De}LRtst8dtn%)7bu2Yb7Ag?>fMepiPi@E(@!YK=92iyx@}o9ZLeur=6o9az)9P z2Nvim&-HN)+(}$+9)^I}bd38&;;q$@iZFke{{l8{j#}oME2dbh5LO{rv)EK0=wx5* zlW;Lf3t3*eqDx+G=!8iRL4@HzuUEWQsM*}=J>SsYLf==}GL88dNz?Kcw}|p7A=GRE0tAJisXv$>zeTb|q-RR2u_)*Cz% zs+9r62)=RK7VJi&-rp(N5WwRUFeR}K_xi})eH`Va4Su;0@EDxw#mIQcUv?_}=(oyo z{c`7u13sF&GAHUKz{s|B2 zwhv^VEH@tso@Im1ynE8B^CwCTPYtGxO9}B^_rv;9;|N_E3bO?--x^`l-V6V<+h7Z1 zE#;VHmpQQm4#OZQO?0jY>i!eSC7dr$2*J7E0~)<(8}V`%HflRe{xraM#6--W{vd#T zrI~cV7wL4BxYtow?pAV$FPzE?>Nx6r+p zPmyupV%7M=JHh~Bl%Fli02u9SFEwBDoZYJ<)nftiEbOk)EM@gv@{HH6?`sY49Hu?{ z1FAgov}_LdQ5APX{LFh0;E}6mQNlT6|BAAfr{Q&u+;eS>YX_o9IsN}(LE3wX2Tclo~zzO z(*T`q;4oO_vO=(^4Ks0i2n9}>7n6s?|UBQJ0YUv%m#cCybj zYvd)gg495LXp0{CzK}IkB!a{_el1suFBk-*gfz?Pmh1rgELuf}kHxMX@jWu(de3+s zv%X8W_+|3*_2fspgJTx}u?LS++*Ogue6fl^;ao|ciO@N2FdF1g*CrqaehwWpSqK>E zQAU&H43|iDFPBH?5Pz>MXrcjh)Dg3^t9a3|5BzHsLAVItjoV20Rr{GWP|piBm-Ckl zXUrPO?!eh58?+B(!5iP17Bu~A!Am^zE@a7W@CqT7!XF@+A3_daq*neRJeP#R=cH;# zKV~Qjyw_}Yi*^TEdF!XY5vs_CZ>Kk$8U5pTxSoS5`yEg&iV%gDL9w3$2MLLNDcV|% zKNa`(j#hN%D3Pc$uEgc%Rg^<@3hgsq95R)(%{5W@A!Gkw8=Z-xl}TVY{}BFgRC=zX zGXF+B-r6O)_+kDNs8AbOHh%?JcL;^*xwofny1~;9(MUz^kJ;&Bb$HU}<81y-_*ytO z0bj}kjGfhYfy$62YPK=!Qa1G?qcs5L%XWhTMl5-nt*b5Y)$n|Gkys_TY-%EH=tx1w zor0^l;Z-pI@@%+QRriw(j~b8mxn{DrI&a#_c=ndo(8YWe@B8lkv-N zV+z*@Uz$B29s8;NG@h2c%(1QcP_Al{rSf}d7)A>LDM#$domx~zs%lk z5VA!a9o<~r{t}zyjjbJ2-Hct_{wL`}TX$0fiGQFGyb`6~jv34e1TAY=K~)AfpA9;+ z9xKr(m8UqWo>4+9wVV$1ES16f1NVI+t(SulQ0FJV`@#6W^kd$m)-0IwVHwdgBZJp< zW~#^Z>uuJN5xDy&q4}$`rUat}SvRAxh6L@2+16lpG&tRZu`~dZ8GBM|fAGtPZ!aOeq@=58WPc^e( zeG!DO;0^%fJR-*o9K$?qMB6dN(X_H;pF{SYo}u;xzr66;ON4fl{#H54ZK5V2y=#LKm5D|%3fI|!GqIAKP{!$i838M zW6hK0c2};ENz%N;ghA9rd^!zh-0}CZfKYIiz8bwq9vgfX{swDj=Jbdh`>+(2lOons zY;E0$jM}FYK#7+Gc$&Nc9~p7_X>w|ZojNRs90Fr=UV9<7lc&*+QE_WNfZ4ky#i0yP z+Htx*NVeI=zBnecSF$!AttK~(J+5!TZRR6_?p z-5h^tF(cE+eX901e@C(v97I%0?FHEe=B5|V11wV^@e5%A#RJ`HE$L3|XKXY`Frsie z$}_qjjI1z*8>P<~j`&uk_#?>S7{BFg1J&4m;N0&e)SAdEYOhF9VENO7k4;}SXlO|o zfx%O8vrx9V(A5_E*aKK_!vk9I**o@om%%uU!8i#30jjs`04GfEu&3J9Z=fpf!4;OP zY9kN}%c<;K7@Si4rHU&K*o`i_GZiQde+bOmY6$isDh2CgdwbqdelSSL#$aUd*?a!5 z=itC!f8LtUVzNPLg^yaMpVVpGRH^iQwlOItX!4Qi7d!91Aw`y_%OZ__>NJpV)jC^LUC6zv#~ehf z4xowc+av_`MslbG7bih==IYJj8dK>l%aW1w6h1)c<$gC&Y^zZhv0^Wmh6xdD+LSya zBX2R&vs4mkk;bt@<%-vy`+=^W{aHc${w=geA2V{<9JN3}U<$)f<|Cn9vJd2-t3lD|g~$&)(UA5iwwHYf{}iurO;m>i z`9>Vtcn^2S1cz)g66qZZ#z#e^v2AAY$N6rz$d#e`zH6*&Z#TNQ?(FC2D0`Ea*)x1= zR7aOeZ@qiShqF)U-oTgD)55#Sz8^V-wEKNJWPU+6rjMV_8b3W?U|~>;x2cf3g)f~a z_{(_Yjf25FgT}m^GcK4TsCic9j&{jw!UO_q5BYT>@OHFiQnSVGf_6O)w%!o`c_%Nm z(nhxUm-J7H1q4L(pYIv|i{dHnWp3*J-*3E9G`)@R)Up4_H;y}SEQUBFwo+5mk=rj! zi%)K+l1i)Mj4j(OWEQTB->_+~U4^W#6F|XGQPC9Qk)Vl**R%9IC4c4gfZ$tc{rpG*h22t4W{~)6R?FYhK&GG zu;-xNF&ftf?o>zUh8|&KNF(_jsr;tafMw&b>=N=xfGBHt2i&_+jSNSMNs@ zh&b^g+W26c;ZGKb{kFq6C<*$S?nfAZJ;*W%!9=?YY3@Z87|MHVPI961{D zg({pKs~DLRH+iMX^5F)QhfEmzdLMF!myq*e_N*-^fH}0zh1H+*@Z|?&2(=dl>_;8Q z2zi$R)Jrp|_;%ky)ERPp`S1mRQ&d05dQFvjYbD%;F2vkLC*OrV_;~%9{yaz&5JCuf zkNU|Lm`7c{yMT+2eRGY2e~yp0#?Q0W=4<8URBq{ICMR5e%VJ-*lCY$LimyB=S4_b{ zt+ilZypWpO=wUS;U29~X8(2GI6(=e3eWG+a#xZ*m**$&MIE16s@z+33o@bsGonx;1&KmW&*7GR)!VAX!;T+7{%qy*8d zbj00NELN5;COvhlAOpH!Tm0vA3xK%5y|%vqBzuCBQU&_b5BwCpr3LBS)T>_fr--q8 z?se`Lv;T(psHHpwR?o;Vcc&Wg>OFR7n7JJgvKA%sNLdoAm;2|$NL~T%@yme|x7I&E)S?dg= zs<619u$KD5+<|DWn7s~KW{@sXf(i1)hMEHE>|<$q(aZydV8E|(#j{jQ#Gqd(-E?Ym z3!fq?D|MUks9myIjQpMCXh}=7^duQ{ovY?p7}txXAME#1tl;F%b7dK*V#TH52sjB& zVl-A)ffa@c#;XxcFrL&@o0s9$rr6k}%Xv~|<86C(Og5|0s()I* zpH>+j(5t`yq{v`)Q`hEq1nv@V>NWZoh*qT!F;;YH$&c;SnMswuvIh+E=sS6FB{ia` z`qb8=H+OP`Vupmh%%wXmX1b|zImF9hYiRAxE?8Sm(~aTarQMv3I;!)<>_!aiHrZfm z^V4`7n$wKb%MO=#HAJTEmCzvU$)HnX(R>FAs%USi*6Hi$Xx>xu6&<*@OAqIX>l2K| zTgX?wMmc?|b6j?3%}d9mS+TK}95}{CXQ}hi+FhhXoKqDQ@Zx+kbp09IbOQUM%JEH( z%P#K2mT<+vGTt7O`q+5aOVXb?k_>Ox)&Jy(p8EPui2P~DS9ah%gVt}<7J1roQ;hZb z{^sYb+Z-8P&%ii!S}R9_owo37Id#NDtF4Y!5|Xj443w_=QwEp+f#G&;y7_vZ<<`bi z#T5NYI^4*Rw?H{Xg^v|cBEV7e?$voQ@)k5Ih8#cklp&@*w~)q#y+eYt1&{?3L$Bvb zZx3Tz;q^Te)FOYqpCHX&6ZS%$IDXeo!0|+F%7|VHPr6J%Aaeod%a!CIpX4xMTjLL} z`e;3TsyPAH^F7(~bkSjgr7&Da16(pt2c}-40&|DX^ch)6Bb!Xqr&2>hNhOQ! zhJa<<)iH->%i`A&(65}8yJBkMkPU%0o$Y<46-?=qMC22wbn{YdEPn%m_gJ0lbLF|@ z7j-PIx`(oFtF|%(#4B_%>B*I z!D5Z`;i5PK6B#i=;a+h_?n3x`KCLl(lI&$g*X!5n@mi5W@32>(F;1pUtM;s@X|-Xmx#B*<7y^ifpO6+fb^h$p2TVC!(#qn?aR#+{$_w*>lCB`U6$J+Fz#}h z3%`XcSXmI2a-Xg?I~Zz)yal;uO^l0UaLBtI_*7MbvP3V?*O|EStQD9qcy24|xE(G{ zl|WboMU^ADiK9G{KM9Ve!4kxg`qU5GCAoaWTj3c8TFaJD+0GZ_$>W4CFq3YhW8oLv z#6fdLYN!#w&R)0Ti=@2Sjh*2hta-krF#3%@hSn-ndScWu^Fu@7#lsgKX-%}?N!yMq zsKk{kN4qNk!*c3i3R}lr!x#Zx`PifMEWAd=U96p^Cz6F*e3oVX_y}HR7jMP_BnK5b zM;2b&4$l4n3EJMH;g&?7@M>7#;nv(;>JI!FR}W6+&gQBuYYYTO_)T)J@LtA*cwd)2Y=;@d&-n-J zbx%lNuP7A4SX+#@u1Ha(lH>@_NDBjIND7#0r!e@khO%+^y4t8C=spJMAjeXbi+In( zjNo75uori2qrT@5@JZ!Fw~UavH> z`;A-sw$3?G(uoqXY0xb^8;~6D8#)&m&%rO4X1nY|4?3xL?j0b>F6oS2NCx7M=)NBO zq$(z}2EnTjcJUUwQc8Z@KxE&aoCiGh>-57y#p1@dTqSd1m;B@yW7cqc@E+CT3-Yza zHOXohQa1Dy=Mswfv8iNDoGuzBlilkn-mn!cUCQ-Z>*ySIkINsi`Q1C5i#}lHHLO)P zV&WlhJ@yjXb8VT8LR~@0TJqY&-5CU115x)J6jRq*eS^XO4`c5bU0JuTYp0TmZQHhO z+pO5OlZtKIwry5y+nzziseF0YTKk-Lt-a6J_K(rp{4v{TW477*Gwy!(yI+ry(R9j4 z7HxD5Et40rJah~-rNOG$#WIek@b&LSefIr)rdGt*m&qmn1xP`6Vb2alq zz|J53e;39S zi9#;t=6N%9*3JE5=H|k+MJx292Y%|R%j2Wl;|5lq?;cPHv>X{t)v`y2iVa|D@6w^G zRRBn#f+Feot5b3uj8=ZQM{jnk4PV%|;y*p#dV<<1D3aCx0*HCI*G91KO+jrJ6wH6? zRUL-wlD+fp)Y&FXb*pHDzfl6%g5KO7_(FQtMjW~420T@21jCnUgfv3oDJT-RZ-&BC zJ;&k0SCkEhsunR4_L3dl#p&QZ8vTlmEdv}Nw)?5{bE4u88&Tnnj;eU$HK=nMq5?BBC?7AUH%^O@ZQ>e@aKFT-=h7|=kSQ!eKRQEngaMLNOR9)Xg?F!m~)yQ+F0{Ol|lq4V!OHv zYnvM@3wZ}i2SnF)cGl)nf6`@wP7zaWVnvHr+W4{l z`SFv~CG<|VrT8Ko@vaiUfu^84-T6C6pga(fb&$J&F|f4w05UODZBarh%s+uawvtzB zbHIT&p5?ioOM6Cw2FsRtbmZZ=j>R=MT3AdJk=ZvOilpD9{d;$5VhUpmJuy|J;06n( z2gPw4s>wT#$hu=l<7t>)&ZL1fI_G0?l{pO$NUAGW*K7GDol}%6+Q?))V)>=0p5kc( zyrlZE5SJWge3A)L?+CP?JzI*i*Jybdqm5iJA5Yc=$j@Y##zICfa*#?cL!4;!!@QM~ z5y$vS*_Nog4jvXky$M|X&ANdPa4s+TQQ8j`F@ybQBN^?NY)MRX)sA^oW_^+bHnF3o zsH{r&0YUp~5LHPGN#^7*jB3e!jMucj{V3b)+uNigf5{45Nl~Lg@Tf3E+*T%Ywl`~9 z_C;L|*}KUdKKg=oN1?0cDf{b*gf8d}8c@qNuoX*;ep)Qs5m~I5JuaxA3=fDvDeR-%q zReSW$)QOhILRa&NgVYCeni|IZ$(% z8p9Q135wDz4T&oK*ipvJv?`vV>#bd9YtrK*MVnh^*Ps@>sS!m2JG$lH$z&1RA zz?Dri%7@6@MC7#yvRomt$}}ssn29$M8=4=2s#lVNu`oQYTInw0QqNOu6 zf65@lCOs?&DyjUgDlr^NSv+4^WK|$mH8-TCNL?4sv#Es~u`x`Rgu_lWSEy*jffAh? z>eong&Y~D=rJ2L~3z~Svv_yh^LwJGD;fPh*2peUtEZn6ad_^(NMguu@mrb-P_2~eO zYp-iqM9D7hiV%%i{&CbU>>leuhCMo?89&ahJ zIy`- zL^)_7nrEh~BbfGN|GtxZ0u&aH#;Nm$j!Z!YP84-=5?Vgw#lys`DQDNlnJJ&5F_m_) z?(y8wcoAvDT_&|qifBA=%Hn-&82z#bZXT zXCM%t7%@D(!GvWpyRZ=?e&hbmk~?rPhkfglXKN(Q`nSr5P!}_<!6f14zvPq~#lcFzg$QqexFiCn&|fFNIaDqaTCSkAaW;Dj!P9 zAn#@S?wB}+!!}qH78wB^{X(2$Eprg{UC)|~KpkPpr!uF>D2hSCQ z!Dz&Z>4v#3g_s`~Y}Ac-yBiU~@=NO=TMe0Q#i8{AsyPCwZ!xrNZlbyIh_)5Ey<_h< zIi+IJ_6S8@NQLhR@KXvkBsiZAz=pz_@kbd$IJ$j#yKNJs2|0D7&4HmznjI)`gLCKE zZs$^nTA3FwzRNKYm0EKGZ@nK^PQy9}b)f-TQ+l$5t`vmxY=M6#<^@*jC>Wucj}R8C zz?h4Ja-AmNwkS&DsI|pQ_5I;8#V-DZ-arjtVsDHXubF#sV$l@@9T!n)S5)ko0`557Pb-x3#`=QdW#t! zinEM?tbgn>|f=UlRc+)QR@wlyslenHN$$K51So>aY+RhHXDFiftn|}w` z`n>th0^qxpwGS5#sVjqvn=7kQqHgrhX%<(v+RTwvV#ejGBSrOvH8hXVj({E~ugk{n zu2bHVF(1;F+5Y))n@9S(?D3tco2|!MqZzPQ(YcZp;Qx44TE!ut~EL(srd+4N}efpzefw)Q~=ii5duvX?X7SxP>Iw_E+0xrF0*w z2ozFAJ6mPW3CWos7C3Qyxgs|*huN1+6okRWGN0)%8U{bG$F~Nu>7J(Op5`eZ;w>Oa zW%BshV{Iq*mChXzyDX6|ivM$mY;79RJ@4z7R@2upt^XIC>7UW_|Dv8{t6RBYFQIO& zU};A1NaB3^rWpF2fq;5d3I>uyP6(OXUyzYdZhu5pdt{yiHuFhN;|=E<-^0wOw$HlQ(WrPeRMz(}`ZX}9 ze<;XBY#O>y>EK~7y}5eMvbRI6Am2+4avOU7d~qCQaT@;iRA$sECMOt;lzxN8bev?7 zNH4OicS1H80EIT=;uE|Ct?u5XpncR4Lb-t^v`t9iia(J7I&Q@nfDX~pQX}PigPqCH zh-9%=m+S`9dpLJ7Jq+gJ@U?$1elIgB|HP~eT%@^b(0XVxrGM+m+RJM=f^_ZL(4uW@ z@RataZNh1{l*=~+-Nm|J4HvskQM@)x+rBbJcD3q&ZL_8jo_O1_u0LT5h~7m9^3P7+@h{R4`AsfQ3>fs+ zOX%e!u*nvG$1H4NPKw#9jgoVq_y2HyM?Fbz2bmUD%O_|d>Eqfd-Yb2U89jLx8r>N> z@~7!AqQpy-jb>HRXf#HIboBj&V}VlBV~-OssL!y2fQ!BfyYEPCAL0|Z@Ry+=X);4#>t9SUeUEXRCWVK6?~C6C09LiP&!2gwlW+yHay{|Spe zKJKtegjJslh=Qu2kQ6Vta`PZ&2MAK>2Kr2VhHNo-+~)Tf=7-c*pBMKh@~thsGlkPH zJ9bw4clBu~ZiQMe^wgrBkgX7YA^gbw7i$5d0K{9*Y3t|3y zvONt}3%X7d_~B#6F2z&5Ro4;g2nIT4i15CwtS$zA9FI?U-rUA6wG&oKuj$f35+Pn?jotKgt`tSnq5n%&q|cj$>a|h}zTc7O{kMQTqgeH|Z6F)`W&TbTyyZ z99qm1bK-!S;+KX;NGz(Qut`n_@6HU&f3S$wDb4e*a2L`v z=08!L{)Bc+Xz&v8nK_s&G5DhLD;Fon=c!_w4B3+4iw*J(2uKYC2#Dil7&3{B zosogHh{abV#KO?!{{n83m9(X?zvz6^rdvzSl@84<>)K5oVOAIG``XfiNZ$#Yg3<83 zDP$4|UC_jt2 z8);lW#FyJ`eFCp35z7$|e3gp3*r4w7hg-?HaqIiI-Q|WB5*ij2Dt=fm+45dUFr)#o zWu)=^*9>#7J&A(`oe6?5OUp`4YbCg`} zkFO(mMzvWn$$vEF+m2t5WFf4vwE>CpKp^Pz_TiX*ZK(dP7j$>?i@hAtk`!4F=V$M1 zNJfTIZTxk|!d7*kyLZd4EMU%K{}sp;C^x2AhqFV1f5|$zpdfKLXq`{ z_{myPdtld7Uq-^+n|!q!lCK@)ayOh;eU0|{YA7519jOEO-#xwrBPnc52p}M7cpxCc z|9K?*JB2b>J=_n)4Aa-Nv6Gn_h7%1*gCed3*7}+VDxqnSB+hk%rJn{;SHYoydyQsm z(%Q@vQpKjb;FLy)JIM zG+VOr&J@~whtI`BT;;d@TjD}DIr&Xm!3aqWUd!~D%FOF8cqBF~krZU5Sjp(fqbzRt zDBM+{xprfa{<2gltkxQb?b_MTrs~p$k-mcJlT!!%O>LZn*&z=#j!BKedg99z66{!wWl4tR1lr8pXGZ`bI zUIwdG@Q1Z3^tj~3M&^!e#QTKVn`yJOQQ6-(H_d2MRmG(kPq2~`SrbL~E%i+O+mKiV z1C0q(loG2*v|wgf*L@EvRVbDtSQrz=u=FyT^2OGJ`8Ol$)gpu@9JV7gYqnKO$$8h@ zIV_HbbMd#xkW&-3MkQ9OB{?QM9^9P+01j5{`xpcG(rBd9$#-jCTRHy=Zk~a-$@hUI z!U4NqYie2|?3PEtib}_HTFrMgK`o9vi5~2!Zt0%FKk{7oorc_3R@_M^WQZvPj^KWT zTvVHUq-j>;k#UTBtGPv=9Z`^0MY}E)#!LDCdQcn=!5oxbO(VJt9EVR19c3eR@i((#j15dKbo zP>SUnVn%w|4p(ja=hIES&0B5+6L#hR6qDYPBQhX_G;4t&8WNM6&P4GoC;Vg5|&TfDd8t~z1@+uLtv@-8=s z`mQ&KFT#M|hoAlywHuK=(=H}8lFQN+vO-!#ImoL?RueSlh_;UIQraz5|3gHWwfx6O zF6%p}-Pm*Gmvtu#>oU)P;MslAul^i-1(wgI|EWC4aAy)l$e^31a z=Be{~VfJ*~(}pVRA#A0Bz2hUr8O;GLtla?>YApzZL3txqC5>GN9(N0U>GZvJaz}-E z1dJiqe2Dh`93-T6p$nB!x7DIz>$VyZ07_N+g{$_tsw`&jn)Ud>I|bdvNVUIm?PP7X z;$_r}bYRKmnsPcb)y|`M3>5uZ+QfR4x;iukHc6@|$lt2IMTJt$Qb+n>T?;#WxmGiI zR_e8DT&6&iQVWT#%3e`{rOx#Ed3WyIGGw8Y%qJ&f zp&G9kl>VQSlN=ZX~LXJOj6EVjR35ni%I>%$s9R2d+I^+u=ZL`s`qwc>A5R zq1v3i)s{Wr2Dd(Y95j54di>|Vzg@3I`dE*0IJK|L`1(8{6RL#G2r6+Y+g_M7hKE=x(Yzw(sdZh!KCzV25L1aU74< zp!8#$7_O|_18@!}%)5X{326zP;Vg%}h~2(rdpp_{uauoAQlBUDNVS0@Z_--JIkm3t zENb^v05=70@pemVbkFO2We^=VPtvXEE0W-6gCsAXbXfMf(+W(pjQB~xIdb$|$vz?} zb*GXm=Yv=^ElmDTVxsK(ju~Xbq zZsl+wbb707e&vhU1CRyX^qxh=>Rjvzo1ev^%DaE?%Xw65MXRGlYJ(v~q99mz!`$)# zb@M=hePk=q-C&S0Y?C)lP>S{>r8jpNKCe_)_ zG&YCOZjT+mGZ?fT^W7sq5&0<|7Owr7VC@+~`GvxOL(-H-)Rsq>C6^S4Ug3bpq*lo_ zxM79DE3lyzG6aZLJhl>mVQL@u9+fcjG#@KNe^Z(({M|jP6P`H&;V2Zq_e=Gg8s>4O zNm^}+{^K4kpKweZ9IiVgzHyar&Xw#W(RfeBckkUK4H}8Ox|MW^PxrP=l^*iVL06*9 z3D;TtYh+!5P5KUfcL8U|=M>W;6Ki=Eg-XI4z|#=&PYHq?2(f_MAe{IE$YS;!bGXNP zLYw^)K+MUn@*4oo^z3c7j36*A&$cI?3p9Lt^62FOp-4nY#Lr|noZWLA<$ifymxb+N zYXjip?nufSyAWdj>Zo0cPv9n2kutHgZ9cS|s#HCEv@Q-AAzG=(*x4JP4Aj?k!M>%> z|Iif&!LvW`zVrmn*Yy`T{+~#CTDO0)5^4WIinsqF-O${huBKUoz_-82^7E`i-nD{*Af+*Vp659#VL| zuvN-m*eb^V{&hjazk=CD&cb#!HeWP884FvJFZ87A7mxnGBHGC+x?k{l6kZVMNa~g_ zo9dle_@hGS4Zd_C35Yp!p$f$Lp-~ge6&w9j7~w*{ft><+mboGP-B_k=%{YaWrU!$Q zZBDP7cBkX*Eq*`0KVbG@#2}EDr>m?8{W0HgXOf?UJUDSZa6xfJL)?dd>u8#U9p9D0 zXl>othb)C$+$I{-enlWH-5@2|y*JKtv<6h)Aj`&QuKn{D0l`LG1Lw}|7H+zY%Xkt7 zYYo>=o+&Ge#x6VDCqj;jrmJm}znedEZ%)ZXlGQ48NZGdVh+#(CN77wv({(4DCR~6`X~v?TXc>0{46O9}Ci{258Bw}Vlaev3 zD1$FJf3{Fq7&GYk)O-Bs=wY9&AGNPMClE=EsucK%Y&>q{~XO2;`e&8i&L_9vo%_dm2K>Vi#G+6{$$@#H7el z5c8#jyj-RbY(C=qA(x=AtJBJi|LeSA|0F|~4oB0AM*=}3v#_Y!A2JmxoaV&`E6rDG z5&@yp9YjLuseD$+PAp9^HnldOH$gcRH}hz4eJtuGve9oEq7j!{(h?aoh11oFIR$TG zYQ&u{(DAY8VL2#L#OA?D4neEi5VtoAP}IhP9*|WFzQkoJ7$04(k38gBMr#2q z`P-h3$3GNFS*OFE@17subo=7N9e4~O6hc@e=+xS_W!I)Ut!_+qLrVABYKq(fcf*DF zCgE!pD1@ngao)GJltgG6R9v52Rz-svDYUeI;*pFf5ay=UIF;-igG+c8FC?iOeo(wu zKwR`GA$iUT;%#;cx&s{L4Tj;B`x^ZY`n z!pX_P)=b|1ul2B?quJLn31^dk^9XvF(383ejKci=$pYvZ zbn*KqQ z%L_t9Wjs_JQVdIEAziAZLP|?96Q!IIVZft40v9A$V|P0Y35n7e{a?c@r4 z6oA;$V{ShtW0hLs-Fg*P;tsp>>%f zDlSh&s(N78>N0P=;wP@yaFqIvN}r*l5{X?SYdg_S8^X|9$<#|skC~8SE@A%bSs>JG=9Hcd?s`V&5NT77bRx3CR2@8#}P#1=cHNDprLK-D5SoQMfG0dPM z6^(iFaa$ln=E;>o2G5AYx6mlWsZF?o9iXe6YGB&HOCNRKY*gYzp?{O#0M8+5R@lQS7yn&8 zK|^fCA_{c27^vb9+C`*?)g9_k$t+5I64EKza1Fl2x*#QREsb_`w@nnz(F+5LK{jR8V|34V$95+ zR{7-XOK8K(%FqRGVf<8JSpy>fO~Q$~ojQ=Zj}~J+cGcC*x(U65VrS4qJyFdWW^q;! zOc8SqQgg%?WNL%&cj#&ZqVvoTB2gyu;GaWZ`O6ft zHT#+$_6A?@OS+wMtroJf_a$) z#ju>K&oi3y42-b~^q`}@4hBZxd#bc2^S5f5S;p0MGH15K?p^iC^8tENMD z$QnRot7S5SR(1dny0j*v8!gAqqkTJB3dWOmQ*oi)`$!@SY5`4d(3)6!EB-~7>mXz) zBEknfFHw&W@m+WY8e(+&W4lVns!5%KvSIH4nG z^AiX&Dh2P2IOeJ(rrs^C9EjpB{Xwe4U>6fMgo*jws-3D0@XecoQBoR}Hb8UpFlX~^3;FKP?JL+W z%oGyTDwDy6=$2?;ALmIxDR01QzMnjPIl3aE=ZA^|qHAo(_h4yG)9F)X6aHet6>Z}uhJ@LGpxvQVss|y_QN;UzFt1dmm~ss4v0$jiwD5;>PJMXF)B@?< z5gJKz^YUIDgr-#Yw-OjKDZccVWqZav%>v2a#i-wldnQ%-YT9o%UME(|za=RK83_gF z-N&jUUiwb;PKf+6YH1UJ_V|D{JrbDwj;ovf+c{^UbKzP>Q19|1B8Ie*&E*JA?RPn2 z<@{?#F$aZ_E;CFeliAiOrbl<@)$}b&du|=?R+F6pcw+c?7JL!-DGy-`{-c zzbX(vy7}iQI1o_i7xwFaRe_{!zq(KTvkd)Hf&A?yyrp5~j&g+R+iRStNd^)U4D?g2 zG$YQ~3I1E;Y!hKYQHTJxOjOglftw5%JM%{R+V{(0DebE*y;(LjuX>1e&!19ALS2h` zbp^kd3*|i%)7QhFIey;+xVMw*LEUQd zNC^v(jgVw82{oc5@9sSGto3m8bV}qUG2o4a1`shIR-6{m4B$D57%jo(wQ!cgC2rGPm|{ zPv4k^wvja45-nuYdQ`uxV!ciOfvQ98HKxw1ujG?$2XN>4{oqpFrV6ALrboQD190W) zQ^wWfg}9Cq?W|g_HEyMtvs>)(q_&>cj(w#Y=DrM>^P^OHY6CE-SajcdRoA79i?$Q( zbQRPD?$VWyASRV0ebbqZUc-?n-xva9EVRJx&L{ktW>&|R^j-q7O;^+XeE$TR9+$`3 zFCTqKLkfKmwO=u3>=;?c7kB1b9Oh7udFuVJZSnc!-+3pdT4PgkH^^Tqqs ztkvytT`5+>V<}ICS_1@OAX(^amAMjK@x#vqpIg6=PC;_1f2dV2FLAk8ZqDN_HR&uZ zT`#ImsVrdb2z@y49X#Q3RgI1{?CeUi-B5zcA7K8>-YThxCEY5-WOEU6S}d}O#&+PX z*)~|Sv_@Q_MUtcD2;8A+17)XnM-zscHk24h>T4;W+p*$+GfB?nbUw=SQ$ZbSoLV4h z-gzYmp-SuLglvSGHj?Xiau*x8htlhdgz_EjKV8q1Y6Dxc6zeFIJ8kJPexcucLi&@p z8+#eZzb6!P^KqvLVCwvsaTo0u?V_slB^<6viVwSB`@ITM*io^|`W~FR0?Jmjgc*ai zlGuVroIA8+O5_PrE8(u(uTArA^R7Cu^L^1UxndV-8?o&XZ^?xnVd%Y!wlyJrPdw;c^nekSpC zS!rdeUg{=h$gCDmk3V;Hh+Z}Xuh>?25No_g>}h=pj2S!niwW{zZ)smYDF^ZAtzHEP zb(4mSTUN&7G@Iobuk>;an<6iNd9xfL2xW!rNLkn;W{hy|zXwXRBK9!yr2lTVe zE*3DR7(+IUsHXVWkoSC7BeJqHzGT$RI>ac12lFEavuLz45}j+W3tl%=NY1S>p5M>=4Pm39j?<+m0gcMFbQB%E3>?{R40F)_Xn{*Lg2Do&nNz zoec@0sIiSfX6RfmBv*JMlm`AK<_9QJ1%_b7bDTjTW(sV6JI3N)leZ94SiL(I) zw|CM%K+u#wV6&8zcE?gpEHm|K)F5XFPj=GapPb&Z=TiSo)zhP2aj!7!l*2WQj#Bo8 z^#GIN;wjEEf0oLb9HTVra;J>s&)VxHwJCD<$B~pnGr1g-Tr|-<^{Vd3TTui2!C`yV zV*mYOjbAY5f`$L+KNBohWan$b1+0!5(?_#~?3HPHi>Rh8+P4&7T5I)+omr~rbpGM@ zVrWU97nqmew8|68B{ljgG00LtV}lhPPlj(Q6i_1AMf<161>FHiJtma_x z?UO_y2Y$c>1uP6&gIKSms#~Jo54AONg@I6S)ZrG4Y&g?hqboRZ-$n;16_Dc&{)u>_ zMDypGvnz7bFU!$2t)T$rNgvsESTNxO4|I=NFXS_jYIrpMKCsVu4&zyK6HF1ZLYx+& zUbcY*&akPzyq!x$mkq?hR4@(yw(0uzj7hV67h$Otkf)(w0JSd|OgS3}rEDLnZU7Ul zzjy&2Qo6^$cTTFw*|LXG6C4%0@PthG2m2Dk#0S#0l%8r(Lw=|B=cfgC$f(fW-=Uy? zDFhrVwEC$p&9?EiN@xGyuTlPUb&{-VBfp@4;%mDyr^tn2rwjlUfx)&j@h5;m%rZnn zXGkZ!HNu>tIn$bV9m?H<-;4awCt>(}8B3J2!RAyawI}Q~!+XLx)Be=exIl_RVk7A>JKJES?Ab7pIKKFR z)f?lV!}y>M&bwtsgKWK2;ieT~maVc*ZLZ)1-Ut_;`mpMROm5ekt*VXN;#kETufYW> zwa{!)re|E72WeES%IQ{fujiLnvMwkB*;~gg+w{YlEWP7`zQ%P1698yN zi0@4Hn|#{)7!Yq}1L)^r$LrlkWMlb4 zebGH#DrQG$K_OM(o}KG8sZl(Z$Zmj*PiwGTr0+9$3X?x^o6j&yUTa~nZ#CCREZZ&F zvom^(04-y#LAfW3P)w)l05EN&7EHC9RV2ZbjZA86o85P1q-`pSJzSTgDIrGd;Sd^& z8oib;LO1LT#~im&>@WdJ)GqI!yUsF)ZBoAdO?#VbeV!wXuwro`TC5#3m9Fkn00B$c zN4vK+wu;MkLhB}}z5#}9tX+n4i9elSprFN!YQg0ktoo#Q^l0#u5p@7ZGsO*NBQ zgbv?sp}EEH$UEo=uclqgmWQE>o_oA(MR)?e*CUoAzoRo!%w~V@kL|!=2vuxbiK-p%8^g9rlj5uQ#5udVH>@4nJ;MZ-5RRv;|=fptu<31S_)`5(f^4`;!7JCPf@r zBdlN?*A8;~@x&OtVow@e~aCp^;)42K<}v-a)^icg?Y(zRWsNNv&8 zWwdMe#m;x{VF<6WV8)Zp-a%(HH`yGma;(MyzPkARX4y62 zi0ubThmLD#i5<%%-o0_rZwKoU_@&bCbXc6&$M0=lk)hxf9~Jp0G7aO#-!$HF2o=&M zb#YzP9ADA#ju4U&zjc2=cRf@e6~i|v4-`#0zYYnTy^_BQultIt8Lu@+mn4Qy z=Pc!H*}3)d-r@UwzGC~Q-rC@BGmsi_#jwe^=yPwM_Q9A2Ka{vnlG=mZLv9Yy-nvVV zY(Q>?P#Fn|@x@G^mj}eL5Oxz66}Z!kkQ|v_dBUF$&ETh0ni%E`nAsJU5o~CG~ z%(D85cUK-$#n>K}u$XBGjV9@_sFoU9Aw4el;+EUOF3}v9;Apc)4w8EaDP9?xNHS-i zfs^8`Bh+EBE;^=@Wn#GyV>&P?&i?YycI%gr2-#BBoRw-xQ4b!kvdmnR3cE1vX%NU> zm0*YHFxO6=uezp@;@E^(Z-{I!s78aKO=W-BENgBm$_RGYS|r;VvqhRi+*-^|L{d5f zieeORTmluw#!HJwz-)%fpum)uQ%ON%@zUx-?yK&yoGfdhd(2_7^ss0?`|$myqfnzf z+JMQrPjh}bkb`biRhu6xEhO(_-_i#%OB0KRJ6W@)wn(VAm^H2nY$E|5MA1~MxI$!Y zs7Rap*hXwXflD;qr*-bg<180vB`f~6V8x^i%#rR$e$S6ha$U0IeNm3x-0V24Z>lY1 zH>2WQmSa?=f%bG8Pv}`e0cMV$KQVPz2r~RR>4k1C0snti)!)2f)IAF@& z3K*hX{82Wws?auQmC<0_@slP%UVPzmFjabpveNLR`Mx91OMdJ;4p6a6U_IZ2wpXB~ zXN&^MT`w)B`7^K^>M=}Q%$y49dOs)X4GK?RrvL3(K*-HV-q^crm)Ls}ZdoVx!lZ?J zsbB-@(V#a#9#9?tBJ>KA8+nEP!1%*TXh$EPzF8Y;9z%cc#L5lV<%gk4zxuOQKRc1@ zP9&9TsJG)@Op2S1(qz@X>yJqdE-(D_oKDXeUZ@|SNQND57WK0(-S9f5<8>*ySa)7R zoik;K3%ci_#Zcj)D=Uir7)t?pMqJj^5V)$+q*F!x`U@5oytazM%#i{8RsCr}S7&pd z4KbW*s-#3{P&kBePI1+RDFz6Mc}36@%PCczSg!Z?oq;>A6bS()`h{&)g*~zeQ#()h zxmor{AltucoMfTsUR^bPM@W%8;_e77eZ{$nbm&cTgnsb|Z)_?z@e7jNGcWTBHkHIT zQin;lIogBbBH6negJ8sC- z2nj#pDQ48_5{ZPN4T;~qN&nzUKh9LQPkRo75@-0{HZO-mdS{e`TBADUz+bCQnVpwv zsm6I7G{yDps@^KjDUu@TZ8J}m{Gtm;m7I97J0vkD(Mkstf-?~{+5Pea)olrcC(A+i zx5|`vRl`a;mRkPVQ+F3qg3t6>}_oKP9* z*n1ow)7WyzhS*}-oUPq#RuW<-${`7$7@g7x6)f|hM-pUD`094|)PBCkSJ?53JDzLM zyNY7*SPW*W9ga5%^LYEAT=j`ex)=4gk*HQ+k3z^^!MgY1jt7DRDj02HG1P@J^>pZf z&h4RU@}#!}w&Ia8Nfe-N5GZ8p-1us+V=IWcic#fHsBE;>t$^Ebag#J<&jHRVq*K~g zE8O5c^H)^{6g}OJE1n2C*cTV9RE%GV;szA5MD3)W19X?E!A538>bxDGLB@=xkAD3x zl0O62l8k*mf5M}jh<$&4hG=VIqbX_&lc%IJ;2bWPLZ@*uq45KfB zTS_{AHn_MLG$X}_Ir3)_3nUqT3j6czG`3wAKpmlnn;A=bxs8#Y`72=Y#C_sz);|B$ z(Rq{~o}P3zCe_%R^QSF_gSTkckC+40TVGZ4E;2b^ z*6`ZB1`S_bAaCK33x}?F0r;Nup-gw_Q*UXW9$GxR@#mPJE7P@Q*+NHSkL4EU!m;e~ z$nyj)jppC;yG>en@v}^o=&(yQS{Xr!(LcnuOe9$&0_pn3k}OccBU7{}ECTOIeE<$i z73RT^P7aE!P|6+o*^V?ZQHY$XElm-otJiA9bI(<#%18Yp*+7ACamBP5(pvrCQWomg z(zvY=OQQQuh0SngQne7L-PkQ`{V~z!A-1uSr<2Q+S#_+^yg%l}UZ*9(WYR!o-Dd!% z6_F>b7m&BILY}{})TPZ-q|vSH8i$Xv$by6tWg!WDYJ(oRZg7lREN(NET%VmmlH<0h zwxR|frZ3mr$t1W9=}(h^w#dBCf0;%C`AXa0vK4TwjMbMSV9hk~R|^ z*>BOLetxw6p@5Vmt-7#05Dq27eQL>NUsRC_l_61G zr5)q}N-i*rnb{f*2 zP@^jUVZ64|)Gi6Mu_)9p$Wxe7u}=2Ts8c9?{e*VD0^!Fc@N|9j=@(SlCfsaVTWYcV zJ#S%Us7kZ>xY?+~91uhH{4rnw8hXnHsY`y=rlq+XT%Zs1mdR%ipzgARr{D+zLAuub z7RNNsX_M*_m5d)lj|;kEPrqvki$|o4l*^ z&j6et!Mhzevd+p6nWNF;J6GJb!@I%yluzgz;!r1dlLAoR1Jq~8lmp#F`3iSapHV}_ zY6B?0x_kn?e6XsSyo>ddGnVeQKI4jeY(?ppqAV#*RTiorv&M#I*T|=D=SbO&FkHz9 zcJ`e@zln~}jkSGYdDKw5LQ7HJ@hYbd*%-+Qvrt{)ZF3Z}20PrE>s7EaO0IuNv)?#s zIKEECX@h51<1%K69x%9tlZXUlU(DpRfC*pEMA^V%!&<44MsqB@*|%VJd63Tru7WOT zsf074%(lq;GK{@W6{JjLC~Dw)M+aKpSCaDCVYO65p1OS>B7m@l&nSZFqBvbecc!42 zR5@5Z@Q|a~bI)hcqf)e&#)k)}Tax>Uh{vJf!b1k?1Oo_b)=vMt60C%>RsHpWkmQ9g zityK&*($x5Bm|q#n;k=_$8~N%fTzVh^7?C8v0lxGAQE4mpm`y|&q)y{t`H&acWtS2 z4s4k#$1P1c4#l752GiSjtu`Lac$e?f2ls?;^m?c`Sg*V9@sAR@(2{qPt05n2Zu_rW_c+UF*%U6{_q(^z>trx0E zqewNW@KAm^2F#wzSGOk@>k1{;cTH&AnO7!XVac=|wZEX{_yu)^=rSe#Wz~B~M9~<7OU>2j4koGlS6aYms{&vmeF6+X z%R($IpeL4V2BPs=E6K(lEQ}Q=R)bLL(rMHM6S0|e#5azP+>_$Axlnz(sOor<-Sc5L zB}VsfAFp0|SvcNZ#+4QmG%-~KY6dS-$=7RM1a*Uc-F4lwWaQ~0x}{xqiLCE9PrIkT zIXT{-^q8Z{2X$*#mKJIo5{i6BEJOxjcjoo$qApB;)!ZGhsDlA4>bQP4biK5-GBwb% z2i&XyzL6#dc0Wz=PaG!GW2NLe`B4Ktf`JOV^S$iKIqCq#Mse6Akq@WIA;r8F;!a?+ z2!aKHdX!WlfBxm!1LY=a5#yZjChf_78t3YTW4_fXeL2uor3ODbj*IzD*D-6v-S1N|dROD{V_hp*K3 z=J85}_mcNUqxQ&VrEiwV;!$S6BazP{10r#$gI~& z1%-iERyr4I|Jm?Rn_B9+VHyv5wKgA4RcYlDwsI?8_`4+&27E@Zelxhv4_@#Q)*OE6 zP7vyqs~n09MkjpOST8Sh@<&sXE#kvRk9qtuhJ~QP6sl3|@L=-M3!c3TLve>1V$_UU zzfeE00jKj2ntZ({37nE4G8D3B3Y?NGLId^w)`_C<@`(!)letQrB*1tH3NXQl{@$iP zHR1P#x{!{Y0U!#Pfu)^^y@{j2pM8Kry1{R0C}7X(xZ`1Qw6^=5CM90G_T^Y9 zkghsFbn+r)Ox#mqBJfgYt_x_~RBhf&oGE3E8qj}=XSQsPV_pyGxCH0{Z;F>&z^o?5 ze`-2()iXN^$)+pyDW&a{^=F<^;)DE{sBHpg5cdJopS!77yU~q$G{6AH$b2MbWLrE> zi1S1(OS2&RUJaNw5}~j<8#@A1br<^n{-F>TbYwf&a5oeFIf|IkU9L`tF28tv-L0s? z$D9j#{y=-V2s|X|TIAApEeCAM#XFMMW{vkGIfEBVh3wH*@%WZHg-dO+Ofer=Q6P+y zI6$eAnU$+RgUx`fK-m8ibDs5qdsBCYD+z>6~gG;TW7f9A-cj}d}*WN z-xR;49DWAV35vvvvr43L3A&f>DMJ_FK8 z$w2b&bEc>-<%@IPc&HSXDvL-2%a@d%>RJ?gEc2S59$&6#EV@~_ExMX%?6+SfCl5=* zlV5Fa9`U%9x6Ujao}Jb@t$ev@L=k2QliQhqzw^5NBEm~Buv?D(l`io?mf&zJTY>BN z%|u~{+9qzgy@?hV*3ry-mv-_D%auu5Y9H6`zG6q9?ClG|%@{7Uv-dAXcYR+x-(uck zR^KE}hyR305H)S`B5HE3e3BIZbd!1e8uV5gHB^F2t1He!la|D2z$i3a`tpp$cwo}Q zy{?zp9-1L+3pql{p-A`2Cb?$&GgN;l^sOSaAN4x70&lgjT&<-eerA{5mO|E|b23RO{p=0t5@r;5mxV)2q%5;(FNu6aJ)=w+v))Xo^)Pgw z@7bCxO=>XJs&;ytCHG{5RM%oxjFyg@Z7o)W+IVjRRy_;6z(!9&^5Gk5YfN}%v}p)E z#^5?5vv(Gz&~Akm5gPJtEcrJ6CN1I&;TbzX^J$)c8YxThPZ0)#bVoqia#PBmS= zcwVv18-o9Sd&ov^$G?1>YZAfmg?>&Pdo@LbBXnl9-;)EqY** zN-AmRtvRlF&xE;rsFzd`8C~ga+qQYZxZ*6K$WdP|{5m+S9ByZ+}CSkDcl;c39yD&fjRtr|f%!?NZ}hAhxdO+w0;G6HsN=I*w4WLacrw7}SY zs@+WErQ@M`A2^dq!UBU{yB53|&10;Flf5W#%de|OL9#SLLtYKmC%o7bujvUTkL$-r zs|B(u9Yh<5`NC4G46c_`Xx2OpH#cVz*hDy`7qBUR+qz^K#uVd{f}NlgQ`P{Q^)9fV zKTQblfTLgE#?uy)g@idi&^80H#Ajw&=fp52#X_L(Q+h&e_GC1j{X*a*<7R{F$yi_9 zCf9YHI3iNrdr}JzEmG8~l(&89f(y?|UT~0i5A2KAnI5t+AT24xRmRg)8FZjA(kS&i z*E`nMh0689A=gNc1UD#C5iotceij%usIMoL?nD~bwKP>Qx~E8eU}#s37ABL*ZAU(N z5t}WLg$l+$dXfx6vpY0s7g%lkay(YQl3#U;%yalv5iKTfmq1T|71G|ZprBQ_y-2Ej z7gS^vR(H-TOiX)>Ws5O^rpYY&F$?fz0Vk#ixzF0uXs1V^UHJ*~I$>iRmSYGFLs?xd zC4A#?i>?g4idC~YW`&d+KKB-k$$+K=xeJEIaT z6-(;@x*Gc?=KJ?^&bJ#Q+u*C65U_1;+uwY$_#)zGwaX1;OeUq52Nl}$)&P8U03u-T zx!>uI5Re5c{UnoAP`8OoNM-2ATLbYS77iKZ)S-9d;!|r~ITv#u)No*H#R1Yt4hUWY zYi_r^ey12hFFKqszYy~2f9i7YU!$Mo0q5(CGIj4>D~GH%hkzes^CQ?SCkG)$X(#h+ zOJ85Bl^^o;OE!e7_Qq+D4RL5E&+LQq^li^rG6J6JS}aXav>wGFKR=R6`ylsO0ZXGW zLUhEElZnL>+Xsn~Z7=bH#xE-LS?0PC9B;3j$&%ifT;uH8rrMA~LGT9;WSf)y%Ki25 zj%vn*wcQ(Vzx!Jk$mFt?3t(U>WldTbSY9F%j$W(?R!{l8b{}H0Qc;kFx@02MW-UC9 z5`_Q`Q+l_<9_IW$LsSU89z#gTu?ejuUt&V@TE$Rw`jF&ylTY=eIHm`~)*Q(6Y#QpJ zBqnAuC2$mCDHbWJOX0m?PGFnIJ7el~P!%`R5D-HcsVb7?l6srwHw<*9&j@=_(v){nU>kAI#=ee;t zXe;3WueRbSw1(294oSj!#v!#R1csAo!jIy`8u#z|feBS{EK7A-Z!F)Y`PV9DnAMX|Y*OvXrp3+DG1gI;U7VE5% zk6iDS)c9P-=)C-zc8s#o2YJe|P>y1ujW^etD(tP3`G`T9I{4APtg)2kUfAcodt?bH z-eZ}$?Tt!4?xOS$Y?Fldz{tqUMT4IKzEoteF@UHsG^anNe$C;G+OTBVi(Rs8bD8DW zG>)gtCz=?~g|>Q&XLzmL*ebR;u&6H|BBa(VutMQzpPa3VE-;}*sLI%H`q(1Fk~Tha zys@;TIy<9EoD(Lg%#pA`Lb^9uSMfmy=5hFV@hsg?UoZ(%t#x)7x7Ut;raA~6wqCV) zTdO02t`w1=+gPMvGPe6>KyH6uWSz1jG)_;1*j#m}ePV;qa(qC{IC$ zEC`I!M5A>ENzy`2OxftAK#WEbJly9kA{%zSyiDZ%|xn|aQn^kSB$ z-4`O$?RbwiF)CmEis<6qc;z2B8fiAJ0h$a8k*A5D%orQTyNuQNTv8%q>l16VKl7Ag zE`^mxCKyviqZUJ;l(5B#jmy#==4n<;rn*v{Vm6MkrVK8(vTR_U z0c{G3ldA`w0#_8jgR;*+X6QAHMI>x(-XjX06GNCxWHd5MfA`*YXfSHBA0PWtF|<@= zzn(fm$ud;wIgenJ?gQjq)p7aSW7h>{qkrKc;l)P~94EeQ_Dcl;h572OgLi`Y+Fb7v zMQ5)S@aQVL3zG zzMjk_SL142hg=O?-@xZOM2r9gB?8%?;$f-nJ-ogeV?jK6_Q77{<^J^+{YiFpaVwhv z5~U$z>CWtzo9#BiQo0X0Fct3=>A0lEn|PpJRb0BYP&EyR6&^95`84591yPk}0)JBM z2~!2m!7evnJUxClh$}pdxxOtUuDCGX47I|Vk~4)Ie@}f^2pw*SK6;QnFZiN4Xf(#r zG~(mwVK!&b`>|6gON^qiXIL4FYlWk9gJ^L|e8T6IG+$ypM&6Gzs~tckxQ1>o1p@q_ zwx))}jH&DgBvjZLz5MeL@)8mE2Mx}#Bi&zA=LGFQkY;F7XGFdNT8&_dWE)rPcBa#k z#TZ9dmr{ui@me&YaZq5^lA*IlQ4_CJ7FNUIkvhIW2HS70iSPt3x~3E+cmoSA(iGz*$9_(*ulzu>+)FTd%o+QDe9t3ZVX5DxvTt^?A`!Q5;|km=7H!UyFTmWD z5%8QX9o$4=@9=_jA6ICUF95A^%(OV=QozzOM@6!Hax!Z&%dd4NDE;fR8CT?Xvs+GA za2|xW=iC+Dj1rf)PD}{nZlHJTGacTjU-!>BEn*%|buQlOF;!1)%rvuZ3NLSl})wQ8lUE1x?C5Zh>mI~IK-56LY zP!iq6aMl@QV5w-}gCoYy*xgtB?o)bTkDB1Z>`rhL zY>k+X*dAX7AAEJ&t*Lth5Jpb08FIp8gt}zV=3!wCIQkMFf|;(5IBV?VPAFekp={o` ziHMPU0n`aPJ|o|u8!svHPp)TDRCKXsIVWp>nA7DiyBW^oAg#1RX)UUl4C?oSTlpyA zGKlXYgmor!S7(7VOZ^EX<+H}unwr9v#8EK!8DQl^)@NXcuKO*4p{Q+F~%$;;(s5 z`0CixJO9Q*7IRYU@{OZEIfAqt<_nJl`S$XPb&gVB)b|zYb8V6?q1QSS(6etkjz3-= zdf10Z?HLghZeb(6|570i*m$Zbf~N)vM;%f8#0aJC73kQargLK}l^nQB9QTKDZRZ1W|Mi3d z1tMoMU@3lb45%Y9=tRNhdGWPrNEj3o9MO~$!4%1aWrR{$!ixv6XIFOqt3>|1 zf@AK|6lw+aKq0H^?yjl3V@|i4clfj8*NqV?>slAjS0(wjRQCG5aDDZc^OZtgfzQ$9 zpn4-R3zS5rZ%1^`=nB)qD&C&nCS*nOVzs~osF{NCp4h$TzoYcTgN=rpUVN}}rWG00hXCD+5oDl0OEGu|LXpr=v@CKG zf-qjjALHg2Ax2b8As=>gUszjMK^Fs*(YradA|;^65xcb*d%jq`8}&+@c5+;3y$dQu zoNdID9q7K-Q+ z4F8TmC%ETPs@+NTXz=+&I>zG%dE3!Xq>lt&$8{JHgqV&l3#LlntB)W?@cB7jyhK$! z;T5!;WmZ(i>JeOm9*!%b)leRyi;=S&!L7l*0Pw^U zazk6-F~0WgGaAz_{nFrf)#%WKe(Zpm>F>z5@G++q|6IhFFX#%qhP}yd4`|_|-vfCK zyPqZA*ae=|3Ez{`&94!7C*A=Jt5krEaOQtusv;FI1n3F;Q+D>k3cP&BsZ?Y;IvSGc_WYM?Pih~7d!w`Dk z(8(~BuqbcBl!eXa7VXw8`8+3#?s_%q^T*qjrqi#5FHuRux$AwP3M^nLi&^*z#AkW-k)#1z=M9+I zr=qN8v8L`KqN@d_wt-OkYBUK&Gel+4}{SaOo`ys~^ajoY92a*B-`9>oIs zd>UXg;a~Onzq2u|Pz3j4qmVp9fdzkr zJ626FcS>FE*?V^b`tVkmaJ(DhQ+BvhK8@fa=#Aa(3b)+}&+h2(DIcHbv-cbGgk@Rr z&*?Q>iQ%Nlmqd81!e&RZ33l9sM5@PB{b}KOZd3Z?w^E zQYJ$>9eWF`zJ%j8pmg7E>MZAc0SS7nZkDlHlfrAo(OJY@r*y7PcfzJ0#=eB$|C%F$ z;#qP&6=vdGg9~fcJ zT(v+2vYTr7KdGO^9^6CASh?PNYPHmCkM+4x4@(6{>R@u&V#e&mMAE|QY8M(i1L85! zz@jYYWu7j|3f*vJyiw|dlV+?4jXX@6_!OUQOLYL-3-Eg7cFVzM8cyS5b{!Jow0xI} zw+}CP67+$ad&vOv(5^A>`eM+fnQjSu{Madr0?j19aOdM@;ES&fuwQ2|W#W4!v}I+J zXL1K4#!_+ej8k(sO4ZIWZK~aa{W+Z=9ka6ZpcAsLIsHK=8T;Q;4!ueHdo(CJi!Gs7)vP6m3ZExif8z$tiCCNKr}8==qza(qtMN~jO;u+mJ)JHFYhk{O1H+Q}-2Q=&KAvM$M0yhE&>2Z*|ooFb36MysbA^ zpqfj~msgU}P$)Hc_e%bPn7!G24}w&21hh+4f=8Ka>HR`VHgk9oNwUW_e@G%)E9%FE z{QN|5ht51#v0Aj!5_GJ5*Ag`_1v52VTFkpL<)UOzPE=l~I*^5YU3LF3l=X5hy}97shto_CbX#WWtqj_~CP~y$47UICy@F7DmYgX>og_js$642WRVz zGo>l^UG`E54ef7T1uTeB&)^K$i{IM!I9AfL%+r$R_EiSqpNy|l08D`|4NRj!1MnXb-+h1EpCnjnQl(N+f;K9qORVX>LQM%#Fw z>QCA9r=DVs+V{|q__}cU6i{oRUg0nt&zy`&Cg-UG3>#M=hDn}Uwb`~fo_nLRxtV~| zq?>)yDk};ldaAK>dam*cJ(~46jqECZzw8k5FwtF z0AY=6s8}{=bTVYs7E!)!ErY|GW?f5oH9+<-GYxP->_XVnnNF9uR+wu$$jQf;zUzH1 zRDpqJ@<2Led>>Ka=9JlEI97BfBy;6Vxo`iGf)n$E48w5mv4`_h6lAXzPwnX#tt`*7 z%*{@w-&a8p1oFa5?oPt|j?>b2-scTKkihhCvV4;VMlNz(r#fW@HIfV32lS#I?H{T) z)2%vEmyzD1RKeZM=)&F1>aw8WV9q_vngIdV#(~<0w(TMjN8x_3pHxTjVTK-$idlhF z%3?S+Y;lf8zkZ-_xmL&wvu%fiWh2DX3D)^KfutXpSt01h3`@V>NF@#Fvkoqb?jf-H z5i@Mu{sK}@+nle5bfiV#HHZ%s(H;su`zK|y{Zoueqpc5zS#A9BzH^XBC@|ffLES>3 zpN;c%)|9JE~4^_fFIi2%9 z{nUMxlezuT{qflwBpNFHmoMd|iF^eS?iez2wgW>`C1`V_y)%00Xvu9fJWt;@(6nD~ zRpoB9g+f3hyA7M$s0id&4P7OzeD*I?@js-a*(-$Z($yYXhc;~TO!TcDpcN{2jjRaY zX38U#>_pa96JU8gr--Ogdl{HTs zFj_j)Q>G7TBF9awhZGp%`J!SY<4WKL9;D=KgBr7SO~-M-3X7I)O}{io<6$;;9Qf)_ zF!<|$ffSgk;07H_4Pf8JOk3ksLzBxEm!*=kC#hW~_06u#G<*~Z_GVG3Z%nN=r?2n2 za*kBH=X_+M?H5#_#y52ajeUXLDdAE!&crj$;^J)&rQWI6^kP|-HU3PvOM%Mx>ao`) z&_K^EarS*s;%H>xNifX{SgS_C+dvwz$`#H#!ngKfCU3O-pdSa?iaWK;SXw=#CsGH- z{BnE-o=-S=%Ob%N%et9zmL^iY5{-A{&v%B*a}MvHA}Eb8YL}p^Ho6$gmJY3*$kTg8kF>7pfGCzP>@^~{AOe;LL7)P~`X15*(ih*WLM@vl z7GKjs#dn!EeT9PfD0tI}3)6j6_-Dn3_OXu}v6u0*>ktLpv70)!W6`)hBbMmTiVCxU0sFN&JFHmomu8h4yJ5mAl#*f)2MRJ)A{``2TE<4I|InR629+u#A1rl zzDqbXZ`mP!Nprtc(9(9ykv~_{xSQ;+0e{T2m>Ke5)-d$#Za$Xuo1sYfF_R}B{OR`x=pZZ}P(GZJz5{%0U(7jLiOp6dPLfB)-C|C)* z{XXzWB zHkosTS@{z@gpTl-AYMAV zvO(hnF%r^Us!v;Wc6P51aXNTL@$B)^kkd#NV9MaKS78dwKYWR&T5rcJo9EaTfO5l= zbI}DZheqOx8uItTPA+WpWA??7$W9tyrC6GVLXcF|uTdn%1h>I;zCzA$)5#B@XGzUn zl6$q^&d9SHC(oA3$O@IW&{%zlm&?{xmfjnLDzd18rW^9gc(22a;sV^J-SkCC`m6YD zu5~%4+B*!g#&K6D&DAnh|Dog2)N=n5FPP2|#|=O9+i;rddBs$I<2Mc|bb=^!smJpr z24`%zIII<~6_-*Z`;_6WRlCi$Ap3gUK12Lkze3~aI|l%dNO!;+!M~ER6ErZivNaGj zv9+^TaM1l;|9`#x_9$B@pr`;&$yZt1R2z%Ky{(%Q_v6=w6e#9Lgh7f%4zY-5o2!>m zot)O6oi{J?%I3>{>>RD}ODMe3FuKcoe8-nFY3HN|NnY{6Cja%xP$S^beB;Lqx2uQC zQ!9F)T$|UuYQyO{hT5W-cDPtr$mj;NYwAE!4WnlvNwjt)kaKWYOv;=y;1#1b3ccXG zZyAGSBGbYV>o`8+)??irpI*A!2kOuoslQe1dF52BUZgp#pjNG{5V4$QXi;d5n_PgNYI+Fk5ZDNWI()H1(Vm>-Zp87MqfQzd3l)1wBw;l5(!d zV3%ON$;8@ylwm7!S+&MEt~`BU3FH!jRY@sAvgnOQll*|adVWix(+xSi=X4R|KG&D= zdS<*AAzScEU@1EYG77EWmYn#ean!5fHkxdWNw8u*&tMT&C8=GiWx4lv+?YsGYK#rB za$1k{qG1fXs1;IzadA&Nq+uG-(z=3uby|jOf{0v*v3hozq3h1T`Vyf-=X8RdCEl;$ zx9KKbhuhCO8z)6YJRfjAc~1t0!9cF+F@(s+)lsEnGR4xR?eS_RCG$aW(jYe(eSmtM z*m6{ay!Q}g683}Nm*GTwV}sO9ZZK*|V%_BRqTLv_D2_4fYq0gigRZyi#SpECwgC5H zWx8XA?04vfa-JXdwOtAhD?>JYG1=Ux1zWYL)#wsyU3s|Jg%S^6AzZr*Mod>+njR$F ziKBiL0;kqT8!>E{lbsxiS8-dEfq>ls^E=bVJhG0?@DVzAn3H*1|I&5A%)UGY{I!uF zTH34X{8-v^E$0<(?Ly^Rc&B-qjj!k626LOUYhMv=+Ph`ax@m|nvY;oq!@>M=S|dxMK$&6KkzQD8!Vj;JL8q@$@;xx!xYruGtebRUYkVw9o0DK`VdIM|P&E z&7Y>-Lv?_J>+Ss9hzP$6ra`2E;WAT#*Ini-d+Zm2U&oL*AnxREp4DFfV>IXQW3+;c zoxOp@zp*K##|}w$@uLQQoGZ4dt(!5O7Fl8yL=o-|z=%f2ct!tm-!lb&GKLg|d{S^l zQpFdBpd$#G!UVBUpj$1C`TXPKNLpiyS4-Qoj%VhHga{GD=BU|f{v*KVXjvkJUV|^l zKSJp*+(q-(4fTm#MFD2TG0=s!@)&3k%Nn1#kFpn)339FDjP`Y@ ztE%%NCY@nEDN{$WuFSF&*n2p zi!x)+s?uHp7EXazq zg;lGGm#7c2RH!g^9ZQNVDD1clYzOYlm@=d(NzoQih6rxW{9R4)8g`3xcYL=SVdT6w z5I2A~E{l16KTwm241(*lQ}^Ap#Z@oQ2ViTUK2hvNHm14J9MerKN7^Ym7RY3kjEkIE zf5lcCK?d#*V`L?cJp1_C;rC^Cly|&tlFM%hzo2Blu#ihLwBHHvU#fhWUF;eYJeT}P zm{-iz1}T(?ps~y!krsn2wCVufwrlTurrMuf7QLlZFtO<0sp`JpY+ksxr?3SUTcLfL z5hk^MBN&;co%@2*lwB4|jlKn10*ZBl)@TEg#wSg%xr#!7U5y?pj zmXruEYQ9QdC~Q|6GB9o~NAHZYMdmc}c}`ANy(8~-PY8)yR6RfYm-dV-Qzn@ExnYJG zTj$eT8zA|rt+&&Fd{t$*fOLj(nzL2?EE>J?_1Pv44Y>J(VNKj%e`SUouxc4FIkNyG zICZ5o|3aF9@tz^oCEm`g216?2uqbkDNB08ui4UeV9)j*#5T(%TNU_Q$(M)^vKo-N&m_URxpfV)=xV@_Dx9g5 zp1-106&Zh>-HlBN6$gHX<_@$9Vr2g^+2+e`c+`dv$B6_qs#Izx!)9i+o8z^+kyCXu zXZwTuJv?Ec2+~L}%LFpoxNop{l>mL9wNyui_o5~|IgkSSQ%I1`bW=nWFYUTzBR~wXLTFn_?S1G|!S&U|qMF0wcN7yEle) z%AwJ)6XE$(qD=G{(9miT9Cw%;@If0Fh6r>~5;88Nurf^vj0RoORw+egP~uEA3oRaK zR5G2e^Qr1_tAjBuCELVUlP_yETQnzjk6f_WZr2hbaOE_y@I5$}t0)R21*I?yrrTOA zP%u74KZ89q`n;ar6{gm+?uxN36;AI5>!Uu(7>wmH)K48pU7i%ll=>_KAIdW=ZcV7z zTMU_;k?f6nCoDd*J*R=6&hU7Q(Lz(cm04drzY*D6f2oFHywrCK4lQr$fZfH&M7$zc z4Q62-6!sIESwAMSbbTsZC`w2=!a-TA%EpZ-jMe?L$b)oPlr1%?^v*1SI;ia$RXQ; z%;buUB6J{c7aDAU)B1zB8^(f(#ST|pFxM5Rc7g!J0GGJf6-QKea^K9gJ7BpRngh)npS#1f$&1GynsK4y#1B?g*p6`< zHg>&_IMwH2YN`!D=V*q~vpmLqxS=$~*c(4I;&eAs?ok3aK-EXRyFk~HRxtjO`=)0Y zUaxF7XkHMi!5Zj!R@7Qj4_N7YP7J}hLDTjCMsFBl3QCZXi;V-)0i~ST7sRf?owNKD zx|q+rOnVS1S`+uQK8dNrqTpi~hUCB4c>U{BiSXE^f(jVq0Y?*n2mqh&;`@N3?*A;j zzx}h^{xe`y5J2#6NJt=1kzY0J0nhsP3lZp8;M-Rj5k&zy30YCVvHM?>adUFq3IhH? z1@QTnqrb0QpKtGe|DQ}oKvqIjL_zVnjOfn@*8n-AZz%xt)_*R*-1YrJ1o|qF4)|_m zYxE1}(-eT0pr2BF_@3gs`2Igp0R%{YN_g~Z!tYTGeq%QF)i-EnOTVB62{|)eWXr;e()1T(3XC+_;6;OI>K*@!F0R#d3^`8KruF(LiHD?zA2YX|H zlC6o}51HntjJrpwc0~ZDMZkyn7e*IA9{#{6@pl>idS!fy2U_U5tO>}gJRmjQFL-(Y z%kLlX#B6o+%?*?QV)Eiv76#H*R%Q;?e}=~0&|2&PfZPFk>9_6Ozpok}XvjZ80~CDC z9qa(7#6(TZ4FvS`4D9S=bS!m@{*IgQH1ET3+M?g|ux|m@xnJ{62#5>%hrFx&72N`0 zxG*#^asY^71BBuKoOgZK;ni3`mGA(bC5FE<4!GC&d_nvp^wahf2ZVkw|8E)3b75#w z24oxvP&?nA|G%#qpCzP6IsJXr_*elVZ~UPaeu*6S z=i+m$)Ggxx9F%_Oqexy4lgR6zhL_1}vC%dMLhQf6MfrE8=O`+P|S|e9&e8 zi2J=-|J(5MG)&+Ryeq{&;{DR}|1D_X)7p3%g6;>)w`t=Kb^OmG&eO;2_yLcv_gmh6g8lxg$oPA2{8n#I18V$0h1UNU zsQ(aN<7xh%1}^x)1Z(s!n0|Kq0hG@A=P(9Osh;Y_|Dd`t`6sIXq9Xqk{;2@^5BNy4 ze}ezs68|KJ{*>yelIjnt3cG(n^;f0+uj+a#M)`we!tq~_{IfLW(-J+^?)yQ8==x7& zKkqF+#eAw9^#gOq>z^>cH^^VmfBpDrtL`bwQ;DJ#qOwxINtv|AFjT_8anltD`?}k3TKM(~Za}xKVZkJ{t5Q` zfbkEzaZd~I)Jp$@39bG&rl;=@Kh@p;D9}^O@ei84hTmv@g8g2gzi$69_B}Nr{=nyJ v{ulWF-JtlizMfh|eh^K!{r|%7zu8D$N`V31fxg9xVFW__CM4JX?brVS=I{&) literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..0f1ada8 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Sat Oct 01 23:56:08 ART 2016 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-bin.zip diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..27309d9 --- /dev/null +++ b/gradlew @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..f6d5974 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/src/main/java/com/google/common/io/ByteStreamsHack.java b/src/main/java/com/google/common/io/ByteStreamsHack.java new file mode 100644 index 0000000..8f0ce9d --- /dev/null +++ b/src/main/java/com/google/common/io/ByteStreamsHack.java @@ -0,0 +1,34 @@ +/* + * DexPatcher - Copyright 2015, 2016 Rodrigo Balerdi + * (GNU General Public License version 3 or later) + * + * DexPatcher 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. + */ + +package com.google.common.io; + +import java.io.IOException; +import java.io.InputStream; + +// TODO: Remove hack when issue is fixed: https://github.com/google/guava/issues/2616 + +public class ByteStreamsHack { + + public static byte[] toByteArray(InputStream inputStream, long expectedSize) throws IOException { + + // WARNING: This implementation relies on non-public API of Guava. + + // An equivalent -though inefficient- implementation using public-only API is: + //return ByteStreams.toByteArray(inputStream); + + if (expectedSize < 0) expectedSize = 0; + return Files.readFile(inputStream, expectedSize); + + } + + private ByteStreamsHack() {} + +} diff --git a/src/main/java/lanchon/multidexlib2/AbstractMultiDexContainer.java b/src/main/java/lanchon/multidexlib2/AbstractMultiDexContainer.java new file mode 100644 index 0000000..a929e16 --- /dev/null +++ b/src/main/java/lanchon/multidexlib2/AbstractMultiDexContainer.java @@ -0,0 +1,75 @@ +/* + * DexPatcher - Copyright 2015, 2016 Rodrigo Balerdi + * (GNU General Public License version 3 or later) + * + * DexPatcher 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. + */ + +package lanchon.multidexlib2; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Map; +import java.util.List; + +import org.jf.dexlib2.Opcodes; +import org.jf.dexlib2.iface.DexFile; +import org.jf.dexlib2.iface.MultiDexContainer; + +public abstract class AbstractMultiDexContainer implements MultiDexContainer { + + private Map entryMap; + private List entryNames; + private Opcodes resolvedOpcodes; + + protected AbstractMultiDexContainer() {} + + protected void initialize(Map entryMap, Opcodes opcodes) { + if (entryMap == null) throw new NullPointerException("entryMap"); + if (this.entryMap != null) throw new IllegalStateException("Already initialized"); + this.entryMap = entryMap; + // See: https://github.com/JesusFreke/smali/issues/458 + entryNames = Collections.unmodifiableList(new ArrayList<>(entryMap.keySet())); + if (opcodes == null) { + //opcodes = getNewestOpcodes(); + for (T entry : entryMap.values()) { + opcodes = OpcodeUtils.getNewestOpcodesNullable(opcodes, entry.getOpcodes()); + } + //if (opcodes == null) throw nullOpcodes(); + } + resolvedOpcodes = opcodes; + } + + @Override + public List getDexEntryNames() { + return entryNames; + } + + @Override + public T getEntry(String entryName) { + return entryMap.get(entryName); + } + + @Override + public Opcodes getOpcodes() { + //if (resolvedOpcodes == null) throw nullOpcodes(); + return resolvedOpcodes; + } + + /* + public Opcodes getNewestOpcodes() { + Opcodes opcodes = null; + for (String entryName : getDexEntryNames()) { + opcodes = OpcodeUtils.getNewestOpcodesNullable(opcodes, getEntry(entryName).getOpcodes()); + } + } + */ + + protected DuplicateEntryNameException throwDuplicateEntryName(String entryName) { + throw new DuplicateEntryNameException(entryName); + } + +} diff --git a/src/main/java/lanchon/multidexlib2/BasicDexFileNamer.java b/src/main/java/lanchon/multidexlib2/BasicDexFileNamer.java new file mode 100644 index 0000000..9f8c1ea --- /dev/null +++ b/src/main/java/lanchon/multidexlib2/BasicDexFileNamer.java @@ -0,0 +1,60 @@ +/* + * DexPatcher - Copyright 2015, 2016 Rodrigo Balerdi + * (GNU General Public License version 3 or later) + * + * DexPatcher 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. + */ + +package lanchon.multidexlib2; + +public class BasicDexFileNamer implements DexFileNamer { + + public static final String DEFAULT_PREFIX = "classes"; + public static final String DEFAULT_SUFFIX = ".dex"; + public static final String DEFAULT_BASE_NAME = DEFAULT_PREFIX + DEFAULT_SUFFIX; + + private final String prefix; + private final String suffix; + + public BasicDexFileNamer() { + this(DEFAULT_PREFIX, DEFAULT_SUFFIX); + } + + public BasicDexFileNamer(String baseName) { + if (!baseName.endsWith(DEFAULT_SUFFIX)) throw new IllegalArgumentException("Invalid dex file base name"); + prefix = baseName.substring(0, baseName.length() - DEFAULT_SUFFIX.length()); + suffix = DEFAULT_SUFFIX; + } + + public BasicDexFileNamer(String prefix, String suffix) { + this.prefix = prefix; + this.suffix = suffix; + } + + @Override + public String getName(int index) { + if (index < 0) throw new IllegalArgumentException("index"); + return prefix + (index > 0 ? index + 1 : "") + suffix; + } + + @Override + public int getIndex(String name) { + if (!(name.startsWith(prefix) && name.endsWith(suffix))) return -1; + String s = name.substring(prefix.length(), name.length() - suffix.length()); + if (s.length() == 0) return 0; + int i; + try { i = Integer.parseInt(s); } + catch (NumberFormatException e) { return -1; } + if (i < 2 || !s.equals(String.valueOf(i))) return -1; + return i - 1; + } + + @Override + public boolean isValidName(String name) { + return getIndex(name) >= 0; + } + +} diff --git a/src/main/java/lanchon/multidexlib2/BasicMultiDexFile.java b/src/main/java/lanchon/multidexlib2/BasicMultiDexFile.java new file mode 100644 index 0000000..e3cac8d --- /dev/null +++ b/src/main/java/lanchon/multidexlib2/BasicMultiDexFile.java @@ -0,0 +1,53 @@ +/* + * DexPatcher - Copyright 2015, 2016 Rodrigo Balerdi + * (GNU General Public License version 3 or later) + * + * DexPatcher 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. + */ + +package lanchon.multidexlib2; + +import java.util.Set; + +import org.jf.dexlib2.Opcodes; +import org.jf.dexlib2.iface.ClassDef; +import org.jf.dexlib2.iface.DexFile; +import org.jf.dexlib2.iface.MultiDexContainer; +import org.jf.dexlib2.iface.MultiDexContainer.MultiDexFile; + +public class BasicMultiDexFile> implements MultiDexFile { + + private final T container; + private final String entryName; + private final DexFile dexFile; + + public BasicMultiDexFile(T container, String entryName, DexFile dexFile) { + this.container = container; + this.entryName = entryName; + this.dexFile = dexFile; + } + + @Override + public Set getClasses() { + return dexFile.getClasses(); + } + + @Override + public Opcodes getOpcodes() { + return dexFile.getOpcodes(); + } + + @Override + public String getEntryName() { + return entryName; + } + + @Override + public T getContainer() { + return container; + } + +} diff --git a/src/main/java/lanchon/multidexlib2/DexFileNameComparator.java b/src/main/java/lanchon/multidexlib2/DexFileNameComparator.java new file mode 100644 index 0000000..51edcb9 --- /dev/null +++ b/src/main/java/lanchon/multidexlib2/DexFileNameComparator.java @@ -0,0 +1,38 @@ +/* + * DexPatcher - Copyright 2015, 2016 Rodrigo Balerdi + * (GNU General Public License version 3 or later) + * + * DexPatcher 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. + */ + +package lanchon.multidexlib2; + +import java.util.Comparator; + +public class DexFileNameComparator implements Comparator { + + private final DexFileNamer namer; + + public DexFileNameComparator(DexFileNamer namer) { + this.namer = namer; + } + + @Override + public int compare(String l, String r) { + int li = namer.getIndex(l); + int ri = namer.getIndex(r); + boolean lv = (li >= 0); + boolean rv = (ri >= 0); + if (lv != rv) return lv ? -1 : 1; + if (!lv) return l.compareTo(r); + return li < ri ? -1 : (li > ri ? 1 : 0); + } + + public DexFileNamer getNamer() { + return namer; + } + +} diff --git a/src/main/java/lanchon/multidexlib2/DexFileNameIterator.java b/src/main/java/lanchon/multidexlib2/DexFileNameIterator.java new file mode 100644 index 0000000..d197fa3 --- /dev/null +++ b/src/main/java/lanchon/multidexlib2/DexFileNameIterator.java @@ -0,0 +1,61 @@ +/* + * DexPatcher - Copyright 2015, 2016 Rodrigo Balerdi + * (GNU General Public License version 3 or later) + * + * DexPatcher 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. + */ + +package lanchon.multidexlib2; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +public class DexFileNameIterator implements Iterator { + + public static int NO_MAX_COUNT = -1; + + private final DexFileNamer namer; + private final int maxCount; + private int count; + + public DexFileNameIterator(DexFileNamer namer) { + this(namer, NO_MAX_COUNT); + } + + public DexFileNameIterator(DexFileNamer namer, int maxCount) { + this.namer = namer; + this.maxCount = maxCount; + } + + @Override + public boolean hasNext() { + return maxCount < 0 || count < maxCount; + } + + @Override + public String next() { + if (!hasNext()) throw new NoSuchElementException(); + return namer.getName(count++); + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + + public DexFileNamer getNamer() { + return namer; + } + + public int getMaxCount() { + return maxCount; + } + + public int getCount() { + return count; + } + +} diff --git a/src/main/java/lanchon/multidexlib2/DexFileNamer.java b/src/main/java/lanchon/multidexlib2/DexFileNamer.java new file mode 100644 index 0000000..329d0e6 --- /dev/null +++ b/src/main/java/lanchon/multidexlib2/DexFileNamer.java @@ -0,0 +1,20 @@ +/* + * DexPatcher - Copyright 2015, 2016 Rodrigo Balerdi + * (GNU General Public License version 3 or later) + * + * DexPatcher 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. + */ + +package lanchon.multidexlib2; + +public interface DexFileNamer { + + String getName(int index); + int getIndex(String name); + + boolean isValidName(String name); + +} diff --git a/src/main/java/lanchon/multidexlib2/DexIO.java b/src/main/java/lanchon/multidexlib2/DexIO.java new file mode 100644 index 0000000..155d229 --- /dev/null +++ b/src/main/java/lanchon/multidexlib2/DexIO.java @@ -0,0 +1,186 @@ +/* + * DexPatcher - Copyright 2015, 2016 Rodrigo Balerdi + * (GNU General Public License version 3 or later) + * + * DexPatcher 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. + */ + +package lanchon.multidexlib2; + +import java.io.File; +import java.io.IOException; +import java.io.InterruptedIOException; +import java.lang.reflect.UndeclaredThrowableException; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Deque; +import java.util.Iterator; +import java.util.List; +import java.util.Queue; +import java.util.Set; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import org.jf.dexlib2.Opcodes; +import org.jf.dexlib2.iface.ClassDef; +import org.jf.dexlib2.iface.DexFile; +import org.jf.dexlib2.writer.io.FileDataStore; +import org.jf.dexlib2.writer.pool.DexPool; + +public class DexIO { + + public static final int DEFAULT_MAX_DEX_POOL_SIZE = 0x10000; + + public interface Logger { + void log(File file, String entryName, int typeCount); + } + + private DexIO() {} + + // Single-Threaded Write + + static void writeRawDexSingleThread(File file, DexFile dexFile, int maxDexPoolSize, DexIO.Logger logger) + throws IOException { + writeCommonSingleThread(false, file, null, SingletonDexContainer.UNDEFINED_ENTRY_NAME, file, dexFile, 0, false, + maxDexPoolSize, logger); + } + + static void writeMultiDexDirectorySingleThread(boolean multiDex, File directory, DexFileNameIterator nameIterator, + DexFile dexFile, int minMainDexClassCount, boolean minimalMainDex, int maxDexPoolSize, DexIO.Logger logger) + throws IOException { + writeCommonSingleThread(multiDex, directory, nameIterator, null, null, dexFile, minMainDexClassCount, + minimalMainDex, maxDexPoolSize, logger); + } + + private static void writeCommonSingleThread(boolean multiDex, File base, DexFileNameIterator nameIterator, + String currentName, File currentFile, DexFile dexFile, int minMainDexClassCount, boolean minimalMainDex, + int maxDexPoolSize, DexIO.Logger logger) throws IOException { + Set classes = dexFile.getClasses(); + if (!multiDex) { + minMainDexClassCount = classes.size(); + minimalMainDex = false; + } + Object lock = new Object(); + synchronized (lock) { // avoid multiple synchronizations in single-threaded mode + writeCommon(base, nameIterator, currentName, currentFile, classes.iterator(), minMainDexClassCount, + minimalMainDex, dexFile.getOpcodes(), maxDexPoolSize, logger, lock); + } + } + + // Multi-Threaded Write + + static void writeMultiDexDirectoryMultiThread(int threadCount, final File directory, + final DexFileNameIterator nameIterator, final DexFile dexFile, final int maxDexPoolSize, + final DexIO.Logger logger) throws IOException { + final Iterator classIterator = dexFile.getClasses().iterator(); + final Object lock = new Object(); + List> callables = new ArrayList<>(threadCount); + for (int i = 0; i < threadCount; i++) { + callables.add(new Callable() { + @Override + public Void call() throws IOException { + writeCommon(directory, nameIterator, null, null, classIterator, 0, false, dexFile.getOpcodes(), + maxDexPoolSize, logger, lock); + return null; + } + }); + } + ExecutorService service = Executors.newFixedThreadPool(threadCount); + try { + List> futures = service.invokeAll(callables); + for (Future future : futures) { + try { + future.get(); + } catch (ExecutionException e) { + Throwable c = e.getCause(); + if (c instanceof IOException) throw (IOException) c; + if (c instanceof RuntimeException) throw (RuntimeException) c; + if (c instanceof Error) throw (Error) c; + throw new UndeclaredThrowableException(c); + } + } + } catch (InterruptedException e) { + InterruptedIOException ioe = new InterruptedIOException(); + ioe.initCause(e); + throw ioe; + } finally { + service.shutdown(); + } + } + + // Common Code + + private static final int PER_THREAD_BATCH_SIZE = 100; + + private static void writeCommon(File base, DexFileNameIterator nameIterator, String currentName, File currentFile, + Iterator classIterator, int minMainDexClassCount, boolean minimalMainDex, + Opcodes opcodes, int maxDexPoolSize, DexIO.Logger logger, Object lock) throws IOException { + Deque queue = new ArrayDeque<>(PER_THREAD_BATCH_SIZE); + ClassDef currentClass = getQueueItem(queue, classIterator, lock); + do { + DexPool dexPool = new DexPool(opcodes); + int fileClassCount = 0; + while (currentClass != null) { + if (minimalMainDex && fileClassCount >= minMainDexClassCount) break; + dexPool.mark(); + dexPool.internClass(currentClass); + fileClassCount++; + boolean overflow = + dexPool.typeSection.getItemCount() > maxDexPoolSize || + //dexPool.protoSection.getItemCount() > maxDexPoolSize || + dexPool.fieldSection.getItemCount() > maxDexPoolSize || + dexPool.methodSection.getItemCount() > maxDexPoolSize || + //dexPool.classSection.getItemCount() > maxDexPoolSize || + false; + if (overflow) { + if (fileClassCount <= minMainDexClassCount) throw new DexPoolOverflowException( + "Dex pool overflowed while writing type " + (fileClassCount) + + " of " + minMainDexClassCount); + if (fileClassCount == 1) throw new DexPoolOverflowException( + "Type too big for dex pool: " + currentClass.getType()); + dexPool.reset(); + fileClassCount--; + break; + } + currentClass = getQueueItem(queue, classIterator, lock); + } + synchronized (lock) { + if (currentFile == null) { + currentName = nameIterator.next(); + currentFile = new File(base, currentName); + } + if (logger != null) logger.log(base, currentName, fileClassCount); + fillQueue(queue, classIterator, PER_THREAD_BATCH_SIZE - 1); + } + dexPool.writeTo(new FileDataStore(currentFile)); + currentFile = null; + minMainDexClassCount = 0; + minimalMainDex = false; + } while (currentClass != null); + } + + private static T getQueueItem(Queue queue, Iterator iterator, Object lock) { + T item = queue.poll(); + if (item == null) { + synchronized (lock) { + fillQueue(queue, iterator, PER_THREAD_BATCH_SIZE); + } + item = queue.poll(); + } + return item; + } + + private static void fillQueue(Queue queue, Iterator iterator, int targetSize) { + for (int i = queue.size(); i < targetSize; i++) { + if (!iterator.hasNext()) break; + queue.add(iterator.next()); + } + } + +} diff --git a/src/main/java/lanchon/multidexlib2/DexPoolOverflowException.java b/src/main/java/lanchon/multidexlib2/DexPoolOverflowException.java new file mode 100644 index 0000000..e3bcba5 --- /dev/null +++ b/src/main/java/lanchon/multidexlib2/DexPoolOverflowException.java @@ -0,0 +1,19 @@ +/* + * DexPatcher - Copyright 2015, 2016 Rodrigo Balerdi + * (GNU General Public License version 3 or later) + * + * DexPatcher 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. + */ + +package lanchon.multidexlib2; + +public class DexPoolOverflowException extends RuntimeException { + + public DexPoolOverflowException(String file) { + super(file); + } + +} diff --git a/src/main/java/lanchon/multidexlib2/DexVersionMap.java b/src/main/java/lanchon/multidexlib2/DexVersionMap.java new file mode 100644 index 0000000..5499025 --- /dev/null +++ b/src/main/java/lanchon/multidexlib2/DexVersionMap.java @@ -0,0 +1,47 @@ +/* + * DexPatcher - Copyright 2015, 2016 Rodrigo Balerdi + * (GNU General Public License version 3 or later) + * + * DexPatcher 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. + */ + +package lanchon.multidexlib2; + +import org.jf.dexlib2.dexbacked.raw.HeaderItem; + +public class DexVersionMap { + + // TODO: Switch to dexlib2's implementation when it gets to support this functionality. + + /* + public static boolean isSupportedApiLevel(int apiLevel) { + return apiLevel <= 25; + } + + public static int getHighestDexVersionFromApiLevel(int apiLevel) { + return apiLevel <= 23 ? 35 : + 37; + } + */ + + public static int getHighestDexVersionFromApiLevel(int apiLevel) { + return HeaderItem.getVersion(HeaderItem.getMagicForApi(apiLevel), 0); + } + + public static boolean isSupportedDexVersion(int dexVersion) { + return dexVersion == 35 || + dexVersion == 37; + } + + public static int getHighestApiLevelFromDexVersion(int dexVersion) { + return dexVersion <= 35 ? 23 : + dexVersion <= 37 ? 25 : + 10000; // Build.VERSION_CODES.CUR_DEVELOPMENT + } + + private DexVersionMap() {} + +} diff --git a/src/main/java/lanchon/multidexlib2/DirectoryDexContainer.java b/src/main/java/lanchon/multidexlib2/DirectoryDexContainer.java new file mode 100644 index 0000000..e440c84 --- /dev/null +++ b/src/main/java/lanchon/multidexlib2/DirectoryDexContainer.java @@ -0,0 +1,39 @@ +/* + * DexPatcher - Copyright 2015, 2016 Rodrigo Balerdi + * (GNU General Public License version 3 or later) + * + * DexPatcher 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. + */ + +package lanchon.multidexlib2; + +import java.io.File; +import java.io.IOException; +import java.util.Map; +import java.util.TreeMap; + +import org.jf.dexlib2.Opcodes; +import org.jf.dexlib2.iface.DexFile; +import org.jf.dexlib2.iface.MultiDexContainer.MultiDexFile; + +public class DirectoryDexContainer extends AbstractMultiDexContainer { + + public DirectoryDexContainer(File directory, DexFileNamer namer, Opcodes opcodes) throws IOException { + Map entryMap = new TreeMap<>(new DexFileNameComparator(namer)); + String[] names = directory.list(); + if (names == null) throw new IOException("Cannot access directory: " + directory); + for (String entryName : names) { + File file = new File(directory, entryName); + if (file.isFile() && namer.isValidName(entryName)) { + DexFile dexFile = RawDexIO.readRawDexFile(file, opcodes); + MultiDexFile multiDexFile = new BasicMultiDexFile<>(this, entryName, dexFile); + if (entryMap.put(entryName, multiDexFile) != null) throwDuplicateEntryName(entryName); + } + } + initialize(entryMap, opcodes); + } + +} diff --git a/src/main/java/lanchon/multidexlib2/DuplicateEntryNameException.java b/src/main/java/lanchon/multidexlib2/DuplicateEntryNameException.java new file mode 100644 index 0000000..d37ce9e --- /dev/null +++ b/src/main/java/lanchon/multidexlib2/DuplicateEntryNameException.java @@ -0,0 +1,19 @@ +/* + * DexPatcher - Copyright 2015, 2016 Rodrigo Balerdi + * (GNU General Public License version 3 or later) + * + * DexPatcher 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. + */ + +package lanchon.multidexlib2; + +public class DuplicateEntryNameException extends RuntimeException { + + public DuplicateEntryNameException(String entryName) { + super(entryName); + } + +} diff --git a/src/main/java/lanchon/multidexlib2/DuplicateTypeException.java b/src/main/java/lanchon/multidexlib2/DuplicateTypeException.java new file mode 100644 index 0000000..2f49489 --- /dev/null +++ b/src/main/java/lanchon/multidexlib2/DuplicateTypeException.java @@ -0,0 +1,19 @@ +/* + * DexPatcher - Copyright 2015, 2016 Rodrigo Balerdi + * (GNU General Public License version 3 or later) + * + * DexPatcher 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. + */ + +package lanchon.multidexlib2; + +public class DuplicateTypeException extends RuntimeException { + + public DuplicateTypeException(String typeDescriptor) { + super(typeDescriptor); + } + +} diff --git a/src/main/java/lanchon/multidexlib2/EmptyMultiDexContainerException.java b/src/main/java/lanchon/multidexlib2/EmptyMultiDexContainerException.java new file mode 100644 index 0000000..1b08003 --- /dev/null +++ b/src/main/java/lanchon/multidexlib2/EmptyMultiDexContainerException.java @@ -0,0 +1,19 @@ +/* + * DexPatcher - Copyright 2015, 2016 Rodrigo Balerdi + * (GNU General Public License version 3 or later) + * + * DexPatcher 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. + */ + +package lanchon.multidexlib2; + +public class EmptyMultiDexContainerException extends RuntimeException { + + public EmptyMultiDexContainerException(String file) { + super(file); + } + +} diff --git a/src/main/java/lanchon/multidexlib2/MultiDexContainerBackedDexFile.java b/src/main/java/lanchon/multidexlib2/MultiDexContainerBackedDexFile.java new file mode 100644 index 0000000..3caa44f --- /dev/null +++ b/src/main/java/lanchon/multidexlib2/MultiDexContainerBackedDexFile.java @@ -0,0 +1,61 @@ +/* + * DexPatcher - Copyright 2015, 2016 Rodrigo Balerdi + * (GNU General Public License version 3 or later) + * + * DexPatcher 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. + */ + +package lanchon.multidexlib2; + +import java.io.IOException; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +import org.jf.dexlib2.Opcodes; +import org.jf.dexlib2.iface.ClassDef; +import org.jf.dexlib2.iface.DexFile; +import org.jf.dexlib2.iface.MultiDexContainer; + +public class MultiDexContainerBackedDexFile implements DexFile { + + private final Set classes; + private final Opcodes opcodes; + + public MultiDexContainerBackedDexFile(MultiDexContainer container) throws IOException { + Set classes; + List entryNames = container.getDexEntryNames(); + if (entryNames.size() == 1) { + String entryName = entryNames.get(0); + T entry = container.getEntry(entryName); + classes = entry.getClasses(); + } else { + LinkedHashSet accumulatedClasses = new LinkedHashSet<>(); + for (String entryName : entryNames) { + T entry = container.getEntry(entryName); + Set entryClasses = entry.getClasses(); + for (ClassDef entryClass : entryClasses) { + if (!accumulatedClasses.add(entryClass)) throw new DuplicateTypeException(entryClass.getType()); + } + } + classes = accumulatedClasses; + } + this.classes = Collections.unmodifiableSet(classes); + this.opcodes = container.getOpcodes(); + } + + @Override + public Set getClasses() { + return classes; + } + + @Override + public Opcodes getOpcodes() { + return opcodes; + } + +} diff --git a/src/main/java/lanchon/multidexlib2/MultiDexDetectedException.java b/src/main/java/lanchon/multidexlib2/MultiDexDetectedException.java new file mode 100644 index 0000000..0f05995 --- /dev/null +++ b/src/main/java/lanchon/multidexlib2/MultiDexDetectedException.java @@ -0,0 +1,19 @@ +/* + * DexPatcher - Copyright 2015, 2016 Rodrigo Balerdi + * (GNU General Public License version 3 or later) + * + * DexPatcher 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. + */ + +package lanchon.multidexlib2; + +public class MultiDexDetectedException extends RuntimeException { + + public MultiDexDetectedException(String file) { + super(file); + } + +} diff --git a/src/main/java/lanchon/multidexlib2/MultiDexIO.java b/src/main/java/lanchon/multidexlib2/MultiDexIO.java new file mode 100644 index 0000000..fafca2b --- /dev/null +++ b/src/main/java/lanchon/multidexlib2/MultiDexIO.java @@ -0,0 +1,125 @@ +/* + * DexPatcher - Copyright 2015, 2016 Rodrigo Balerdi + * (GNU General Public License version 3 or later) + * + * DexPatcher 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. + */ + +package lanchon.multidexlib2; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.List; + +import org.jf.dexlib2.Opcodes; +import org.jf.dexlib2.iface.DexFile; +import org.jf.dexlib2.iface.MultiDexContainer; + +public class MultiDexIO { + + public static final int DEFAULT_MAX_THREADS = 4; + + private MultiDexIO() {} + + // Read + + public static DexFile readDexFile(boolean multiDex, File file, DexFileNamer namer, Opcodes opcodes, + DexIO.Logger logger) throws IOException { + MultiDexContainer container = readMultiDexContainer(multiDex, file, namer, opcodes, logger); + return new MultiDexContainerBackedDexFile<>(container); + } + + public static MultiDexContainer readMultiDexContainer(boolean multiDex, File file, + DexFileNamer namer, Opcodes opcodes, DexIO.Logger logger) throws IOException { + MultiDexContainer container = readMultiDexContainer(file, namer, opcodes, logger); + int entries = container.getDexEntryNames().size(); + if (entries == 0) throw new EmptyMultiDexContainerException(file.toString()); + if (!multiDex && entries > 1) throw new MultiDexDetectedException(file.toString()); + return container; + } + + public static MultiDexContainer readMultiDexContainer(File file, DexFileNamer namer, + Opcodes opcodes, DexIO.Logger logger) throws IOException { + MultiDexContainer container = readMultiDexContainer(file, namer, opcodes); + if (logger != null) { + for (String name : container.getDexEntryNames()) { + logger.log(file, name, container.getEntry(name).getClasses().size()); + } + } + return container; + } + + public static MultiDexContainer readMultiDexContainer(File file, DexFileNamer namer, + Opcodes opcodes) throws IOException { + if (file.isDirectory()) return new DirectoryDexContainer(file, namer, opcodes); + if (!file.isFile()) throw new FileNotFoundException(file.toString()); + if (ZipFileDexContainer.isZipFile(file)) return new ZipFileDexContainer(file, namer, opcodes); + return new SingletonDexContainer(RawDexIO.readRawDexFile(file, opcodes)); + } + + // Write + + public static int writeDexFile(boolean multiDex, File file, DexFileNamer namer, DexFile dexFile, + int maxDexPoolSize, DexIO.Logger logger) throws IOException { + return writeDexFile(multiDex, 1, file, namer, dexFile, maxDexPoolSize, logger); + } + + public static int writeDexFile(boolean multiDex, int threadCount, File file, DexFileNamer namer, DexFile dexFile, + int maxDexPoolSize, DexIO.Logger logger) throws IOException { + return writeDexFile(multiDex, threadCount, file, namer, dexFile, 0, false, maxDexPoolSize, logger); + } + + public static int writeDexFile(boolean multiDex, File file, DexFileNamer namer, DexFile dexFile, + int minMainDexClassCount, boolean minimalMainDex, int maxDexPoolSize, + DexIO.Logger logger) throws IOException { + return writeDexFile(multiDex, 1, file, namer, dexFile, minMainDexClassCount, minimalMainDex, maxDexPoolSize, + logger); + } + + public static int writeDexFile(boolean multiDex, int threadCount, File file, DexFileNamer namer, DexFile dexFile, + int minMainDexClassCount, boolean minimalMainDex, int maxDexPoolSize, + DexIO.Logger logger) throws IOException { + if (file.isDirectory()) { + return writeMultiDexDirectory(multiDex, threadCount, file, namer, dexFile, minMainDexClassCount, + minimalMainDex, maxDexPoolSize, logger); + } else { + if (multiDex) throw new UnsupportedOperationException( + "Must output to a directory if multi-dex mode is enabled"); + RawDexIO.writeRawDexFile(file, dexFile, maxDexPoolSize, logger); + return 1; + } + } + + public static int writeMultiDexDirectory(boolean multiDex, int threadCount, File directory, DexFileNamer namer, + DexFile dexFile, int minMainDexClassCount, boolean minimalMainDex, int maxDexPoolSize, DexIO.Logger logger) + throws IOException { + purgeMultiDexDirectory(multiDex, directory, namer); + DexFileNameIterator nameIterator = new DexFileNameIterator(namer); + if (threadCount <= 0) { + threadCount = Runtime.getRuntime().availableProcessors(); + if (threadCount > DEFAULT_MAX_THREADS) threadCount = DEFAULT_MAX_THREADS; + } + if (threadCount > 1 && multiDex && minMainDexClassCount == 0 && !minimalMainDex) { + DexIO.writeMultiDexDirectoryMultiThread(threadCount, directory, nameIterator, dexFile, maxDexPoolSize, + logger); + } else { + DexIO.writeMultiDexDirectorySingleThread(multiDex, directory, nameIterator, dexFile, minMainDexClassCount, + minimalMainDex, maxDexPoolSize, logger); + } + return nameIterator.getCount(); + } + + public static void purgeMultiDexDirectory(boolean multiDex, File directory, DexFileNamer namer) throws IOException { + List names = new DirectoryDexContainer(directory, namer, null).getDexEntryNames(); + if (!multiDex && names.size() > 1) throw new MultiDexDetectedException(directory.toString()); + for (String name : names) { + File existingFile = new File(directory, name); + if (!existingFile.delete()) throw new IOException("Cannot delete file: " + existingFile.toString()); + } + } + +} diff --git a/src/main/java/lanchon/multidexlib2/OpcodeUtils.java b/src/main/java/lanchon/multidexlib2/OpcodeUtils.java new file mode 100644 index 0000000..7aa8917 --- /dev/null +++ b/src/main/java/lanchon/multidexlib2/OpcodeUtils.java @@ -0,0 +1,44 @@ +/* + * DexPatcher - Copyright 2015, 2016 Rodrigo Balerdi + * (GNU General Public License version 3 or later) + * + * DexPatcher 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. + */ + +package lanchon.multidexlib2; + +import org.jf.dexlib2.Opcodes; +import org.jf.dexlib2.VersionMap; + +public class OpcodeUtils { + + public static Opcodes getOpcodesFromDexVersion(int dexVersion) { + return Opcodes.forApi(DexVersionMap.getHighestApiLevelFromDexVersion(dexVersion)); + } + + public static int getDexVersionFromOpcodes(Opcodes opcodes) { + if (opcodes.api == VersionMap.NO_VERSION) throw undefinedApiLevel(); + return DexVersionMap.getHighestDexVersionFromApiLevel(opcodes.api); + } + + public static Opcodes getNewestOpcodesNullable(Opcodes o1, Opcodes o2) { + if (o1 == null) return o2; + if (o2 == null) return o1; + return getNewestOpcodes(o1, o2); + } + + public static Opcodes getNewestOpcodes(Opcodes o1, Opcodes o2) { + if (o1.api == VersionMap.NO_VERSION || o2.api == VersionMap.NO_VERSION) throw undefinedApiLevel(); + return o1.api >= o2.api ? o1 : o2; + } + + private static IllegalArgumentException undefinedApiLevel() { + return new IllegalArgumentException("Opcodes instance has undefined api level"); + } + + private OpcodeUtils() {} + +} diff --git a/src/main/java/lanchon/multidexlib2/RawDexIO.java b/src/main/java/lanchon/multidexlib2/RawDexIO.java new file mode 100644 index 0000000..31eecef --- /dev/null +++ b/src/main/java/lanchon/multidexlib2/RawDexIO.java @@ -0,0 +1,80 @@ +/* + * DexPatcher - Copyright 2015, 2016 Rodrigo Balerdi + * (GNU General Public License version 3 or later) + * + * DexPatcher 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. + */ + +package lanchon.multidexlib2; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +import com.google.common.io.ByteStreamsHack; +import com.google.common.io.Files; +import org.jf.dexlib2.Opcodes; +import org.jf.dexlib2.dexbacked.DexBackedDexFile; +import org.jf.dexlib2.dexbacked.raw.HeaderItem; +import org.jf.dexlib2.iface.DexFile; +import org.jf.dexlib2.util.DexUtil; + +public class RawDexIO { + + private RawDexIO() {} + + // Read + + public static DexBackedDexFile readRawDexFile(File file, Opcodes opcodes, DexIO.Logger logger) throws IOException { + DexBackedDexFile dexFile = readRawDexFile(file, opcodes); + if (logger != null) { + logger.log(file, SingletonDexContainer.UNDEFINED_ENTRY_NAME, dexFile.getClasses().size()); + } + return dexFile; + } + + public static DexBackedDexFile readRawDexFile(File file, Opcodes opcodes) throws IOException { + /* + InputStream inputStream = new FileInputStream(file); + try { + return readRawDexFile(inputStream, file.length(), opcodes); + } finally { + inputStream.close(); + } + */ + byte[] buf = Files.toByteArray(file); + return readRawDexFile(buf, 0, opcodes); + } + + public static DexBackedDexFile readRawDexFile(InputStream inputStream, long expectedSize, Opcodes opcodes) + throws IOException { + // TODO: Remove hack when issue is fixed: https://github.com/google/guava/issues/2616 + //byte[] buf = ByteStreams.toByteArray(inputStream); + byte[] buf = ByteStreamsHack.toByteArray(inputStream, expectedSize); + return readRawDexFile(buf, 0, opcodes); + } + + public static DexBackedDexFile readRawDexFile(byte[] buf, int offset, Opcodes opcodes) throws IOException { + DexUtil.verifyDexHeader(buf, offset); + if (opcodes == null) { + int dexVersion = HeaderItem.getVersion(buf, offset); + opcodes = OpcodeUtils.getOpcodesFromDexVersion(dexVersion); + }; + return new DexBackedDexFile(opcodes, buf, 0); + } + + // Write + + public static void writeRawDexFile(File file, DexFile dexFile, int maxDexPoolSize, DexIO.Logger logger) + throws IOException { + DexIO.writeRawDexSingleThread(file, dexFile, maxDexPoolSize, logger); + } + + public static void writeRawDexFile(File file, DexFile dexFile, int maxDexPoolSize) throws IOException { + DexIO.writeRawDexSingleThread(file, dexFile, maxDexPoolSize, null); + } + +} diff --git a/src/main/java/lanchon/multidexlib2/SingletonDexContainer.java b/src/main/java/lanchon/multidexlib2/SingletonDexContainer.java new file mode 100644 index 0000000..c8b726b --- /dev/null +++ b/src/main/java/lanchon/multidexlib2/SingletonDexContainer.java @@ -0,0 +1,37 @@ +/* + * DexPatcher - Copyright 2015, 2016 Rodrigo Balerdi + * (GNU General Public License version 3 or later) + * + * DexPatcher 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. + */ + +package lanchon.multidexlib2; + +import java.util.Collections; +import java.util.Map; + +import org.jf.dexlib2.Opcodes; +import org.jf.dexlib2.iface.DexFile; +import org.jf.dexlib2.iface.MultiDexContainer.MultiDexFile; + +public class SingletonDexContainer extends AbstractMultiDexContainer { + + // I insist that some dex container entries do not have names + // even though dexlib2 does not allow null entry names. + public static final String UNDEFINED_ENTRY_NAME = null; + + public SingletonDexContainer(DexFile dexFile) { + this(UNDEFINED_ENTRY_NAME, dexFile); + } + + public SingletonDexContainer(String entryName, DexFile dexFile) { + Opcodes opcodes = dexFile.getOpcodes(); + MultiDexFile multiDexFile = new BasicMultiDexFile<>(this, entryName, dexFile); + Map entryMap = Collections.singletonMap(entryName, multiDexFile); + initialize(entryMap, opcodes); + } + +} diff --git a/src/main/java/lanchon/multidexlib2/ZipFileDexContainer.java b/src/main/java/lanchon/multidexlib2/ZipFileDexContainer.java new file mode 100644 index 0000000..6856200 --- /dev/null +++ b/src/main/java/lanchon/multidexlib2/ZipFileDexContainer.java @@ -0,0 +1,65 @@ +/* + * DexPatcher - Copyright 2015, 2016 Rodrigo Balerdi + * (GNU General Public License version 3 or later) + * + * DexPatcher 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. + */ + +package lanchon.multidexlib2; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Enumeration; +import java.util.Map; +import java.util.TreeMap; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import org.jf.dexlib2.Opcodes; +import org.jf.dexlib2.iface.DexFile; +import org.jf.dexlib2.iface.MultiDexContainer.MultiDexFile; + +public class ZipFileDexContainer extends AbstractMultiDexContainer { + + public static boolean isZipFile(File zip) { + if (!zip.isFile()) return false; + try { + ZipFile zipFile = new ZipFile(zip); + zipFile.close(); + return true; + } catch (IOException e) { + return false; + } + } + + public ZipFileDexContainer(File zip, DexFileNamer namer, Opcodes opcodes) throws IOException { + Map entryMap = new TreeMap<>(new DexFileNameComparator(namer)); + ZipFile zipFile = new ZipFile(zip); + try { + Enumeration zipEntries = zipFile.entries(); + while (zipEntries.hasMoreElements()) { + ZipEntry zipEntry = zipEntries.nextElement(); + String entryName = zipEntry.getName(); + if (namer.isValidName(entryName)) { + DexFile dexFile; + InputStream inputStream = zipFile.getInputStream(zipEntry); + try { + dexFile = RawDexIO.readRawDexFile(inputStream, zipEntry.getSize(), opcodes); + } finally { + inputStream.close(); + } + MultiDexFile multiDexFile = new BasicMultiDexFile<>(this, entryName, dexFile); + if (entryMap.put(entryName, multiDexFile) != null) throwDuplicateEntryName(entryName); + } + } + } finally { + zipFile.close(); + } + initialize(entryMap, opcodes); + } + +} diff --git a/src/main/resources/LICENSE.txt b/src/main/resources/LICENSE.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/src/main/resources/LICENSE.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +.