diff --git a/.gitignore b/.gitignore index 5d947ca..02f3d23 100644 --- a/.gitignore +++ b/.gitignore @@ -1,18 +1,2 @@ -# Build and Release Folders -bin-debug/ -bin-release/ -[Oo]bj/ -[Bb]in/ - -# Other files and folders -.settings/ - -# Executables -*.swf -*.air -*.ipa -*.apk - -# Project files, i.e. `.project`, `.actionScriptProperties` and `.flexProperties` -# should NOT be excluded as they contain compiler settings and other important -# information for Eclipse / Flash Builder. +/recoverTestFiles/ +/build/ \ No newline at end of file diff --git a/LICENSE b/LICENSE index 9e32cde..d159169 100644 --- a/LICENSE +++ b/LICENSE @@ -1,127 +1,339 @@ - 木兰宽松许可证, 第2版 + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 - 木兰宽松许可证, 第2版 - 2020年1月 http://license.coscl.org.cn/MulanPSL2 + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + Preamble - 您对“软件”的复制、使用、修改及分发受木兰宽松许可证,第2版(“本许可证”)的如下条款的约束: + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. - 0. 定义 + 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 +this service 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 make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. - “贡献”是指由任一“贡献者”许可在“本许可证”下的受版权法保护的作品。 + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. 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. - “贡献者”是指将受版权法保护的作品许可在“本许可证”下的自然人或“法人实体”。 + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. - “法人实体”是指提交贡献的机构及其“关联实体”。 + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. - “关联实体”是指,对“本许可证”下的行为方而言,控制、受控制或与其共同受控制的机构,此处的控制是指有受控方或共同受控方至少50%直接或间接的投票权、资金或其他有价证券。 + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. - 1. 授予版权许可 + The precise terms and conditions for copying, distribution and +modification follow. - 每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的版权许可,您可以复制、使用、修改、分发其“贡献”,不论修改与否。 + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - 2. 授予专利许可 + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". - 每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的(根据本条规定撤销除外)专利许可,供您制造、委托制造、使用、许诺销售、销售、进口其“贡献”或以其他方式转移其“贡献”。前述专利许可仅限于“贡献者”现在或将来拥有或控制的其“贡献”本身或其“贡献”与许可“贡献”时的“软件”结合而将必然会侵犯的专利权利要求,不包括对“贡献”的修改或包含“贡献”的其他结合。如果您或您的“关联实体”直接或间接地,就“软件”或其中的“贡献”对任何人发起专利侵权诉讼(包括反诉或交叉诉讼)或其他专利维权行动,指控其侵犯专利权,则“本许可证”授予您对“软件”的专利许可自您提起诉讼或发起维权行动之日终止。 +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. - 3. 无商标许可 + 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. - “本许可证”不提供对“贡献者”的商品名称、商标、服务标志或产品名称的商标许可,但您为满足第4条规定的声明义务而必须使用除外。 +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. - 4. 分发限制 + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: - 您可以在任何媒介中将“软件”以源程序形式或可执行形式重新分发,不论修改与否,但您必须向接收者提供“本许可证”的副本,并保留“软件”中的版权、商标、专利及免责声明。 + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. - 5. 免责声明与责任限制 + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. - “软件”及其中的“贡献”在提供时不带任何明示或默示的担保。在任何情况下,“贡献者”或版权所有者不对任何人因使用“软件”或其中的“贡献”而引发的任何直接或间接损失承担责任,不论因何种原因导致或者基于何种法律理论,即使其曾被建议有此种损失的可能性。 + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) - 6. 语言 - “本许可证”以中英文双语表述,中英文版本具有同等法律效力。如果中英文版本存在任何冲突不一致,以中文版为准。 +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. - 条款结束 +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. - 如何将木兰宽松许可证,第2版,应用到您的软件 - - 如果您希望将木兰宽松许可证,第2版,应用到您的新软件,为了方便接收者查阅,建议您完成如下三步: +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. - 1, 请您补充如下声明中的空白,包括软件名、软件的首次发表年份以及您作为版权人的名字; + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: - 2, 请您在软件包的一级目录下创建以“LICENSE”为名的文件,将整个许可证文本放入该文件中; + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, - 3, 请将如下声明文本放入每个源文件的头部注释中。 + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, - Copyright (c) [Year] [name of copyright holder] - [Software Name] is licensed under Mulan PSL v2. - You can use this software according to the terms and conditions of the Mulan PSL v2. - You may obtain a copy of Mulan PSL v2 at: - http://license.coscl.org.cn/MulanPSL2 - THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - See the Mulan PSL v2 for more details. + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. - Mulan Permissive Software License,Version 2 +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. - Mulan Permissive Software License,Version 2 (Mulan PSL v2) - January 2020 http://license.coscl.org.cn/MulanPSL2 + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. - Your reproduction, use, modification and distribution of the Software shall be subject to Mulan PSL v2 (this License) with the following terms and conditions: - - 0. Definition - - Software means the program and related documents which are licensed under this License and comprise all Contribution(s). - - Contribution means the copyrightable work licensed by a particular Contributor under this License. - - Contributor means the Individual or Legal Entity who licenses its copyrightable work under this License. - - Legal Entity means the entity making a Contribution and all its Affiliates. - - Affiliates means entities that control, are controlled by, or are under common control with the acting entity under this License, ‘control’ means direct or indirect ownership of at least fifty percent (50%) of the voting power, capital or other securities of controlled or commonly controlled entity. + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. - 1. Grant of Copyright License + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. - Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable copyright license to reproduce, use, modify, or distribute its Contribution, with modification or not. + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +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 +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. - 2. Grant of Patent License +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. - Subject to the terms and conditions of this License, each Contributor hereby grants to you a perpetual, worldwide, royalty-free, non-exclusive, irrevocable (except for revocation under this Section) patent license to make, have made, use, offer for sale, sell, import or otherwise transfer its Contribution, where such patent license is only limited to the patent claims owned or controlled by such Contributor now or in future which will be necessarily infringed by its Contribution alone, or by combination of the Contribution with the Software to which the Contribution was contributed. The patent license shall not apply to any modification of the Contribution, and any other combination which includes the Contribution. If you or your Affiliates directly or indirectly institute patent litigation (including a cross claim or counterclaim in a litigation) or other patent enforcement activities against any individual or entity by alleging that the Software or any Contribution in it infringes patents, then any patent license granted to you under this License for the Software shall terminate as of the date such litigation or activity is filed or taken. +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. - 3. No Trademark License +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. - No trademark license is granted to use the trade names, trademarks, service marks, or product names of Contributor, except as required to fulfill notice requirements in Section 4. + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. - 4. Distribution Restriction + 9. The Free Software Foundation may publish revised and/or new versions +of the 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. - You may distribute the Software in any medium with or without modification, whether in source or executable forms, provided that you provide recipients with a copy of this License and retain copyright, patent, trademark and disclaimer statements in the Software. +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. - 5. Disclaimer of Warranty and Limitation of Liability + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. - THE SOFTWARE AND CONTRIBUTION IN IT ARE PROVIDED WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED. IN NO EVENT SHALL ANY CONTRIBUTOR OR COPYRIGHT HOLDER BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO ANY DIRECT, OR INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING FROM YOUR USE OR INABILITY TO USE THE SOFTWARE OR THE CONTRIBUTION IN IT, NO MATTER HOW IT’S CAUSED OR BASED ON WHICH LEGAL THEORY, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + NO WARRANTY - 6. Language + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. - THIS LICENSE IS WRITTEN IN BOTH CHINESE AND ENGLISH, AND THE CHINESE VERSION AND ENGLISH VERSION SHALL HAVE THE SAME LEGAL EFFECT. IN THE CASE OF DIVERGENCE BETWEEN THE CHINESE AND ENGLISH VERSIONS, THE CHINESE VERSION SHALL PREVAIL. + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE 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. - END OF THE TERMS AND CONDITIONS + END OF TERMS AND CONDITIONS - How to Apply the Mulan Permissive Software License,Version 2 (Mulan PSL v2) to Your Software + How to Apply These Terms to Your New Programs - To apply the Mulan PSL v2 to your work, for easy identification by recipients, you are suggested to complete following three steps: + 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. - i Fill in the blanks in following statement, including insert your software name, the year of the first publication of your software, and your name identified as the copyright owner; + 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 +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. - ii Create a file named “LICENSE” which contains the whole context of this License in the first directory of your software package; + + Copyright (C) - iii Attach the statement to the appropriate annotated syntax at the beginning of each source file. + 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 2 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. - Copyright (c) [Year] [name of copyright holder] - [Software Name] is licensed under Mulan PSL v2. - You can use this software according to the terms and conditions of the Mulan PSL v2. - You may obtain a copy of Mulan PSL v2 at: - http://license.coscl.org.cn/MulanPSL2 - THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - See the Mulan PSL v2 for more details. + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision 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, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This 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. diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..190d9fb --- /dev/null +++ b/build.gradle @@ -0,0 +1,74 @@ +plugins { + id 'java' + id 'application' +} + +mainClassName = 'org.bdware.sc.ContractProcess' + +sourceSets { + main { + java { + srcDirs 'src/main/java', 'src/main/analysis', 'src/main/data-mask' + } + resources { + srcDir 'src/main/resources' + } + } + test { + java { + srcDirs 'src/test/java', 'src/test/data-mask' + } + resources { + srcDir 'src/test/resources' + } + } +} + +dependencies { + implementation project(":common") + implementation project(":mockjava") + + implementation 'com.atlassian.commonmark:commonmark:0.17.0' + implementation 'com.idealista:format-preserving-encryption:1.0.0' + implementation 'com.squareup.okhttp3:okhttp:4.9.1' + implementation 'com.sun.mail:javax.mail:1.6.2' + implementation 'org.apache.commons:commons-math3:3.6.1' + implementation 'org.codehaus.groovy:groovy-all:3.0.8' + implementation 'org.jsoup:jsoup:1.14.2' + + implementation fileTree(dir: 'lib', include: '*.jar') + + testImplementation 'junit:junit:4.13.2' +} + +jar { + String libs = '' + configurations.runtimeClasspath.each { + libs = libs + " libs/" + it.name + } + + manifest { + attributes 'Manifest-Version': project.version + attributes 'Main-Class': mainClassName + attributes 'Class-Path': libs + } +} + +tasks.processResources.setDuplicatesStrategy(DuplicatesStrategy.INCLUDE) + +task copyLibs(type: Copy, dependsOn: ":common:jar") { + into "./build/output/libs/" + from configurations.runtimeClasspath +} + +task copyJar(type: Copy, dependsOn: ":cp:jar") { + into "./build/output/" + from "./build/libs/$project.name-${version}.jar" + rename { String fileName -> "yjs.jar" } +} + +task buildBundle(dependsOn: [":cp:copyLibs", ":cp:copyJar"]) { + doLast { + println "buildBundle in ./build/output/ successfully" + } +} \ No newline at end of file diff --git a/lib/datax-common-0.0.1-SNAPSHOT.jar b/lib/datax-common-0.0.1-SNAPSHOT.jar new file mode 100644 index 0000000..35915e3 Binary files /dev/null and b/lib/datax-common-0.0.1-SNAPSHOT.jar differ diff --git a/lib/datax-core-0.0.1-SNAPSHOT.jar b/lib/datax-core-0.0.1-SNAPSHOT.jar new file mode 100644 index 0000000..0aa2ca8 Binary files /dev/null and b/lib/datax-core-0.0.1-SNAPSHOT.jar differ diff --git a/lib/datax-transformer-0.0.1-SNAPSHOT.jar b/lib/datax-transformer-0.0.1-SNAPSHOT.jar new file mode 100644 index 0000000..d95b2b9 Binary files /dev/null and b/lib/datax-transformer-0.0.1-SNAPSHOT.jar differ diff --git a/lib/nashorn.jar b/lib/nashorn.jar new file mode 100644 index 0000000..c0a52c8 Binary files /dev/null and b/lib/nashorn.jar differ diff --git a/lib/plugin-rdbms-util-0.0.1-SNAPSHOT.jar b/lib/plugin-rdbms-util-0.0.1-SNAPSHOT.jar new file mode 100644 index 0000000..4fb673b Binary files /dev/null and b/lib/plugin-rdbms-util-0.0.1-SNAPSHOT.jar differ diff --git a/lib/streamwriter-0.0.1-SNAPSHOT.jar b/lib/streamwriter-0.0.1-SNAPSHOT.jar new file mode 100644 index 0000000..cfd55d4 Binary files /dev/null and b/lib/streamwriter-0.0.1-SNAPSHOT.jar differ diff --git a/src/main/data-mask/maskingJobs/MaskingJob.java b/src/main/data-mask/maskingJobs/MaskingJob.java new file mode 100644 index 0000000..cc8856d --- /dev/null +++ b/src/main/data-mask/maskingJobs/MaskingJob.java @@ -0,0 +1,337 @@ +package maskingJobs; + +import com.alibaba.datax.common.element.*; +import com.alibaba.datax.common.exception.DataXException; +import com.alibaba.datax.common.util.Configuration; +import com.alibaba.datax.core.transport.record.DefaultRecord; +import com.alibaba.datax.core.transport.transformer.TransformerErrorCode; +import com.alibaba.datax.core.transport.transformer.TransformerExecution; + +import com.alibaba.datax.core.util.TransformerUtil; +import com.alibaba.datax.core.util.container.ClassLoaderSwapper; +import com.alibaba.datax.core.util.container.CoreConstant; +import com.alibaba.datax.plugin.rdbms.reader.Key; +import com.alibaba.datax.plugin.rdbms.reader.util.SingleTableSplitUtil; +import com.alibaba.datax.plugin.rdbms.util.DBUtil; +import com.alibaba.datax.plugin.rdbms.util.DBUtilErrorCode; +import com.alibaba.datax.plugin.rdbms.util.DataBaseType; +import com.alibaba.datax.plugin.rdbms.util.RdbmsException; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonPrimitive; +import org.apache.commons.lang3.Validate; +import org.bdware.sc.util.JsonUtil; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.Types; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + + +public class MaskingJob { + + DataBaseType dataBaseType = DataBaseType.MySql; + private String username; + private String password; + private String jdbcUrl; + private String table; + private Configuration maskConf; + private Configuration readerPara; + private List buffer; + private List transformerExecs; + + + public void init(String confContent) { + maskConf = Configuration.from(confContent); + System.out.println("maskConf"+maskConf.toString()); + System.out.println(("maskCOnfjob"+maskConf.get("job").toString())); + readerPara = maskConf.getConfiguration(CoreConstant.DATAX_JOB_CONTENT_READER_PARAMETER); + System.out.println(readerPara); + username = readerPara.getString(Key.USERNAME); + password = readerPara.getString(Key.PASSWORD); + jdbcUrl = readerPara.getString(Key.JDBC_URL); + table = readerPara.getString(Key.TABLE); + buffer = new ArrayList<>(); + System.out.println("maskConf11"+maskConf.getConfiguration(CoreConstant.DATAX_JOB_CONTENT + "[0]")); + transformerExecs = TransformerUtil.buildTransformerInfo(maskConf.getConfiguration(CoreConstant.DATAX_JOB_CONTENT + "[0]")); + } + + public String buildQuerySql() { + String column = "*"; + //String column = readerPara.getString(Key.COLUMN); + String table = readerPara.getString(Key.TABLE); + String where = readerPara.getString(Key.WHERE, null); + //String querySql = SingleTableSplitUtil.buildQuerySql(column, table, where) + " limit 100"; + String querySql = SingleTableSplitUtil.buildQuerySql(column, table, where) + " limit 100"; + + return querySql; + } + + public JsonPrimitive getMaskedData(String confContent) { + init(confContent); + return startRead(); + //return new JsonPrimitive(getResult()); + } + + public JsonPrimitive startRead() { + String querySql = buildQuerySql(); + System.out.println("startRead"+dataBaseType+jdbcUrl+username+password); + Connection conn = DBUtil.getConnection(dataBaseType, jdbcUrl, username, password); + System.out.println(dataBaseType+jdbcUrl+username+password); + int columnNumber = 0; + String res=""; + ArrayListcolumnName=new ArrayList<>(); + try { + ResultSet rs = DBUtil.query(conn, querySql); + ResultSetMetaData metaData = rs.getMetaData(); + columnNumber = metaData.getColumnCount(); + for(int i=1;i<=metaData.getColumnCount();i++){ + //获取列表 index 从1开始、列名、列类型、列的数据长度 + //System.out.println("aaa"+metaData.getColumnName(i)+"\t"+metaData.getColumnTypeName(i)+"\t"+metaData.getColumnDisplaySize(i)); + columnName.add(metaData.getColumnName(i)); + + } + + while (rs.next()) { + transportOneRecord(rs, metaData, columnNumber); + } + + + } catch (Exception e) { + throw RdbmsException.asQueryException(dataBaseType, e, querySql, table, username); + } finally { + DBUtil.closeDBResources(null, conn); + } + ////for(int i=0;i= record.getColumnNumber()) { + throw DataXException.asDataXException(TransformerErrorCode.TRANSFORMER_ILLEGAL_PARAMETER, + String.format("columnIndex[%s] out of bound[%s]. name=%s", + transformerInfoExec.getColumnIndex(), record.getColumnNumber(), + transformerInfoExec.getTransformerName())); + } + transformerInfoExec.setIsChecked(true); + } + + try { + result = transformerInfoExec.getTransformer().evaluate(result, transformerInfoExec.gettContext(), transformerInfoExec.getFinalParas()); + } catch (Exception e) { + errorMsg = String.format("transformer(%s) has Exception(%s)", transformerInfoExec.getTransformerName(), + e.getMessage()); + failed = true; + //LOG.error(errorMsg, e); + // transformerInfoExec.addFailedRecords(1); + //脏数据不再进行后续transformer处理,按脏数据处理,并过滤该record。 + break; + + } finally { + if (transformerInfoExec.getClassLoader() != null) { + classLoaderSwapper.restoreCurrentThreadClassLoader(); + } + } + + if (result == null) { + break; + } + + } + + + if (failed) { + return null; + } else { + System.out.println("result"+result); + return result; + } + + } + + protected Record buildRecord(ResultSet rs, ResultSetMetaData metaData, + int columnNumber) { + final byte[] EMPTY_CHAR_ARRAY = new byte[0]; + Record record = new DefaultRecord(); + try { + for (int i = 1; i <= columnNumber; i++) { + switch (metaData.getColumnType(i)) { + + case Types.CHAR: + case Types.NCHAR: + case Types.VARCHAR: + case Types.LONGVARCHAR: + case Types.NVARCHAR: + case Types.LONGNVARCHAR: + case Types.CLOB: + case Types.NCLOB: + record.addColumn(new StringColumn(rs.getString(i))); + break; + + case Types.SMALLINT: + case Types.TINYINT: + case Types.INTEGER: + case Types.BIGINT: + record.addColumn(new LongColumn(rs.getString(i))); + break; + + case Types.NUMERIC: + case Types.DECIMAL: + record.addColumn(new DoubleColumn(rs.getString(i))); + break; + + case Types.FLOAT: + case Types.REAL: + case Types.DOUBLE: + record.addColumn(new DoubleColumn(rs.getString(i))); + break; + + case Types.TIME: + record.addColumn(new DateColumn(rs.getTime(i))); + break; + + // for mysql bug, see http://bugs.mysql.com/bug.php?id=35115 + case Types.DATE: + if (metaData.getColumnTypeName(i).equalsIgnoreCase("year")) { + record.addColumn(new LongColumn(rs.getInt(i))); + } else { + record.addColumn(new DateColumn(rs.getDate(i))); + } + break; + + case Types.TIMESTAMP: + record.addColumn(new DateColumn(rs.getTimestamp(i))); + break; + + case Types.BINARY: + case Types.VARBINARY: + case Types.BLOB: + case Types.LONGVARBINARY: + record.addColumn(new BytesColumn(rs.getBytes(i))); + break; + + // warn: bit(1) -> Types.BIT 可使用BoolColumn + // warn: bit(>1) -> Types.VARBINARY 可使用BytesColumn + case Types.BOOLEAN: + case Types.BIT: + record.addColumn(new BoolColumn(rs.getBoolean(i))); + break; + + case Types.NULL: + String stringData = null; + if (rs.getObject(i) != null) { + stringData = rs.getObject(i).toString(); + } + record.addColumn(new StringColumn(stringData)); + break; + + default: + throw DataXException + .asDataXException( + DBUtilErrorCode.UNSUPPORTED_TYPE, + String.format( + "您的配置文件中的列配置信息有误. 因为DataX 不支持数据库读取这种字段类型. 字段名:[%s], 字段名称:[%s], 字段Java类型:[%s]. 请尝试使用数据库函数将其转换datax支持的类型 或者不同步该字段 .", + metaData.getColumnName(i), + metaData.getColumnType(i), + metaData.getColumnClassName(i))); + } + } + } catch (Exception e) { + if (e instanceof DataXException) { + throw (DataXException) e; + } + } + return record; + } + +// private String recordToString(Record record) { +// final String NEWLINE_FLAG = "\n"; +// String fieldDelimiter = "\t"; +// +// int recordLength = record.getColumnNumber(); +// if (0 == recordLength) { +// return NEWLINE_FLAG; +// } +// +// Column column; +// StringBuilder sb = new StringBuilder(); +// for (int i = 0; i < recordLength; i++) { +// column = record.getColumn(i); +// sb.append(column.asString()).append(fieldDelimiter); +// } +// sb.setLength(sb.length() - 1); +// sb.append(NEWLINE_FLAG); +// +// return sb.toString(); +// } + + public String getResult(ArrayList columnName) { + List dataList = new ArrayList<>(); + int size = buffer.size(); + //System.out.println("CCULUMN"+readerPara.getString(Key.COLUMN).toString()); + //String[] colmnNames = readerPara.getString(Key.COLUMN).replace(" ", "").split(","); + int colmnSize= columnName.size(); + for (int i = 0; i < colmnSize; ++i) { + Map rowData = new HashMap<>(); + for (int j = 0; j < size; ++j) { + rowData.put(columnName.get(i), buffer.get(j).getColumn(i).asString()); + } + dataList.add(rowData); + } + + + return JsonUtil.toJson(dataList); + } + +} + diff --git a/src/main/java/org/bdware/sc/ContractProcess.java b/src/main/java/org/bdware/sc/ContractProcess.java new file mode 100644 index 0000000..14457e4 --- /dev/null +++ b/src/main/java/org/bdware/sc/ContractProcess.java @@ -0,0 +1,1309 @@ +package org.bdware.sc; + +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSyntaxException; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.MalformedJsonException; +import jdk.nashorn.internal.objects.Global; +import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.core.config.Configurator; +import org.bdware.analysis.BasicBlock; +import org.bdware.analysis.CFGraph; +import org.bdware.analysis.FrontCF; +import org.bdware.analysis.dynamic.NaiveDynamicTaintAnalysis; +import org.bdware.analysis.dynamic.TracedFile; +import org.bdware.analysis.example.MultiSourceTaintAnalysis; +import org.bdware.analysis.gas.Evaluates; +import org.bdware.analysis.gas.PPCount; +import org.bdware.analysis.taint.TaintBB; +import org.bdware.analysis.taint.TaintCFG; +import org.bdware.analysis.taint.TaintResult; +import org.bdware.sc.ContractResult.Status; +import org.bdware.sc.bean.*; +import org.bdware.sc.boundry.JavaScriptEntry; +import org.bdware.sc.boundry.Resources; +import org.bdware.sc.boundry.utils.FileUtil; +import org.bdware.sc.boundry.utils.RocksDBUtil; +import org.bdware.sc.boundry.utils.UtilRegistry; +import org.bdware.sc.compiler.YJSCompiler; +import org.bdware.sc.conn.ByteUtil; +import org.bdware.sc.conn.ServiceServer; +import org.bdware.sc.conn.SocketGet; +import org.bdware.sc.engine.DesktopEngine; +import org.bdware.sc.engine.hook.*; +import org.bdware.sc.handler.ContractHandler; +import org.bdware.sc.index.TimeSerialIndex; +import org.bdware.sc.node.*; +import org.bdware.sc.trace.ProgramPointCounter; +import org.bdware.sc.util.HashUtil; +import org.bdware.sc.util.JsonUtil; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.MethodNode; + +import javax.script.ScriptContext; +import javax.script.ScriptEngine; +import javax.script.ScriptException; +import java.io.*; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.zip.ZipFile; + +public class ContractProcess { + private static final byte[] ZIP_HEADER_1 = new byte[]{80, 75, 3, 4}; + private static final byte[] ZIP_HEADER_2 = new byte[]{80, 75, 5, 6}; + private static final org.apache.logging.log4j.Logger LOGGER = + org.apache.logging.log4j.LogManager.getLogger(ContractProcess.class); + public static ContractProcess instance; + + public final String cmi; + private final Set cachedRequests = new HashSet<>(); + public ServiceServer server; + public DesktopEngine engine; + String dbPath; + String dir; + Contract contract; + ProjectConfig projectConfig; + ContractNode cn; + DumpTask dt; + Map isOpen = new HashMap<>(); + long gasLimit = 0; + Map logDetails = new HashMap<>(); + String memorySet; // from manifest + HashMap CFGmap = new HashMap<>(); + HashMap ppCountMap = new HashMap<>(); + List function = new ArrayList<>(); + private Global global; + private TimeSerialIndex logIndex; + private RocksDBUtil edion; + private String pid; + + public ContractProcess(int port, String cmi) { + ContractHandler handler = new ContractHandler(this); + this.server = new ServiceServer(handler, port); + this.cmi = cmi; + } + + public static void main(String[] args) { + int port = 1616; + String cmi = ""; + for (String arg : args) { + if (arg.startsWith("-port")) { + String portStr = arg.substring(6); + if (portStr.replaceAll("\\d+", "").isEmpty()) { + port = Integer.parseInt(portStr); + } + } else if (arg.startsWith("-cmi")) { + cmi = arg.substring(5); + } else if (arg.startsWith("-debug")) { + Configurator.setRootLevel(Level.DEBUG); + } + } + Scanner sc = new Scanner(System.in); + for (String str; sc.hasNextLine(); ) { + str = sc.nextLine(); + System.out.println("[CP From STDIN] " + str); + if (str.contains("CP PID:")) { + int pid = Integer.parseInt(str.replace("CP PID:", "")); + System.setProperty("io.netty.processId", pid + ""); + System.out.println("[CP SET PID DONE] " + str); + break; + } + } + System.out.println("[Create CP]"); + instance = new ContractProcess(port, cmi); + ; + } + + public static boolean isArchiveFile(File file) { + if (null == file) { + return false; + } + + if (file.isDirectory()) { + return false; + } + + boolean isArchive = false; + try (InputStream input = new FileInputStream(file)) { + byte[] buffer = new byte[4]; + int length = input.read(buffer, 0, 4); + if (length == 4) { + isArchive = + (Arrays.equals(ZIP_HEADER_1, buffer)) + || (Arrays.equals(ZIP_HEADER_2, buffer)); + } + } catch (IOException e) { + e.printStackTrace(); + } + + return isArchive; + } + + public static long toByte(String size) { + String[] unit = {"B", "KB", "MB", "GB", "TB"}; + + long res; + String[] a = size.split(" "); + double r = Double.parseDouble(a[0]); + + if (a[1].equals(unit[1])) { + r = Math.pow(1024, 1); + } else if (a[1].equals(unit[2])) { + r = Math.pow(1024, 2); + } else if (a[1].equals(unit[3])) { + r = Math.pow(1024, 3); + } else if (a[1].equals(unit[4])) { + r = Math.pow(1024, 4); + } + + res = (long) r; + return res; + } + + public String getContractName() { + return cn.getContractName(); + } + + public String staticVerify(Contract c) { + // ContractResult ret = new ContractResult(Status.Exception, ""); + LOGGER.info("ccccc--cccc" + JsonUtil.toJson(c) + "\n" + c.getPublicKey()); + ContractResult ret = new ContractResult(Status.Error, new JsonPrimitive("")); + try { + String script = c.getScriptStr(); + ContractNode cn; + YJSCompiler compiler = new YJSCompiler(); + if (script.startsWith("/")) { + ZipFile zf = new ZipFile(script); + ContractZipBundle czb = compiler.compile(zf); + + cn = czb.mergeContractNode(); + } else { + cn = + compiler.compile( + new ByteArrayInputStream(script.getBytes()), "contract_main.yjs"); + } + DesktopEngine engine = new DesktopEngine(); // engine.loadJar(zf); + engine.loadContract(c, cn, ret.isInsnLimit); + Map clzs = engine.dumpClass(); + Map methods = new HashMap<>(); + for (byte[] clz : clzs.values()) { + ClassNode classNode = new ClassNode(); + ClassReader cr = new ClassReader(clz); + cr.accept(classNode, ClassReader.EXPAND_FRAMES); + for (MethodNode mn : classNode.methods) { + methods.put(mn.name, mn); + } + } + JsonObject result = new JsonObject(); + for (FunctionNode fn : cn.getFunctions()) { + System.out.println("[ContractManager] verify:" + fn.functionName); + + MethodNode mn = methods.get(fn.functionName); + if (mn != null) { + System.out.println( + "[ContractManager] getMethodNode, verify:" + fn.functionName); + TaintResult.nLocals = mn.maxLocals; + TaintResult.nStack = mn.maxStack; + TaintCFG cfg = new TaintCFG(mn); + TaintResult.printer.setLabelOrder(cfg.getLabelOrder()); + try { + MultiSourceTaintAnalysis analysis = new MultiSourceTaintAnalysis(cfg); + analysis.analysis(); + TaintBB bb = cfg.getLastBlock(); + if (bb != null) + result.addProperty(fn.functionName, bb.getResultWithTaintBit()); + System.out.println("[ContractManager] verifyDone:" + fn.functionName); + } catch (Exception e) { + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + e.printStackTrace(new PrintStream(bo)); + result.addProperty(fn.functionName, bo.toString()); + e.printStackTrace(); + } + } + } + ret.status = Status.Success; + ret.result = result; + } catch (Exception e) { + ret.status = Status.Exception; + JsonObject a = new JsonObject(); + a.addProperty("info", e.getMessage()); + ret.result = a; + e.printStackTrace(); + } + return JsonUtil.toJson(ret); + } + + public String getControlFlow(Contract c) { + try { + // String parameters = c.getOwner(); + c.setPublicKey("temporypubkey"); + long start = System.currentTimeMillis(); + ContractNode cn; + DesktopEngine engine = new DesktopEngine(); // engine.loadJar(zf); + YJSCompiler compiler = new YJSCompiler(); + cn = compiler.compile(new ZipFile(c.getScriptStr())).mergeContractNode(); + engine.loadContract(c, cn, false); + Map clzs = engine.dumpClass(); + Map methods = new HashMap<>(); + for (byte[] clz : clzs.values()) { + ClassNode classNode = new ClassNode(); + ClassReader cr = new ClassReader(clz); + cr.accept(classNode, ClassReader.EXPAND_FRAMES); + for (MethodNode mn : classNode.methods) { + methods.put(mn.name, mn); + } + } + Map result = new HashMap<>(); + for (FunctionNode fn : cn.getFunctions()) { + System.out.println("[ContractManager] getCFG:" + fn.functionName); + MethodNode mn = methods.get(fn.functionName); + if (mn != null) { + /* + * CFGraph cfg = new CFGraph(mn) { + * + * @Override public BasicBlock getBasicBlock(int id) { return new + * BasicBlock(id); } }; FrontCF frontCF = new FrontCF(graph); String[] + data = + * fn.plainText().split("\n"); for (int i = 0; i < + graph.getBasicBlockSize(); + * i++) { BasicBlock bb = graph.getBasicBlockAt(i); String decompiled = + ""; if + * (bb.lineNum - 1 < data.length && bb.lineNum > 0) { decompiled = + * data[bb.lineNum - 1]; } frontCF.addBB(bb, decompiled); Set + suc = + * graph.getSucBlocks(bb); for (BasicBlock sucBB : suc) + frontCF.addEdge(bb, + * sucBB); } + */ + TaintResult.nLocals = mn.maxLocals; + TaintResult.nStack = mn.maxStack; + TaintCFG cfg = new TaintCFG(mn); + TaintResult.printer.setLabelOrder(cfg.getLabelOrder()); + MultiSourceTaintAnalysis analysis = new MultiSourceTaintAnalysis(cfg); + // ByValueDependencyAnalysis + analysis.analysis(); + // ControlDependencyAnalysis + Map> map = MultiSourceTaintAnalysis.depAnalysis(cfg); + FrontCF frontCF = new FrontCF(cfg); + String[] data = fn.plainText().split("\n"); + for (int i = 0; i < cfg.getBasicBlockSize(); i++) { + BasicBlock bb = cfg.getBasicBlockAt(i); + String decompiled = ""; + if (bb.lineNum - 1 < data.length && bb.lineNum > 0) { + decompiled = data[bb.lineNum - 1]; + } + List ids = map.get(i); + frontCF.addBB(bb, decompiled, ids, cfg); + Set suc = cfg.getSucBlocks(bb); + for (BasicBlock sucBB : suc) frontCF.addEdge(bb, sucBB); + } + // get result + // TaintBB lastBlock = cfg.getLastBlock(); + // if (lastBlock != null) { + // frontCF.ret = lastBlock.getResultWithTaintBit(); + // // System.out.println(frontCF.ret); + // if (parameters != null && parameters != "") { + // // System.out.println(parameters); + // // frontCF.finalRet = "yes"; + // Gson gson = JsonUtil; + // JsonParser jsonParser = new JsonParser(); + // JsonArray jsonArray = + // jsonParser.parse(parameters).getAsJsonArray(); + // List listConstraint = new ArrayList<>(); + // List listResource = new ArrayList<>(); + // for (JsonElement je : jsonArray) { + // Bean bean = gson.fromJson(je, Bean.class); + // switch (bean.name) { + // case "open": + // listConstraint.add("open"); + // break; + // case "byValue": + // listConstraint.add("byValue"); + // break; + // case "control": + // listConstraint.add("control"); + // break; + // case "close": + // listConstraint.add("close"); + // break; + // case "originalData": + // listResource.add("originalData"); + // break; + // case "contractCall": + // listResource.add("contractCall"); + // break; + // } + // } + //// String dep = + // frontCF.blocks.get(frontCF.blocks.size() - 1).blockDep; + //// if ((listConstraint.contains("open") + //// || + // listConstraint.contains("close")) + //// && (frontCF.ret != null || dep != null)) + //// frontCF.finalRet = "不通过"; + //// else frontCF.finalRet = "通过"; + // } + // } + result.put(fn.functionName, frontCF); + } + } + System.out.println("Test:" + JsonUtil.toJson(result)); + long end = System.currentTimeMillis(); + System.out.println(end - start); + return JsonUtil.toJson(result); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return "{\"status\":\"failed\"}"; + } + + // 启动时写入数据库 + private void logCode() { + Map clzs = engine.dumpClass(); // 合约字节码 + // 将clzs中byte[]进行分Base64编码 + + Map clzs2 = new HashMap<>(); + for (String k : clzs.keySet()) { + String v = ByteUtil.encodeBASE64(clzs.get(k)); + clzs2.put(k, v); + } + String code = JsonUtil.toJson(clzs2); + Map map1 = new HashMap<>(); + map1.put("contract-bytecode", code); // 合约字节码 + map1.put("contractID", contract.getID()); + map1.put("contractType", contract.getType().name()); + // String str = ContractManager.dbPath + ";" + contractName + ";startContract" + + // ";" + map1; + map1.put("operation", "startContract"); + map1.put("timestamp", System.currentTimeMillis() + ""); + writeContractDB(map1); + } + + // TODO + public String setDesktopPermission(String isChanged) { + try { + System.out.println("permission" + isChanged); + String[] pmList = isChanged.split(","); + String yancloud_desktop = ""; + isOpen.put(pmList[0], pmList[1]); + yancloud_desktop += UtilRegistry.getInitStr(pmList[0], pmList[1].equals("open")); + engine.getNashornEngine() + .getContext() + .setAttribute( + ScriptEngine.FILENAME, yancloud_desktop, ScriptContext.ENGINE_SCOPE); + engine.getNashornEngine().eval(yancloud_desktop); + } catch (ScriptException e) { + e.printStackTrace(); + } + return "success"; + } + + public String getMemorySet() { + if (null == memorySet) { + return ""; + } + return this.memorySet; + } + + public String getLogType(String funName) { + return logDetails.get(funName); + } + + // 判断是否满足Oracle和Contact的执行要求 + public String verifyOracleAndContractPermission(Contract contract) { + // 权限校验 如果是Oracle 启动方式只能是Sole 否则报错 + if (cn.getYjsType() == YjsType.Oracle && contract.getType() != ContractExecType.Sole) { + LOGGER.info("Oracle only support Sole ContractType!"); + return JsonUtil.toJson( + new ContractResult( + Status.Error, + new JsonPrimitive("Oracle only support Sole ContractType!"))); + } + // 权限校验 如果是contract 申请了MySQL等权限 报错 + if (cn.getYjsType() == YjsType.Contract) { + for (Permission per : cn.getPermission()) { + if (per == Permission.SQL + || per == Permission.Http + || per == Permission.RocksDB + || per == Permission.MongoDB) { + LOGGER.debug("Contract can not have permissions of IO!"); + return JsonUtil.toJson( + new ContractResult( + Status.Error, + new JsonPrimitive("Contract can not have permissions of IO|"))); + } + } + } + return ""; + } + + public String setContractBundle(Contract contract) { + try { + // long start = System.currentTimeMillis(); + // long start0 = start; + this.contract = contract; + JavaScriptEntry.random = new Random(); + JavaScriptEntry.invokeID = 0L; + JavaScriptEntry.random.setSeed(Integer.parseInt(contract.getID())); + JavaScriptEntry.numOfCopies = this.contract.getNumOfCopies(); + JavaScriptEntry.shadingId = + this.contract.getShadingId(); // 设置javaScriptEntry中的shadingID + // JavaScriptEntry + String zipPath = contract.getScriptStr(); + if (isArchiveFile(new File(zipPath))) { + ZipFile zf = new ZipFile(zipPath); + ContractZipBundle zipBundle = new YJSCompiler().compile(zf); + cn = zipBundle.mergeContractNode(); + // check functionNodes + List functionNodes = cn.getFunctions(); + LOGGER.debug( + "functionNodes jointInfo: " + + StringUtils.join( + functionNodes.stream() + .map( + x -> { + JoinInfo joinInfo = x.getJoinInfo(); + return null == joinInfo + ? "null" + : joinInfo; + }) + .toArray(), + " ")); + injectHandlers(); + + this.contract.setYjsType(cn.getYjsType()); + memorySet = cn.memorySet; + this.contract.sourcePath = zipBundle.getManifest().sourcePath; + + LOGGER.debug( + "check sourcePath\n\tin-contract=" + + this.contract.sourcePath + + "\n\tin-manifest=" + + zipBundle.getManifest().sourcePath); + // zhanghongwei + + /* if (ret.getManifest().getInsnLimit() != 0) { + gasLimit=ret.getManifest().getInsnLimit(); + isInsnLimit = true; + }*/ + String ver = verifyOracleAndContractPermission(contract); + if (!ver.isEmpty()) { + return ver; + } + + for (Permission per : cn.getPermission()) { + isOpen.put(per.name(), "open"); + } + + handleLog(); + + // System.out.println("[ret.getManifest().getInsnLimit()]" + + // ret.getManifest().getInsnLimit()); + + engine = new DesktopEngine(zipBundle.getManifest(), zipPath, contract); + engine.loadJar(zf); + engine.registerResource(new Resources(zf, engine.getClassLoad())); + String retStr = + JsonUtil.toJson( + engine.loadContract(contract, cn, cn.getInstrumentBranch())); + invokeOnCreate(); + LOGGER.debug("result: " + retStr); + return retStr; + } else { + contract.setScript(FileUtil.getContent(zipPath)); + return setContract(contract); + } + + } catch (MalformedJsonException | JsonSyntaxException e) { + return JsonUtil.toJson( + new ContractResult( + Status.Error, + new JsonPrimitive("parse manifest.json error, not json format!"))); + } catch (Exception e) { + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + e.printStackTrace(new PrintStream(bo)); + return JsonUtil.toJson( + new ContractResult(Status.Error, new JsonPrimitive(bo.toString()))); + } + } + + private void injectHandlers() { + // 正式启动 + if (!this.contract.isDebug()) { + // this.engine.getResources().loadAsString("/maskConfig.json"); + for (FunctionNode fun : cn.getFunctions()) { + + if (fun.isExport()) { + // System.out.println("isExport"); + fun.appendBeforeInvokeHandler(new MockTemplateHandler()); + ; + } + } + } + for (FunctionNode fun : cn.getFunctions()) { + if (fun.isConfidential()) { + fun.appendBeforeInvokeHandler(new ConfidentialHandler(fun)); + } + if (fun.isHomomorphicEncrypt()) { + LOGGER.info("injectHandlers--------------------------------1"); + fun.appendAfterInvokeHandler(new HomomorphicEncryptHandler(fun)); + } + if (fun.isHomomorphicDecrypt()) { + fun.appendAfterInvokeHandler(new HomomorphicDecryptHandler(fun)); + } + if (fun.isExport()) { + fun.appendAfterInvokeHandler(new ObjToJsonHandler()); + // fun.appendBeforeInvokeHandler(new ReadMeHandler()); + // Mask是用于返回真正结果之后,做一些偏移,以保护数据隐私。 + // if (fun.isMask()) { + + // String maskConfig = + // engine.getResources().loadAsString("/maskConfig.json"); + // System.out.println("injectMask"+maskConfig); + // System.out.println("injectMask"+this.contract.Mask); + fun.appendAfterInvokeHandler(new MaskHandler()); + // } + } + } + } + + public String changeDumpPeriod(String period) { + System.out.println("[ContractProcess] period" + period); + + startAutoDump(); + return "success"; + } + + public String getDumpPeriod() { + return projectConfig.getDumpPeriod(); + } + + public String setContract(Contract contract) { + try { + JavaScriptEntry.random = new Random(); + JavaScriptEntry.invokeID = 0L; + JavaScriptEntry.random.setSeed(Integer.parseInt(contract.getID())); + JavaScriptEntry.numOfCopies = contract.getNumOfCopies(); + // TODO Optimize, 4 seconds takes to create an Engine. + engine = new DesktopEngine(); + this.contract = contract; + this.contract.sourcePath = "script_" + System.currentTimeMillis(); + YJSCompiler compiler = new YJSCompiler(); + cn = compiler.compile(contract.getScript(), null); // 这一步初始化ContractNode + contract.setYjsType(cn.getYjsType()); + + injectHandlers(); + String ver = verifyOracleAndContractPermission(contract); + if (!ver.equals("")) { + return ver; + } + handleLog(); + String ret = + JsonUtil.toJson(engine.loadContract(contract, cn, cn.getInstrumentBranch())); + invokeOnCreate(); + + return ret; + } catch (Exception e) { + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + e.printStackTrace(new PrintStream(bo)); + return JsonUtil.toJson( + new ContractResult(Status.Error, new JsonPrimitive(bo.toString()))); + } + } + + private void handleLog() { + for (FunctionNode fun : cn.getFunctions()) { + StringBuilder detail = new StringBuilder(); + + for (LogType type : fun.getLogTypes()) { + switch (type) { + case Arg: + detail.append("Arg;"); + break; + case Branch: + detail.append("Branch;"); + break; + case Result: + detail.append("Result;"); + break; + default: + break; + } + } + + if (fun.getLogToBDContract()) detail.append("bdcontract;"); + if (fun.getLogToNamedLedger()) { + for (String str : fun.getLedgerNames()) { + detail.append("bdledger:").append(str).append(";"); + } + } + logDetails.put(fun.functionName, detail.toString()); + } + } + + public String setDBInfo(String path) { + dbPath = path; + /* + * File confDB = new File(path); if (!confDB.exists()) confDB.mkdirs(); + */ + return "success"; + } + + public long getUsedMemory(String arg) { + Runtime r = Runtime.getRuntime(); + return r.totalMemory() - r.freeMemory(); + } + + private void invokeOnCreate() { + long start = System.currentTimeMillis(); + logIndex = new TimeSerialIndex("./ContractDB/" + cn.getContractName() + ".index"); + LOGGER.debug("timeSerialIndex: " + (System.currentTimeMillis() - start)); + start = System.currentTimeMillis(); + edion = RocksDBUtil.loadDB("defaultLog", false); + LOGGER.debug("create RocksDB: " + (System.currentTimeMillis() - start)); + start = System.currentTimeMillis(); + engine.redirectTracePS(new Logger(new ByteArrayOutputStream(), this)); + // startContract时写入数据库 + if (null != cn.getLogTypes() && cn.getLogTypes().contains(LogType.Code)) { + logCode(); + } + + JavaScriptEntry.setSM2KeyPair(contract.getPublicKey(), contract.getKey()); + if (null != contract.getDOI() && !contract.getDOI().isEmpty()) { + JavaScriptEntry.doi = contract.getDOI(); + } + if (null != contract.getAuthInfoPersistDOI() + && !contract.getAuthInfoPersistDOI().isEmpty()) { + JavaScriptEntry.authInfoPersistDOI = contract.getAuthInfoPersistDOI(); + } + JavaScriptEntry.isDebug = contract.isDebug(); + ContractRequest onCreate = new ContractRequest(); + onCreate.setAction("onCreate"); + onCreate.setArg("null"); + onCreate.setRequester(contract.getOwner()); + if (contract.getDoipFlag() && null != contract.getDOI() && !contract.getDOI().isEmpty()) { + onCreate.setRequesterDOI(contract.getDOI()); + } else { + onCreate.setRequesterDOI("empty"); + } + FunctionNode funNode = cn.getFunction("onCreate"); + invoke(start, onCreate, funNode); + } + + private void invokeOnRecover() { + long start = System.currentTimeMillis(); + ContractRequest onRecover = new ContractRequest(); + onRecover.setAction("onRecover"); + onRecover.setArg("null"); + onRecover.setRequester(contract.getOwner()); + if (contract.getDoipFlag() + && (contract.getDOI() != null) + && (contract.getDOI().length() > 0)) { + onRecover.setRequesterDOI(contract.getDOI()); + } else { + onRecover.setRequesterDOI("empty"); + } + FunctionNode funNode = cn.getFunction("onRecover"); + invoke(start, onRecover, funNode); + } + + private void invoke(long start, ContractRequest onRecover, FunctionNode funNode) { + // start = System.currentTimeMillis(); + if (funNode != null) { + LOGGER.debug( + "getFunction:" + (System.currentTimeMillis() - start) + " " + funNode.functionName); + long start1 = System.currentTimeMillis(); + funNode.setIsExport(true); + engine.executeContract(onRecover); + LOGGER.debug("executeOnCreate:" + (System.currentTimeMillis() - start1)); + start1 = System.currentTimeMillis(); + funNode.setIsExport(false); + engine.getTracePS().clean(); + LOGGER.debug("clearTrace:" + (System.currentTimeMillis() - start1)); + // start1 = System.currentTimeMillis(); + + } + } + + // public String executeBundle(ContractZipBundle czb, String arg) { + // ContractRequest ac = null; + // ContractResult result = null; + // try { + // ac = JsonUtil.fromJson(arg, ContractRequest.class); + // } catch (Exception e) { + // } + // if (ac == null) { + // result = new ContractResult(ContractResult.Status.Error, "Illegal + // Arguments!"); + // return JsonUtil.toJson(result); + // } + // + // ContractManifest cm = czb.getManifest(); + // switch (cm.getType()) { + // case Data: + // case Algorithm: + // result = engine.executeContract(ac); + // return JsonUtil.toJson(result); + // case Application: + // default: + // return "todo"; + // } + // } + + public boolean isSigRequired() { + return cn.sigRequired; + } + + public String requestLog(long offset, int size) { + List hashes = logIndex.request(offset, size); + List> jo = new ArrayList<>(); + + TypeToken> token = new TypeToken>() { + }; + for (Long hash : hashes) + try { + Map obj = + JsonUtil.fromJson(edion.get(hash.toString()), token.getType()); + jo.add(obj); + } catch (JsonSyntaxException e) { + e.printStackTrace(); + } + return JsonUtil.toJson(jo); + } + + public String requestLast(int count) { + List hashes = logIndex.requestLast(count); + List> jo = new ArrayList<>(); + TypeToken> token = new TypeToken>() { + }; + String log; + for (Long hash : hashes) + try { + log = edion.get(hash.toString()); + if (null == log || 0 == log.length()) { + continue; + } + Map obj = JsonUtil.fromJson(log, token.getType()); + if (obj == null) { + System.out.println( + "[ContractProcess] requestLast, parseJsonError:" + log + "=="); + continue; + } + obj.put("hash", hash + ""); + jo.add(obj); + } catch (Exception e) { + e.printStackTrace(); + } + return JsonUtil.toJson(jo); + } + + public long logSize() { + return logIndex.size(); + } + + public String executeContract(String arg) { + // TODO + // eventCenter.pub(new EventMsg("executeContract", arg)); + ContractRequest request; + ContractResult result; + + try { + request = JsonUtil.fromJson(arg, ContractRequest.class); + } catch (Exception ignored) { + result = + new ContractResult( + ContractResult.Status.Error, new JsonPrimitive("Illegal Arguments!")); + return JsonUtil.toJson(result); + } + String reqID = request.getRequestID(); + if (cachedRequests.contains(reqID)) { + try { + String cachedResult = edion.get(reqID); + if (cachedResult != null && !cachedResult.isEmpty()) { + return cachedResult; + } + } catch (Exception ignored) { + } + } + try { + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + if (request.withDynamicAnalysis) { + ContractProcess.Logger previous = engine.getTracePS(); + engine.redirectTracePS(new Logger(bo, this)); + result = engine.executeContract(request); + result.analysis = bo.toString(); + System.out.println( + "[ContractProcess] result.analysis = " + + result.analysis); // 动态分析bug null pointer + // branchResult = JsonUtil.toJson(result); + // branchTrace = result.analysis; + engine.redirectTracePS(previous); + dynamicAnalysis(request, result); + } else if (request.withEvaluatesAnalysis) { + ContractProcess.Logger previous = engine.getTracePS(); + + System.out.println("[size:]" + function.size()); + System.out.println("[action index]:" + function.indexOf(request.getAction())); + + System.out.println("[InsnFeeValue]" + request.getValue()); + System.out.println("[InsnFeeLimit]" + gasLimit); + int functionIndex = function.indexOf(request.getAction()); + if (ppCountMap == null || ppCountMap.isEmpty()) { + System.out.println("没有提前进行预估"); + evaluatesAnalysis(request.getAction()); + } + + engine.redirectTracePS( + new ProgramPointCounter( + bo, + this, + gasLimit, + functionIndex, + request.getValue(), + 0L, + request.getAction(), + ppCountMap)); + result = engine.executeContract(request); + + result.analysis = bo.toString(); + // System.out.println( + // "[withEvaluatesAnalysis ContractProcess] result.analysis = + // " + // + result.analysis); + engine.redirectTracePS(previous); + + } else { + ContractProcess.Logger previous = engine.getTracePS(); + engine.redirectTracePS(new Logger(bo, this)); + result = engine.executeContract(request); + engine.redirectTracePS(previous); + } + // + + // System.out.println("res" + result.result); + // result.addProperty("result",maskResult.getMaskResult(maskConf, + // ret.get("result")).toString()); + + String ret = JsonUtil.toJson(result); + cachedRequests.add(reqID); + edion.put(reqID, ret); + return ret; + } catch (Exception e) { + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + e.printStackTrace(new PrintStream(bo)); + return bo.toString(); + } + } + + public String evaluatesAnalysis(String getFunction) { + // System.out.println("当前的function:" + getFunction); + Map clzs = engine.dumpClass(); + Map methods = new HashMap<>(); + for (byte[] clz : clzs.values()) { + ClassNode classNode = new ClassNode(); + ClassReader cr = new ClassReader(clz); + cr.accept(classNode, ClassReader.EXPAND_FRAMES); + for (MethodNode mn : classNode.methods) { + methods.put(mn.name, mn); + } + } + int flag = 0; + for (String s : function) { + MethodNode mn = methods.get(s); + if (mn != null) { + CFGraph cfg = + new CFGraph(mn) { + @Override + public BasicBlock getBasicBlock(int id) { + return new BasicBlock(id); + } + }; + // cfg.printSelf(); + CFGmap.put(s, cfg); + PPCount countFee = new PPCount(cfg, flag); + + BasicBlock bb = cfg.getBasicBlockAt(0); + countFee.dfs(cfg, bb); + // System.out.println("[ppmap]:" + PPCount.ppMap); + // System.out.println("[PPCount.branchCount]"+PPCount.branchCount); + Evaluates feEvaluates = new Evaluates(); + feEvaluates.getGas(PPCount.branchCount); + feEvaluates.getInsnGas(PPCount.ppMap); + + PPCount.countFunction(s, Evaluates.map); + ppCountMap = Evaluates.map; + System.out.println("+++++++" + PPCount.ppMap); + flag++; + } + } + for (Map.Entry map : PPCount.functionSumGas.entrySet()) { + if (map.getKey().contains(getFunction) && map.getKey().contains("true")) { + System.out.println("[合约方法pub中条件循环为true时:]" + map.getValue()); + } else if (map.getKey().contains(getFunction) && map.getKey().contains("false")) { + System.out.println("[合约方法pub中条件循环为false时:]" + map.getValue()); + } else if (map.getKey().contains(getFunction)) { + System.out.println("[合约方法pub中其他语句消耗:]" + map.getValue()); + } + } + return PPCount.functionSumGas.toString(); + } + + public void dynamicAnalysis(ContractRequest ac, ContractResult result) { + Map classes = engine.dumpClass(); + Map methods = new HashMap<>(); + for (byte[] clz : classes.values()) { + ClassNode classNode = new ClassNode(); + ClassReader cr = new ClassReader(clz); + System.out.print("[cr:]" + cr); + cr.accept(classNode, ClassReader.EXPAND_FRAMES); + for (MethodNode mn : classNode.methods) { + methods.put(mn.name, mn); + } + } + + MethodNode mn = methods.get(ac.getAction()); + if (mn != null) { + TaintResult.nLocals = mn.maxLocals; + TaintResult.nStack = mn.maxStack; + TaintCFG cfg = new TaintCFG(mn); + String trace = result.analysis; + System.out.println("TraceFile:\n" + trace); + System.out.println("TraceFile结束====================================="); + System.out.println("打印cfg图====================================="); + cfg.printSelf(); + System.out.println("打印cfg图====================================="); + TracedFile tf = new TracedFile(new ByteArrayInputStream(trace.getBytes())); + TaintResult.printer.setLabelOrder(cfg.getLabelOrder()); + NaiveDynamicTaintAnalysis analysis = new NaiveDynamicTaintAnalysis(cfg, tf); + analysis.analysis(); + + TaintBB bb = cfg.getLastBlock(); + result.analysis = bb.getResultWithTaintBit(); + System.out.println( + "[ContractProcess] dynamically verify: " + + ac.getAction() + + "-->" + + result.analysis); + } + } + + public String registerMangerPort(String arg) { + JavaScriptEntry.get = new SocketGet("127.0.0.1", Integer.parseInt(arg)); + return "success"; + } + + public void subscribe(String functionName) { + cn.getFunction(functionName).setHandler(true); + cn.getFunction("_preSub").setHandler(true); + } + + public void unSubscribe(String functionName) { + cn.getFunction(functionName).setHandler(false); + } + + public boolean checkSub() { + return !JavaScriptEntry.topic_handlers.isEmpty(); + } + + public void beforeSuicide() { + } + + public String redo(String path) { + return engine.syncUtil.redo(path); + } + + public String getMemoryDump(String path) { + return engine.syncUtil.dumpMemory(path, contract.getStateful()); + } + + public String getJSERandomCur() { + return JavaScriptEntry.random.toString(); + } + + public String loadMemoryDump(String path) { + String str = engine.syncUtil.loadMemoryDump(path, contract.getStateful()); + invokeOnRecover(); + return str; + } + + // 查看当前合约的权限 + public String showPermission() { + return JsonUtil.toJson(isOpen); + } + + // 查看合约进程占用内存大小 + public String getStorage() { + Runtime run = Runtime.getRuntime(); + long mem = run.totalMemory() - run.freeMemory(); + System.out.println("[ContractProcess] getStorage = " + ByteUtil.byteTo(mem)); + return ByteUtil.byteTo(mem); + } + + /* + * 将合约操作计入该合约的本地数据库中 + */ + public void writeContractDB(Map data) { + String path = dbPath; + if (path == null) { + // return "nopath"; + return; + } + try { + String result = JsonUtil.toJson(data); + long hash = HashUtil.hashStr2Long(result); + logIndex.index(hash); + edion.put(String.valueOf(hash), result); + } catch (Exception e) { + e.printStackTrace(); + // return "failed"; + } + // return "success"; + } + + @Override + public void finalize() { + } + + public String getDeclaredEvents() { + return JsonUtil.toJson(cn.events); + } + + public String getAnnotations() { + return JsonUtil.toJson(cn.annotations); + } + + public String getExportedFunctions() { + List ret = new ArrayList<>(); + for (FunctionNode fn : cn.getFunctions()) { + if (fn.isExport() && !fn.functionName.equals("onCreate")) { + function.add(fn.functionName); + FunctionDesp desp = + new FunctionDesp(fn.functionName, fn.annotations, fn.getRouteInfo()); + ret.add(desp); + } + } + return JsonUtil.toJson(ret); + } + + public String getContract() { + return JsonUtil.toJson(contract); + } + + public String getPID() { + return this.pid; + } + + public void setPID(String pid) { + this.pid = pid; + } + + public String startAutoDump() { + String dumpPeriod = projectConfig.getDumpPeriod(); + System.out.println( + "[ContractProcess] startAutoDump : " + + cn.getContractName() + + " period = " + + dumpPeriod); + String status = "startAutoDump status 0"; + if (null != dt) { + if (null == dumpPeriod || dumpPeriod.isEmpty()) { + dt.cancel(); + status = "startAutoDump status 1"; + } else { + dt.cancel(); + Timer timer = new Timer(); + dt = new DumpTask(); + timer.schedule(dt, new Date(), Long.parseLong(dumpPeriod)); + status = "startAutoDump status 2"; + } + } else { + if (dumpPeriod != null && !dumpPeriod.equals("")) { + Timer timer = new Timer(); + dt = new DumpTask(); + timer.schedule(dt, new Date(), Long.parseLong(dumpPeriod)); + status = "startAutoDump status 3"; + } + } + + LOGGER.debug("[ContractProcess] status : " + status); + return status; + } + + public String getDir() { + return this.dir; + } + + public void setDir(String s) { + this.dir = s + "/ADSPDir/" + contract.getID() + "/"; + engine.syncUtil.setDir(dir); + } + + public boolean isDebug() { + return contract.isDebug(); + } + + public String getCachedTransRecords(String startSeq) { + int start = Integer.parseInt(startSeq); + + if (engine.syncUtil != null && engine.syncUtil.transRecordUtil != null) { + return engine.syncUtil.transRecordUtil.getCachedTransRecords(start); + } + + return ""; + } + + public void clearSyncFiles(String arg) { + if (engine.syncUtil == null) { + LOGGER.debug("syncUtil is null, can not clear all sync files!"); + return; + } + engine.syncUtil.clearAllFiles(); + } + + public String getStateful() { + return contract.getStateful() + ""; + } + + public void startSync() { + // engine.syncUtil.setContractID(contract.getID()); + engine.syncUtil.setStartFlag(true); + } + + public void setCRFile(String fileName) { + engine.syncUtil.setCRFile(fileName); + } + + public void stopSync() { + engine.syncUtil.setStartFlag(false); + } + + public String changeDebugFlag(Boolean b) { + contract.setDebug(b); + JavaScriptEntry.isDebug = b; + return "success"; + } + + public String parseYpkPermissions(String ypkPath) { + YJSCompiler compiler = new YJSCompiler(); + try { + ContractZipBundle bundle = compiler.compile(new ZipFile(ypkPath)); + ContractNode contractNode = bundle.mergeContractNode(); + return JsonUtil.toJson(contractNode.getPermission()); + } catch (IOException e) { + e.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(); + } + return "[]"; + } + + public ProjectConfig getProjectConfig() { + return projectConfig; + } + + public void setProjectConfig(String args) { + projectConfig = JsonUtil.fromJson(args, ProjectConfig.class); + String period = projectConfig.getDumpPeriod(); + + if (period != null && period.length() > 0) { + changeDumpPeriod(period); + } + // System.out.println("ContractProcessMask"); + // JsonObject argsJS = JsonParser.parseString(args).getAsJsonObject(); + // String contractID = ""; + // String operation = ""; + // JsonElement mask = JsonParser.parseString(""); + // if (argsJS.has("contractID") && argsJS.has("operation") && argsJS.has("maskInfo")) + // { + // contractID = argsJS.get("contractID").getAsString(); + // System.out.println(contractID); + // operation = argsJS.get("operation").getAsString(); + // System.out.println(operation); + // mask = argsJS.get("maskInfo"); + // System.out.println("mask" + mask); + // this.contract.setMask(operation, mask); + // } + } + + public String getDependentContracts() { + return JsonUtil.toJson(cn.getDependentContracts()); + } + + public static class Logger extends PrintStream { + + ContractProcess cp; + OutputStream out; + + public Logger(OutputStream out, ContractProcess cp) { + super(out); + this.cp = cp; + this.out = out; + } + + public Logger(OutputStream out) { + super(out); + cp = null; + this.out = out; + } + + public Logger(PrintStream err) { + super(err); + this.out = null; + } + + public ContractProcess getCp() { + return cp; + } + + public void writeToDB(Map data) { + if (cp != null) { + cp.writeContractDB(data); + } + } + // TODO we do not need outputTrace? + // public void outputTrace(String operation) { + // cp.writeContractDB(operation, this.toString()); + // } + + public String getOutputStr() { + return out.toString(); + } + + public void clean() { + if (out instanceof ByteArrayOutputStream) { + out = new ByteArrayOutputStream(); + } + } + } + + public static class Bean { + public String name; + public String value; + } + + private class DumpTask extends TimerTask { + @Override + public void run() { + System.out.println( + "[ContractProcess DumpTask] auto dump period : " + + projectConfig.getDumpPeriod()); + File file1 = new File(dir); + File file2 = new File(file1.getParent()); + String dir2 = file2.getParent() + "/memory/"; + System.out.println("[ContractProcess] auto dump dir " + dir2); + SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd.HH_mm_ss"); // 设置日期格式 + File f = new File(dir2 + cn.getContractName(), df.format(new Date())); + System.out.println("[ContractProcess] dump file " + f.getAbsolutePath()); + + File parent = f.getParentFile(); + if (!parent.exists()) { + parent.mkdirs(); + } + getMemoryDump(f.getAbsolutePath()); + } + } +} diff --git a/src/main/java/org/bdware/sc/analysis/dynamic/FSAnalysis.java b/src/main/java/org/bdware/sc/analysis/dynamic/FSAnalysis.java new file mode 100644 index 0000000..294a35b --- /dev/null +++ b/src/main/java/org/bdware/sc/analysis/dynamic/FSAnalysis.java @@ -0,0 +1,122 @@ +package org.bdware.sc.analysis.dynamic; + +import org.bdware.analysis.BasicBlock; +import org.bdware.analysis.BreadthFirstSearch; +import org.bdware.analysis.taint.*; +import org.bdware.sc.bean.Contract; +import org.bdware.sc.compiler.YJSCompiler; +import org.bdware.sc.engine.DesktopEngine; +import org.bdware.sc.node.ContractNode; +import org.bdware.sc.node.ContractZipBundle; +import org.bdware.sc.node.FunctionNode; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.MethodNode; + +import java.io.ByteArrayInputStream; +import java.io.FileInputStream; +import java.util.*; +import java.util.zip.ZipFile; + +public class FSAnalysis extends BreadthFirstSearch { + TaintCFG cfg; + public static boolean isDebug = false; + + public FSAnalysis(TaintCFG cfg) { + this.cfg = cfg; + List toAnalysis = new ArrayList<>(); + // TODO add inputBlock! + TaintBB b = (TaintBB) cfg.getBasicBlockAt(0); + + b.preResult = new TaintResult(); + // local0=scriptfuncion, is not tainted; + // local1=this, is not tainted; + // local2=this, is not tainted; + + b.preResult.frame.setLocal(0, HeapObject.getRootObject()); + b.preResult.frame.setLocal(1, new TaintValue(1, 0)); + b.preResult.frame.setLocal(2, new TaintValue(1, 1)); + + b.preResult.ret = new TaintValue(1); + TaintResult.printer.setLabelOrder(cfg.getLabelOrder()); + toAnalysis.add(b); + b.setInList(true); + setToAnalysis(toAnalysis); + if (isDebug) { + System.out.println("===Method:" + cfg.getMethodNode().name + cfg.getMethodNode().desc); + System.out.println( + "===Local:" + + cfg.getMethodNode().maxLocals + + " " + + cfg.getMethodNode().maxStack); + } + } + + @Override + public TaintResult execute(TaintBB t) { + return t.forwardAnalysis(); + } + + @Override + public Collection getSuc(TaintBB t) { + Set subBlock = cfg.getSucBlocks(t); + Set ret = new HashSet<>(); + for (BasicBlock bb : subBlock) { + TaintBB ntbb = (TaintBB) bb; + ntbb.preResult.mergeResult(t.sucResult); + ret.add(ntbb); + } + + return ret; + } + + public static String staticVerify(Contract c) { + try { + String script = c.getScriptStr(); + ContractNode cn = null; + YJSCompiler compiler = new YJSCompiler(); + if (script.startsWith("/")) { + String zipPath = script; + ZipFile zf = new ZipFile(zipPath); + ContractZipBundle czb = compiler.compile(zf); + cn = czb.mergeContractNode(); + } else { + cn = + compiler.compile( + new ByteArrayInputStream(script.getBytes()), "contract_main.yjs"); + } + DesktopEngine engine = new DesktopEngine(); // engine.loadJar(zf); + engine.loadContract(c, cn, false); + Map clzs = engine.dumpClass(); // 拿到的类和对应的字节码 + Map methods = new HashMap<>(); + for (byte[] clz : clzs.values()) { + ClassNode classNode = new ClassNode(); + ClassReader cr = new ClassReader(clz); + cr.accept(classNode, ClassReader.EXPAND_FRAMES); + for (MethodNode mn : classNode.methods) { + methods.put(mn.name, mn); + } + } + Map result = new HashMap<>(); + for (FunctionNode fn : cn.getFunctions()) { + MethodNode mn = methods.get(fn.functionName); + if (mn != null && mn.name.equals("statAge")) { + System.out.println("[ContractManager] verify:" + fn.functionName); + TaintResult.nLocals = mn.maxLocals; + TaintResult.nStack = mn.maxStack; + TaintCFG cfg = new TaintCFG(mn); + TaintResult.printer.setLabelOrder(cfg.getLabelOrder()); + FSAnalysis analysis = new FSAnalysis(cfg); + analysis.analysis(); + TaintBB bb = cfg.getLastBlock(); + if (bb != null) result.put(fn.functionName, bb.getResult()); + cfg.printSelf(); + } + } + return "success"; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/src/main/java/org/bdware/sc/blockdb/Constants.java b/src/main/java/org/bdware/sc/blockdb/Constants.java new file mode 100644 index 0000000..90f6abb --- /dev/null +++ b/src/main/java/org/bdware/sc/blockdb/Constants.java @@ -0,0 +1,5 @@ +package org.bdware.sc.blockdb; + +public class Constants { + public static final int ELASTIC_DB = 0; +} diff --git a/src/main/java/org/bdware/sc/blockdb/DBRepository.java b/src/main/java/org/bdware/sc/blockdb/DBRepository.java new file mode 100644 index 0000000..221e0d8 --- /dev/null +++ b/src/main/java/org/bdware/sc/blockdb/DBRepository.java @@ -0,0 +1,13 @@ +package org.bdware.sc.blockdb; + +import org.bdware.sc.commParser.BDLedger.Transaction; + +import java.util.Map; + +public interface DBRepository { + public String Get(Map condition);//get hash of transaction + public boolean Put(Transaction trans);//put transaction into databases + public boolean Delete(String hash);//delete transaction + public boolean Create_DB();//createDB + public boolean Open_DB(); //OpenDB +} \ No newline at end of file diff --git a/src/main/java/org/bdware/sc/blockdb/DBUtil.java b/src/main/java/org/bdware/sc/blockdb/DBUtil.java new file mode 100644 index 0000000..7cca7ca --- /dev/null +++ b/src/main/java/org/bdware/sc/blockdb/DBUtil.java @@ -0,0 +1,12 @@ +package org.bdware.sc.blockdb; + +public class DBUtil { + private static DBRepository instance = null; + + public static DBRepository getInstance(int type) { + if (null == instance && type == Constants.ELASTIC_DB) { + instance = new ElasticDBUtil(); + } + return instance; + } +} diff --git a/src/main/java/org/bdware/sc/blockdb/ElasticDBUtil.java b/src/main/java/org/bdware/sc/blockdb/ElasticDBUtil.java new file mode 100644 index 0000000..bf82f54 --- /dev/null +++ b/src/main/java/org/bdware/sc/blockdb/ElasticDBUtil.java @@ -0,0 +1,106 @@ +package org.bdware.sc.blockdb; + +import okhttp3.*; +import org.bdware.sc.commParser.BDLedger.Transaction; +import org.bdware.sc.util.JsonUtil; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ElasticDBUtil implements DBRepository { + public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); + public OkHttpClient client = new OkHttpClient(); + public List transactions = new ArrayList<>(); + public int bulk = 10000; + + @Override + public String Get(Map condition) { + // TODO Auto-generated method stub + Map map = new HashMap<>(); + Map map1 = new HashMap<>(); + Map map2 = new HashMap<>(); + map2.put("data", condition.get("data") + "*"); + map1.put("wildcard", map2); + map.put("query", map1); + String json = JsonUtil.toJson(map); + RequestBody requestbody = FormBody.create(json, JSON); + Request request = new Request.Builder().url("http://127.0.0.1:9200/transaction/_doc/_search").post(requestbody).build(); + try { + Response resp = client.newCall(request).execute(); + System.out.print(resp.body().string()); + resp.body().close(); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return json; + } + + @Override + public boolean Put(Transaction trans) { + // TODO Auto-generated method stub + transactions.add(trans); + if (transactions.size() == bulk) { + StringBuilder sb = new StringBuilder(); + try { + for (int i = 0; i < bulk; i++) { + sb + .append("{\"index\":{}}\n{\"data\":\"") + .append(new String(transactions.get(i).data, StandardCharsets.UTF_8)) + .append("\",") + .append("\"hash\":") + .append("\"") + .append(new String(transactions.get(i).hash, StandardCharsets.UTF_8)) + .append("\"") + .append("}") + .append("\n"); + } + //System.out.println(sb.toString()); + RequestBody requestbody = FormBody.create(sb.toString(), JSON); + Request request = new Request.Builder().url("http://127.0.0.1:9200/transaction/_doc/_bulk").post(requestbody).build(); + Response res1 = client.newCall(request).execute(); + boolean res = res1.isSuccessful(); + res1.body().close(); + System.out.println(res); + transactions.clear(); + return res; + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + return false; + } + + @Override + public boolean Delete(String hash) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean Create_DB() { + // TODO Auto-generated method stub + RequestBody body = RequestBody.create("", JSON); + Request request = new Request.Builder().url("http://127.0.0.1:9200/transaction/").put(body).build(); + try { + Response response = client.newCall(request).execute(); + boolean res = response.isSuccessful(); + response.body().close(); + return res; + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return false; + } + + @Override + public boolean Open_DB() { + // TODO Auto-generated method stub + return false; + } +} diff --git a/src/main/java/org/bdware/sc/blockdb/MongoDBUtil.java b/src/main/java/org/bdware/sc/blockdb/MongoDBUtil.java new file mode 100644 index 0000000..eaf752c --- /dev/null +++ b/src/main/java/org/bdware/sc/blockdb/MongoDBUtil.java @@ -0,0 +1,36 @@ +package org.bdware.sc.blockdb; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +public class MongoDBUtil { + public static Object connect(String url, int port, String dbName, String usrName, String pwd) { + try { + Class serverAddr = Class.forName("com.mongodb.ServerAddress"); + Constructor cons = serverAddr.getConstructor(String.class, Integer.TYPE); + Object serverAddress = cons.newInstance(url, port); + List addrs = new ArrayList<>(); + addrs.add(serverAddress); + Method createeScramSha1 = + Class.forName("com.mongodb.MongoCredential") + .getDeclaredMethod( + "createScramSha1Credential", + String.class, + String.class, + char[].class); + Object credential = createeScramSha1.invoke(null, usrName, dbName, pwd.toCharArray()); + List credentials = new ArrayList<>(); + credentials.add(credential); + Constructor mongoClient = + Class.forName("com.mongodb.MongoClient").getConstructor(List.class, List.class); + Object client = mongoClient.newInstance(addrs, credentials); + // 通过连接认证获取MongoDB连接 + return client; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } +} diff --git a/src/main/java/org/bdware/sc/blockdb/RocksDBUtil.java b/src/main/java/org/bdware/sc/blockdb/RocksDBUtil.java new file mode 100644 index 0000000..9740a7b --- /dev/null +++ b/src/main/java/org/bdware/sc/blockdb/RocksDBUtil.java @@ -0,0 +1,72 @@ +package org.bdware.sc.blockdb; + +import org.bdware.sc.commParser.BDLedger.Transaction; +import org.rocksdb.Options; +import org.rocksdb.RocksDB; +import org.rocksdb.RocksDBException; + +import java.io.File; +import java.util.Map; + +public class RocksDBUtil implements DBRepository{ + private static RocksDB rocksdb; + static { + RocksDB.loadLibrary(); + } + + public static RocksDB loadDB(String path, String readOnly) { + try { + Options options = new Options(); + options.setCreateIfMissing(true); + RocksDB rocksDB; + File lockFile = new File(path,"LOCK"); + lockFile.delete(); + if (readOnly != null && readOnly.equals("true")) { + rocksDB = RocksDB.openReadOnly(options, path); + } else + rocksDB = RocksDB.open(options, path); + rocksdb = rocksDB; + return rocksDB; + + } catch (RocksDBException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return null; + } + + @Override + public String Get(Map condition) { + // TODO Auto-generated method stub + if(condition.containsKey("start")&&condition.containsKey("end")) { + int start = (int)condition.get("start"); + int end = (int)condition.get("end"); + } + return null; + } + + @Override + public boolean Put(Transaction trans) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean Delete(String hash) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean Create_DB() { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean Open_DB() { + // TODO Auto-generated method stub + return false; + } + +} diff --git a/src/main/java/org/bdware/sc/blockdb/SqliteDBUtil.java b/src/main/java/org/bdware/sc/blockdb/SqliteDBUtil.java new file mode 100644 index 0000000..be8fa92 --- /dev/null +++ b/src/main/java/org/bdware/sc/blockdb/SqliteDBUtil.java @@ -0,0 +1,117 @@ +package org.bdware.sc.blockdb; + +import org.bdware.sc.commParser.BDLedger.Block; +import org.bdware.sc.commParser.BDLedger.BlockBody; +import org.bdware.sc.commParser.BDLedger.BlockHeader; +import org.bdware.sc.util.HashUtil; + +import java.io.File; +import java.sql.*; + +public class SqliteDBUtil { + private Connection conn; + + public static SqliteDBUtil connect(String url) { + try { + String name = "org.sqlite.JDBC"; + SqliteDBUtil util = new SqliteDBUtil(); + String path = "jdbc:sqlite:"; + File file = new File(url); + path = path + file.getAbsolutePath(); + System.out.println("[SqliteDBUtil] connect:" + path); + Class.forName(name); + util.conn = DriverManager.getConnection(path); + return util; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public BlockBody getBlockBody(String headerHash, String bodyHash) { + try { + Statement stmt = conn.createStatement(); + // ResultSet result = stmt.executeQuery("select * from BlockHeader where hash = + // " + headerHash); + String sql = "select * from BlockBody where ID = ?"; + PreparedStatement pre = conn.prepareStatement(sql); + pre.setBytes(1, HashUtil.str16ToBytes(bodyHash)); + ResultSet result = pre.executeQuery(); + // Assert we get only one!!!! + while (result.next()) { + System.out.println(result.getBytes("ID")); + return BlockBody.fromBytes(result.getBytes("Data")); + } + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + public Block getBlock(String headerHash, String bodyHash) { + try { + BlockHeader header = new BlockHeader(); + BlockBody body = new BlockBody(); + Statement stmt = conn.createStatement(); + String sql = "select * from BlockBody where ID = ?"; + PreparedStatement pre = conn.prepareStatement(sql); + pre.setBytes(1, HashUtil.str16ToBytes(bodyHash)); + ResultSet result = pre.executeQuery(); + while (result.next()) { + body = BlockBody.fromBytes(result.getBytes("Data")); + } + String sql1 = "select * from BlockHeader where Hash = ?"; + pre = conn.prepareStatement(sql1); + pre.setBytes(1, HashUtil.str16ToBytes(headerHash)); + result = pre.executeQuery(); + while (result.next()) { + header.index = result.getInt(1); + header.hash = result.getBytes(2); + header.version = result.getInt(3); + header.timestamp = result.getInt(4); + header.prevblockID = result.getBytes(5); + header.merkleroot = result.getBytes(6); + header.creatorID = result.getBytes(7); + Block block = new Block(header,body); + return block; + //return Block.fromBytes(result.getBytes("Data")); + } + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + public byte[] bodyselectall() { + try { + Statement stmt = conn.createStatement(); + // ResultSet result = stmt.executeQuery("select * from BlockHeader where hash = + // " + headerHash); + String sql = "select * from BlockBody limit 1,1"; + PreparedStatement pre = conn.prepareStatement(sql); + ResultSet result = pre.executeQuery(); + // Assert we get only one!!!! + while (result.next()) { + return result.getBytes(1); + } + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + public byte[] headerselectall() { + try { + Statement stmt = conn.createStatement(); + // ResultSet result = stmt.executeQuery("select * from BlockHeader where hash = + // " + headerHash); + String sql = "select * from BlockHeader limit 1,1"; + PreparedStatement pre = conn.prepareStatement(sql); + ResultSet result = pre.executeQuery(); + // Assert we get only one!!!! + while (result.next()) { + return result.getBytes(2); + } + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/src/main/java/org/bdware/sc/blockdb/TimeDBUtil.java b/src/main/java/org/bdware/sc/blockdb/TimeDBUtil.java new file mode 100644 index 0000000..8dfb183 --- /dev/null +++ b/src/main/java/org/bdware/sc/blockdb/TimeDBUtil.java @@ -0,0 +1,39 @@ +package org.bdware.sc.blockdb; + +import org.bdware.sc.commParser.BDLedger.Transaction; + +import java.util.Map; + +public class TimeDBUtil implements DBRepository{ + + @Override + public String Get(Map condition) { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean Put(Transaction trans) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean Delete(String hash) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean Create_DB() { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean Open_DB() { + // TODO Auto-generated method stub + return false; + } + +} diff --git a/src/main/java/org/bdware/sc/boundry/AccountIndex.java b/src/main/java/org/bdware/sc/boundry/AccountIndex.java new file mode 100644 index 0000000..c946e12 --- /dev/null +++ b/src/main/java/org/bdware/sc/boundry/AccountIndex.java @@ -0,0 +1,200 @@ +package org.bdware.sc.boundry; + +import org.bdware.sc.boundry.TimeIndex.Data; +import org.bdware.sc.index.LenVarTimeSerialIndex2; +import org.bdware.sc.util.HashUtil; +import wrp.jdk.nashorn.api.scripting.ScriptObjectMirror; +import wrp.jdk.nashorn.internal.objects.Global; +import wrp.jdk.nashorn.internal.objects.NativeArray; +import wrp.jdk.nashorn.internal.runtime.PropertyMap; +import wrp.jdk.nashorn.internal.runtime.ScriptObject; +import wrp.jdk.nashorn.internal.scripts.JO; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.PrintStream; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class AccountIndex { + static Map fileMap = new HashMap<>(); + + public static AccountIndex createIndex() { + return new AccountIndex(); + } + + private static String getString(ScriptObjectMirror obj, String member) { + Object mem = obj.getMember(member); + if (mem != null && !(mem instanceof String)) { + return mem.toString(); + } + return (String) mem; + } + + private static Integer getInteger(ScriptObjectMirror obj, String member) { + Object mem = obj.getMember(member); + if (mem != null && !(mem instanceof Integer)) { + return Integer.valueOf(mem.toString()); + } + return (Integer) mem; + } + + private static Long getLong(ScriptObjectMirror obj, String member) { + Object mem = obj.getMember(member); + if (mem != null && !(mem instanceof Long)) { + return Long.valueOf(mem.toString()); + } + return (Long) mem; + } + + public ScriptObject createFile(ScriptObjectMirror args) { + JO ret = new JO(PropertyMap.newMap()); + if (!args.hasMember("account")) { + ret.put("result", "Missing Argumemt", false); + ret.put("status", "Error", false); + return ret; + } + if (!args.hasMember("file")) { + ret.put("result", "Missing Argumemt", false); + ret.put("status", "Error", false); + return ret; + } + if (!args.hasMember("dataLength")) { + ret.put("result", "Missing Argumemt", false); + ret.put("status", "Error", false); + return ret; + } + try { + Object file = args.get("file"); + if (!(file instanceof String)) { + ret.put("result", "Illegal Type, file is not String", false); + ret.put("status", "Error", false); + return ret; + } + Object address = args.get("account"); + if (!(address instanceof String)) { + ret.put("result", "Illegal Type, file is not String", false); + ret.put("status", "Error", false); + return ret; + } + String fileName = "./" + address + file; + File f = new File(fileName + ".datasize"); + FileOutputStream fout = new FileOutputStream(f, false); + Object dataLength = args.get("dataLength"); + int dataLengthInt = Integer.parseInt(dataLength.toString()); + for (int i = 0; i < dataLengthInt; i++) + fout.write(1); + fout.close(); + LenVarTimeSerialIndex2 index = getIndexFile(fileName); + ret.put("dataLength", dataLength, false); + ret.put("datasize", f.length(), false); + + ret.put("status", "Success", false); + return ret; + } catch (Exception e) { + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + e.printStackTrace(new PrintStream(bo)); + ret.put("status", "Success", false); + ret.put("result", bo.toString(), false); + return ret; + } + } + + public ScriptObject requestByTime(ScriptObjectMirror args) { + JO ret = new JO(PropertyMap.newMap()); + if (!args.hasMember("account")) { + ret.put("result", "Missing Argumemt", false); + ret.put("status", "Error", false); + return ret; + } + if (!args.hasMember("file")) { + ret.put("result", "Missing Argumemt: file", false); + ret.put("status", "Error", false); + return ret; + } + if (!args.hasMember("startTime")) { + ret.put("result", "Missing Argumemt: startTime", false); + ret.put("status", "Error", false); + return ret; + } + if (!args.hasMember("endTime")) { + ret.put("result", "Missing Argumemt: endTime", false); + ret.put("status", "Error", false); + return ret; + } + + try { + LenVarTimeSerialIndex2 index = getIndexFile(getString(args, "account") + getString(args, "file")); + long startTime = getLong(args, "startTime"); + long endTime = getLong(args, "endTime"); + List result = index.requestByTime(startTime, endTime); + ret.put("status", "Success", false); + NativeArray array = Global.allocate(new int[0]); + ret.put("list", array, false); + for (byte[] bytes : result) { + JO data = new JO(PropertyMap.newMap()); + Data d = new Data(bytes); + data.put("data", d.data, false); + data.put("date", d.date, false); + NativeArray.push(array, data); + } + return ret; + } catch (Exception e) { + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + e.printStackTrace(new PrintStream(bo)); + ret.put("status", "Error", false); + ret.put("data", bo.toString(), false); + return ret; + } + } + + private LenVarTimeSerialIndex2 getIndexFile(String str) { + LenVarTimeSerialIndex2 indexFile = fileMap.get(str); + if (indexFile == null) { + indexFile = new LenVarTimeSerialIndex2(str); + fileMap.put(str, indexFile); + } + return indexFile; + } + + public ScriptObject manullyIndex(ScriptObjectMirror args) { + JO ret = new JO(PropertyMap.newMap()); + if (!args.hasMember("account")) { + ret.put("result", "Missing Argumemt: account", false); + ret.put("status", "Error", false); + return ret; + } + if (!args.hasMember("date")) { + ret.put("result", "Missing Argumemt: date", false); + ret.put("status", "Error", false); + return ret; + } + if (!args.hasMember("content")) { + ret.put("result", "Missing Argumemt: content", false); + ret.put("status", "Error", false); + return ret; + } + if (!args.hasMember("file")) { + ret.put("result", "Missing Argumemt: file", false); + ret.put("status", "Error", false); + return ret; + } + + try { + LenVarTimeSerialIndex2 index = getIndexFile(getString(args, "account") + getString(args, "file")); + long date = getLong(args, "date"); + String content = getString(args, "content"); + index.manullyIndex(date, HashUtil.str16ToBytes(content)); + ret.put("status", "Success", false); + return ret; + } catch (Exception e) { + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + e.printStackTrace(new PrintStream(bo)); + ret.put("status", "Error", false); + ret.put("data", bo.toString(), false); + return ret; + } + } +} diff --git a/src/main/java/org/bdware/sc/boundry/JavaScriptEntry.java b/src/main/java/org/bdware/sc/boundry/JavaScriptEntry.java new file mode 100644 index 0000000..d846c83 --- /dev/null +++ b/src/main/java/org/bdware/sc/boundry/JavaScriptEntry.java @@ -0,0 +1,742 @@ +package org.bdware.sc.boundry; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.bdware.sc.ContractProcess; +import org.bdware.sc.bean.ContractRequest; +import org.bdware.sc.boundry.utils.SQLUtil; +import org.bdware.sc.conn.ResultCallback; +import org.bdware.sc.conn.SocketGet; +import org.bdware.sc.engine.DesktopEngine; +import org.bdware.sc.engine.SyncMechUtil; +import org.bdware.sc.event.REvent; +import org.bdware.sc.http.ApiGate; +import org.bdware.sc.syncMech.SyncType; +import org.bdware.sc.util.HashUtil; +import org.bdware.sc.util.JsonUtil; +import org.zz.gmhelper.SM2KeyPair; +import wrp.jdk.nashorn.api.scripting.NashornScriptEngine; +import wrp.jdk.nashorn.internal.objects.Global; +import wrp.jdk.nashorn.internal.runtime.PropertyMap; +import wrp.jdk.nashorn.internal.runtime.ScriptFunction; +import wrp.jdk.nashorn.internal.runtime.ScriptObject; +import wrp.jdk.nashorn.internal.scripts.JO; + +import javax.mail.*; +import javax.mail.internet.InternetAddress; +import javax.mail.internet.MimeMessage; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintStream; +import java.math.BigInteger; +import java.net.URL; +import java.net.URLConnection; +import java.security.Security; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.*; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import static org.bdware.sc.event.REvent.REventType.*; + +public class JavaScriptEntry { + // private static final HostnameVerifier DO_NOT_VERIFY = (hostname, session) -> true; + public static final Map topic_handlers = new HashMap<>(); + private static final Logger LOGGER = LogManager.getLogger(JavaScriptEntry.class); + public static NashornScriptEngine currentEngine; + public static SyncMechUtil currentSyncUtil; + // public static int contractManagerPort; + public static Random random; + public static long invokeID; + public static String doi; + public static String authInfoPersistDOI; + public static SocketGet get; // public static CloseableHttpClient httpClient = getHttpClient(); + public static int numOfCopies; + public static boolean isDebug; + public static List msgList; + public static int shadingId; + // private static SM2KeyPair keyPair = new SM2().generateKeyPair(); // TODO ?? 本地服务器的,39上运行39的 + // public static String privKey; + // public static String pubKey; + private static SM2KeyPair keyPair; + + public static void setSM2KeyPair(String pubKey, String privKey) { + keyPair = + new SM2KeyPair( + SM2KeyPair.publicKeyStr2ECPoint(pubKey), new BigInteger(privKey, 16)); + } + + public static SM2KeyPair getKeyPair() { + return keyPair; + } + + public static Global getEngineGlobal() { + return currentEngine.getNashornGlobal(); + } + + public static String byteArrayHash(byte[] hash) { + return HashUtil.hashByteArray(hash); + } + + public static Connection getMysqlConnection(String url, String usrName, String pwd) { + return SQLUtil.getConnection("jdbc:mysql://" + url, usrName, pwd); + } + + public static String example(String arg) { + LOGGER.debug("called: " + arg); + return arg + 1; + } + + // public static MongoClient connectMongoDb(String url, int port, String dbName, String usrName, + // String pwd) { + // return getMongoDBConnection(url, port, dbName, usrName, pwd); + // } + // + // public static MongoClient getMongoDBConnection(String url, int port, String dbName, String + // usrName, String pwd) { + // return MongoDBUtil.connect(url, port, dbName, usrName, pwd); + // } + + public static String bytes2Str(byte[] bytes) { + return new String(bytes); + } + + public static Object connectNeo4j(String url, String usrName, String pwd) { + try { + if (url.startsWith("jdbc:neo4j")) { + Connection con; + con = DriverManager.getConnection(url, usrName, pwd); + return con; + } + } catch (SQLException e) { + e.printStackTrace(); + } + return null; + } + + public static long currentTimeMillis() { + return System.currentTimeMillis(); + } + + public static Lock createLock() { + return new ReentrantLock(); + } + + public static String asyncTest(String str, ScriptFunction fun) { + LOGGER.debug(str); + DesktopEngine.applyWithGlobal(fun, currentEngine.getNashornGlobal(), str); + return "success"; + } + + // public static String http(String baseUrl, String method, Map header, + // Map argMap, + // List reservedList) { + // return HttpUtil.request(baseUrl, method, header, argMap, reservedList); + // } + + public static byte[] inputStreamToBytes(InputStream in) { + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + byte[] buff = new byte[4 * 1024 * 1024]; + try { + for (int count; (count = in.read(buff)) > 0; ) { + bo.write(buff, 0, count); + } + } catch (IOException e) { + e.printStackTrace(); + } + return bo.toByteArray(); + } + + // private static String list2Str(List reservedList) { + // return JsonUtil.toJson(reservedList); + // } + // + // private static String map2Str(Map map) { + // return JsonUtil.toJson(map); + // } + + // private static CloseableHttpClient getHttpClient(String url) { + // try { + // SSLContext sslcontext = SSLContexts.custom().loadTrustMaterial(null, new TrustStrategy() { + // + // @Override + // public boolean isTrusted(java.security.cert.X509Certificate[] arg0, String arg1) + // throws java.security.cert.CertificateException { + // return true; + // } + // }).build(); + // + // SSLConnectionSocketFactory sslSf = new SSLConnectionSocketFactory(sslcontext, null, null, + // new NoopHostnameVerifier()); + // int tle = 10; + // if (url.contains("data.tj.gov.cn")) + // tle = 3; + // return HttpClients.custom().setSSLSocketFactory(sslSf) + // .setKeepAliveStrategy(new ConnectionKeepAliveStrategy() { + // @Override + // public long getKeepAliveDuration(HttpResponse arg0, HttpContext arg1) { + // return 0; + // } + // }).setConnectionTimeToLive(tle, TimeUnit.SECONDS).build(); + // + // } catch (Exception e) { + // e.printStackTrace(); + // } + // return null; + // } + + public static InputStream httpAsInputStream(String url) { + try { + URL realUrl = new URL(url); + URLConnection conn = realUrl.openConnection(); + return conn.getInputStream(); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + // public static String httpPost(String str) { + // System.out.println("JavaSScriptEntry httpPost:" + str); + // PostRequest req = new PostRequest(); + // req = JsonUtil.fromJson(str, PostRequest.class); + // // System.out.println("url========>" + req.url); + // // System.out.println("data=======>" + req.data); + // + // Result r = new Result(); + // try { + // URL url = new URL(req.url);// + // HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + // connection.setDoOutput(true); + // connection.setDoInput(true); + // connection.setUseCaches(false); + // connection.setInstanceFollowRedirects(true); + // connection.setRequestMethod("POST"); // 璁剧疆璇锋眰鏂瑰紡 + // connection.setRequestProperty("Accept", "application/json"); // 璁剧疆鎺ユ敹鏁版嵁鐨勬牸寮� + // connection.setRequestProperty("Content-Type", "application/json"); // 璁剧疆鍙戦�佹暟鎹殑鏍煎紡 + // connection.connect(); + // OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream(), "UTF-8"); // + // utf-8缂栫爜 + // out.append(req.data); + // out.flush(); + // out.close(); + // + // r.resposeCode = connection.getResponseCode(); + // InputStream input = connection.getInputStream(); + // + // Scanner sc = new Scanner(input); + // StringBuilder sb = new StringBuilder(); + // for (; sc.hasNextLine();) { + // sb.append(sc.nextLine()).append("\n"); + // } + // sc.close(); + // r.response = sb.toString(); + // return JsonUtil.toJson(r); + // } catch (Throwable e) { + // r.resposeCode = 505; + // // ByteArrayOutputStream bo = new ByteArrayOutputStream(); + // // e.printStackTrace(new PrintStream(bo)); + // r.response = e.getMessage(); + // return JsonUtil.toJson(r); + // } + // } + + public static void executeFunction(ScriptFunction callback, Object arg) { + DesktopEngine.applyWithGlobal(callback, currentEngine.getNashornGlobal(), arg); + } + + public static ApiGate createAPIGate(String ip) { + return new ApiGate(ip); + } + + public static ApiGate createAPIGate(String ip, String port) { + return new ApiGate(ip, Integer.parseInt(port)); + } + + public static String executeContractWithSig( + String contractID, String action, String arg, String pubkey, String sig) { + try { + ContractRequest app = new ContractRequest(); + app.setContractID(contractID).setAction(action).setArg(arg); + app.setPublicKey(pubkey); + app.setSignature(sig); + app.fromContract = keyPair.getPublicKeyStr(); + if (!app.verifySignature()) { + return "{\"status\":\"Exception\",\"data\":\"invalid signature\"}"; + } + app.setRequesterDOI(doi); + app.setFromDebug(isDebug); + if (numOfCopies > 1) { + // The caller is special. + app.setRequestID( + app.getPublicKey().hashCode() + + "_" + + numOfCopies + + "_" + + (invokeID++) + + "_" + + random.nextInt() + + "_mul"); + } else { + app.setRequestID( + app.getPublicKey().hashCode() + + "_" + + (invokeID++) + + "_" + + random.nextInt()); + } + return get.syncGet("dd", "executeContract", JsonUtil.toJson(app)); + + } catch (Exception e) { + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + e.printStackTrace(new PrintStream(bo)); + return bo.toString(); + } + } + + public static String executeContract(String contractID, String action, String arg) { + if (currentSyncUtil.engine.recovering) { + String str = + currentSyncUtil.transRecoverUtil.curRecoverRecord.getExecuteResult( + invokeID + ""); + String[] strs = str.split(""); + String flag1 = strs[0]; + String flag = strs[1]; + String res = strs[2]; + if (flag1.equals("1")) { + invokeID++; + } + if (flag.equals("1")) { + random.nextInt(); + } + return res; + } + + long formerInvokeID = invokeID; + int flag1 = 0; // 标志invokeID++操作是否进行过 + int flag = 0; // 标志random是否取下一个 + + try { + ContractRequest app = new ContractRequest(); + app.setContractID(contractID).setAction(action).setArg(arg); + app.doSignature(keyPair); + app.setRequesterDOI(doi); + app.setFromDebug(isDebug); + if (numOfCopies > 1) { + app.setRequestID( + String.format( + "%d_%d_%d_%d_mul", + keyPair.getPublicKeyStr().hashCode(), + numOfCopies, + (invokeID++), + random.nextInt())); + // The caller is special. + flag = 1; + flag1 = 1; + LOGGER.warn("invoke contractExecution! " + JsonUtil.toJson(app)); + } else { + app.setRequestID( + String.format( + "%d_%d_%d", + keyPair.getPublicKeyStr().hashCode(), + (invokeID++), + random.nextInt())); + flag = 1; + flag1 = 1; + } + return executeContract(formerInvokeID, flag1, flag, app); + } catch (Exception e) { + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + e.printStackTrace(new PrintStream(bo)); + String result = bo.toString(); + if (currentSyncUtil.startFlag + && currentSyncUtil.currType == SyncType.Trans + && !currentSyncUtil.engine.recovering) { + currentSyncUtil.transRecordUtil.recordExecutes( + formerInvokeID + "", flag1 + "" + flag + "" + result); + } + return result; + } + } + + private static String executeContract(long formerInvokeID, int flag1, int flag, ContractRequest app) { + String result = get.syncGet("dd", "executeContract", JsonUtil.toJson(app)); + if (currentSyncUtil.startFlag + && currentSyncUtil.currType == SyncType.Trans + && !currentSyncUtil.engine.recovering) { + currentSyncUtil.transRecordUtil.recordExecutes( + formerInvokeID + "", + flag1 + "" + flag + "" + result); + } + return result; + } + + public static void executeContractAsyncWithoutSig( + String contractID, String action, String arg, final ScriptFunction cb) { + try { + ContractRequest app = new ContractRequest(); + app.setContractID(contractID).setAction(action).setArg(arg); + app.setRequestID((invokeID++) + "_" + random.nextInt()); + get.asyncGet( + "dd", + "executeContract", + JsonUtil.toJson(app), + new ResultCallback() { + @Override + public void onResult(String str) { + if (null != cb) { + DesktopEngine.applyWithGlobal( + cb, currentEngine.getNashornGlobal(), str); + } + } + }); + } catch (Exception e) { + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + e.printStackTrace(new PrintStream(bo)); + } + } + + /* public static String executeContract(String contractID, String action, String arg) { + //redo,use record data + if(currentSyncUtil.transRecoverUtil != null && currentSyncUtil.transRecoverUtil.recovering){ + String k = TransRecordUtil.produceExecuteIdentifier(contractID,action,arg); + return currentSyncUtil.transRecoverUtil.curRecoverRecord.getExecuteResult(k); + } + + try { + ContractRequest app = new ContractRequest(); + app.setContractID(contractID).setAction(action).setArg(arg); + //app.doSignature(keyPair.getPrivateKey().toString(16)); + app.doSignature(keyPair); + String result = get.syncGet("dd", "executeContract", JsonUtil.toJson(app)); + if(currentSyncUtil.startFlag && currentSyncUtil.currType == SyncType.Trans){ + String k = currentSyncUtil.transRecordUtil.produceExecuteIdentifier(contractID,action,arg); + currentSyncUtil.transRecordUtil.recordExecutes(k,result); + } + return result; + } catch (Exception e) { + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + e.printStackTrace(new PrintStream(bo)); + String result = bo.toString(); + if(currentSyncUtil.startFlag && currentSyncUtil.currType == SyncType.Trans){ + String k = TransRecordUtil.produceExecuteIdentifier(contractID,action,arg); + currentSyncUtil.transRecordUtil.recordExecutes(k,result); + } + return result; + } + }*/ + + // public static String queryContractIdByDOI(String contractDOI) throws Exception { + // DigitalObject contractDO; + // DoipClient doipClient = + // DoipClient.createByRepoUrlAndMsgFmt( + // DOIPMainServer.repoUrl, DoipMessageFormat.PACKET.getName()); + // DoMessage response = doipClient.retrieve(contractDOI, null, null); + // if (response.parameters.response == DoResponse.Success) { + // contractDO = DigitalObject.parse(response.body); + // } else { + // response = DOAClient.getGlobalInstance().retrieve(contractDOI, null, null); + // contractDO = DigitalObject.parse(response.body); + // } + // ContractInstanceDO contractInstanceDO = + // (ContractInstanceDO) + // ContractManager.toObject(contractDO.elements.get(0).getData()); + // return contractInstanceDO.id; + // } + + // public static String executeContractByDOI(String contractDOI, String action, String arg) { + // try { + // String contractID = queryContractIdByDOI(contractDOI); + // return executeContract(contractID, action, arg); + // } catch (Exception e) { + // ByteArrayOutputStream bo = new ByteArrayOutputStream(); + // e.printStackTrace(new PrintStream(bo)); + // return bo.toString(); + // } + // } + // + // public static String getAuthInfo() { + // try { + // DigitalObject contractDO; + // DoipClient doipClient = + // DoipClient.createByRepoUrlAndMsgFmt( + // DOIPMainServer.repoUrl, DoipMessageFormat.PACKET.getName()); + // DoMessage response = doipClient.retrieve(authInfoPersistDOI, null, null); + // if (response.parameters.response != DoResponse.Success) { + // response = DOAClient.getGlobalInstance().retrieve(authInfoPersistDOI, null, + // null); + // } + // contractDO = DigitalObject.parse(response.body); + // return new String(contractDO.elements.get(0).getData()); + // } catch (Exception e) { + // ByteArrayOutputStream bo = new ByteArrayOutputStream(); + // e.printStackTrace(new PrintStream(bo)); + // return "Failed: " + bo.toString(); + // } + // } + // + // public static String setAuthInfo(String authInfo) { + // try { + // + // DigitalObject contractDO = new DigitalObject(authInfoPersistDOI, DoType.Json); + // Element e = new Element("authInfo", "JsonString"); + // e.setData(authInfo.getBytes()); + // contractDO.addElements(e); + // + // DoipClient doipClient = + // DoipClient.createByRepoUrlAndMsgFmt( + // DOIPMainServer.repoUrl, DoipMessageFormat.PACKET.getName()); + // DoMessage response = doipClient.update(contractDO); + // if (response.parameters.response != DoResponse.Success) { + // DoHandleRecord dohr = + // DOAClient.getGlobalInstance().resolveDO(authInfoPersistDOI); + // if (dohr == null) { + // return "Failed: Can not resolve authInfoPersistDOI: " + + // authInfoPersistDOI; + // } + // ServiceHandleRecord repoHandleRecord = + // DOAClient.getGlobalInstance().resolveDOIPService(dohr.repository); + // doipClient = + // DoipClient.createByRepoUrlAndMsgFmt( + // repoHandleRecord.getListenerInfos().get(0).url, + // DoipMessageFormat.PACKET.getName()); + // response = doipClient.update(contractDO); + // if (response.parameters.response != DoResponse.Success) { + // return "Failed: Can not update authInfoPersistDOI: " + authInfoPersistDOI; + // } + // } + // return "Succeeded"; + // } catch (Exception e) { + // ByteArrayOutputStream bo = new ByteArrayOutputStream(); + // e.printStackTrace(new PrintStream(bo)); + // return "Failed: " + bo.toString(); + // } + // } + + public static String executeContractAsync( + String contractID, String action, String arg, final ScriptFunction cb) { + try { + + ContractRequest app = new ContractRequest(); + app.setContractID(contractID).setAction(action).setArg(arg); + app.doSignature(keyPair); + app.setRequestID((invokeID++) + "_" + random()); + app.setRequesterDOI(doi); + get.asyncGet( + "dd", + "executeContract", + JsonUtil.toJson(app), + new ResultCallback() { + @Override + public void onResult(String str) { + if (cb != null) { + DesktopEngine.applyWithGlobal( + cb, currentEngine.getNashornGlobal(), str, arg); + } + } + }); + return "success"; + } catch (Exception e) { + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + e.printStackTrace(new PrintStream(bo)); + return bo.toString(); + } + } + + /** + * publish an event with semantic AT_LEAST_ONCE + * + * @param topic the topic + * @param content the content + * @author Kaidong Wu + */ + public static void pubEvent(String topic, String content) { + pubEventConstraint(topic, content, null); + } + + /** + * publish an event with some semantic + * + * @param topic the topic + * @param content the content + * @param constraint the constraint, AT_LEAST_ONCE, AT_MOST_ONCE, and ONLY_ONCE + * @author Kaidong Wu + */ + public static void pubEventConstraint(String topic, String content, String constraint) { + String reqID = + String.format( + "%d_%d_%d_%s_pe", + keyPair.getPublicKeyStr().hashCode(), numOfCopies, invokeID, random()); + REvent msg = new REvent(topic, PUBLISH, content, reqID); + if (null != constraint) { + msg.setSemantics(REvent.REventSemantics.valueOf(constraint)); + } + msgList.add(msg); + } + + /** + * subscribe a topic + * + * @param topic event topic + * @param fun related handler function + * @author Kaidong Wu + */ + public static void subscribe(String topic, ScriptFunction fun) { + subscribe(topic, fun, false); + if (topic_handlers.containsKey(topic)) { + ContractProcess.instance.unSubscribe(topic_handlers.get(topic).getName()); + } + topic_handlers.put(topic, fun); + } + + private static void subscribe(String topic, ScriptFunction fun, boolean fromPreSub) { + String reqID = + String.format( + "%d_%d_%d_%s_se", + keyPair.getPublicKeyStr().hashCode(), numOfCopies, invokeID, random()); + + REvent msg = + new REvent( + topic, + SUBSCRIBE, + String.format( + "{\"subscriber\":\"%s\",\"handler\":\"%s\"}", + ContractProcess.instance.getContractName(), fun.getName()), + reqID); + if (fromPreSub) { + msg.setSemantics(REvent.REventSemantics.ONLY_ONCE); + } + msgList.add(msg); + + ContractProcess.instance.subscribe(fun.getName()); + } + + public static void unsubscribe(String topic) { + String reqID = + String.format( + "%d_%d_%d_%s_us", + keyPair.getPublicKeyStr().hashCode(), numOfCopies, invokeID, random()); + String content; + if (null == topic) { + content = "{\"subscriber\":\"" + ContractProcess.instance.getContractName() + "\"}"; + topic_handlers.forEach((k, c) -> { + topic_handlers.remove(k); + ContractProcess.instance.unSubscribe(c.getName()); + }); + } else { + String handler = topic_handlers.get(topic).getName(); + content = + String.format( + "{\"subscriber\":\"%s\",\"handler\":\"%s\"}", + ContractProcess.instance.getContractName(), handler); + topic_handlers.remove(topic); + ContractProcess.instance.unSubscribe(handler); + } + REvent msg = + new REvent( + topic, + UNSUBSCRIBE, + content, + reqID); + msgList.add(msg); + } + + /** + * pre-sub in ONLY_ONCE + * + * @param topic the topic + * @param content the content + * @author Kaidong Wu + */ + public static void preSub(String topic, String content) { + String newTopic = topic + "|" + content + "|" + ContractProcess.instance.getContractName(); + subscribe(newTopic, topic_handlers.get(topic), true); + String reqID = + String.format( + "%d_%d_%d_%s_pse", + keyPair.getPublicKeyStr().hashCode(), numOfCopies, (invokeID++), random()); + REvent msg = new REvent(topic, REvent.REventType.PRESUB, newTopic, reqID); + msg.setSemantics(REvent.REventSemantics.ONLY_ONCE); + msgList.add(msg); + } + + /** + * @return a random value with string format + * @author Kaidong Wu + */ + public static String random() { + String seed = String.valueOf(null == random ? System.currentTimeMillis() : random.nextInt()); + return HashUtil.sha3(seed); + } + + public static String getContractInfo(String topic) { + return null; + // TODO + } + + public static String sendEmail(String json) { + try { + final JsonObject jo = JsonParser.parseString(json).getAsJsonObject(); + Properties props = new Properties(); + props.setProperty("mail.debug", "false"); + props.setProperty("mail.smtp.auth", "true"); + props.setProperty("mail.smtp.host", jo.get("host").getAsString()); + props.setProperty("mail.smtp.port", jo.get("port").getAsString()); + props.setProperty("mail.transport.protocol", "smtp"); + props.put("mail.smtp.auth", "true"); + Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider()); + final String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory"; + props.setProperty("mail.smtp.socketFactory.class", SSL_FACTORY); + props.setProperty("mail.smtp.socketFactory.fallback", "false"); + props.setProperty("mail.smtp.socketFactory.port", jo.get("port").getAsString()); + Session session = + Session.getDefaultInstance( + props, + new Authenticator() { + public PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication( + jo.get("from").getAsString(), + jo.get("pwd").getAsString()); // 发件人邮件用户名、密码 + } + }); + // 创建邮件对象 + + Message msg = new MimeMessage(session); + msg.setSubject(jo.get("subject").getAsString()); + msg.setText(jo.get("content").getAsString()); + msg.setFrom(new InternetAddress(jo.get("from").getAsString())); + msg.addRecipient( + Message.RecipientType.TO, new InternetAddress(jo.get("to").getAsString())); + Transport.send(msg); + } catch (Exception e) { + e.printStackTrace(); + return "failed"; + } + return "success"; + } + + public static ScriptObject getCaller(int i) { + JO ret = new JO(PropertyMap.newMap()); + StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace(); + if (stacktrace.length > i + 2) { + ret.put("name", stacktrace[i + 2].getMethodName(), false); + ret.put("file", stacktrace[i + 2].getFileName(), false); + } + return ret; + } + + public static class Result { + public int responseCode; + public String response; + } + + static class PostRequest { + String url; + String data; + } +} diff --git a/src/main/java/org/bdware/sc/boundry/Resources.java b/src/main/java/org/bdware/sc/boundry/Resources.java new file mode 100644 index 0000000..dfaeaa4 --- /dev/null +++ b/src/main/java/org/bdware/sc/boundry/Resources.java @@ -0,0 +1,93 @@ +package org.bdware.sc.boundry; + +import org.bdware.sc.engine.YJSClassLoader; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import java.util.zip.ZipInputStream; +public class Resources { + private final ZipFile zf; + YJSClassLoader loader; + + public Resources(ZipFile zf, YJSClassLoader loader) { + this.zf = zf; + this.loader = loader; + } + + public InputStream loadAsInputStream(String path) { + try { + ZipEntry entry = zf.getEntry(path); + if (entry == null) + return null; + return zf.getInputStream(entry); + } catch (Exception ignored) { + + } + return null; + } + + public Scanner loadAsScanner(String path) { + try { + ZipEntry entry = zf.getEntry(path); + if (entry == null) + return null; + return new Scanner(zf.getInputStream(entry)); + } catch (Exception ignored) { + + } + return null; + } + + public String loadAsString(String path) { + try { + InputStream sc = loadAsInputStream(path); + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + byte[] buff = new byte[1024]; + for (int k = 0; (k = sc.read(buff)) > 0; ) { + bo.write(buff, 0, k); + } + return new String(bo.toByteArray()); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return null; + } + + public List testloadAsScanner(String path) { + BufferedReader reader; + List fileList = new ArrayList<>(); + try { + ZipEntry entry = zf.getEntry(path); + if (entry == null) + return null; + reader = new BufferedReader(new InputStreamReader(zf.getInputStream(entry), StandardCharsets.UTF_8)); + String line = null; + while ((line = reader.readLine()) != null) { + fileList.add(line); + // System.out.println(line); + } + return fileList; + // return new ArrayList<>(); + } catch (Exception ignored) { + + } + return null; + } + + public String unzipToDir(String path) { + ZipEntry entry = zf.getEntry(path); + try { + return loader.unzipLibrary(zf.getInputStream(entry), entry.getName().replaceAll(".*/", "")); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/src/main/java/org/bdware/sc/boundry/TimeIndex.java b/src/main/java/org/bdware/sc/boundry/TimeIndex.java new file mode 100644 index 0000000..2f01c66 --- /dev/null +++ b/src/main/java/org/bdware/sc/boundry/TimeIndex.java @@ -0,0 +1,306 @@ +package org.bdware.sc.boundry; + +import org.bdware.sc.index.LenVarTimeSerialIndex2; +import org.bdware.sc.util.HashUtil; +import wrp.jdk.nashorn.api.scripting.ScriptObjectMirror; +import wrp.jdk.nashorn.internal.objects.Global; +import wrp.jdk.nashorn.internal.objects.NativeArray; +import wrp.jdk.nashorn.internal.runtime.PropertyMap; +import wrp.jdk.nashorn.internal.runtime.ScriptObject; +import wrp.jdk.nashorn.internal.scripts.JO; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.PrintStream; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class TimeIndex { + static Map fileMap = new HashMap<>(); + + public static TimeIndex createIndex() { + return new TimeIndex(); + } + + private static String getString(ScriptObjectMirror obj, String member) { + Object mem = obj.getMember(member); + if (mem != null && !(mem instanceof String)) { + return mem.toString(); + } + return (String) mem; + } + + private static Integer getInteger(ScriptObjectMirror obj) { + Object mem = obj.getMember("count"); + if (mem != null && !(mem instanceof Integer)) { + return Integer.valueOf(mem.toString()); + } + return (Integer) mem; + } + + private static Long getLong(ScriptObjectMirror obj, String member) { + Object mem = obj.getMember(member); + if (mem != null && !(mem instanceof Long)) { + return Long.valueOf(mem.toString()); + } + return (Long) mem; + } + + public ScriptObject createFile(ScriptObjectMirror args) { + JO ret = new JO(PropertyMap.newMap()); + if (!args.hasMember("file")) { + ret.put("result", "Missing Argumemt", false); + ret.put("status", "Error", false); + return ret; + } + if (!args.hasMember("dataLength")) { + ret.put("result", "Missing Argumemt", false); + ret.put("status", "Error", false); + return ret; + } + try { + Object file = args.get("file"); + if (!(file instanceof String)) { + ret.put("result", "Illegal Type, file is not String", false); + ret.put("status", "Error", false); + return ret; + } + String fileName = "./" + file; + File f = new File(fileName + ".datasize"); + FileOutputStream fout = new FileOutputStream(f, false); + Object dataLength = args.get("dataLength"); + int dataLengthInt = Integer.parseInt(dataLength.toString()); + for (int i = 0; i < dataLengthInt; i++) + fout.write(1); + fout.close(); + LenVarTimeSerialIndex2 index = getIndexFile(fileName); + ret.put("dataLength", dataLength, false); + ret.put("datasize", f.length(), false); + + ret.put("status", "Success", false); + return ret; + } catch (Exception e) { + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + e.printStackTrace(new PrintStream(bo)); + ret.put("status", "Success", false); + ret.put("result", bo.toString(), false); + return ret; + } + } + + public ScriptObject index(ScriptObjectMirror args) { + JO ret = new JO(PropertyMap.newMap()); + if (!args.hasMember("file")) { + ret.put("result", "Missing Argumemt: file", false); + ret.put("status", "Error", false); + return ret; + } + if (!args.hasMember("content")) { + ret.put("result", "Missing Argumemt: content", false); + ret.put("status", "Error", false); + return ret; + } + + try { + LenVarTimeSerialIndex2 index = getIndexFile(getString(args, "file")); + String content = getString(args, "content"); + long result = index.index(HashUtil.str16ToBytes(content)); + ret.put("date", result, false); + ret.put("status", "Success", false); + return ret; + } catch (Exception e) { + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + e.printStackTrace(new PrintStream(bo)); + ret.put("exception", bo.toString(), false); + ret.put("status", "Error", false); + return ret; + } + } + + public ScriptObject dataSize(ScriptObjectMirror args) { + JO ret = new JO(PropertyMap.newMap()); + if (!args.hasMember("file")) { + ret.put("result", "Missing Argumemt: file", false); + ret.put("status", "Error", false); + return ret; + } + try { + LenVarTimeSerialIndex2 index = getIndexFile(getString(args, "file")); + ret.put("fileSize", index.fileSize, false); + ret.put("dataSize", index.dataSize, false); + ret.put("status", "Success", false); + return ret; + + } catch (Exception e) { + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + e.printStackTrace(new PrintStream(bo)); + ret.put("exception", bo.toString(), false); + ret.put("status", "Error", false); + return ret; + } + } + + public ScriptObject requestByTime(ScriptObjectMirror args) { + JO ret = new JO(PropertyMap.newMap()); + if (!args.hasMember("file")) { + ret.put("result", "Missing Argumemt: file", false); + ret.put("status", "Error", false); + return ret; + } + if (!args.hasMember("startTime")) { + ret.put("result", "Missing Argumemt: startTime", false); + ret.put("status", "Error", false); + return ret; + } + if (!args.hasMember("endTime")) { + ret.put("result", "Missing Argumemt: endTime", false); + ret.put("status", "Error", false); + return ret; + } + + try { + LenVarTimeSerialIndex2 index = getIndexFile(getString(args, "file")); + long startTime = getLong(args, "startTime"); + long endTime = getLong(args, "endTime"); + List result = index.requestByTime(startTime, endTime); + ret.put("status", "Success", false); + NativeArray array = Global.allocate(new int[0]); + ret.put("list", array, false); + for (byte[] bytes : result) { + JO data = new JO(PropertyMap.newMap()); + Data d = new Data(bytes); + data.put("data", d.data, false); + data.put("date", d.date, false); + NativeArray.push(array, data); + } + return ret; + } catch (Exception e) { + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + e.printStackTrace(new PrintStream(bo)); + ret.put("status", "Error", false); + ret.put("data", bo.toString(), false); + return ret; + } + } + + public ScriptObject request(ScriptObjectMirror args) { + JO ret = new JO(PropertyMap.newMap()); + if (!args.hasMember("file")) { + ret.put("result", "Missing Argumemt: file", false); + ret.put("status", "Error", false); + return ret; + } + if (!args.hasMember("offset")) { + ret.put("result", "Missing Argumemt: offset", false); + ret.put("status", "Error", false); + return ret; + } + if (!args.hasMember("count")) { + ret.put("result", "Missing Argumemt: count", false); + ret.put("status", "Error", false); + return ret; + } + + try { + LenVarTimeSerialIndex2 index = getIndexFile(getString(args, "file")); + long offset = getLong(args, "offset"); + int count = getInteger(args); + List result = index.request(offset, count); + ret.put("status", "Success", false); + NativeArray array = Global.allocate(new int[0]); + ret.put("list", array, false); + for (byte[] bytes : result) { + JO data = new JO(PropertyMap.newMap()); + Data d = new Data(bytes); + data.put("data", d.data, false); + data.put("date", d.date, false); + NativeArray.push(array, data); + } + return ret; + } catch (Exception e) { + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + e.printStackTrace(new PrintStream(bo)); + ret.put("status", "Error", false); + ret.put("data", bo.toString(), false); + return ret; + } + } + + public ScriptObject getSize(ScriptObjectMirror args) { + JO ret = new JO(PropertyMap.newMap()); + if (!args.hasMember("file")) { + ret.put("result", "Missing Argumemt: file", false); + ret.put("status", "Error", false); + return ret; + } + try { + LenVarTimeSerialIndex2 index = getIndexFile(getString(args, "file")); + int size = (int) index.size(); + ret.put("status", "Success", false); + ret.put("size", size, false); + return ret; + } catch (Exception e) { + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + e.printStackTrace(new PrintStream(bo)); + ret.put("status", "Error", false); + ret.put("data", bo.toString(), false); + return ret; + } + } + + private LenVarTimeSerialIndex2 getIndexFile(String str) { + LenVarTimeSerialIndex2 indexFile = fileMap.get(str); + if (indexFile == null) { + indexFile = new LenVarTimeSerialIndex2(str); + fileMap.put(str, indexFile); + } + return indexFile; + } + + public ScriptObject manuallyIndex(ScriptObjectMirror args) { + JO ret = new JO(PropertyMap.newMap()); + if (!args.hasMember("date")) { + ret.put("result", "Missing Argumemt: date", false); + ret.put("status", "Error", false); + return ret; + } + if (!args.hasMember("content")) { + ret.put("result", "Missing Argumemt: content", false); + ret.put("status", "Error", false); + return ret; + } + if (!args.hasMember("file")) { + ret.put("result", "Missing Argumemt: file", false); + ret.put("status", "Error", false); + return ret; + } + + try { + LenVarTimeSerialIndex2 index = getIndexFile(getString(args, "file")); + long date = getLong(args, "date"); + String content = getString(args, "content"); + index.manullyIndex(date, HashUtil.str16ToBytes(content)); + ret.put("status", "Success", false); + return ret; + } catch (Exception e) { + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + e.printStackTrace(new PrintStream(bo)); + ret.put("status", "Error", false); + ret.put("data", bo.toString(), false); + return ret; + } + } + + static class Data { + long date; + String data; + + public Data(byte[] bytes) { + date = HashUtil.bytes2Long(bytes); + data = HashUtil.byteArray2Str(bytes, 8); + } + } + +} diff --git a/src/main/java/org/bdware/sc/boundry/utils/AESUtil.java b/src/main/java/org/bdware/sc/boundry/utils/AESUtil.java new file mode 100644 index 0000000..c1e8d05 --- /dev/null +++ b/src/main/java/org/bdware/sc/boundry/utils/AESUtil.java @@ -0,0 +1,50 @@ +package org.bdware.sc.boundry.utils; + +import org.bdware.sc.compiler.PermissionStub; +import org.bdware.sc.node.Permission; +import wrp.jdk.nashorn.internal.runtime.PropertyMap; +import wrp.jdk.nashorn.internal.runtime.ScriptObject; +import wrp.jdk.nashorn.internal.scripts.JO; + +import javax.crypto.*; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import javax.xml.bind.DatatypeConverter; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; + +@PermissionStub(permission = Permission.AES) +public class AESUtil { + public static ScriptObject encrypt(String key, String plaintext) throws NoSuchPaddingException, NoSuchAlgorithmException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException, InvalidKeyException { + JO ret = new JO(PropertyMap.newMap()); + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + String iv = generateKey(128); + IvParameterSpec ivSpec = new IvParameterSpec(DatatypeConverter.parseHexBinary(iv)); + byte[] byteContent = plaintext.getBytes(); + SecretKeySpec secretKeySpecSpec = new SecretKeySpec(DatatypeConverter.parseHexBinary(key), "AES"); + cipher.init(Cipher.ENCRYPT_MODE, secretKeySpecSpec, ivSpec); + byte[] result = cipher.doFinal(byteContent); + ret.put("iv", iv, false); + ret.put("cipherText", DatatypeConverter.printHexBinary(result).toLowerCase(), false); + return ret; + } + + public static String decrypt(String key, String ciphertext, String iv) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { +// JO ret = new JO(PropertyMap.newMap()); + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + IvParameterSpec ivSpec = new IvParameterSpec(DatatypeConverter.parseHexBinary(iv)); + byte[] byteContent = DatatypeConverter.parseHexBinary(ciphertext); + SecretKeySpec secretKeySpecSpec = new SecretKeySpec(DatatypeConverter.parseHexBinary(key), "AES"); + cipher.init(Cipher.DECRYPT_MODE, secretKeySpecSpec, ivSpec); + byte[] result = cipher.doFinal(byteContent); + return new String(result); + } + + public static String generateKey(int bit) throws NoSuchAlgorithmException { + KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); + keyGenerator.init(bit); + SecretKey secretKey = keyGenerator.generateKey(); + return DatatypeConverter.printHexBinary(secretKey.getEncoded()).toLowerCase(); + } +} diff --git a/src/main/java/org/bdware/sc/boundry/utils/AsyncUtil.java b/src/main/java/org/bdware/sc/boundry/utils/AsyncUtil.java new file mode 100644 index 0000000..f2594d2 --- /dev/null +++ b/src/main/java/org/bdware/sc/boundry/utils/AsyncUtil.java @@ -0,0 +1,117 @@ +package org.bdware.sc.boundry.utils; + +import org.bdware.sc.bean.ContractRequest; +import org.bdware.sc.boundry.JavaScriptEntry; +import org.bdware.sc.compiler.PermissionStub; +import org.bdware.sc.conn.ResultCallback; +import org.bdware.sc.conn.ServiceServer; +import org.bdware.sc.engine.DesktopEngine; +import org.bdware.sc.node.Permission; +import org.bdware.sc.util.JsonUtil; +import wrp.jdk.nashorn.internal.runtime.ScriptFunction; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.util.Timer; +import java.util.TimerTask; + +@PermissionStub(permission = Permission.Async) +public class AsyncUtil { + private static final Timer TIMER = new Timer(); +// public static ExecutorService executorService = Executors.newFixedThreadPool(10); + + public static String sleep(long sleep) { + try { + Thread.sleep(sleep); + } catch (InterruptedException e) { + e.printStackTrace(); + } + return "success"; + } + + public static String postFunction(final ScriptFunction callback, Object wrapper) { + ServiceServer.executor.execute( + () -> JavaScriptEntry.executeFunction(callback, wrapper)); + return "success"; + } + + public static TimerTask setTimeOut( + final ScriptFunction callback, long delay, final Object arg) { + TimerTask task = + new TimerTask() { + @Override + public void run() { + JavaScriptEntry.executeFunction(callback, arg); + } + }; + TIMER.schedule(task, delay); + return task; + } + + public static TimerTask setInterval( + final ScriptFunction callback, long delay, long interval, final Object arg) { + TimerTask task = + new TimerTask() { + @Override + public void run() { + JavaScriptEntry.executeFunction(callback, arg); + } + }; + TIMER.schedule(task, delay, interval); + return task; + } + + public static void executeContractAsyncWithoutSig( + String contractID, String action, String arg, final ScriptFunction cb) { + try { + ContractRequest app = new ContractRequest(); + app.setContractID(contractID).setAction(action).setArg(arg); + app.setRequestID((JavaScriptEntry.invokeID++) + "_" + JavaScriptEntry.random.nextInt()); + JavaScriptEntry.get.asyncGet( + "dd", + "executeContract", + JsonUtil.toJson(app), + new ResultCallback() { + @Override + public void onResult(String str) { + if (null != cb) { + DesktopEngine.applyWithGlobal( + cb, JavaScriptEntry.currentEngine.getNashornGlobal(), str); + } + } + }); + } catch (Exception e) { + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + e.printStackTrace(new PrintStream(bo)); + } + } + public static String executeContractAsync( + String contractID, String action, String arg, final ScriptFunction cb) { + try { + + ContractRequest app = new ContractRequest(); + app.setContractID(contractID).setAction(action).setArg(arg); + app.doSignature(JavaScriptEntry.getKeyPair()); + app.setRequestID((JavaScriptEntry.invokeID++) + "_" + JavaScriptEntry.random()); + app.setRequesterDOI(JavaScriptEntry.doi); + JavaScriptEntry.get.asyncGet( + "dd", + "executeContract", + JsonUtil.toJson(app), + new ResultCallback() { + @Override + public void onResult(String str) { + if (cb != null) { + DesktopEngine.applyWithGlobal( + cb, JavaScriptEntry.currentEngine.getNashornGlobal(), str, arg); + } + } + }); + return "success"; + } catch (Exception e) { + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + e.printStackTrace(new PrintStream(bo)); + return bo.toString(); + } + } +} diff --git a/src/main/java/org/bdware/sc/boundry/utils/BDWareTimeSeriesDBUtil.java b/src/main/java/org/bdware/sc/boundry/utils/BDWareTimeSeriesDBUtil.java new file mode 100644 index 0000000..838ce32 --- /dev/null +++ b/src/main/java/org/bdware/sc/boundry/utils/BDWareTimeSeriesDBUtil.java @@ -0,0 +1,24 @@ +package org.bdware.sc.boundry.utils; + +import org.bdware.sc.ContractProcess; +import org.bdware.sc.compiler.PermissionStub; +import org.bdware.sc.db.TimeDBUtil; +import org.bdware.sc.db.TimeRocksDBUtil; +import org.bdware.sc.node.Permission; + +import java.io.File; + +@PermissionStub(permission = Permission.BDWareTimeSeriesDB) +public class BDWareTimeSeriesDBUtil { + public static TimeRocksDBUtil getConnection() { + File parent = new File("./ContractDB/" + ContractProcess.instance.getContractName()); + parent = new File(parent, "BDWareTimeSeriesDB"); + return new TimeRocksDBUtil(parent.getAbsolutePath()); + } + + public static TimeRocksDBUtil getConnection(String dbName) { + File parent = new File("./ContractDB/" + ContractProcess.instance.getContractName()); + parent = new File(parent, dbName); + return new TimeRocksDBUtil(parent.getAbsolutePath()); + } +} diff --git a/src/main/java/org/bdware/sc/boundry/utils/CMUtil.java b/src/main/java/org/bdware/sc/boundry/utils/CMUtil.java new file mode 100644 index 0000000..1ea1bb9 --- /dev/null +++ b/src/main/java/org/bdware/sc/boundry/utils/CMUtil.java @@ -0,0 +1,12 @@ +package org.bdware.sc.boundry.utils; + +import org.bdware.sc.boundry.JavaScriptEntry; +import org.bdware.sc.compiler.PermissionStub; +import org.bdware.sc.node.Permission; + +@PermissionStub(permission = Permission.CM) +public class CMUtil { + public static String getTimesOfExecution(String contractName) { + return JavaScriptEntry.get.syncGet("", "getTimesOfExecution", contractName); + } +} diff --git a/src/main/java/org/bdware/sc/boundry/utils/DOIPUtil.java b/src/main/java/org/bdware/sc/boundry/utils/DOIPUtil.java new file mode 100644 index 0000000..6a9c080 --- /dev/null +++ b/src/main/java/org/bdware/sc/boundry/utils/DOIPUtil.java @@ -0,0 +1,192 @@ +package org.bdware.sc.boundry.utils; + +import com.google.gson.JsonObject; +import org.bdware.doip.application.client.ContractDOAClient; +import org.bdware.doip.core.doipMessage.DoipMessage; +import org.bdware.doip.core.exception.DoDecodeException; +import org.bdware.doip.core.exception.IrpClientException; +import org.bdware.doip.core.model.digitalObject.DigitalObject; +import org.bdware.doip.core.model.digitalObject.Element; +import org.bdware.doip.core.utils.DoipGson; +import org.bdware.sc.compiler.PermissionStub; +import org.bdware.sc.node.Permission; +import org.bdware.sc.util.JsonUtil; + +import java.io.IOException; + +@PermissionStub(permission = Permission.DOIP) +public class DOIPUtil { + // private static final Logger LOGGER = LogManager.getLogger(DOIPUtil.class); + public static ContractDOAClient doaClient = null; + + static { + initClient(); + } + + public static String test(String doi) { + return "create DOClient And hello " + doi + " World"; + } + + public static String hello(String repoID) { + initClient(); + DigitalObject respDO; + DoipMessage msg; + try { + msg = doaClient.hello(repoID); + } catch (IrpClientException ie) { + ie.printStackTrace(); + return "send doip message error: " + ie.getMessage(); + } + try { + respDO = msg.body.getDataAsDigitalObject(); + return respDO.toString(); + } catch (DoDecodeException | IOException e) { + e.printStackTrace(); + return new String(msg.body.getEncodedData()); + } + } + + public static String retrieve(String doi, String args) { + initClient(); + DigitalObject respDO; + DoipMessage msg; + JsonObject argObj = JsonUtil.fromJson(args, JsonObject.class); + String elementID = argObj.get("elementID") == null ? null : argObj.get("elementID").getAsString(); + boolean includeElementData = + argObj.get("includeElementData") != null && + argObj.get("includeElementData").getAsString().equals("true"); + try { + msg = doaClient.retrieve(doi, elementID, includeElementData); + } catch (IrpClientException ie) { + ie.printStackTrace(); + return "send doip message error: " + ie.getMessage(); + } + try { + respDO = msg.body.getDataAsDigitalObject(); + return respDO.toString(); + } catch (DoDecodeException | IOException e) { + e.printStackTrace(); + return new String(msg.body.getEncodedData()); + } + } + + public static String call(String doi, String action, String args) { + initClient(); + DoipMessage msg; + try { + msg = doaClient.call(doi, action, args.getBytes()); + return msg.body.getDataAsJsonString(); + } catch (IrpClientException e) { + e.printStackTrace(); + return e.getMessage(); + } + } + + public static String create(String repoID, String doString) { + initClient(); + DigitalObject respDO; + DoipMessage msg; + DigitalObject dObj = DoipGson.getDoipGson().fromJson(doString, DigitalObject.class); + for (Element e : dObj.elements) { + if (null != e.dataString) { + e.setData(e.dataString.getBytes()); + } + e.dataString = null; + } + try { + msg = doaClient.create(repoID, dObj); + } catch (IrpClientException ie) { + ie.printStackTrace(); + return "send doip message error: " + ie.getMessage(); + } + try { + respDO = msg.body.getDataAsDigitalObject(); + return respDO.toString(); + } catch (DoDecodeException | IOException e) { + e.printStackTrace(); + return new String(msg.body.getEncodedData()); + } + } + + public static String delete(String doID, String repoID) { + initClient(); + DigitalObject respDO; + DoipMessage msg; + try { + msg = doaClient.delete(doID, repoID); + } catch (IrpClientException ie) { + ie.printStackTrace(); + return "send doip message error: " + ie.getMessage(); + } + try { + respDO = msg.body.getDataAsDigitalObject(); + return respDO.toString(); + } catch (DoDecodeException | IOException e) { + e.printStackTrace(); + return new String(msg.body.getEncodedData()); + } + } + + public static String listOperation(String doID) { + initClient(); + DigitalObject respDO; + DoipMessage msg; + try { + msg = doaClient.listOperations(doID); + } catch (IrpClientException ie) { + ie.printStackTrace(); + return "send doip message error: " + ie.getMessage(); + } + try { + respDO = msg.body.getDataAsDigitalObject(); + return respDO.toString(); + } catch (DoDecodeException | IOException e) { + e.printStackTrace(); + return new String(msg.body.getEncodedData()); + } + } + + +// public static String create(String repoID, ScriptObjectMirror doStr){ +// logger.debug(JsonUtil.toJson(doStr)); +// SM2KeyPair kp = JavaScriptEntry.getKeyPair(); +// HandleServiceUtils.CustomizeHandleService(kp,JavaScriptEntry.doi,HandleServiceUtils.LHS_Address); +// DOAClient client = DOAClient.getGlobalInstance(); +// logger.debug(JsonUtil.toJson(doStr)); +// DigitalObject digitalObject = new DigitalObject( +// doStr.get("doID").toString(), +// DoType.DoString +// ); +// digitalObject.addAttribute("content", doStr.get("doBody").toString()); +// try { +// return new String(client.create(repoID,digitalObject).parameters.toByteArray()); +// }catch (Exception e){ +// e.printStackTrace(); +// return e.getMessage(); +// } +// } + +// public static String update(ScriptObjectMirror doStr){ +// SM2KeyPair kp = JavaScriptEntry.getKeyPair(); +// HandleServiceUtils.CustomizeHandleService(kp,JavaScriptEntry.doi,HandleServiceUtils.LHS_Address); +// DOAClient client = DOAClient.getGlobalInstance(); +// DigitalObject digitalObject = new DigitalObject( +// doStr.get("doID").toString(), +// DoType.DoString +// ); +// digitalObject.addAttribute("content", doStr.get("doBody").toString()); +// try { +// return new String(client.update(digitalObject).parameters.toByteArray()); +// }catch (Exception e){ +// e.printStackTrace(); +// return e.getMessage(); +// } +// } + + + public static void initClient() { + if (null == doaClient) { + doaClient = ContractDOAClient.getContractDOAClientForTest(); + } + } +} diff --git a/src/main/java/org/bdware/sc/boundry/utils/DOMUtil.java b/src/main/java/org/bdware/sc/boundry/utils/DOMUtil.java new file mode 100644 index 0000000..9521f82 --- /dev/null +++ b/src/main/java/org/bdware/sc/boundry/utils/DOMUtil.java @@ -0,0 +1,10 @@ +package org.bdware.sc.boundry.utils; + +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; + +public class DOMUtil { + public static Document parse(String html) { + return Jsoup.parse(html); + } +} diff --git a/src/main/java/org/bdware/sc/boundry/utils/FileUtil.java b/src/main/java/org/bdware/sc/boundry/utils/FileUtil.java new file mode 100644 index 0000000..c9dc12a --- /dev/null +++ b/src/main/java/org/bdware/sc/boundry/utils/FileUtil.java @@ -0,0 +1,42 @@ +package org.bdware.sc.boundry.utils; + +import org.bdware.sc.ContractProcess; +import org.bdware.sc.compiler.PermissionStub; +import org.bdware.sc.node.Permission; + +import javax.script.ScriptException; +import java.io.File; +import java.io.PrintStream; + +@PermissionStub(permission = Permission.File) +public class FileUtil extends org.bdware.sc.util.FileUtil { + private static String getInternalFile(String path) { + File parent = new File("./ContractDB/" + ContractProcess.instance.getContractName()); + if (path.contains("..")) { + return null; + } + File f = new File(parent, path); + return f.getAbsolutePath(); + } + + public static String getContent(String path) { + return getFileContent(getInternalFile(path)); + } + + public static void copyTo(String src, String dst) { + try { + String from = getInternalFile(src); + String to = getInternalFile(dst); + if (null == from || null == to) { + throw new ScriptException("incorrect file name of from /to"); + } + copyFile(from, to); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static PrintStream openAsPrinter(String path, boolean isAppend) { + return openFileAsPrinter(getInternalFile(path), isAppend); + } +} diff --git a/src/main/java/org/bdware/sc/boundry/utils/FileUtilStub.java b/src/main/java/org/bdware/sc/boundry/utils/FileUtilStub.java new file mode 100644 index 0000000..0238cbf --- /dev/null +++ b/src/main/java/org/bdware/sc/boundry/utils/FileUtilStub.java @@ -0,0 +1,11 @@ +package org.bdware.sc.boundry.utils; + +import javax.script.ScriptException; + +public class FileUtilStub { + + public static String getDir(String fullFileName) throws ScriptException { + throw new ScriptException("Do not have File Permission"); + } + +} diff --git a/src/main/java/org/bdware/sc/boundry/utils/HttpUtil.java b/src/main/java/org/bdware/sc/boundry/utils/HttpUtil.java new file mode 100644 index 0000000..ce3736a --- /dev/null +++ b/src/main/java/org/bdware/sc/boundry/utils/HttpUtil.java @@ -0,0 +1,307 @@ +package org.bdware.sc.boundry.utils; + +import okhttp3.*; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.ssl.SSLContexts; +import org.bdware.sc.compiler.PermissionStub; +import org.bdware.sc.engine.DesktopEngine; +import org.bdware.sc.http.ApiGate; +import org.bdware.sc.node.Permission; +import org.bdware.sc.util.JsonUtil; +import wrp.jdk.nashorn.api.scripting.NashornScriptEngine; +import wrp.jdk.nashorn.api.scripting.ScriptObjectMirror; +import wrp.jdk.nashorn.internal.runtime.PropertyMap; +import wrp.jdk.nashorn.internal.runtime.ScriptFunction; +import wrp.jdk.nashorn.internal.runtime.ScriptObject; +import wrp.jdk.nashorn.internal.scripts.JO; + +import javax.net.ssl.SSLContext; +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.Scanner; +import java.util.concurrent.TimeUnit; + +@PermissionStub(permission = Permission.Http) +public class HttpUtil { + public static NashornScriptEngine currentEngine; + + public static ScriptObject request(ScriptObjectMirror str) { + JO ret = new JO(PropertyMap.newMap()); + try { + URL url = new URL((String) str.get("url")); + String method = (String) str.get("method"); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setDoOutput(true); + connection.setDoInput(true); + connection.setUseCaches(false); + connection.setInstanceFollowRedirects(true); + connection.setRequestMethod(method.toUpperCase()); + Object headers = str.get("headers"); + if (headers != null && headers instanceof ScriptObjectMirror) { + ScriptObjectMirror som = (ScriptObjectMirror) headers; + for (String key : som.getOwnKeys(true)) { + Object val = som.get(key); + if (val instanceof String) connection.setRequestProperty(key, (String) val); + } + } else { + connection.setRequestProperty("Accept", "application/json"); + connection.setRequestProperty("Content-Type", "application/json"); + } + connection.connect(); + OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream(), "UTF-8"); + if (str.get("data") != null) + out.append((String) str.get("data")); + out.flush(); + out.close(); + ret.put("responseCode", connection.getResponseCode(), false); + InputStream input = connection.getInputStream(); + Scanner sc = new Scanner(input); + StringBuilder sb = new StringBuilder(); + for (; sc.hasNextLine(); ) { + sb.append(sc.nextLine()).append("\n"); + } + sc.close(); + ret.put("response", sb.toString(), false); + } catch (Throwable e) { + ret.put("responseCode", 505, false); + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + e.printStackTrace(new PrintStream(bo)); + ret.put("response", bo.toString(), false); + } + return ret; + } + public static String encodeURI(String str){ + return URLEncoder.encode(str); + } + public static String decodeURI(String str){ + return URLDecoder.decode(str); + } + + public static ScriptObject get(String str) { + JO ret = new JO(PropertyMap.newMap()); + try { + URL url = new URL(str); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + ret.put("responseCode", connection.getResponseCode(), false); + InputStream input = connection.getInputStream(); + Scanner sc = new Scanner(input); + StringBuilder sb = new StringBuilder(); + while (sc.hasNextLine()) { + sb.append(sc.nextLine()).append("\n"); + } + sc.close(); + ret.put("response", sb.toString(), false); + } catch (Throwable e) { + ret.put("resposeCode", 505, false); + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + e.printStackTrace(new PrintStream(bo)); + ret.put("response", bo.toString(), false); + } + return ret; + } + + public static ScriptObject post(ScriptObjectMirror str) { + JO ret = new JO(PropertyMap.newMap()); + try { + URL url = new URL((String) str.get("url")); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setDoOutput(true); + connection.setDoInput(true); + connection.setUseCaches(false); + connection.setInstanceFollowRedirects(true); + connection.setRequestMethod("POST"); + Object headers = str.get("headers"); + if (headers instanceof ScriptObjectMirror) { + ScriptObjectMirror som = (ScriptObjectMirror) headers; + for (String key : som.getOwnKeys(true)) { + Object val = som.get(key); + if (val instanceof String) { + connection.setRequestProperty(key, (String) val); + } + } + } else { + connection.setRequestProperty("Accept", "application/json"); + connection.setRequestProperty("Content-Type", "application/json"); + } + connection.connect(); + OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream(), StandardCharsets.UTF_8); + out.append((String) str.get("data")); + out.flush(); + out.close(); + ret.put("responseCode", connection.getResponseCode(), false); + InputStream input = connection.getInputStream(); + Scanner sc = new Scanner(input); + StringBuilder sb = new StringBuilder(); + while (sc.hasNextLine()) { + sb.append(sc.nextLine()).append("\n"); + } + sc.close(); + ret.put("response", sb.toString(), false); + } catch (Throwable e) { + ret.put("responseCode", 505, false); + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + e.printStackTrace(new PrintStream(bo)); + ret.put("response", bo.toString(), false); + } + return ret; + } + + private static CloseableHttpClient getHttpClient(String url) { + try { + SSLContext sslcontext = + SSLContexts.custom() + .loadTrustMaterial( + null, + (arg0, arg1) -> true) + .build(); + + SSLConnectionSocketFactory sslSf = + new SSLConnectionSocketFactory( + sslcontext, null, null, new NoopHostnameVerifier()); + int tle = 10; + if (url.contains("data.tj.gov.cn")) { + tle = 3; + } + return HttpClients.custom() + .setSSLSocketFactory(sslSf) + .setKeepAliveStrategy((arg0, arg1) -> 0) + .setConnectionTimeToLive(tle, TimeUnit.SECONDS) + .build(); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + // public static String httpPost(String str) { + // System.out.println("JavaSScriptEntry httpPost:" + str); + // PostRequest req = new PostRequest(); + // req = JsonUtil.fromJson(str, PostRequest.class); + // // System.out.println("url========>" + req.url); + // // System.out.println("data=======>" + req.data); + // + // Result r = new Result(); + // try { + // URL url = new URL(req.url);// + // HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + // connection.setDoOutput(true); + // connection.setDoInput(true); + // connection.setUseCaches(false); + // connection.setInstanceFollowRedirects(true); + // connection.setRequestMethod("POST"); + // connection.setRequestProperty("Accept", "application/json"); + // connection.setRequestProperty("Content-Type", "application/json"); + // connection.connect(); + // OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream(), "UTF-8"); // + // utf-8缂栫爜 + // out.append(req.data); + // out.flush(); + // out.close(); + // + // r.resposeCode = connection.getResponseCode(); + // InputStream input = connection.getInputStream(); + // + // Scanner sc = new Scanner(input); + // StringBuilder sb = new StringBuilder(); + // for (; sc.hasNextLine();) { + // sb.append(sc.nextLine()).append("\n"); + // } + // sc.close(); + // r.response = sb.toString(); + // return JsonUtil.toJson(r); + // } catch (Throwable e) { + // r.resposeCode = 505; + // // ByteArrayOutputStream bo = new ByteArrayOutputStream(); + // // e.printStackTrace(new PrintStream(bo)); + // r.response = e.getMessage(); + // return JsonUtil.toJson(r); + // } + // } + + public static String postTask(String args, final ScriptFunction callback) { + System.out.println("[JavaScriptEntry]" + args); + PostRequest req = new PostRequest(); + req = JsonUtil.fromJson(args, PostRequest.class); + + OkHttpClient okHttpClient = new OkHttpClient(); // + RequestBody body = + RequestBody.create(MediaType.parse("application/json; charset=utf-8"), req.data); + Request request = new Request.Builder().url(req.url).post(body).build(); // 2.瀹氫箟涓�涓猺equest + Call call = okHttpClient.newCall(request); // + call.enqueue( + new Callback() { // + @Override + public void onFailure(Call call, IOException e) { + } + + @Override + public void onResponse(Call call, Response response) throws IOException { + String result = response.body().string(); // + System.out.println("currentEngine:"); + DesktopEngine.applyWithGlobal( + callback, currentEngine.getNashornGlobal(), result); + } + }); + return "success"; + } + + // public static String httpGet(String str) { + // // System.out.println("JavaScriptEntry httpGet:" + str); + // Result r = new Result(); + // try { + // HttpGet httpGet = new HttpGet(str); + // RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(60000) + // .setConnectTimeout(60000).setSocketTimeout(60000).build(); + // httpGet.setConfig(requestConfig); + // httpGet.addHeader("Pragma", "no-cache"); + // httpGet.addHeader("Cache-Control", "no-cache"); + // httpGet.addHeader("Upgrade-Insecure-Requests", "1"); + // httpGet.addHeader("User-Agent", + // "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) + // Chrome/78.0.3904.97 Safari/537.36"); + // httpGet.addHeader("Sec-Fetch-User", "?1"); + // httpGet.addHeader("Accept", + // + // "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3"); + // httpGet.addHeader("Sec-Fetch-Site", "none"); + // httpGet.addHeader("Sec-Fetch-Mode", "navigate"); + // httpGet.addHeader("Accept-Encoding", "gzip, deflate, br"); + // httpGet.addHeader("Accept-Language", "zh-CN,zh;q=0.9"); + // CloseableHttpResponse response1 = getHttpClient(str).execute(httpGet); + // InputStream content = response1.getEntity().getContent(); + // ByteArrayOutputStream bo = new ByteArrayOutputStream(); + // byte[] buff = new byte[4096]; + // for (int k = 0; (k = content.read(buff)) > 0;) { + // bo.write(buff, 0, k); + // } + // r.response = bo.toString(); + // return JsonUtil.toJson(r); + // } catch (Throwable e) { + // r.resposeCode = 505; + // // ByteArrayOutputStream bo = new ByteArrayOutputStream(); + // // e.printStackTrace(new PrintStream(bo)); + // r.response = e.getMessage(); + // return JsonUtil.toJson(r); + // } + // } + + public static ApiGate createAPIGate(String ip) { + return new ApiGate(ip); + } + + public static ApiGate createAPIGate(String ip, String port) { + return new ApiGate(ip, Integer.parseInt(port)); + } + + static class PostRequest { + String url; + String data; + } +} diff --git a/src/main/java/org/bdware/sc/boundry/utils/LedgerUtil.java b/src/main/java/org/bdware/sc/boundry/utils/LedgerUtil.java new file mode 100644 index 0000000..451134e --- /dev/null +++ b/src/main/java/org/bdware/sc/boundry/utils/LedgerUtil.java @@ -0,0 +1,54 @@ +package org.bdware.sc.boundry.utils; + +import org.bdware.bdledger.api.grpc.Client; +import org.bdware.bdledger.api.grpc.pb.CommonProto.Transaction; +import org.bdware.bdledger.api.grpc.pb.CommonProto.TransactionType; +import org.bdware.bdledger.api.grpc.pb.LedgerProto.SendTransactionResponse; +import org.bdware.bdledger.api.grpc.pb.QueryProto.GetTransactionByHashResponse; +import org.bdware.sc.compiler.PermissionStub; +import org.bdware.sc.node.Permission; +import org.bdware.sc.util.HashUtil; +import wrp.jdk.nashorn.api.scripting.ScriptObjectMirror; +import wrp.jdk.nashorn.internal.runtime.PropertyMap; +import wrp.jdk.nashorn.internal.runtime.ScriptObject; +import wrp.jdk.nashorn.internal.scripts.JO; + +import java.security.SecureRandom; + +@PermissionStub(permission = Permission.Ledger) +public class LedgerUtil { + static SecureRandom random = new SecureRandom((System.currentTimeMillis() + "").getBytes()); + + public static Client getClient(ScriptObjectMirror str) { + return new Client((String) str.get("ip"), Integer.parseInt(str.get("port").toString())); + } + + public static ScriptObject queryByHash(Client c, ScriptObjectMirror str) { + String ledger = str.get("ledger").toString(); + String hash = str.get("hash").toString(); + JO ret = new JO(PropertyMap.newMap()); + GetTransactionByHashResponse result = c.getTransactionByHashSync(ledger, hash); + Transaction transaction = result.getTransaction(); + ret.put("from", HashUtil.byteArray2Str(transaction.getFrom().toByteArray(), 0), false); + ret.put("to", HashUtil.byteArray2Str(transaction.getTo().toByteArray(), 0), false); + ret.put("type", transaction.getType().toString(), false); + ret.put("data", new String(transaction.getData().toByteArray()), false); + return ret; + } + + public static String sendTransaction(Client c, ScriptObjectMirror str) { + String ledger = str.get("ledger").toString(); + String from = str.get("from").toString(); + String to = str.get("to").toString(); + String data = str.get("data").toString(); + SendTransactionResponse result = + c.sendTransactionSync( + ledger, + TransactionType.MESSAGE, + from, + random.nextLong(), + to, + data.getBytes()); + return HashUtil.byteArray2Str(result.getHash().toByteArray(), 0); + } +} diff --git a/src/main/java/org/bdware/sc/boundry/utils/MongoDBUtil.java b/src/main/java/org/bdware/sc/boundry/utils/MongoDBUtil.java new file mode 100644 index 0000000..75e8c77 --- /dev/null +++ b/src/main/java/org/bdware/sc/boundry/utils/MongoDBUtil.java @@ -0,0 +1,8 @@ +package org.bdware.sc.boundry.utils; + +import org.bdware.sc.compiler.PermissionStub; +import org.bdware.sc.node.Permission; + +@PermissionStub(permission = Permission.MongoDB) +public class MongoDBUtil extends org.bdware.sc.blockdb.MongoDBUtil { +} diff --git a/src/main/java/org/bdware/sc/boundry/utils/README.md b/src/main/java/org/bdware/sc/boundry/utils/README.md new file mode 100644 index 0000000..2073536 --- /dev/null +++ b/src/main/java/org/bdware/sc/boundry/utils/README.md @@ -0,0 +1,19 @@ +# 简介 + +这个包里对yjs层提供了XXUtil功能的调用。 要添加一个Util需要以下步骤。 + +## 1.新增加一个带@PermissionStub的注解 + +注意注解里的Permission要和类名一致。 + +```java + +@PermissionStub(permission = "ABC") +public class ABCUtil { + +} +``` + +## 2.在org.bdware.sc.node.Permission中添加这个权限 + +## 3.在doc项目的@Permission注解说明里 diff --git a/src/main/java/org/bdware/sc/boundry/utils/RocksDBUtil.java b/src/main/java/org/bdware/sc/boundry/utils/RocksDBUtil.java new file mode 100644 index 0000000..ac0bad1 --- /dev/null +++ b/src/main/java/org/bdware/sc/boundry/utils/RocksDBUtil.java @@ -0,0 +1,105 @@ +package org.bdware.sc.boundry.utils; + +import org.bdware.sc.ContractProcess; +import org.bdware.sc.compiler.PermissionStub; +import org.bdware.sc.node.Permission; +import org.rocksdb.Options; +import org.rocksdb.RocksDB; +import org.rocksdb.RocksDBException; +import org.rocksdb.RocksIterator; +import wrp.jdk.nashorn.internal.runtime.PropertyMap; +import wrp.jdk.nashorn.internal.runtime.ScriptObject; +import wrp.jdk.nashorn.internal.scripts.JO; + +import java.io.File; + +@PermissionStub(permission = Permission.RocksDB) +public class RocksDBUtil { + static { + RocksDB.loadLibrary(); + } + + RocksDB rocksDB; + + public RocksDBUtil(String path, boolean readOnly) { + try { + Options options = new Options(); + options.setCreateIfMissing(true); + File parent = new File("./ContractDB/" + ContractProcess.instance.getContractName()); + path = new File(parent, path).getAbsolutePath(); + File lockFile = new File(path, "LOCK"); + lockFile.delete(); + if (readOnly) { + rocksDB = RocksDB.openReadOnly(options, path); + } else rocksDB = RocksDB.open(options, path); + } catch (RocksDBException e) { + e.printStackTrace(); + } + } + + public static RocksDBUtil loadDB(String path, boolean readOnly) { + return new RocksDBUtil(path, readOnly); + } + + public static RocksDBUtil loadDB(String path, String readOnly) { + return new RocksDBUtil(path, Boolean.parseBoolean(readOnly)); + } + + public String get(String key) { + try { + return new String(rocksDB.get(key.getBytes())); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public long estimateKeySize() { + try { + return rocksDB.getLongProperty("rocksdb.estimate-num-keys"); + } catch (Exception e) { + e.printStackTrace(); + return 0; + } + } + + public void put(String key, String value) { + try { + rocksDB.put(key.getBytes(), value.getBytes()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public String delete(String key) { + try { + rocksDB.delete(key.getBytes()); + + return "success"; + } catch (Exception e) { + e.printStackTrace(); + } + return "failed"; + } + + public RocksIterator newIterator() { + try { + return rocksDB.newIterator(); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public ScriptObject getNext(RocksIterator iter) { + + if (iter.isValid()) { + JO ret = new JO(PropertyMap.newMap()); + ret.put("key", new String(iter.key()), false); + ret.put("value", new String(iter.value()), false); + iter.next(); + return ret; + } + return null; + } +} diff --git a/src/main/java/org/bdware/sc/boundry/utils/SM2Util.java b/src/main/java/org/bdware/sc/boundry/utils/SM2Util.java new file mode 100644 index 0000000..cdf9bc8 --- /dev/null +++ b/src/main/java/org/bdware/sc/boundry/utils/SM2Util.java @@ -0,0 +1,93 @@ +package org.bdware.sc.boundry.utils; + +import org.bdware.sc.compiler.PermissionStub; +import org.bdware.sc.node.Permission; +import org.bouncycastle.crypto.InvalidCipherTextException; +import org.bouncycastle.crypto.params.ECPrivateKeyParameters; +import org.bouncycastle.crypto.params.ECPublicKeyParameters; +import org.bouncycastle.pqc.math.linearalgebra.ByteUtils; +import org.zz.gmhelper.BCECUtil; +import org.zz.gmhelper.SM2KeyPair; +import org.zz.gmhelper.SM3Util; +import wrp.jdk.nashorn.api.scripting.ScriptObjectMirror; +import wrp.jdk.nashorn.internal.runtime.PropertyMap; +import wrp.jdk.nashorn.internal.runtime.ScriptObject; +import wrp.jdk.nashorn.internal.scripts.JO; + +import java.math.BigInteger; + +@PermissionStub(permission = Permission.SM2) +public class SM2Util { + + public static ScriptObject generateKeyPair() { + JO ret = new JO(PropertyMap.newMap()); + SM2KeyPair keyPair = org.zz.gmhelper.SM2Util.generateSM2KeyPair(); + ret.put("publicKey", keyPair.getPublicKeyStr(), false); + ret.put("privateKey", keyPair.getPrivateKeyStr(), false); + return ret; + } + + public static ScriptObject sign(String content, ScriptObjectMirror keyPair) { + JO ret = new JO(PropertyMap.newMap()); + try { + BigInteger privateKey = new BigInteger(keyPair.getMember("privateKey").toString(), 16); + ECPrivateKeyParameters priKey = + new ECPrivateKeyParameters(privateKey, org.zz.gmhelper.SM2Util.DOMAIN_PARAMS); + byte[] sign = org.zz.gmhelper.SM2Util.sign(priKey, content.getBytes()); + sign = org.zz.gmhelper.SM2Util.decodeDERSM2Sign(sign); + ret.put("status", "success", false); + ret.put("signature", ByteUtils.toHexString(sign), false); + } catch (Exception e) { + ret.put("status", "failed", false); + ret.put("message", "invalid keyPair", false); + } + return ret; + } + + public static ScriptObject verify(String content, String signature, String pubKeyStr) { + JO ret = new JO(PropertyMap.newMap()); + try { + byte[] sig = ByteUtils.fromHexString(signature); + sig = org.zz.gmhelper.SM2Util.encodeSM2SignToDER(sig); + ECPublicKeyParameters pubKey = + BCECUtil.createECPublicKeyFromStrParameters( + pubKeyStr, + org.zz.gmhelper.SM2Util.CURVE, + org.zz.gmhelper.SM2Util.DOMAIN_PARAMS); + boolean value = org.zz.gmhelper.SM2Util.verify(pubKey, content.getBytes(), sig); + if (value) ret.put("status", "success", false); + else ret.put("status", "failed", false); + ret.put("result", value, false); + } catch (Exception e) { + ret.put("status", "failed", false); + ret.put("result", "invalid keyPair or signature ", false); + e.printStackTrace(); + } + return ret; + } + + public static String encrypt(String content, String pubkey) { + try { + return ByteUtils.toHexString( + org.zz.gmhelper.SM2Util.encrypt( + SM2KeyPair.publicKeyStr2ECPoint(pubkey), content.getBytes())); + } catch (InvalidCipherTextException e) { + e.printStackTrace(); + } + return null; + } + + public static String decrypt(String content, String privateKey) { + try { + ECPrivateKeyParameters privateKeyParam = + new ECPrivateKeyParameters( + new BigInteger(privateKey, 16), org.zz.gmhelper.SM2Util.DOMAIN_PARAMS); + return new String( + org.zz.gmhelper.SM2Util.decrypt( + privateKeyParam, ByteUtils.fromHexString(content))); + } catch (InvalidCipherTextException e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/src/main/java/org/bdware/sc/boundry/utils/SQLUtil.java b/src/main/java/org/bdware/sc/boundry/utils/SQLUtil.java new file mode 100644 index 0000000..12d33b2 --- /dev/null +++ b/src/main/java/org/bdware/sc/boundry/utils/SQLUtil.java @@ -0,0 +1,62 @@ +package org.bdware.sc.boundry.utils; + +import org.bdware.sc.ContractProcess; +import org.bdware.sc.compiler.PermissionStub; +import org.bdware.sc.node.Permission; + +import java.lang.reflect.Method; +import java.sql.Connection; +import java.util.Properties; + +@PermissionStub(permission = Permission.SQL) +public class SQLUtil { + public static void initDriver(String driver) { + try { + Thread.currentThread() + .setContextClassLoader(ContractProcess.instance.engine.getClassLoad()); + Class.forName(driver, true, ContractProcess.instance.engine.getClassLoad()); + } catch (Exception e) { + System.out.println( + "Still can't find class! Cl of SQLUtil:\n\t\t" + + SQLUtil.class.getClassLoader()); + System.out.println( + "Cl of DEgine:\n\t\t" + ContractProcess.instance.engine.getClassLoad()); + e.printStackTrace(); + } + } + + public static Connection getConnection(String url, String user, String password) { + try { + Thread.currentThread() + .setContextClassLoader(ContractProcess.instance.engine.getClassLoad()); + if (!url.startsWith("jdbc")) { + url += "jdbc:mysql://"; + } + java.util.Properties info = new java.util.Properties(); + + if (user != null && !"undefined".equals(user)) { + info.put("user", user); + } + if (password != null && !"undefined".equals(password)) { + info.put("password", password); + } + if (url.startsWith("jdbc:postgresql")) info.put("sslmode", "allow"); + + Class clz = + Class.forName( + "java.sql.DriverManager", + true, + ContractProcess.instance.engine.getClassLoad()); + // set caller class into null, thus use YJSClassLoader in + // DriverManager.isDriverAllowed(driver,classloader); + Method m = + clz.getDeclaredMethod( + "getConnection", String.class, Properties.class, Class.class); + m.setAccessible(true); + return (Connection) m.invoke(null, url, info, null); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/src/main/java/org/bdware/sc/boundry/utils/UtilRegistry.java b/src/main/java/org/bdware/sc/boundry/utils/UtilRegistry.java new file mode 100644 index 0000000..920c241 --- /dev/null +++ b/src/main/java/org/bdware/sc/boundry/utils/UtilRegistry.java @@ -0,0 +1,59 @@ +package org.bdware.sc.boundry.utils; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.bdware.sc.compiler.PermissionStub; +import org.bdware.sc.compiler.PermissionStubGenerator; +import org.bdware.sc.engine.YJSClassLoader; +import org.bdware.sc.node.Permission; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class UtilRegistry { + private static final Logger LOGGER = LogManager.getLogger(UtilRegistry.class); + public static Map stubClzNameMap = new HashMap<>(); + + public static List> getUtilClasses() { + List allName = Permission.allName(); + List> ret = new ArrayList<>(); + for (String name : allName) { + Class clz; + try { + clz = Class.forName(String.format("%s.%sUtil", UtilRegistry.class.getPackage().getName(), name)); + ret.add(clz); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } + return ret; + } + + public static void defineUtilClass(YJSClassLoader classLoader) { + List> clzs = UtilRegistry.getUtilClasses(); + for (Class aClass : clzs) { + PermissionStub stub = aClass.getAnnotation(PermissionStub.class); + if (stub == null) { + continue; + } + byte[] stubClz = PermissionStubGenerator.generateStub(aClass, stub.permission().name()); + String stubClzName = aClass.getCanonicalName() + "Stub"; + stubClzNameMap.put(stub.permission().name(), stubClzName); + classLoader.defineStubClass(stubClzName, stubClz); + } + } + + public static String getInitStr(String s, boolean open) { + if (stubClzNameMap.containsKey(s)) { + String ret = + String.format( + "%sUtil = %s.%sUtil%s;\n", + s, UtilRegistry.class.getPackage().getName(), s, open ? "" : "Stub"); + LOGGER.debug(ret); + return ret; + } + return ""; + } +} diff --git a/src/main/java/org/bdware/sc/compiler/AnnotationProcessor.java b/src/main/java/org/bdware/sc/compiler/AnnotationProcessor.java new file mode 100644 index 0000000..f356f71 --- /dev/null +++ b/src/main/java/org/bdware/sc/compiler/AnnotationProcessor.java @@ -0,0 +1,16 @@ +package org.bdware.sc.compiler; + +import org.bdware.sc.node.AnnotationNode; +import org.bdware.sc.node.ContractNode; +import org.bdware.sc.node.FunctionNode; + +public abstract class AnnotationProcessor { + public void processContract(AnnotationNode anno, ContractNode contractNode) { + return; + } + + public void processFunction( + AnnotationNode anno, ContractNode contractNode, FunctionNode functionNode) { + return; + } +} diff --git a/src/main/java/org/bdware/sc/compiler/YJSCompiler.java b/src/main/java/org/bdware/sc/compiler/YJSCompiler.java new file mode 100644 index 0000000..0f96338 --- /dev/null +++ b/src/main/java/org/bdware/sc/compiler/YJSCompiler.java @@ -0,0 +1,224 @@ +package org.bdware.sc.compiler; + +import org.antlr.v4.runtime.ANTLRInputStream; +import org.antlr.v4.runtime.CommonTokenStream; +import org.antlr.v4.runtime.DiagnosticErrorListener; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.bdware.sc.engine.YJSFilter; +import org.bdware.sc.node.*; +import org.bdware.sc.parser.JavaScriptLexer; +import org.bdware.sc.parser.YJSParser; +import org.bdware.sc.parser.YJSParser.ProgramContext; +import org.bdware.sc.util.JsonUtil; +import org.bdware.sc.visitor.ContractReader; +import wrp.jdk.nashorn.internal.objects.Global; +import wrp.jdk.nashorn.internal.runtime.Context; +import wrp.jdk.nashorn.internal.runtime.ErrorManager; +import wrp.jdk.nashorn.internal.runtime.ScriptFunction; +import wrp.jdk.nashorn.internal.runtime.Source; +import wrp.jdk.nashorn.internal.runtime.options.Options; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +public class YJSCompiler { + public boolean withProgramPointCount; + YJSErrorListener errorListener = new YJSErrorListener(); + ContractNode contract; + private static final Logger LOGGER = LogManager.getLogger(YJSCompiler.class); + + public YJSCompiler() { + } + + public static ScriptFunction compileWithGlobal(Source source, Global global, Context context) { + Global oldGlobal = Context.getGlobal(); + boolean globalChanged = (oldGlobal != global); + try { + if (globalChanged) { + Context.setGlobal(global); + } + return context.compileScript(source).getFunction(global); + } catch (Exception e) { + e.printStackTrace(); + return null; + } finally { + if (globalChanged) { + Context.setGlobal(oldGlobal); + } + } + } + + private static Context makeContext( + final InputStream in, final OutputStream out, final OutputStream err) { + final PrintStream pout = + out instanceof PrintStream ? (PrintStream) out : new PrintStream(out); + final PrintStream perr = + err instanceof PrintStream ? (PrintStream) err : new PrintStream(err); + final PrintWriter wout = new PrintWriter(pout, true); + final PrintWriter werr = new PrintWriter(perr, true); + + // Set up error handler. + final ErrorManager errors = new ErrorManager(werr); + // Set up options. + final Options options = new Options("nashorn", werr); + options.process(new String[] {}); + // detect scripting mode by any source's first character being '#' + options.set("persistent.code.cache", true); + options.set("print.code", "true"); + options.set("print.parse", true); + + if (!options.getBoolean("scripting")) { + for (final String fileName : options.getFiles()) { + final File firstFile = new File(fileName); + if (firstFile.isFile()) { + try (final FileReader fr = new FileReader(firstFile)) { + final int firstChar = fr.read(); + // starts with '# + if (firstChar == '#') { + options.set("scripting", true); + break; + } + } catch (final IOException e) { + // ignore this. File IO errors will be reported later + // anyway + } + } + } + } + return new Context( + options, + errors, + wout, + werr, + Thread.currentThread().getContextClassLoader(), + new YJSFilter(), + null); + } + + public ContractZipBundle compile(ZipFile zf) throws Exception { + ContractZipBundle czb = new ContractZipBundle(); + ZipEntry manifest = zf.getEntry("/manifest.json"); + if (null == manifest) { + throw new IllegalStateException("manifest.json is not exists!"); + } + InputStream manifestInput = zf.getInputStream(manifest); + // Gson gson = new GsonBuilder().registerTypeAdapter(Contract.Type.class, + // typeAdapter) + + ContractManifest cm = + JsonUtil.GSON.fromJson( + new InputStreamReader(manifestInput), ContractManifest.class); + + // 如果没有就不限制,根据gas进行插装 + if (0L != cm.getInsnLimit()) { + System.out.println("++++++++++++++++++++++true"); + } + czb.setManifest(cm); + Set toParse = new HashSet<>(); + toParse.add(cm.main); + Set todo = new HashSet<>(); + while (toParse.size() > 0) { + for (String str : toParse) { + if (czb.containsPath(str)) { + continue; + } + ZipEntry entry = zf.getEntry("/" + str); + if (null == entry) { + throw new IllegalStateException("missing import:" + str); + } + ContractNode cn = compile(zf.getInputStream(entry), str); + czb.put(str, cn); + System.out.println("----" + str); + for (ImportNode in : cn.getImports()) { + todo.add(in.getPath()); + } + } + toParse.clear(); + for (String str : todo) { + if (!czb.containsPath(str)) { + toParse.add(str); + } + } + todo.clear(); + } + // add function _preSub + // Kaidong Wu + String preSubConName = cm.main.substring(0, cm.main.length() - 4) + "PreSub"; + String preSubContract = + "contract " + + preSubConName + + " { function _preSub (e) { YancloudUtil.preSub(e.topic, e.content); }}"; + ContractNode preSubNode = + compile( + new ByteArrayInputStream(preSubContract.getBytes(StandardCharsets.UTF_8)), + preSubConName + ".yjs"); + czb.put(preSubConName + ".yjs", preSubNode); + LOGGER.info("--compile-- " + preSubConName); + return czb; + } + + public ContractNode compile(InputStream input, String fileName) throws IOException { + // 词法分析 + JavaScriptLexer lexer = new JavaScriptLexer(new ANTLRInputStream(input)); + lexer.setUseStrictDefault(true); + CommonTokenStream cts = new CommonTokenStream(lexer); + // 语法分析 + YJSParser parser = new YJSParser(cts); + parser.removeErrorListeners(); + parser.addErrorListener(errorListener); + parser.addErrorListener(new DiagnosticErrorListener()); + ProgramContext tree = parser.program(); + // 应该是antlr4访问器进行遍历语法树 + ContractReader reader = new ContractReader(fileName); + System.out.println("遍历语法树"); + contract = reader.visitProgram(tree); + // 遍历完 获取 contract 里的 yjs type + System.out.println(contract.getYjsType()); + contract.initPlainText(cts); + handleAnnotation(contract);//处理注解 + return contract; + } + + private void handleAnnotation(ContractNode contractNode) { + System.out.println("handleAnnotation"); + for (AnnotationNode node : contract.annotations) { + AnnotationProcessor processor = findProcessor(node); + if (processor != null) { + processor.processContract(node, contractNode); + } + } + for (FunctionNode functionNode : contractNode.getFunctions()) { + List annos = functionNode.annotations;//函数里的annotation + if (annos != null) + for (AnnotationNode anno : annos) { + System.out.println(anno.getType());//打印类型和参数 + System.out.println(anno.getArgs()); + AnnotationProcessor processor = findProcessor(anno); + if (processor != null) + processor.processFunction(anno, contractNode, functionNode); + } + } + } + + private AnnotationProcessor findProcessor(AnnotationNode node) { + try { + String clzName = YJSCompiler.class.getPackage().getName(); + clzName += ".ap." + node.getType(); + Class clz = Class.forName(clzName); + return (AnnotationProcessor) clz.getConstructor().newInstance(); + } catch (Exception e) { + // e.printStackTrace(); + } + return null; + } + + public List syntaxError() { + return errorListener.result; + } +} diff --git a/src/main/java/org/bdware/sc/compiler/ap/Access.java b/src/main/java/org/bdware/sc/compiler/ap/Access.java new file mode 100644 index 0000000..20fb18e --- /dev/null +++ b/src/main/java/org/bdware/sc/compiler/ap/Access.java @@ -0,0 +1,15 @@ +package org.bdware.sc.compiler.ap; + +import org.bdware.sc.compiler.AnnotationProcessor; +import org.bdware.sc.node.AnnotationNode; +import org.bdware.sc.node.ContractNode; + +public class Access extends AnnotationProcessor { + @Override + public void processContract(AnnotationNode anno, ContractNode contractNode) { + contractNode.sigRequired = false; + if (anno != null) { + contractNode.sigRequired = "\"verified\"".equals(anno.getArgs().get(0)); + } + } +} diff --git a/src/main/java/org/bdware/sc/compiler/ap/Confidential.java b/src/main/java/org/bdware/sc/compiler/ap/Confidential.java new file mode 100644 index 0000000..8a7a655 --- /dev/null +++ b/src/main/java/org/bdware/sc/compiler/ap/Confidential.java @@ -0,0 +1,12 @@ +package org.bdware.sc.compiler.ap; + +import org.bdware.sc.compiler.AnnotationProcessor; +import org.bdware.sc.node.AnnotationNode; +import org.bdware.sc.node.ContractNode; +import org.bdware.sc.node.FunctionNode; + +public class Confidential extends AnnotationProcessor { + @Override + public void processFunction(AnnotationNode anno, ContractNode contractNode, FunctionNode functionNode) { + functionNode.setConfidential(true); } +} diff --git a/src/main/java/org/bdware/sc/compiler/ap/Cost.java b/src/main/java/org/bdware/sc/compiler/ap/Cost.java new file mode 100644 index 0000000..99fa2f6 --- /dev/null +++ b/src/main/java/org/bdware/sc/compiler/ap/Cost.java @@ -0,0 +1,19 @@ +package org.bdware.sc.compiler.ap; + +import org.bdware.sc.compiler.AnnotationProcessor; +import org.bdware.sc.node.AnnotationNode; +import org.bdware.sc.node.ContractNode; +import org.bdware.sc.node.CostDetail; +import org.bdware.sc.node.FunctionNode; +import org.bdware.sc.util.JsonUtil; + +public class Cost extends AnnotationProcessor { + @Override + public void processFunction( + AnnotationNode anno, ContractNode contractNode, FunctionNode functionNode) { + CostDetail detail = JsonUtil.fromJson(anno.getArgs().get(0), CostDetail.class); + functionNode.setCost(detail); + if (detail.isCountGas()) + contractNode.setInstrumentBranch(true); + } +} diff --git a/src/main/java/org/bdware/sc/compiler/ap/HomomorphicDecrypt.java b/src/main/java/org/bdware/sc/compiler/ap/HomomorphicDecrypt.java new file mode 100644 index 0000000..d1d9309 --- /dev/null +++ b/src/main/java/org/bdware/sc/compiler/ap/HomomorphicDecrypt.java @@ -0,0 +1,18 @@ +package org.bdware.sc.compiler.ap; + +import com.google.gson.JsonParser; +import org.bdware.sc.compiler.AnnotationProcessor; +import org.bdware.sc.node.AnnotationNode; +import org.bdware.sc.node.ContractNode; +import org.bdware.sc.node.FunctionNode; + +public class HomomorphicDecrypt extends AnnotationProcessor { + @Override + public void processFunction(AnnotationNode anno, ContractNode contractNode, FunctionNode functionNode) { + functionNode.setHomomorphicDecrypt(true); + functionNode.setKeyManagerID(anno.getArgs().get(0)); + functionNode.setSecretID(anno.getArgs().get(1)); + functionNode.setHomoDecryptConf(JsonParser.parseString(anno.getArgs().get(2))); + } +} + diff --git a/src/main/java/org/bdware/sc/compiler/ap/HomomorphicEncrypt.java b/src/main/java/org/bdware/sc/compiler/ap/HomomorphicEncrypt.java new file mode 100644 index 0000000..2e8109b --- /dev/null +++ b/src/main/java/org/bdware/sc/compiler/ap/HomomorphicEncrypt.java @@ -0,0 +1,17 @@ +package org.bdware.sc.compiler.ap; + +import com.google.gson.JsonParser; +import org.bdware.sc.compiler.AnnotationProcessor; +import org.bdware.sc.node.AnnotationNode; +import org.bdware.sc.node.ContractNode; +import org.bdware.sc.node.FunctionNode; + +public class HomomorphicEncrypt extends AnnotationProcessor { + @Override + public void processFunction(AnnotationNode anno, ContractNode contractNode, FunctionNode functionNode) { + functionNode.setHomomorphicEncrypt(true); + functionNode.setKeyManagerID(anno.getArgs().get(0)); + functionNode.setSecretID(anno.getArgs().get(1)); + functionNode.setHomoEncryptConf(JsonParser.parseString(anno.getArgs().get(2))); + } +} diff --git a/src/main/java/org/bdware/sc/compiler/ap/Join.java b/src/main/java/org/bdware/sc/compiler/ap/Join.java new file mode 100644 index 0000000..4820828 --- /dev/null +++ b/src/main/java/org/bdware/sc/compiler/ap/Join.java @@ -0,0 +1,17 @@ +package org.bdware.sc.compiler.ap; + +import org.bdware.sc.bean.JoinInfo; +import org.bdware.sc.compiler.AnnotationProcessor; +import org.bdware.sc.node.AnnotationNode; +import org.bdware.sc.node.ContractNode; +import org.bdware.sc.node.FunctionNode; + +public class Join extends AnnotationProcessor { + @Override + public void processFunction( + AnnotationNode anno, ContractNode contractNode, FunctionNode functionNode) { + // functionNode.setRouteInfo(RouteInfo.create(anno,contractNode)); + //增加标记,在ContractNode中记录Join相关的函数和Join规则 + functionNode.setJoinInfo(JoinInfo.create(anno,contractNode)); + } +} diff --git a/src/main/java/org/bdware/sc/compiler/ap/LogLocation.java b/src/main/java/org/bdware/sc/compiler/ap/LogLocation.java new file mode 100644 index 0000000..8f08e95 --- /dev/null +++ b/src/main/java/org/bdware/sc/compiler/ap/LogLocation.java @@ -0,0 +1,32 @@ +package org.bdware.sc.compiler.ap; + +import org.bdware.sc.compiler.AnnotationProcessor; +import org.bdware.sc.node.AnnotationNode; +import org.bdware.sc.node.ContractNode; +import org.bdware.sc.node.FunctionNode; + +public class LogLocation extends AnnotationProcessor { + @Override + public void processContract(AnnotationNode anno, ContractNode contractNode) { + for (FunctionNode fn : contractNode.getFunctions()) { + fn.addAnnotation(anno); + } + } + + @Override + public void processFunction( + AnnotationNode anno, ContractNode contractNode, FunctionNode functionNode) { + if (anno != null && anno.getArgs() != null) + for (String s : anno.getArgs()) { + if (s.equals("\"dataware\"") + || s.equals("\"bdledger\"") + || s.equals("\"bdledger:\"")) { + functionNode.setLogToBDContract(true); + } else if (s.startsWith("\"bdledger:") && s.length() > 11) { + functionNode.setLogToNamedLedger(true); + String[] tmp = s.substring(1, s.length() - 1).split(":"); + functionNode.addLedgerName(tmp[1]); + } + } + } +} diff --git a/src/main/java/org/bdware/sc/compiler/ap/LogType.java b/src/main/java/org/bdware/sc/compiler/ap/LogType.java new file mode 100644 index 0000000..87ef97e --- /dev/null +++ b/src/main/java/org/bdware/sc/compiler/ap/LogType.java @@ -0,0 +1,26 @@ +package org.bdware.sc.compiler.ap; + +import org.bdware.sc.compiler.AnnotationProcessor; +import org.bdware.sc.node.AnnotationNode; +import org.bdware.sc.node.ContractNode; +import org.bdware.sc.node.FunctionNode; + +public class LogType extends AnnotationProcessor { + @Override + public void processContract(AnnotationNode anno, ContractNode contractNode) { + contractNode.setLogType(anno.getArgs()); + for (FunctionNode fn : contractNode.getFunctions()) { + fn.addAnnotation(anno); + } + } + + @Override + public void processFunction( + AnnotationNode anno, ContractNode contractNode, FunctionNode functionNode) { + for (String str : anno.getArgs()) { + org.bdware.sc.node.LogType type = org.bdware.sc.node.LogType.parse(str); + functionNode.addLogType(type); + if (type == org.bdware.sc.node.LogType.Branch) contractNode.setInstrumentBranch(true); + } + } +} diff --git a/src/main/java/org/bdware/sc/compiler/ap/Param.java b/src/main/java/org/bdware/sc/compiler/ap/Param.java new file mode 100644 index 0000000..3dbbceb --- /dev/null +++ b/src/main/java/org/bdware/sc/compiler/ap/Param.java @@ -0,0 +1,6 @@ +package org.bdware.sc.compiler.ap; + +import org.bdware.sc.compiler.AnnotationProcessor; + +public class Param extends AnnotationProcessor { +} diff --git a/src/main/java/org/bdware/sc/compiler/ap/Permission.java b/src/main/java/org/bdware/sc/compiler/ap/Permission.java new file mode 100644 index 0000000..9d09bcf --- /dev/null +++ b/src/main/java/org/bdware/sc/compiler/ap/Permission.java @@ -0,0 +1,12 @@ +package org.bdware.sc.compiler.ap; + +import org.bdware.sc.compiler.AnnotationProcessor; +import org.bdware.sc.node.AnnotationNode; +import org.bdware.sc.node.ContractNode; + +public class Permission extends AnnotationProcessor { + @Override + public void processContract(AnnotationNode anno, ContractNode contractNode) { + contractNode.setPermission(anno.getArgs()); + } +} diff --git a/src/main/java/org/bdware/sc/compiler/ap/Route.java b/src/main/java/org/bdware/sc/compiler/ap/Route.java new file mode 100644 index 0000000..7714e85 --- /dev/null +++ b/src/main/java/org/bdware/sc/compiler/ap/Route.java @@ -0,0 +1,17 @@ +package org.bdware.sc.compiler.ap; + +import com.google.gson.Gson; +import org.bdware.sc.bean.RouteInfo; +import org.bdware.sc.compiler.AnnotationProcessor; +import org.bdware.sc.node.AnnotationNode; +import org.bdware.sc.node.ContractNode; +import org.bdware.sc.node.CostDetail; +import org.bdware.sc.node.FunctionNode; + +public class Route extends AnnotationProcessor { + @Override + public void processFunction( + AnnotationNode anno, ContractNode contractNode, FunctionNode functionNode) { + functionNode.setRouteInfo(RouteInfo.create(anno,contractNode)); + } +} diff --git a/src/main/java/org/bdware/sc/compiler/ap/Split.java b/src/main/java/org/bdware/sc/compiler/ap/Split.java new file mode 100644 index 0000000..a720204 --- /dev/null +++ b/src/main/java/org/bdware/sc/compiler/ap/Split.java @@ -0,0 +1,16 @@ +package org.bdware.sc.compiler.ap; + +import org.bdware.sc.bean.RouteInfo; +import org.bdware.sc.compiler.AnnotationProcessor; +import org.bdware.sc.node.AnnotationNode; +import org.bdware.sc.node.ContractNode; +import org.bdware.sc.node.FunctionNode; + +public class Split extends AnnotationProcessor { + + @Override + public void processFunction( + AnnotationNode anno, ContractNode contractNode, FunctionNode functionNode) { + functionNode.setRouteInfo(RouteInfo.create(anno,contractNode)); + } +} diff --git a/src/main/java/org/bdware/sc/engine/ConfidentialContractUtil.java b/src/main/java/org/bdware/sc/engine/ConfidentialContractUtil.java new file mode 100644 index 0000000..e327c65 --- /dev/null +++ b/src/main/java/org/bdware/sc/engine/ConfidentialContractUtil.java @@ -0,0 +1,323 @@ +package org.bdware.sc.engine; + +import com.google.gson.reflect.TypeToken; +import org.apache.commons.io.FileUtils; +import org.bdware.sc.bean.ContractRequest; +import org.bdware.sc.node.ContractNode; +import org.bdware.sc.node.FunctionNode; +import org.bdware.sc.util.JsonUtil; +import wrp.jdk.nashorn.api.scripting.ScriptObjectMirror; +import wrp.jdk.nashorn.internal.objects.Global; + +import javax.script.Invocable; +import javax.script.ScriptException; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.lang.reflect.Type; +import java.nio.charset.StandardCharsets; +import java.util.*; + +public class ConfidentialContractUtil { + + public static final String CONFIDENTIAL_TEMPLATE_PATH = System.getenv("GRAPHENE_DIR") + + File.separator + "Examples" + File.separator + "nodejs-secret"; + public static final String CONFIDENTIAL_SCRIPT_PATH = System.getenv("GRAPHENE_DIR") + + File.separator + "App"; + public static final String[] COMMAND = {"bash", "executeContract.sh"}; + private static final Type MapType = TypeToken.getParameterized(HashMap.class, String.class, String.class).getType(); + + public static String executeConfidentialContract(ContractRequest input) throws IOException, InterruptedException { + File runDir = new File(CONFIDENTIAL_SCRIPT_PATH + File.separator + input.getRequestID()); + ProcessBuilder pb = new ProcessBuilder(COMMAND); + pb.directory(runDir); + Process p = pb.start(); + p.waitFor(); + File resultFile = new File(CONFIDENTIAL_SCRIPT_PATH + File.separator + input.getRequestID() + + File.separator + "result.json"); + return FileUtils.readFileToString(resultFile, StandardCharsets.UTF_8); + } + + public static void generateConfidentialContract(ContractNode cn, ScriptObjectMirror globalVars, Global global) { + List functionNodes = cn.getFunctions(); + for (FunctionNode fn : functionNodes) { + // assuming only one confidential function for now + if (fn.isConfidential()) { + StringBuilder jsStr = new StringBuilder(); + // find all dependent functions + Set dependentFunctions = findAllDependentFunctions(cn, fn); + // add self and all dependent function declaration + for (FunctionNode fNode : functionNodes) { + if (dependentFunctions.contains(fNode.functionName)) { + jsStr.append(fNode.plainText()).append("\n"); + } + } + // load necessary Node.js libraries + jsStr.append("var fs = require('fs');\n" + "var crypto = require('crypto');\n" + "var sm2 = require('sm-crypto').sm2;\n"); + // load Global variables and arguments from files + jsStr.append("let rawGlobal = fs.readFileSync('global.json').toString();\n" + "let Global = JSON.parse(rawGlobal);\n"); + jsStr.append("let rawArg = fs.readFileSync('arg.json').toString();\n" + "let jsonArg = JSON.parse(rawArg);\n" + "let requester = jsonArg.requester;\n" + "let arg = jsonArg.arg;\n"); + jsStr.append("let srcStr = fs.readFileSync('contract.js').toString();\n"); + // verify signatures and decrypt all confidential variables Important!!!!! + jsStr.append("for (var k in Global) {\n" + " if (Global.hasOwnProperty(k)) {\n" + " if (k.startsWith('conf_')) {\n" + " let sig = Global[k].signature;\n" + " let pubKey = Global[k].owner;\n" + " let verifyResult = sm2.doVerifySignature(srcStr, sig, pubKey);\n" + " if (verifyResult) {\n" + " let newKey = k.substring(5);\n" + " let decKey = Buffer.from(process.env['KEY_'+pubKey.substring(0,10).toUpperCase()], 'hex');\n" + " let decIv = Buffer.from(Global[k].iv, 'hex');\n" + " let cipherText = Buffer.from(Global[k].cipherText, 'hex');\n" + " let decipher = crypto.createDecipheriv('aes-256-cbc', decKey, decIv);\n" + " let decrypted = decipher.update(cipherText);\n" + " decrypted = Buffer.concat([decrypted, decipher.final()]);\n" + " let plaintext = decrypted.toString();\n" + " Global[newKey] = plaintext;\n" + " }\n" + " }\n" + " }\n" + "}\n"); + // call function + jsStr.append("var ret = ").append(fn.functionName).append("(arg, requester, null);\n"); + // TODO: encrypt all confidential variables so state can be updated in confidential function @shujunyi + // encrypt return value and write to a file + jsStr.append("var retStr = JSON.stringify(ret);\n" + "var key = Buffer.from(process.env['KEY_'+requester.substring(0,10).toUpperCase()], 'hex');\n" + "var iv = crypto.randomBytes(16);\n" + "let cipher = crypto.createCipheriv('aes-256-cbc', key, iv); \n" + "let encRet = cipher.update(retStr);\n" + "encRet = Buffer.concat([encRet, cipher.final()]);\n" + "let result = {iv: iv.toString('hex'), encryptedData: encRet.toString('hex')};\n" + "let resultStr = JSON.stringify(result);\n" + "fs.writeFileSync('result.json', resultStr);\n"); + // put script into Global so owner can send it and collect signatures + Object som = ScriptObjectMirror.wrap(jsStr.toString(), global); + globalVars.put("src_" + fn.functionName, som); + break; + } + } + } + + public static void copyTemplateToDestination(ContractRequest input) { + String dest = CONFIDENTIAL_SCRIPT_PATH + File.separator + input.getRequestID(); + File srcDir = new File(CONFIDENTIAL_TEMPLATE_PATH); + File destDir = new File(dest); + try { + FileUtils.copyDirectory(srcDir, destDir); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static void dumpScriptAndStates( + Invocable engine, + FunctionNode functionNode, + ContractRequest input, + ScriptObjectMirror globalVars) + throws IOException, ScriptException, NoSuchMethodException { + Map globalMap = (Map) convertIntoJavaObject(globalVars); + String dest = CONFIDENTIAL_SCRIPT_PATH + File.separator + input.getRequestID(); + // dump script + String jsStr = globalMap.remove("src_" + functionNode.functionName).toString(); + String scriptPath = dest + File.separator + "contract.js"; + BufferedWriter writer = new BufferedWriter(new FileWriter(scriptPath)); + writer.write(jsStr); + writer.close(); + // dump global variables + globalMap.remove("Resources"); + String globalStr = JsonUtil.toJson(globalMap); + String globalPath = dest + File.separator + "global.json"; + writer = new BufferedWriter(new FileWriter(globalPath)); + writer.write(globalStr); + writer.close(); + // dump arg and requester + Map argMap = new HashMap<>(); + argMap.put("arg", input.getArg()); + argMap.put("requester", input.getRequester()); + String argStr = JsonUtil.toJson(argMap); + String argPath = dest + File.separator + "arg.json"; + writer = new BufferedWriter(new FileWriter(argPath)); + writer.write(argStr); + writer.close(); + // generate manifest + String manifestStr = generateGrapheneManifestStr(engine, input); + String manifestPath = dest + File.separator + "nodejs.manifest.template"; + writer = new BufferedWriter(new FileWriter(manifestPath)); + writer.write(manifestStr); + writer.close(); + } + + private static Set findAllDependentFunctions(ContractNode cn, FunctionNode fn) { + Set dependentFunctions = fn.getDependentFunctions(); + for (String functionName : dependentFunctions) { + for (FunctionNode functionNode : cn.getFunctions()) { + if (functionNode.functionName.equals(functionName)) { + dependentFunctions.addAll(findAllDependentFunctions(cn, functionNode)); + } + } + } + dependentFunctions.add(fn.functionName); + return dependentFunctions; + } + + private static String generateGrapheneManifestStr(Invocable engine, ContractRequest input) throws ScriptException, NoSuchMethodException { + String manifestStr = "# Nodejs manifest file example\n" + + "#\n" + + "# This manifest was prepared and tested on Ubuntu 18.04.\n" + + "\n" + + "loader.argv0_override = \"nodejs\"\n" + + "\n" + + "# LibOS layer library of Graphene. There is currently only one implementation,\n" + + "# so it is always set to libsysdb.so.\n" + + "loader.preload = \"file:$(GRAPHENEDIR)/Runtime/libsysdb.so\"\n" + + "\n" + + "# Show/hide debug log of Graphene ('inline' or 'none' respectively).\n" + + "loader.debug_type = \"$(GRAPHENEDEBUG)\"\n" + + "\n" + + "# Read application arguments directly from the command line. Don't use this on production!\n" + + "loader.insecure__use_cmdline_argv = 1\n" + + "\n" + + "# Specify paths to search for libraries. The usual LD_LIBRARY_PATH syntax\n" + + "# applies. Paths must be in-Graphene visible paths, not host-OS paths (i.e.,\n" + + "# paths must be taken from fs.mount.xxx.path, not fs.mount.xxx.uri).\n" + + "loader.env.LD_LIBRARY_PATH = \"/lib:/usr/lib:$(ARCH_LIBDIR):/usr/$(ARCH_LIBDIR):./\"\n" + + "\n" + + "# Mount host-OS directory to required libraries (in 'uri') into in-Graphene\n" + + "# visible directory /lib (in 'path').\n" + + "fs.mount.lib.type = \"chroot\"\n" + + "fs.mount.lib.path = \"/lib\"\n" + + "fs.mount.lib.uri = \"file:$(GRAPHENEDIR)/Runtime\"\n" + + "\n" + + "fs.mount.lib2.type = \"chroot\"\n" + + "fs.mount.lib2.path = \"$(ARCH_LIBDIR)\"\n" + + "fs.mount.lib2.uri = \"file:$(ARCH_LIBDIR)\"\n" + + "\n" + + "#fs.mount.lib3.type = \"chroot\"\n" + + "#fs.mount.lib3.path = \"/usr/$(ARCH_LIBDIR)\"\n" + + "#fs.mount.lib3.uri = \"file:/usr/$(ARCH_LIBDIR)\"\n" + + "\n" + + "fs.mount.usr.type = \"chroot\"\n" + + "fs.mount.usr.path = \"/usr\"\n" + + "fs.mount.usr.uri = \"file:/usr\"\n" + + "\n" + + "# Host-level directory to NSS files required by Glibc + NSS libs\n" + + "fs.mount.etc.type = \"chroot\"\n" + + "fs.mount.etc.path = \"/etc\"\n" + + "fs.mount.etc.uri = \"file:/etc\"\n" + + "\n" + + "# Workload needs to create temporary files\n" + + "fs.mount.tmp.type = \"chroot\"\n" + + "fs.mount.tmp.path = \"/tmp\"\n" + + "fs.mount.tmp.uri = \"file:/tmp\"\n" + + "\n" + + "# Set enclave size to 2GB; NodeJS expects around 1.7GB of heap on startup,\n" + + "# see e.g. https://github.com/nodejs/node/issues/13018.\n" + + "# Recall that SGX v1 requires to specify enclave size at enclave creation time.\n" + + "sgx.enclave_size = \"2G\"\n" + + "\n" + + "# Set maximum number of in-enclave threads (somewhat arbitrarily) to 8. Recall\n" + + "# that SGX v1 requires to specify the maximum number of simultaneous threads at\n" + + "# enclave creation time.\n" + + "sgx.thread_num = 16\n" + + "\n" + + "# Specify all libraries used by Node.js and its dependencies (including all libs\n" + + "# which can be loaded at runtime via dlopen).\n" + + "sgx.trusted_files.ld = \"file:$(GRAPHENEDIR)/Runtime/ld-linux-x86-64.so.2\"\n" + + "sgx.trusted_files.libc = \"file:$(GRAPHENEDIR)/Runtime/libc.so.6\"\n" + + "sgx.trusted_files.libm = \"file:$(GRAPHENEDIR)/Runtime/libm.so.6\"\n" + + "sgx.trusted_files.libdl = \"file:$(GRAPHENEDIR)/Runtime/libdl.so.2\"\n" + + "sgx.trusted_files.librt = \"file:$(GRAPHENEDIR)/Runtime/librt.so.1\"\n" + + "sgx.trusted_files.libutil = \"file:$(GRAPHENEDIR)/Runtime/libutil.so.1\"\n" + + "sgx.trusted_files.libpthread = \"file:$(GRAPHENEDIR)/Runtime/libpthread.so.0\"\n" + + "sgx.trusted_files.libnssdns = \"file:$(GRAPHENEDIR)/Runtime/libnss_dns.so.2\"\n" + + "sgx.trusted_files.libresolv = \"file:$(GRAPHENEDIR)/Runtime/libresolv.so.2\"\n" + + "\n" + + "sgx.trusted_files.libstdc = \"file:/usr/$(ARCH_LIBDIR)/libstdc++.so.6\"\n" + + "sgx.trusted_files.libgccs = \"file:$(ARCH_LIBDIR)/libgcc_s.so.1\"\n" + + "sgx.trusted_files.libaptpkg = \"file:/usr/$(ARCH_LIBDIR)/libapt-pkg.so.5.0\"\n" + + "sgx.trusted_files.liblz4 = \"file:/usr/$(ARCH_LIBDIR)/liblz4.so.1\"\n" + + "sgx.trusted_files.libsystemd = \"file:$(ARCH_LIBDIR)/libsystemd.so.0\"\n" + + "sgx.trusted_files.libselinux = \"file:$(ARCH_LIBDIR)/libselinux.so.1\"\n" + + "sgx.trusted_files.libgcrypt = \"file:$(ARCH_LIBDIR)/libgcrypt.so.20\"\n" + + "sgx.trusted_files.libpcre = \"file:$(ARCH_LIBDIR)/libpcre.so.3\"\n" + + "sgx.trusted_files.libgpgerror = \"file:$(ARCH_LIBDIR)/libgpg-error.so.0\"\n" + + "sgx.trusted_files.libexpat = \"file:$(ARCH_LIBDIR)/libexpat.so.1\"\n" + + "sgx.trusted_files.libz = \"file:$(ARCH_LIBDIR)/libz.so.1\"\n" + + "sgx.trusted_files.libz2 = \"file:$(ARCH_LIBDIR)/libbz2.so.1.0\"\n" + + "sgx.trusted_files.liblzma = \"file:$(ARCH_LIBDIR)/liblzma.so.5\"\n" + + "sgx.trusted_files.libmpdec = \"file:/usr/$(ARCH_LIBDIR)/libmpdec.so.2\"\n" + + "\n" + + "# Name Service Switch (NSS) libraries (Glibc dependencies)\n" + + "sgx.trusted_files.libnssfiles = \"file:$(ARCH_LIBDIR)/libnss_files.so.2\"\n" + + "sgx.trusted_files.libnsscompat = \"file:$(ARCH_LIBDIR)/libnss_compat.so.2\"\n" + + "sgx.trusted_files.libnssnis = \"file:$(ARCH_LIBDIR)/libnss_nis.so.2\"\n" + + "sgx.trusted_files.libnsl = \"file:$(ARCH_LIBDIR)/libnsl.so.1\"\n" + + "sgx.trusted_files.libnssmyhostname = \"file:$(ARCH_LIBDIR)/libnss_myhostname.so.2\"\n" + + "sgx.trusted_files.libnssmdns = \"file:$(ARCH_LIBDIR)/libnss_mdns4_minimal.so.2\"\n" + + "\n" + + "# Scratch space\n" + + "sgx.allowed_files.tmp = \"file:/tmp\"\n" + + "\n" + + "# APT config files\n" + + "sgx.allowed_files.aptconfd = \"file:/etc/apt/apt.conf.d\"\n" + + "sgx.allowed_files.aptconf = \"file:/etc/apt/apt.conf\"\n" + + "sgx.allowed_files.apport = \"file:/etc/default/apport\"\n" + + "\n" + + "# Name Service Switch (NSS) files (Glibc reads these files)\n" + + "sgx.allowed_files.nsswitch = \"file:/etc/nsswitch.conf\"\n" + + "sgx.allowed_files.group = \"file:/etc/group\"\n" + + "sgx.allowed_files.passwd = \"file:/etc/passwd\"\n" + + "\n" + + "# DNS hostname resolution files (Glibc reads these files)\n" + + "sgx.allowed_files.hostconf = \"file:/etc/host.conf\"\n" + + "sgx.allowed_files.hosts = \"file:/etc/hosts\"\n" + + "sgx.allowed_files.gaiconf = \"file:/etc/gai.conf\"\n" + + "sgx.allowed_files.resolv = \"file:/etc/resolv.conf\"\n" + + "\n" + + "sgx.allowed_files.openssl = \"file:/etc/ssl/openssl.cnf\"\n" + + "\n" + + "# System's file system table\n" + + "sgx.allowed_files.fstab = \"file:/etc/fstab\"\n" + + "\n" + + "$(NODEJS_TRUSTED_LIBS)\n" + + "\n" + + "# JavaScript (trusted)\n" + + "sgx.allowed_files.smlib = \"file:node_modules\"\n" + + "sgx.trusted_files.npminfo = \"file:package.json\"\n" + + "sgx.trusted_files.contract = \"file:contract.js\"\n" + + "sgx.trusted_files.globaljson = \"file:global.json\"\n" + + "sgx.trusted_files.argjson = \"file:arg.json\"\n" + + "\n" + + "sys.insecure__allow_eventfd = 1\n" + + "\n" + + "sgx.remote_attestation = 1\n" + + "\n" + + "loader.env.LD_PRELOAD = \"libsecret_prov_attest.so\"\n" + + "loader.env.SECRET_PROVISION_CONSTRUCTOR = \"1\"\n" + + "loader.env.SECRET_PROVISION_SET_PF_KEY = \"1\"\n" + + "loader.env.SECRET_PROVISION_CA_CHAIN_PATH = \"certs/test-ca-sha256.crt\"\n" + + "loader.env.SECRET_PROVISION_SERVERS = \"localhost:4433\"\n" + + "\n" + + "sgx.trusted_files.libsecretprovattest = \"file:libsecret_prov_attest.so\"\n" + + "sgx.trusted_files.cachain = \"file:certs/test-ca-sha256.crt\"\n" + + "\n" + + "# Specify your SPID and linkable/unlinkable attestation policy\n" + + "sgx.ra_client_spid = \"DF3A8BA098E93F66CC64E8A215E98333\"\n" + + "sgx.ra_client_linkable = 0\n"; + // add secret servers + manifestStr += "loader.env.SECRET_PROVISION_CC_SERVERS = "; + Object resultStr = engine.invokeFunction( + "getAllSecret", + "", + input.getRequester(), + input.getRequesterDOI()); + Map resultMap = JsonUtil.fromJson(resultStr.toString(), MapType); + Map serverMap = JsonUtil.fromJson(resultMap.get("result"), MapType); + List entries = new ArrayList<>(); + for (Map.Entry entry : serverMap.entrySet()) { + String key = entry.getKey(); + String server = entry.getValue(); + String envVar = "KEY_" + key.substring(0, 10).toUpperCase(); + entries.add(envVar + "=" + server); + } + manifestStr += "\"" + String.join(";", entries) + "\""; + return manifestStr; + } + + private static Object convertIntoJavaObject(Object scriptObj) { + if (scriptObj instanceof ScriptObjectMirror) { + ScriptObjectMirror scriptObjectMirror = (ScriptObjectMirror) scriptObj; + if (scriptObjectMirror.isArray()) { + List list = new ArrayList<>(); + for (Map.Entry entry : scriptObjectMirror.entrySet()) { + list.add(convertIntoJavaObject(entry.getValue())); + } + return list; + } else { + Map map = new HashMap<>(); + for (Map.Entry entry : scriptObjectMirror.entrySet()) { + map.put(entry.getKey(), convertIntoJavaObject(entry.getValue())); + } + return map; + } + } else { + return scriptObj; + } + } +} diff --git a/src/main/java/org/bdware/sc/engine/DesktopEngine.java b/src/main/java/org/bdware/sc/engine/DesktopEngine.java new file mode 100644 index 0000000..4a6306c --- /dev/null +++ b/src/main/java/org/bdware/sc/engine/DesktopEngine.java @@ -0,0 +1,884 @@ +package org.bdware.sc.engine; + +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; +import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.bdware.analysis.BasicBlock; +import org.bdware.analysis.CFGraph; +import org.bdware.analysis.gas.Evaluates; +import org.bdware.analysis.gas.PPCount; +import org.bdware.sc.ContractProcess; +import org.bdware.sc.ContractResult; +import org.bdware.sc.ContractResult.Status; +import org.bdware.sc.JSEngine; +import org.bdware.sc.bean.Contract; +import org.bdware.sc.bean.ContractRequest; +import org.bdware.sc.bean.ProjectConfig; +import org.bdware.sc.boundry.JavaScriptEntry; +import org.bdware.sc.boundry.Resources; +import org.bdware.sc.boundry.utils.UtilRegistry; +import org.bdware.sc.encrypt.HardwareInfo; +import org.bdware.sc.encrypt.HardwareInfo.OSType; +import org.bdware.sc.event.Event; +import org.bdware.sc.event.REvent; +import org.bdware.sc.event.REvent.REventSemantics; +import org.bdware.sc.node.*; +import org.bdware.sc.syncMech.SyncType; +import org.bdware.sc.trace.ProgramPointCounter; +import org.bdware.sc.util.JsonUtil; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.tree.MethodNode; +import wrp.jdk.nashorn.api.scripting.NashornScriptEngine; +import wrp.jdk.nashorn.api.scripting.NashornScriptEngineFactory; +import wrp.jdk.nashorn.api.scripting.ScriptObjectMirror; +import wrp.jdk.nashorn.internal.objects.Global; +import wrp.jdk.nashorn.internal.runtime.*; + +import javax.script.*; +import java.io.*; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.*; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +public class DesktopEngine extends JSEngine { + private static final String ScriptFileName = "contract_main.yjs"; + private static final Logger LOGGER = LogManager.getLogger(DesktopEngine.class); + public static boolean _with_init_script = true; + // static String script = ""; + public NashornScriptEngine engine; + public SyncMechUtil syncUtil; + public boolean recovering; // 如果正在通过trace、trans恢复,设置为true,此时即使是StableMode也不记录 + Resources resources; + // Class clz; + // byte[] stub; + YJSClassLoader classLoader; + private ContractNode cn; + private Global global; + // private Object obj; + // private SimpleScriptContext simpleContext; + // private String traceDir; + private ContractProcess.Logger tracePS = null; + private Contract contract; + + public DesktopEngine() { + startEngine(); + } + + public DesktopEngine(ContractManifest manifest, String zipPath, Contract contract) { + File zipFile = new File(zipPath); + String dirName = zipFile.getName().replaceAll(".zip$", "").replaceAll(".ypk$", ""); + File traceDirFile = new File(zipFile.getParent(), dirName); + + this.contract = contract; + if (!traceDirFile.exists()) { + // traceDirFile.mkdirs(); + } + // traceDir = traceDirFile.getAbsolutePath(); + startEngine(); + } + + public static void applyWithGlobal(ScriptFunction script, Global global, Object... obj) { + Global oldGlobal = Context.getGlobal(); + boolean globalChanged = (oldGlobal != global); + try { + if (globalChanged) { + Context.setGlobal(global); + } + // System.out.println("[DesktopEngine]" + script.getName() + " -->\n" + + // script.safeToString()); + ScriptRuntime.apply(script, global, obj); + + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (globalChanged) { + Context.setGlobal(oldGlobal); + } + } + } + + public void setRecovering(boolean b) { + recovering = b; + } + + public NashornScriptEngine getNashornEngine() { + return engine; + } + + public Global getDesktopGlobal() { + return global; + } + + public YJSClassLoader getClassLoad() { + return classLoader; + } + + public void redirectTracePS(ContractProcess.Logger ps) { + TraceType.ps = tracePS = (ps); + if (ps instanceof TraceMethod) { + TraceType.mTracer = (TraceMethod) ps; + } + } + + private void startEngine() { + try { + syncUtil = new SyncMechUtil(this); + ClassLoader ccl = Thread.currentThread().getContextClassLoader(); + ccl = (ccl == null) ? NashornScriptEngineFactory.class.getClassLoader() : ccl; + String[] args = new String[]{"--loader-per-compile=false", "-strict=false"}; + classLoader = new YJSClassLoader(ccl, new YJSFilter()); + engine = + (NashornScriptEngine) + new NashornScriptEngineFactory() + .getScriptEngine( + args, // "--print-ast", + // "true", + // "-d=/Users/huaqiancai/Downloads/dumpedClz", + // "--trace-callsites=enterexit" + // "--log=methodhandles:all", + // fields:all, + // "--print-parse", "true" "--print-code", + // fields:finest + classLoader); + + Context.TRACEIF = false; + // engine = (NashornScriptEngine) new + // NashornScriptEngineFactory().getScriptEngine(new YJSFilter()); + if (_with_init_script) { + InputStream in = + DesktopEngine.class + .getClassLoader() + .getResourceAsStream("org/bdware/sc/engine/yancloud_desktop.js"); + assert in != null; + InputStreamReader streamReader = new InputStreamReader(in); + engine.getContext() + .setAttribute( + ScriptEngine.FILENAME, + "org/bdware/sc/engine/yancloud_desktop.js", + ScriptContext.ENGINE_SCOPE); + engine.eval(streamReader); + } + global = engine.getNashornGlobal(); + JavaScriptEntry.currentEngine = engine; + JavaScriptEntry.currentSyncUtil = syncUtil; + } catch (ScriptException e) { + e.printStackTrace(); + } + } + + public void initStubClasses() { + UtilRegistry.defineUtilClass(classLoader); + } + + public void setPermission(List setPermission) { + initStubClasses(); + try { + StringBuilder yancloud_desktop = new StringBuilder(); + List permissionStub = Permission.allName(); + for (Permission permission : setPermission) { + yancloud_desktop.append(UtilRegistry.getInitStr(permission.name(), true)); + permissionStub.remove(permission.name()); + } + for (String str : permissionStub) { + yancloud_desktop.append(UtilRegistry.getInitStr(str, false)); + } + // LOGGER.debug("[initScript] " + yancloud_desktop); + engine.getContext() + .setAttribute( + ScriptEngine.FILENAME, + yancloud_desktop.toString(), + ScriptContext.ENGINE_SCOPE); + engine.eval(yancloud_desktop.toString()); + } catch (ScriptException e) { + e.printStackTrace(); + } + } + + // byte[]中是字节码 + public Map dumpClass() { + ScriptLoader loader = engine.getNashornContext().getScriptLoader(); + Map clzCache = loader.getClzCache(); + Map ret = new HashMap<>(clzCache); + // for (String str : clzCache.keySet()) { + // System.out.println("===ScriptClzName:" + str); + // } + StructureLoader sLoader = (StructureLoader) (engine.getNashornContext().getStructLoader()); + clzCache = sLoader.getClzCache(); + // for (String str : clzCache.keySet()) { + // System.out.println("===StructureClzName:" + str); + // } + ret.putAll(clzCache); + return ret; + } + + public void registerResource(Resources resources) { + Invocable cal = engine; + this.resources = resources; + try { + cal.invokeFunction("defineProp", "Resources", resources); + } catch (NoSuchMethodException | ScriptException e) { + e.printStackTrace(); + } + } + + public Resources getResources() { + return this.resources; + } + + @Override + public ContractResult loadContract( + Contract contract, ContractNode contractNode, boolean isInsnLimit) { + LOGGER.info("loadContract isInsnLimit:" + isInsnLimit); + cn = contractNode; + engine.getContext() + .setAttribute(ScriptEngine.FILENAME, ScriptFileName, ScriptContext.ENGINE_SCOPE); + try { + setPermission(cn.getPermission()); + } catch (Exception e) { + e.printStackTrace(); + } + + for (FunctionNode fun : contractNode.getFunctions()) + try { + String str = fun.plainText(); + engine.getContext() + .setAttribute( + ScriptEngine.FILENAME, + fun.getFileName(), + ScriptContext.ENGINE_SCOPE); + compileFunction(str, isInsnLimit); + } catch (ScriptException e) { + return wrapperException(e, fun); + } catch (Exception e) { + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + e.printStackTrace(new PrintStream(bo)); + e.printStackTrace(); + return new ContractResult(Status.Error, new JsonPrimitive(bo.toString())); + } + LOGGER.debug(JsonUtil.toJson(contractNode.events)); + for (String event : contractNode.events.keySet()) { + try { + String str; + REventSemantics semantics = contractNode.events.get(event); + if (REventSemantics.AT_LEAST_ONCE.equals(semantics)) { + str = + String.format( + "function %s(arg) { YancloudUtil.pubEvent(\"%s\", arg); }", + event, event); + } else { + str = + String.format( + "function %s(arg) { YancloudUtil.pubEventConstraint(\"%s\", arg, \"%s\"); }", + event, event, semantics.name()); + } + compileFunction(str, false); + str = + String.format( + "function %ss(arg0, arg1) { YancloudUtil.pubEventConstraint(\"%s\", arg0, arg1); }", + event, event); + compileFunction(str, false); + } catch (ScriptException e) { + e.printStackTrace(); + } + } + for (ClassNode cn : contractNode.getClzs()) { + try { + System.out.println(cn.plainText()); + // engine.eval(cn.plainText()); + } catch (Exception e) { + // return wrapperException(e, cn.getFileName(), cn.getLine(), + // cn.getPos()); + } + } + ScriptObjectMirror globalVars = (ScriptObjectMirror) engine.get("Global"); + ConfidentialContractUtil.generateConfidentialContract(cn, globalVars, global); + ContractResult cResult = + new ContractResult(Status.Success, new JsonPrimitive(contract.getPublicKey())); + cResult.isInsnLimit = isInsnLimit; + return cResult; + } + + // /** + // * Load a contract into contract engine + // * + // * @param contractNode a contract node generated by YJS compiler + // * @return whether contract is loaded successfully + // */ + // @Override + // public ContractResult loadContract(Contract contract, ContractNode contractNode) { + // cn = contractNode; + // engine.getContext() + // .setAttribute(ScriptEngine.FILENAME, ScriptFileName, + // ScriptContext.ENGINE_SCOPE); + // try { + // setPermission(cn.getPermission()); + // } catch (Exception e) { + // e.printStackTrace(); + // } + // + // for (FunctionNode fun : cn.getFunctions()) { + // try { + // String str = fun.plainText(); + // engine.getContext() + // .setAttribute( + // ScriptEngine.FILENAME, + // fun.getFileName(), + // ScriptContext.ENGINE_SCOPE); + // Object scriptFunction = engine.eval(str); + // ScriptObjectMirror sf = (ScriptObjectMirror) scriptFunction; + // compileFunction(sf, fun.getLogTypes().contains(LogType.Branch)); + // } catch (ScriptException e) { + // return wrapperException(e, fun); + // } catch (Exception e) { + // ByteArrayOutputStream bo = new ByteArrayOutputStream(); + // e.printStackTrace(new PrintStream(bo)); + // e.printStackTrace(); + // return new ContractResult(Status.Error, new JsonPrimitive(bo.toString())); + // } + // } + // for (String event : cn.events) { + // String str = + // "function " + // + event + // + "(arg){ return YancloudUtil.pubEvent(\"" + // + event + // + "\",arg);}"; + // + // try { + // Object scriptFunction = engine.eval(str); + // ScriptObjectMirror sf = (ScriptObjectMirror) scriptFunction; + // compileFunction(sf, false); + // } catch (ScriptException e) { + // e.printStackTrace(); + // } + // } + // + // for (ClassNode classNode : cn.getClzs()) { + // try { + // System.out.println(classNode.plainText()); + // // engine.eval(cn.plainText()); + // } catch (Exception e) { + // // return wrapperException(e, cn.getFileName(), cn.getLine(), + // // cn.getPos()); + // } + // } + // + // // dump confidential functions and corresponding dependent functions to a String in + // Global + // // variable. + // // The String will be passed to collect signature. + // + // return new ContractResult(Status.Success, new JsonPrimitive("")); + // } + private void compileFunction(ScriptObjectMirror sf, boolean instrumentBranch) { + Global oldGlobal = Context.getGlobal(); + boolean globalChanged = (oldGlobal != global); + try { + if (globalChanged) { + Context.setGlobal(global); + } + if (instrumentBranch) { + Context.TRACEIF = true; + Context.TRACEMETHOD = true; + } + sf.compileScriptFunction(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (globalChanged) Context.setGlobal(oldGlobal); + Context.TRACEIF = false; + } + } + + private void compileFunction(String snippet, boolean instrumentBranch) throws ScriptException { + compileFunction((ScriptObjectMirror) engine.eval(snippet), instrumentBranch); + } + + @Override + public synchronized ContractResult executeContract(ContractRequest input) { + ContractProcess.Logger previous = this.getTracePS(); + ByteArrayOutputStream bo = null; + if (syncUtil.startFlag && syncUtil.currType == SyncType.Trace && !recovering) { + syncUtil.traceRecordUtil.startNext(); + } else if (syncUtil.startFlag && syncUtil.currType == SyncType.Trans && !recovering) { + if (input.needSeq) { + syncUtil.transRecordUtil.startNext(input.getAction(), input.getArg(), input.seq); + } else { + syncUtil.transRecordUtil.startNext(input.getAction(), input.getArg()); + } + } + // TODO remove this in executeContract, using getFunctionNodes in ContractManger instead. + if (input.getAction().equals("getFunctionNodes")) { + return getFunctionNodes(); + } + JavaScriptEntry.msgList = new ArrayList<>(); + FunctionNode fun = cn.getFunction(input.getAction()); + ProgramPointCounter ppc = null; + try { + if (fun.getCost() != null && fun.getCost().isCountGas()) { + List functions = new ArrayList<>(); + for (FunctionNode fn : cn.getFunctions()) { + if (fn.isExport()) { + functions.add(fn.functionName); + } + } + int functionIndex = functions.indexOf(input.getAction()); + // TODO calculate ppCountMap at loading time? + HashMap ppCountMap = evaluatesAnalysis(input.getAction(), functions); + Long extraGas = getExtraGas(fun.getCost().getExtraGas(), input); + bo = new ByteArrayOutputStream(); + ppc = + new ProgramPointCounter( + bo, + previous.getCp(), + Long.MAX_VALUE, + functionIndex, + input.getGasLimit(), + extraGas, + input.getAction(), + ppCountMap); + this.redirectTracePS(ppc); + } + Invocable cal = engine; + if (fun.isExport() + // if the function has been registered as event handler + || (fun.isHandler() + && (input.getRequester().length() == 40 + || input.getRequester().equals("event")))) { + Object ret = null; + // long start = System.currentTimeMillis(); + + for (AnnotationHook handler : fun.beforeExecutionAnnotations()) { + + ret = handler.handle(input, this, ret); + } + // actually invoke! + if (ret == null) { + ret = + cal.invokeFunction( + input.getAction(), + (fun.isHandler() + ? JsonUtil.fromJson(input.getArg(), Event.class) + : input.getArg()), + input.getRequester(), + input.getRequesterDOI()); + } + for (AnnotationHook handler : fun.afterExecutionAnnotations()) { + //Mask在after裏面 + //System.out.println("afterHook"+contract.Mask); + + ret = handler.handle(input, this, ret); + } + //System.out.println("[DesktopEngine MaskConfig]"+ContractProcess.instance.getProjectConfig().getMaskConfig().config.toString()); + ContractResult contractRes = new ContractResult(Status.Success, (JsonElement) ret); + if (ppc != null) { + contractRes.extraGas = ppc.extraGas; + contractRes.executionGas = ppc.cost; + contractRes.totalGas = ppc.extraGas + ppc.cost; + } + if (bo != null) { + contractRes.analysis = bo.toString(); + } + + if (fun.getLogTypes().contains(LogType.Branch)) { + contractRes.branch = tracePS.getOutputStr(); + } + + List msgList = JavaScriptEntry.msgList; + JavaScriptEntry.msgList = null; + if (!msgList.isEmpty()) { + contractRes.events = msgList; + contractRes.eventRelated = true; + } + + if (fun.isHandler() && input.getRequester().length() == 40) { + contractRes.eventRelated = true; + } + if (syncUtil.startFlag && !recovering) { + switch (syncUtil.currType) { + case Trace: + syncUtil.traceRecordUtil.eachFinish(); + break; + case Trans: + syncUtil.transRecordUtil.eachFinish(); + break; + case Memory: + default: + break; + } + } + + return contractRes; + } else { + // return new ContractResult(Status.Exception, "Action " + input.getAction() + " + // is not exported!"); + return new ContractResult( + Status.Exception, + new JsonPrimitive("Action " + input.getAction() + " is not exported!")); + } + + } catch (ScriptException e) { + Throwable cause = e.getCause(); + e.printStackTrace(); + return new ContractResult( + Status.Exception, + new JsonPrimitive(extractException(e.getMessage(), extract(cn, cause)))); + } catch (Throwable e) { + ByteArrayOutputStream bo1 = new ByteArrayOutputStream(); + PrintStream ps = new PrintStream(bo1); + e.printStackTrace(ps); + e.printStackTrace(); + if (e.getCause() != null && e.getCause() instanceof ScriptException) { + return new ContractResult( + Status.Exception, + new JsonPrimitive( + extractException(bo1.toString(), extract(cn, e.getCause())))); + } else { + return new ContractResult( + Status.Exception, + new JsonPrimitive(extractException(bo1.toString(), extract(cn, e)))); + } + } finally { + this.redirectTracePS(previous); + } + } + + private String extractException(String msg, List stack) { + int endIndex = Math.min(msg.indexOf("in"), msg.length()); + StringBuilder msb = new StringBuilder(msg.substring(0, endIndex)); + for (String str : stack) { + msb.append("\n").append(str); + } + return msb.toString(); + } + + private HashMap evaluatesAnalysis(String getFunction, List functions) { + // System.out.println("当前的function:" + getFunction); + HashMap CFGmap = new HashMap<>(); + HashMap ppCountMap = new HashMap<>(); + Map clzs = this.dumpClass(); + Map methods = new HashMap<>(); + for (byte[] clz : clzs.values()) { + org.objectweb.asm.tree.ClassNode classNode = new org.objectweb.asm.tree.ClassNode(); + ClassReader cr = new ClassReader(clz); + cr.accept(classNode, ClassReader.EXPAND_FRAMES); + for (MethodNode mn : classNode.methods) { + methods.put(mn.name, mn); + } + } + int flag = 0; + for (String function : functions) { + MethodNode mn = methods.get(function); + if (mn != null) { + CFGraph cfg = + new CFGraph(mn) { + @Override + public BasicBlock getBasicBlock(int id) { + return new BasicBlock(id); + } + }; + // cfg.printSelf(); + CFGmap.put(function, cfg); + PPCount countFee = new PPCount(cfg, flag); + + BasicBlock bb = cfg.getBasicBlockAt(0); + countFee.dfs(cfg, bb); + // System.out.println("[ppmap]:" + PPCount.ppMap); + // System.out.println("[PPCount.branchCount]"+PPCount.branchCount); + Evaluates feEvaluates = new Evaluates(); + feEvaluates.getGas(PPCount.branchCount); + feEvaluates.getInsnGas(PPCount.ppMap); + + PPCount.countFunction(function, Evaluates.map); + ppCountMap = Evaluates.map; + // System.out.println("+++++++" + PPCount.ppMap); + flag++; + } + } + /* for (Map.Entry map : PPCount.functionSumGas.entrySet()) { + if (map.getKey().contains(getFunction) && map.getKey().contains("true")) { + System.out.println("[合约方法pub中条件循环为true时:]" + map.getValue()); + } else if (map.getKey().contains(getFunction) && map.getKey().contains("false")) { + System.out.println("[合约方法pub中条件循环为false时:]" + map.getValue()); + } else if (map.getKey().contains(getFunction)) { + System.out.println("[合约方法pub中其他语句消耗:]" + map.getValue()); + } + }*/ + return ppCountMap; + } + + private Long getExtraGas(String costFunction, ContractRequest input) + throws ScriptException, NoSuchMethodException { + if (costFunction == null || costFunction.equals("")) { + return 0L; + } + Invocable cal = engine; + Object ret = + cal.invokeFunction( + costFunction, + input.getArg(), + input.getRequester(), + input.getRequesterDOI()); + if (ret != null && StringUtils.isNumeric(ret.toString())) { + return Long.parseLong(ret.toString()); + } else { + return 0L; + } + } + + private ContractResult getFunctionNodes() { + String msg = JsonUtil.toJson(cn.getFunctions()); + return new ContractResult(Status.Exception, new JsonPrimitive(msg)); + } + + private void dump(Class clz) { + try { + String name = clz.getCanonicalName().replace(".", "/") + ".class"; + System.out.println("DumpClzz:" + clz.getCanonicalName() + " -->" + name); + name = "/Script.class"; + + InputStream input = clz.getClassLoader().getResourceAsStream(name); + FileOutputStream fout = + new FileOutputStream("./output/" + clz.getCanonicalName() + ".class"); + byte[] arr = new byte[1024]; + int l; + assert input != null; + while ((l = input.read(arr)) > 0) { + fout.write(arr, 0, l); + } + fout.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private LinkedHashMap getClassCache(Context c) { + try { + Field f = c.getClass().getDeclaredField("classCache"); + f.setAccessible(true); + Object classCache = f.get(c); + return (LinkedHashMap) classCache; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + private ContractResult wrapperException(ScriptException e, FunctionNode fun) { + int line = fun.getLine(); + int pos = fun.getPos(); + StringBuilder content = new StringBuilder(); + String message = e.getMessage(); + message = message.replaceFirst("^[^:]*:[^:]*:[^ ]* ", ""); + int actLine = e.getLineNumber(); + if (actLine != -1) { + actLine += line - 1; + } + message = + message.replaceAll( + "at line number " + e.getLineNumber(), "at line number " + (actLine)); + if (fun.getFileName() != null) + message = message.replace("in contract_main.yjs", "in " + fun.getFileName()); + content.append(message); + content.append("("); + if (fun.functionName != null) content.append(fun.functionName); + else content.append("contract_main.yjs"); + content.append(":"); + + content.append(actLine); + content.append(":").append(pos).append(")"); + return new ContractResult(Status.Exception, new JsonPrimitive(content.toString())); + } + + private List extract(ContractNode c, Throwable cause) { + StackTraceElement[] stack = cause.getStackTrace(); + List ret = new ArrayList<>(); + for (StackTraceElement element : stack) { + + if (element == null || element.getFileName() == null) { + continue; + } + String methodName = element.getMethodName(); + String fileName = element.getFileName(); + + if (fileName.endsWith(".java")) continue; + if (c.isBundle()) { + fileName = fixFile(c, methodName); + } + if (fileName.equals("--")) continue; + ret.add( + String.format( + "at %s(%s:%d)", + methodName, + fileName, + (fixLine(c, methodName) + element.getLineNumber()))); + } + return ret; + } + + private String fixFile(ContractNode c, String methodName) { + return c.queryFile(methodName); + } + + private int fixLine(ContractNode c, String methodName) { + return c.queryLine(methodName) - 1; + } + + public Global getGlobal() { + return engine.getNashornGlobal(); + } + + @Override + public Object eval(String script, ScriptContext context) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Object eval(Reader reader, ScriptContext context) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Object eval(String script) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Object eval(Reader reader) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Object eval(String script, Bindings n) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Object eval(Reader reader, Bindings n) { + // TODO Auto-generated method stub + return null; + } + + @Override + public void put(String key, Object value) { + // TODO Auto-generated method stub + + } + + @Override + public Object get(String key) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Bindings getBindings(int scope) { + // TODO Auto-generated method stub + return null; + } + + @Override + public void setBindings(Bindings bindings, int scope) { + // TODO Auto-generated method stub + + } + + @Override + public Bindings createBindings() { + // TODO Auto-generated method stub + return null; + } + + @Override + public ScriptContext getContext() { + // TODO Auto-generated method stub + return null; + } + + @Override + public void setContext(ScriptContext context) { + // TODO Auto-generated method stub + + } + + @Override + public ScriptEngineFactory getFactory() { + // TODO Auto-generated method stub + return null; + } + + public void loadJar(ZipFile zf) { + YJSClassLoader loader = getAppLoader(); + Enumeration entries = zf.entries(); + while (entries.hasMoreElements()) { + ZipEntry entry = entries.nextElement(); + if (entry.isDirectory()) { + continue; + } + try { + assert null != loader; + if (entry.getName().endsWith(".jar")) { + System.out.println("[DesktopEngine] loadJar:" + entry.getName()); + System.out.println("[DesktopEngine] classLoader:" + getClassLoad()); + + loader.loadJar(zf.getInputStream(entry), entry.getName().replaceAll(".*/", "")); + } + if (entry.getName().endsWith(".so") || entry.getName().endsWith(".so.1")) { + System.out.println("unzip library:" + entry.getName().replaceAll(".*/", "")); + loader.unzipLibrary( + zf.getInputStream(entry), entry.getName().replaceAll(".*/", "")); + } + if (HardwareInfo.type == OSType.mac && entry.getName().endsWith(".dylib")) { + System.out.println("unzip library:" + entry.getName().replaceAll(".*/", "")); + loader.unzipLibrary( + zf.getInputStream(entry), entry.getName().replaceAll(".*/", "")); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + if (null != loader) { + loader.loadLibraries(); + } + } + + private YJSClassLoader getAppLoader() { + try { + Field f = engine.getClass().getDeclaredField("nashornContext"); + f.setAccessible(true); + Context c = (Context) f.get(engine); + Method m = Context.class.getDeclaredMethod("getAppLoader"); + m.setAccessible(true); + return (YJSClassLoader) m.invoke(c); + } catch (Exception e) { + e.printStackTrace(); + } + // TODO Auto-generated method stub + return null; + } + + public void initManifest(ContractManifest manifest) { + // TODO Auto-generated method stub + } + + public ContractProcess.Logger getTracePS() { + return tracePS; + } + + public Contract getContract() { + return this.contract; + } + + public ProjectConfig getProjectConfig() { + return ContractProcess.instance.getProjectConfig(); + } +} diff --git a/src/main/java/org/bdware/sc/engine/JSONTool.java b/src/main/java/org/bdware/sc/engine/JSONTool.java new file mode 100644 index 0000000..3b9e2de --- /dev/null +++ b/src/main/java/org/bdware/sc/engine/JSONTool.java @@ -0,0 +1,101 @@ +package org.bdware.sc.engine; + +import com.google.gson.*; + +import wrp.jdk.nashorn.api.scripting.ScriptObjectMirror; + +import java.util.HashSet; +import java.util.Set; + +public class JSONTool { + private static Set recorded = null; + + public static JsonElement copy(ScriptObjectMirror ret2) { + recorded = new HashSet<>(); + JsonElement jsonElement = copyInternal(ret2); + recorded.clear(); + ; + return jsonElement; + } + + private static JsonElement copyInternal(Object obj) { + if (recorded.contains(obj)) return JsonNull.INSTANCE; + if (obj == null) return JsonNull.INSTANCE; + if (obj.getClass() == wrp.jdk.nashorn.internal.runtime.Undefined.class) + return JsonNull.INSTANCE; + if (obj.getClass() == ScriptObjectMirror.class) { + recorded.add(obj); + ScriptObjectMirror som = (ScriptObjectMirror) obj; + if (som.isFunction()) { + return JsonNull.INSTANCE; + } + if (som.isArray()) { + JsonArray jarray = new JsonArray(); + + for (String str : som.getOwnKeys(true)) { + try { + if (Integer.parseInt(str) >= 0) + jarray.add(copyInternal(som.getMember(str))); + } catch (Exception e) { + // System.out.println("[JSONTool] ignore key:"+str); + } + } + return jarray; + } else { + JsonObject jo = new JsonObject(); + for (String str : som.getOwnKeys(true)) { + jo.add(str, copyInternal(som.getMember(str))); + } + return jo; + } + } else if (obj.getClass() == jdk.nashorn.api.scripting.ScriptObjectMirror.class) { + recorded.add(obj); + jdk.nashorn.api.scripting.ScriptObjectMirror som = + (jdk.nashorn.api.scripting.ScriptObjectMirror) obj; + if (som.isFunction()) { + return JsonNull.INSTANCE; + } + if (som.isArray()) { + JsonArray jarray = new JsonArray(); + + for (String str : som.getOwnKeys(true)) { + try { + if (Integer.parseInt(str) >= 0) + jarray.add(copyInternal(som.getMember(str))); + } catch (Exception e) { + // System.out.println("[JSONTool] ignore key:"+str); + } + } + return jarray; + } else { + JsonObject jo = new JsonObject(); + for (String str : som.getOwnKeys(true)) { + jo.add(str, copyInternal(som.getMember(str))); + } + return jo; + } + } else if (obj.getClass() == jdk.internal.dynalink.beans.StaticClass.class) { + return JsonNull.INSTANCE; + } else if (obj instanceof Number) { + return new JsonPrimitive((Number) obj); + + } else if (obj instanceof String) { + return new JsonPrimitive((String) obj); + + } else if (obj instanceof Character) { + return new JsonPrimitive((Character) obj); + } + if (obj instanceof Boolean) { + return new JsonPrimitive((Boolean) obj); + } + return JsonNull.INSTANCE; + } + + public static JsonElement copy(jdk.nashorn.api.scripting.ScriptObjectMirror res) { + recorded = new HashSet<>(); + JsonElement jsonElement = copyInternal(res); + recorded.clear(); + ; + return jsonElement; + } +} diff --git a/src/main/java/org/bdware/sc/engine/SyncMechUtil.java b/src/main/java/org/bdware/sc/engine/SyncMechUtil.java new file mode 100644 index 0000000..1ffe897 --- /dev/null +++ b/src/main/java/org/bdware/sc/engine/SyncMechUtil.java @@ -0,0 +1,301 @@ +package org.bdware.sc.engine; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.bdware.sc.memory.MemoryDumpUtil; +import org.bdware.sc.memory.MemoryRecoverUtil; +import org.bdware.sc.redo.TransRecordUtil; +import org.bdware.sc.redo.TransRecoverUtil; +import org.bdware.sc.syncMech.SyncRecord; +import org.bdware.sc.syncMech.SyncType; +import org.bdware.sc.trace.TraceRecordUtil; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Random; +import java.util.concurrent.atomic.AtomicInteger; + +/* + * 决策使用什么机制记录 + */ +public class SyncMechUtil { + private static final Logger LOGGER = LogManager.getLogger(SyncMechUtil.class); + public AtomicInteger filedTrans; // 记录到文件中的trans数 + + public Boolean startFlag = false; + public List syncRecords; + // public List syncRecoverRecords; + public SyncType currType; + + public MemoryDumpUtil memoryDumpUtil; + public MemoryRecoverUtil memoryRecoverUtil; + public TraceRecordUtil traceRecordUtil; + // public TraceRecoverUtil traceRecoverUtil; + public TransRecordUtil transRecordUtil; + public TransRecoverUtil transRecoverUtil; + + public DesktopEngine engine; + public String contractID; + public String syncFileName; + public String dir; + public String memoryDir; + public String traceDir; + public String transDir; + public String syncDir; + public String crDir; // ContractRecord dir + + public SyncMechUtil(DesktopEngine en) { + this.engine = en; + } + + /* + * 路径操作 + */ + public void setDir(String str) { + this.dir = str; + String[] strs = str.split("/"); + this.contractID = strs[strs.length - 1]; + setMemoryDir(dir + "memory"); + setTraceDir(dir + "trace"); + setTransDir(dir + "trans"); + setSyncDir(dir + "sync"); + setCrDir(dir + "cr"); + } + + public void setMemoryDir(String dir) { + this.memoryDir = dir; + File f = new File(memoryDir); + if (!f.exists()) { + f.mkdirs(); + } + } + + public void setTraceDir(String dir) { + this.traceDir = dir; + File f = new File(traceDir); + if (!f.exists()) { + f.mkdirs(); + } + } + + public void setTransDir(String dir) { + this.transDir = dir; + File f = new File(transDir); + if (!f.exists()) { + f.mkdirs(); + } + } + + public void setSyncDir(String dir) { + this.syncDir = dir; + File f = new File(syncDir); + if (!f.exists()) { + f.mkdirs(); + } + } + + public void setCrDir(String dir) { + this.crDir = dir; + File f = new File(crDir); + if (!f.exists()) { + f.mkdirs(); + } + } + + public void clearAllFiles() { + File file = new File(syncDir); + if (file.isDirectory()) { + String[] children = file.list(); + for (int i = 0; i < children.length; i++) { + File temp = new File(file, children[i]); + temp.delete(); + } + } + + file = new File(crDir); + if (file.isDirectory()) { + String[] children = file.list(); + for (int i = 0; i < children.length; i++) { + File temp = new File(file, children[i]); + temp.delete(); + } + } + + file = new File(memoryDir); + if (file.isDirectory()) { + String[] children = file.list(); + for (int i = 0; i < children.length; i++) { + File temp = new File(file, children[i]); + temp.delete(); + } + } + + file = new File(traceDir); + if (file.isDirectory()) { + String[] children = file.list(); + for (int i = 0; i < children.length; i++) { + File temp = new File(file, children[i]); + temp.delete(); + } + } + + file = new File(transDir); + if (file.isDirectory()) { + String[] children = file.list(); + for (int i = 0; i < children.length; i++) { + File temp = new File(file, children[i]); + temp.delete(); + } + } + } + + /* + * memory的操作 + * 无需startFlag就可以使用memory的操作 + */ + public synchronized String dumpMemory(String path) { + if (memoryDumpUtil == null) memoryDumpUtil = new MemoryDumpUtil(engine.engine); + return memoryDumpUtil.dumpMemory(path, true); + } + + public synchronized String dumpMemory(String path, boolean stateful) { + LOGGER.info("dumpMemroy : stateful=" + stateful); + if (memoryDumpUtil == null) memoryDumpUtil = new MemoryDumpUtil(engine.engine); + return memoryDumpUtil.dumpMemory(path, stateful); + } + + public synchronized String loadMemoryDump(String path) { + if (memoryRecoverUtil == null) + memoryRecoverUtil = new MemoryRecoverUtil(engine.engine, engine.resources); + memoryRecoverUtil.loadMemory(path, true); + return "success"; + } + + public synchronized String loadMemoryDump(String path, boolean stateful) { + LOGGER.info("loadMemroy : stateful=" + stateful); + if (memoryRecoverUtil == null) + memoryRecoverUtil = new MemoryRecoverUtil(engine.engine, engine.resources); + memoryRecoverUtil.loadMemory(path, stateful); + return "success"; + } + + /* + * 同步机制操作 + */ + // 设置ContractRecord持久化的文件 + public void setCRFile(String fileName) { + syncFileName = fileName.substring(15); + File file = new File(syncDir + "/" + syncFileName); + try { + FileWriter fw = new FileWriter(file, true); + PrintWriter pw = new PrintWriter(fw); + pw.println(fileName); + pw.flush(); + fw.flush(); + pw.close(); + fw.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void setStartFlag(boolean b) { + synchronized (startFlag) { + if (startFlag == b && !b) { + return; + } + + this.startFlag = b; + if (startFlag) { // start + // 如果之前start过了,此次start就是一个检查点 + + filedTrans = new AtomicInteger(-1); + syncRecords = new ArrayList<>(); + // dump current + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH_mm_ss"); + String path = format.format(new Date()) + "_" + new Random().nextInt(); + String state = dumpMemory(memoryDir + "/" + path); + + syncRecords.add(new SyncRecord(SyncType.Memory, path)); + + changeCurrType(SyncType.Trans); + path = format.format(new Date()) + "_" + new Random().nextInt(); + transRecordUtil.setFileName(path); + syncRecords.add(new SyncRecord(SyncType.Trans, path)); + + // write syncRecords + appendSyncFile(syncFileName, 0, 1); + } else { // stop + clearAllFiles(); + } + } + } + + public void changeCurrType(SyncType t) { + if (t == currType) return; + + // finASyncRecord(); + currType = t; + switch (currType) { + case Trace: + if (traceRecordUtil == null) { + traceRecordUtil = new TraceRecordUtil(engine, this); + } + break; + case Trans: + if (transRecordUtil == null) { + transRecordUtil = new TransRecordUtil(engine, this); + } + break; + case Memory: + if (memoryDumpUtil == null) memoryDumpUtil = new MemoryDumpUtil(engine.engine); + break; + default: + break; + } + // startASyncRecord(); + } + + // 追加写sync文件 + public void appendSyncFile(String fileName, int start, int end) { + File file = new File(syncDir + "/" + fileName); + try { + FileWriter fw = new FileWriter(file, true); + PrintWriter pw = new PrintWriter(fw); + for (int i = start; i <= end; i++) { + pw.println(syncRecords.get(i).getContent()); + } + pw.flush(); + fw.flush(); + pw.close(); + fw.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /* + * Trans操作 + */ + public synchronized String redo(String path) { + if (transRecoverUtil == null) transRecoverUtil = new TransRecoverUtil(engine); + + // 先清空,否则会重复执行一些trans + if (transRecoverUtil.transRecords != null && !transRecoverUtil.transRecords.isEmpty()) + transRecoverUtil.transRecords.clear(); + + // 某一次检查点之后没有transRecords + File file = new File(path); + if (!file.exists()) return "success"; + + transRecoverUtil.setTraceRecords(path); + transRecoverUtil.recoverFromTransRecord(); + return "success"; + } +} \ No newline at end of file diff --git a/src/main/java/org/bdware/sc/engine/TestClassFilter.java b/src/main/java/org/bdware/sc/engine/TestClassFilter.java new file mode 100644 index 0000000..609dfa1 --- /dev/null +++ b/src/main/java/org/bdware/sc/engine/TestClassFilter.java @@ -0,0 +1,21 @@ +package org.bdware.sc.engine; + +import wrp.jdk.nashorn.api.scripting.NashornScriptEngineFactory; + +import javax.script.ScriptEngine; + +public class TestClassFilter { + public TestClassFilter() { + final String script = "print(java.lang.System.getProperty(\"java.home\"));" + + "print(\"Create file variable\");" + + "var File = Java.type(\"java.io.File\");"; + NashornScriptEngineFactory factory = new NashornScriptEngineFactory(); + ScriptEngine engine = factory.getScriptEngine(new YJSFilter()); + try { + engine.eval(script); + System.out.print("test push in"); + } catch (Exception e) { + System.out.println("exception caught:" + e.toString()); + } + } +} diff --git a/src/main/java/org/bdware/sc/engine/YJSClassLoader.java b/src/main/java/org/bdware/sc/engine/YJSClassLoader.java new file mode 100644 index 0000000..589bba8 --- /dev/null +++ b/src/main/java/org/bdware/sc/engine/YJSClassLoader.java @@ -0,0 +1,105 @@ +package org.bdware.sc.engine; + +import wrp.jdk.nashorn.api.scripting.ClassFilter; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.lang.reflect.Field; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.List; + +public class YJSClassLoader extends URLClassLoader { + ClassFilter classFilter; + File libDir = null; + List toLoad = new ArrayList<>(); + + public YJSClassLoader(ClassLoader parent, ClassFilter cf) { + super(new URL[]{}, parent); + classFilter = cf; + } + + @Override + public Class findClass(final String fullName) throws ClassNotFoundException { + if (classFilter != null && !classFilter.exposeToScripts(fullName)) { + throw new ClassNotFoundException(fullName); + } + return super.findClass(fullName); + } + + public Class defineStubClass(String name, byte[] bytes) { + return defineClass(name, bytes, 0, bytes.length); + } + + public void loadJar(InputStream inputStream, String path) { + String fileName = unzipLibrary(inputStream, path); + try { + super.addURL(new File(fileName).toURI().toURL()); + } catch (MalformedURLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + private byte[] asByteArray(InputStream in) { + try { + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + byte[] buff = new byte[1024]; + + for (int len = 0; (len = in.read(buff)) > 0; ) { + bo.write(buff, 0, len); + } + return bo.toByteArray(); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public String unzipLibrary(InputStream inputStream, String name) { + try { + if (libDir == null) { + libDir = new File(System.getProperty("java.io.tmpdir"), "yjscontract_" + System.currentTimeMillis()); + libDir.mkdirs(); + } + File f = new File(libDir, name); + f.createNewFile(); + toLoad.add(f.getAbsolutePath()); + FileOutputStream fout = new FileOutputStream(f); + byte[] buff = new byte[1024 * 100]; + for (int k = 0; (k = inputStream.read(buff)) > 0; ) { + fout.write(buff, 0, k); + } + fout.close(); + return f.getAbsolutePath(); + } catch (Exception e) { + e.printStackTrace(); + } + return "/dev/null"; + } + + private void addDirToPath(String s) { + try { + System.out.println("[YJSClassloader] addtopath:" + s); + Field field = ClassLoader.class.getDeclaredField("sys_paths"); + field.setAccessible(true); + String[] path = (String[]) field.get(null); + String[] temp = new String[path.length + 1]; + System.arraycopy(path, 0, temp, 0, path.length); + temp[path.length] = s; + field.set(null, temp); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void loadLibraries() { + if (libDir != null) + addDirToPath(libDir.getAbsolutePath()); + } + +} diff --git a/src/main/java/org/bdware/sc/engine/YJSFilter.java b/src/main/java/org/bdware/sc/engine/YJSFilter.java new file mode 100644 index 0000000..02cd2cf --- /dev/null +++ b/src/main/java/org/bdware/sc/engine/YJSFilter.java @@ -0,0 +1,11 @@ +package org.bdware.sc.engine; + +import wrp.jdk.nashorn.api.scripting.ClassFilter; + +public class YJSFilter implements ClassFilter { + @Override + public boolean exposeToScripts(String arg0) { + return true; + //return arg0.compareTo("java.io.File") != 0; + } +} diff --git a/src/main/java/org/bdware/sc/engine/gbk.yjs b/src/main/java/org/bdware/sc/engine/gbk.yjs new file mode 100644 index 0000000..7555779 --- /dev/null +++ b/src/main/java/org/bdware/sc/engine/gbk.yjs @@ -0,0 +1,173 @@ + +var GBK = function () { 'use strict'; + var GBK = function (gbk_us) { + var arr_index = 0x8140; // 33088; + var gbk = { + decode: function (arr) { + var str = ""; + for (var n = 0, max = arr.length; n < max; n++) { + var code = arr[n]; + if (code & 0x80) { + code = gbk_us[(code << 8 | arr[++n]) - arr_index]; + } + str += String.fromCharCode(code); + } + return str; + }, + encode: function (str) { + str += ''; + var gbk = []; + var wh = '?'.charCodeAt(0); // gbk中没有的字符的替换符 + for (var i = 0; i < str.length; i++) { + var charcode = str.charCodeAt(i); + if (charcode < 0x80) gbk.push(charcode); + else { + var gcode = gbk_us.indexOf(charcode); + if (~gcode) { + gcode += arr_index; + gbk.push(0xFF & (gcode >> 8), 0xFF & gcode); + } else { + gbk.push(wh); + } + } + } + return gbk; + } + }; + return gbk; + }; + var gbk = GBK; + + var URI = function(GBK){ + var passChars = '!\'()*-._~'; + var otherPassChars = '#$&+,/:;=?@'; + function getModue(passChars){ + var passBits = passChars.split('').sort(); + var isPass = function (s){ + return ~passChars.indexOf(s) || /[0-9a-zA-Z]/.test(s) + }; + return { + encode:function(str){ + return (str+'').replace(/./g,function(v){ + if(isPass(v)) return v; + var bitArr = GBK.encode(v); + for(var i=0; i 126) return NaN; + n += (code - 38) * Math.pow(89, w - i - 1); + } + return n; + }; + + // 解压Unicode编码字符串函数 构建时会替换占位符 + var Fn_unzip = function unZip() { + return arguments[0].replace(/\x23(\d+)\x24/g, function (a, b) { + return Array(+b + 4).join("#"); + }) + .replace(/[\x26-\x7e]\x25[\x26-\x7e]/g,function(a){ + var b = a.substr(0,1).charCodeAt(0) + ,e = a.substr(2).charCodeAt(0) + ,str = String.fromCharCode(b); + while(b++ 0) { + data.length += 0x40 + 1; + } + for (var j = 0x40; j <= 0xfe; j++) { + if ( + (j == 0x7f) || + ((0xa1 <= i && i <= 0xa7) && j <= 0xa0) || + ((0xaa <= i && i <= 0xaf) && j >= 0xa1) || + (0xf8 <= i && j >= 0xa1) + ) { + data.push(undefined); + continue; + } + var hex = gbkArr[k++]; + var key = Fn_Hex_decode(hex); + data.push(key ? key : undefined); + } + } + return data; + } + var GBK$1 = function () { + // 生成按GBk编码顺数排列的编码映射数组 构建时会替换 zipData 的占位符 + var gbk_us = gbkArray(Fn_unzip("(T!HJ%LUX]e%gilotuwy{} (U!)-%/137>BDGHO%RTUW%\\_a%jl%rtw} (V!*+-0%27>C%EHJ%MP%R\\`cdfn%ptvz{} (W!()*,/3%579;=%CFGM%QWX\\^cdg%ilnprtvy%} (X!&')%.468CDHJLMOPSTWY%\\_b%dg%ilnprtuwxz%|~ (Y!'(*+-469%=?%GI%KO%RT%V[%_bdikmnptuy{}~ (Z!&')+%-/%;>@ACE%GKMNPR%TW[_%ikmo%rt%vy%{} ([!'(%+-%024%;=%BD%LO%QSTX%[]^`%ce%y{} (\\!()+%/1%7:%LN%SU%WY%cf%im%prt%xz%~ (]!&'%*-%/1%68%EG%cgloqs%uwx|%~ (^!')%-/02356;>FJKOPRSVWZ%]_`dfi%kmor%vyz (_!'+%-124%68;=@ACE%MOQRUVX%]_adegjqwx|~ (`!&)*-%/689;%=?%ADFIKLNOVX^%cehilmoq%uwyz|%~ (a!'),%/124%=?AD%HJ%PRSU%[]e%ho%qu%~ (b!()*,%.024%79;%=?A%FH%KM%WY%`c%ei%loq%tvy%| (c!'*+-.1346%8:%<>%GKLOQSUZ%\\_cghjltwy{| (d!(,/1%4679=>@D%JLMOQRTVWZ]`%ce%km%pr%tvy%} (e!+,-/0279%;>?DQW[%]_bdhqu%wy (f!&().47:;>ACEFHIKMP%SU^a%egikm%tx}~ (g!)*,.02%58<>BCGI%MPY[]`%bdeginpuv (h!(*-2%6=>A%CF%KMPRT%WZ\\%`deg%ln%qswxz{} (i!&+-%/1%469;>@AD%HJ%MP%TV%Y[\\abdh%mrsvx~ (j!&,%.0235%7:;>@%FH%PRTVXZ\\_%cf%hjkn%puw%{~ (k!').04578;=?%CFI%NQRTW%^`acdg%ilmo%ru%wz|~ (l!&(*%,.%9=%ACDHIK%OQS%U[%^`%ce%hk%ru%{~ (m!&')%79%CE%KM%PR%^`%hjkmnqxz%~ (n!&(*+./2%478<%>ACG%WYZ\\%^`%cgmnp%txy{} (o!&'%)+,.5%9;%BE%UWZ\\^%`b%il%ps%ux%~ (s!&)%:<%?A%CE%OQ%SU%bd%ilnpqstvwy%~ (t!&')+,.%246%9=>ACDF%ILNRVXY[\\ac%fiklprsvxy (u!&(%,.013%?BDG%IK%MRVXY[%^abeg%jl%ostyz}~ (v!'(%,.013%9;%=@%CIJMOR%VXZ[]%_a%lnp%rtv~ (w!&(%+-/%24%689<=?A%CE%KNPR%VX%Z\\%`bcf%oq%tv%|~ (x!&'(*+-%5:;=%@B%SU%[^%km%svxy{%~ (y!&(),%1346%:<>@B%DF%HKMNPQSU%Y[%qs%~ (z!()%ACEFH%OQ%_bfnpqwx{}~ ({!&)+-%023569=ADEG%IKMV^%`c%fhinq%swxz (|!&'%)+%-/2%:>@ADEG%KMO%U[\\^`acefi%lnpquwy|%~ (}!&(+-%02%578:%?AI%MP%TVZ%\\^`be%hjlnoq%vx%} )&!&'%+-%356:<>?ABD%MO%TWX[%`b%fhj%mopr%vx{}~ )'!&)%-/%69%@BCG%QSTVX%bdghj%mo%{}~ )(!&'%9;%=?%WY%eg%mo%{} ))!'(+,2458=>@%DGHLOQ%SUVZ[_f%mp%twxz%~ )*!()-%025%:<%BE%IKLNOR%`dfhmp%rtwx{%} )+!(.137%:>%BD%HJP%SU%^a%fjkm%pr%} ),!&(%02568%:B%DFI%KMOQSVWY%[^%aehikmo%uxz%|~ )-!&'%358=%@B%DGIKLORSVX%Z\\^a%cgjq%suwxz~ ).!&(%+-%2467:%?AC%FI%MRSUVY^%`e%gijmnpqstwz{}~ )/!&()+,.9%;=>BCEIJLPQT%V^%`b%fh%loprv%|~ )0!'(*,-/%1457%:>?GJKMNPWY%[^%acdg%jlnp%ruwz{}~ )1!')*.035%79:=%DG%IL%PR%TVWY[^a%ejqruwx{%~ )2!&)%,.1%37%;=%@B%EHILO%QS%eg%nprtvwy%{}~ )3!&'%*,%/1%47%=?%BDF%XZ[]%ac%jl%txy{%~ )4!&'%+-%24%68%<>A%EHJ%Z\\%ik%su%z|~ )5!/058%:@D%FH%KN%SW\\_%afijlmp%su%wy%{} )7!(*+-59;?GHJKNTUZ\\_b%ejm%pt%wyz|%~ )8!&(%*-78:=%?ABD%ILMO%RUXY[b%eg%nqu%wy{%} )9!'(*%-014%79;%>CEIK%MOQ%WY\\^cgijmnqsuw%{} ):!&')%+02%46%<>AC%GJKM%PRTVX%[]bce%ilmpqt%y|~ );!()%+-%/14%9;%?ABDFHIOQ%WY[%]_%ce%lnp%rt%} )!'(+%.2578;%?ABEFHIKM%ORSUWZ%\\_`b%eh%jlnpqs%~ )?!&'(*%,/%146%8:ABD%HJMNP%RTVY%[_%ac%egj%mor%uwy{| )A!'(%+-/024%:=>@AHIK%NPRSUWY%]a%cehik%mo%qsuvx%{}~ )B!&')%,/%35%=@%DF%JL%OQ%TV%oqu%|~ )C!&(%-/34689;?%EJLMO%QTV%XZ\\^%ceglnpqt%wyz|} )D!&)*,/0279:<%@BG%IKLPQSVY[]%`beghjkmoq%tv%y{~ )E!'+%-0258:=>@E%LNQ%Za%cgkmopr%tvwyz~ )F!()%/14%79@CEGHK%OQ%SU%[^%dg%imnrz~ )G!'),0%9DF%MOR%Z\\^a%hj%ln%pr%{}~ )H!&*%-/2357%@BD%IKMO%RTUWXZ\\%`bce%nps%uw%y|~ )I!&'(*%,.%2479;%FI%KM%TVWY%[]%`b%dfhik%{}~ )J!'(*+.01346%9;<>?A%EIJL%NPRTY%[]%befhil%uxy{}~ )K!&()+,.%02%68%?ACEG%IK%PR%TW%bd%gi%rtv%~ )L!&(%36%;=?%DFH%KMO%QS%Y\\%`bce%ln%twy%} )M!&'(*%46%<>?A%CE%GI%QSV%Z\\%ce%lnq%~ )N!&'%~ )O!&'%178:%CE%HJM%OQ%TVWZ\\]_%jl%sz{}~ )P!&'%136%9>AEG%JMNP%RU%Y[%bd%koq%wy|} )Q!&'%*,.018:<%@B%IL%NP%RTV%XZ%\\^%dh%lnrw|%~ )R!'*,2%48:=>@%CEFJ%LOR%VX%Z]_%aijl%nr%vxz|~ )S!&(%*-.2589;ABGINTUWXZ[]%_bd%fh%kmqrt%y{}~ )U!()+,02%46;<>@EHLQ%TWY[]^`acdg%il%oqru%wy%} )V!&')*-.02359%=?EHOPSTVWYZ\\%ad%fk%mp%su%xz}~ )W!&),-/1%479:<>%@BDG%NP%SUY\\]_bcefhilp%rtvxz{} )X!&'(*,%36%=@%CFHJKM%OQ%[]^`%nq%suxy{%~ )Y!&)%/1%35689;<>@AC%FHKMPQTV%X[%^`%bd%fhjnpqs%u{ )Z!&)%24%79%@B%DFGI%MO%QU%^`%bd%gkmoqstv%|~ )[!&'%+.%024%=?%ACE%GI%KM%RU%WY[%]_ac%ik%mpqu%~ )\\!&'(*%-/%35%?ABDEG%LNP%UW%]`%jlo%z}~ )]!&'%DF%MP%VX%hj%ln%~ )^!&()+%8:%EIL%ORT%VX\\%_a%cf%hj%lnrsuvy%~ )_!&'%,246%8<@AF%IKM%Y\\^%`b%eglpr%xz|%~ )`!'(%14%8:;=@D%NP%W[%^`%mo%rtvx%~ )a!&'%+-/%359%=?%AD%GIKLN%SU%Y[%^`%ce%gj%nq%wy%{}~ )b!&'%)+-%/1%9;%DF%JM%VX%[]_%df%oq%|~ )c!&'%:<%EGIK%MP%RXZ\\^%dg%il%oq%suvxz|~ )d!()*-/%25689;%=@%BGHJ%NQSUVX%ce%psv%xz )e!&'%,1%35%8;=?%BDFG 'W!,-. &(+&.'&-~&'u'W!/1 ')>.= '.u'/!K. '0`'/!94 '1t'0T'/!?Bu`\\Q1t '0!)* '/!xy2IH ';!*( &'}')!\\] '+{.;U&'q.>!&' ')Z&'t',5':!GF '9!eiha`;:ML ')e'-!XVWY 'W?'-!67%?#3$ '6!-.%@ '5!rs%~ '6!&'%, '5!^_%g## ']!67%?## '-!&'%1## .;!RST .>+.;!VW%~ .)'W!mn%~ 'X!&'%f#8$t%~ 'Y!&'%p#5$ &0!=>%MO%U#5$]%mo%u#4$ .9!89<=BC@AD%G##>?:;4#67#6$ &1!cd%hTi%~ &2!&'%)#12$*%/K0%I#10$ &.!()7 ')!=?O_ '+}',('-!\\]%_ '/!)37fz{ '0z'8!CD%ft%~ '9!&'%)-%/VW|%~ ':!&J '0P'W!>IJ#8$ &(!uU &+7&(T&).&(]&)6&(\\&)F&(a&+9&(`&)h&(g&+;&(f&*-&(n&+=&(m&+!?ACE &(!p^ &,a-Qc&)!_c -Qd&,q#1$'Z!&'%J#18$ 'W!MN%U '^`'a!@AN%PSv 'b!'*+. .93.>!(*# ',@']G#'):#0$'Yv'X!no 'Y!wx 'W2'X!pq .9!LM%UW%Z\\%ik%n -R!*+%6 'W3#10$'7!LM%~ '8!&'%>#12$ )e!HIKN%SVWabei%lnp%uw%y{%~ )f!'+%-23679%;@BCEFHIM%PS%_abdf%ik%rt%~ )g!(*%79%=?@BDFGIJL%OQ%TV%XZ[]%bdfgkn%prsv%y{}~ )h!&'(,-/3%9;%>@B%EGIK%MO%RT%cehil%or%z}~ )i!&'%)+,/13579:?%CE%HJ%\\^`eh%tvwy%} )j!'(%,.13%57%9;<>@%JLN%UY%hj%~ )k!&')%1357;=%CF%IKN%TV%Y[%bdfhj%mqstv%z|} )l!'+1369:<>%ACDFGJM%PR%UZ%ad%fh%npr%tw%{}~ )m!&()+%.0%2479@%CEFHIMOQ%TVX%Z\\%_aeg%ilnrswyz|} )o!()+%-/346%=@%EGI%MOQ%TV%\\^%`b%iklnq%suw{|~ )p!&()+-.013%<>%FHILN%WYZ\\ (iC*r5(pM)89(gy(h[(gk)p*)o>*A;)s|*9E)ui)cO*s5*ux)R/({@(Z*)7s)B.(~d*4~)F{*42)@K)pg(_l)>Q)a|*2'*Jb(\\0(u2)4?)\\@*9t)8])5n(eJ(f+)|s(^7)mH))<)7>*Yr*ua)6M*2O(o@*t|*0J)cV)oo)E[)op);L(XR*W~)7F)z6)?3)hN);2)66*8L*xa)Dd)cf)61)76(Wo)k9(cY(a_*.d*b,))v)G`)Jk*6R*.k)HS)vH*E'*oR([d*U/*:L*4b(bm*L>(a&)p!]`bdelnrsu%wy%} )q!&'%-035%7:;=?@BCEFJLN%X[%^ac%egj%lnp%ty{}~ )r!&)+%-/%69%@C *B**t=(Yf(qR*{F({T)6!th )BK*V+++A)b})DT)um)12(c!`& *^r*4P*Wv*mT(Z=)e4(t-)1k)`B*K0(tz*:])Cj)}<)&|*/8)l*)TJ*[[*`!0t +3')Q4*cF)}()-`)v**@.*A<)Q!596 ))I)*v)nD*q<)>X),G).P*_0(s@*7;*a^*rQ*v?*_J*/W*X,)5](YH(e5(cm*_!9:< *a,)F:)-N*6j*JF+,1)3Y(`E)nu)-P)?.)\\_)Z'({u);N(^!A| )EP(T_)yA*{Q)_5)r!DE%GKNPQT%_a%ch%jm%rvwz%~ )s!&'%,/12469;%=?@BD%HJLN%Z\\%df%hk%or )mi)*e)gu*=C)(dx*E0)PD)1!mh )^Z*:;*8Q(Vg)SU*Bu)Y)lB(i*(ZQ*Y,)6G*mQ)C[(ky)[T))*(f9)^m*^P)62)*Y(*JJ)<>)yh(pX)Lv)5,(fL(UE)z*)1i)[j*T>)6B*`V*~U)y\\(e`)n?)7k(c()Rg*_p),X*~:*2q+3k(Xj(}?*Xd*1T)?G)_?(]j(^~*D_)&Z({W)7'*d@)lq*ZZ)z?)2()~4(V[*/9)rl(TW*7f(`7(_m)M5(d^*[|*n^*sl)YY*rZ)J))u!`abdfgklnp%ruyz|~ )v!')+%28%;=%@BCE%GI%KO%RT%VY%[]%jl%np%tvxy{|~ )w!&'%*,%.0%6 )tu(\\&)se):o*N`(t*):B)(~){E)Ie(W[*8Y(j8(Tx)mR){])*!Qy *q>(`5(f=)^e)9.*n~(oe)@n)Ig*d[(hY)W=*.I*IY)5O*/1)mY*;=)vD*si*_/)2o)kM*T1)Ov(`T*XP)O3*3G*>{(n-(bn(Vb(Ta(_D*(G*d_*&i(YL*[t*&C){b);m)&g(\\**51)nL*(i)W6*1o)D6(zh(|V)vN)<[):r)9b)8<*ns);3*_O)}h)nt)5o(tM(fJ)P2([z)5P))n)P?(Vw*X7*Ji)-i*`f)w!78%<>%GI%MO%]_%cgil%oqt%|~ )x!&)*2457:%=?A%GJL%PSTW%Z\\%_a%c )/R*2s)7/(U&(cd*b~)9p*4J)@/)R5(X()1n)W+*TB),v*Ef)-7)82(^&*;v)G=(_s)8t*[=(ZB(~G)xH(|Z(`J)zZ)1<*a2)pp).B)-{)ov*[a)^J)om)}])s8(_f*ar(qU(X0)Z3*_{)>G)}/)e0)VG*1n(yJ)6x)++(nl*?3)}@))e),\\*`J*/U*y')9:)Y_)ut)_;(^D*uF(p5)l2(W~)l5)+-)1f(u-)Vc)Px)ue(eY*sr(_!>t )9A(eg*mF*Tg*Ys)cW)u{*G_*_~*Tq(e=)x!de%jl%wy%~ )y!&'%*,%047:<=?@BDF%HKLNOQ%VX%Z]`bdfi%oqrtvwy|} )z!&'%)+.%24578:; (TG)q/(eK*m<*xV+2S*o.({Q*S_(T!hb (^x*>m)47(ai)F>(Xy)0D(_.)Ts(^()6Y)?9*rW*UQ*`O)m|*c*)rJ)Q2)dO)eX*T_(qf)r`*XL)DA*oA*3w)+<)Wk(u_)|\\)s{*o<)Pn)?O*/O(q7(]v*qn(|W(s((f,*[g)>a*x_(my*mP)q>*`y)9?(gq(t!@` (o~*\\N)Cs*ZH*8U(`[)1p(qF*F@)&;+0<(YM*x}*Sv(w@)0O(d:)6?*a.*c/*{T)0B*2B(]d*2i(|r*{J)U-(Uy)z!<>@AC%QS%UWY]_%df%oq%uw%~ ){!&'%57%9;A%DHKMO%RT%VYZ_%adgh *X0(e.*0B)}c(WK(U<*qO)T*)h1*C6))N)lg*21)L')t3*mE*-4(_T)_h(e**_e*:q*X))dt*{B)T0(o-*9z)?[*4.)5[*r((uu(W:*S|*.T)>9*=U*uI(iZ*ye*4)(c9*Ta(e}*4>)+5)Sf*X9*9s*d.(f-)Q{(_y*.Q(oB)`C)S,*(9(tq(W8)/1)2K*(Z(Tv(|_)E7*FD)&C*ne*yU)mS)`&*`Z(^{*/^*Sz(to(_W(X=(f*(tQ)>r*4(({,)69)7,*^z)*4)R&)}:(WJ(Ya)CK){!ijmo%qt%xz%~ )|!&'%+-%79%BDEG%JNOQT%Y[]%ehikm%ortvy%{} )}!&'*%,.0135%7;=A )Uj)VM)x`*K6),T)l()6]*^o(Yx*eW)?I*5!Z| )+2*5{*Xt(a0*MY*XK(t3([\\(Vl*qk)cT*6K*Wx(|**S`*r:(uT*/[(g;(ld(kU*TI)>4)JQ*mL)po)Xz)*a)kn)D+)E])|l*3z*Xv)2F)y>)>]*Xc(^T(`4*mU*/y*3x*.L(~C)Wy)DE*&;)o}+&I*6a*0|*),):}*oQ)z^(fN(h7)O^):`)4}+04*4w)m=(a3*uT*>e)Fo*F&*qP*s1*nF(Tp(ea*.s)Fl*Z-*2K)C2)+0*1H)}!CDFH%KMOQS%XZ\\^abgikmprsuw%~ )~!&'(*+./13578:<%?A%GIJL%NQS%VY%[^%`i%kmnp%rt%{}~ *&&(pL*2u)Gq))-)>6(a`)0F+4-(X}*\\H(^8({b),P))1)Re)7[*Wz(^=*m\\(bf)SM*:M)eC(p,)Di*X-(tE*_-*=*(g@)~H(Wk)Sk(zt(vE+2X(eA*Ee*~r*UB*3~)>@*x^(n6*sd(`H)k2(`j(|?)7l*L.(UC)7:)/\\)H{(^?({O(^l*N<)~\\*{[*08)1o)^'*X/(]n)*n*`S)ix*N>(ni)tz)-6+42*qI*^R+'T*TE)oj)Fu)Eh*Z8*X5(`W*^t)Yr)HN*n_*bs(n9)E(*K~*_X(gs*&!'*%-/%246%:=>@%BD%FI%KM%OQRT%XZ%]_a%hj%lopr%wy%~ *'!&')%.124%@B%GK +&)(zy)Us)R-(V9({j*~Q*d7)3v*b5*v{(f/)VX(|0(_p(j**0=*2&)u*4e*G])e<*(z)XG*'!LM%UW%{~ *(!&'%*.%8:%@CDFI%KPQSV%Y[%]_`d%hjk ),d*DB(h~)6g(V&)SX)5S*9x(h)(c])fQ)Yi)l8(`,(b~*TA)KF)-n)/2)W8(o2)O4)gi)G-*_i*/T)8s)0|(hv)n5*Um)`>)VF({])*j*;g)2s+1b)v}*G@*'0)oy(_c)1v)`u)A3)*;)0&*Tr)^K)86*^s).H)0;*Eo(ms)Pz)0m)35(cX)1`)AV*X?)yu(WU)_k)RN*Sp*TV*.r*;y)@X(wu+'Z)UM)WA*UL)U7(WT)^F*@%EG%NPQS%`b%vxz%} **!&'(*%,.%4 *3i*{:*`1)\\M*Sb+/q(v`*/!*J (ef)Df)HY*^{*'V*sc(e')/W)mb)Ry(d)(y2*.A)85(_S*55))9*@7)6C(^L(zs(WI)x>(`\\)18)UJ({!{y *S!^m )@+).W*r;(u`*/(*.D(kP)EC(t_(XU({m(aa*;o*xj*X>)l/*mq(Zw)z[(W2)EB*~H(y*)P5)pj(o=(|t)}N*qC)`w(^H*4-*97(uE*/E*;<)HA)Ex)v4)uS)7M)8r)~;(Yv(a+(_B*;e)KQ*g=*ZC*X1*N;*o/)~h(W1**!56%km%tv%~ *+!&'%= ([<*8P(`k*{D)WZ)Xv)VJ),7(\\s(vP(|d)UB)Rf)m**?<)GB(t|*So(c/*dE*rC*AH)I:)w+)`O*4z(V8*bP)UC*~N(v{(mQ):d*nJ)sy(Y.*5E)eM*NL*{O*/u*.x(a@)>T*dI*^!im (eH){\\):L)9])ox)yp*J5*r,)5F(al*9I)G.)DU)9/)rR)|Z)TV*.m*N](vD)5.*Bo*9l)lI(ZO(V_)mI*TO(}O))F)}_)?F*eL(V^)Tz*M2*)~*o'(VY*U3*_l*u^)A;)xR*_b)_n)Ut*+!>?%JL%RT%~ *,!&'%F (}B(as*;[(^.*:|)rB)Af++l(V@)1J*(!nc *.i(V)*R|)A_*xh*uD(r[)>g*o])-h)mm*uA)|!LK (_3)_1){^):I){<*.:)gP*w&(U2)^S(UJ*d&(d_)>L)@0*7!u~ (g9(}6)m>*v2)7B)eE)ma(}J*~C*=-(}E(g+)sw(U+)S\\*37)7<)9&))0(^C*Z!+l *o0(Yz(eB)1g)_.(a()8a+0:(w:(ZV)qw(d-*.|)<2)>&)6L)9P(ZD)cS*NC(_&*S}*.w(o**=/*mZ(^g(ex)&N*,!GH%~ *-!&'%-/%35%9;%P (YS)|P)UV*bg*~Y(iy(gA(cp(gZ),=):H)JF(_b)36(_}(q[(b@(o1)tB)qK)+M)3E*)7)5w)6Z(V6)^p*29)7a)_f*uK(oZ*:I)E{)Hv)vX*xw)yI(sr(g^(eL)W~(]p(`U({Y*Tb*43(i<(p0)0L(o4(f1){@)0)(zd)9_)6c(e@)6&({~)E;(h?){e*:T*dK)+)*Ki(t^(p8)7x*Z6*4s(o:)~2(Y2).v({t)OP(c0)}d)e.)Fy)t4)qv)@@(_((U|)pm(~k){k*?&(tt+'Y([W*-!QR%tv%~ *.!&'%46%8HNUVp~ */!-:KQ_xz|%~ *0!&'%)+.%7:; *{])2N)Xt(oG)@O)8W(n,)7V)6,)+i*qc(of)73(j'*Fc*5u*_4(i_*)_[)V@(b:(U=*t;*on*A})vM**-(]F(ou)AC%FHK%OS%UWX[]%`b%eghj%qsuw%{}~ *1!&'(*+/12457%=@B%FIJMOQ%SU%XZ\\^%befh%mqr )n-)|8*(B)SS*sS(a\\)j2(h;(Yr*31*V*5c*nX)/})_>*.]*(^(_<)G[*(a*96(Tj*^p*eJ)An(VB*Ti)(er*n7(Y,)?g(}!jf */V*DE)R6)-o)gA)Y|*/@)&9)8,(zz)Y~(d+(U^)9X)lb)6d*^X(Wa(Ve)ST*.P*Sw*>'*HJ*0?*`s*n})~d*~k*K}*>G)Tp*~P*.v(uU+1Y)gU)t6*Dv*~!6L (kb(et(pU(U]+1D(ce*_Y*54)ry*{g*F0)Yy*@k)C:)30)Zj*3![^_begj%oqrtv{ *4!'*%,0479:<=?IK%OS%Y\\cdfgjry{} *5!&)%,.%02367@BDF%HJ%VXY[^%`bd%hj *U4*9Y*;@)q2)Qs).d**:s*nt)Q;)si*my(c~*:p(^^)*,*V>*X8(U5)ge)E&)G_*dJ*tM)a4)SO)qI(xT*oB)Q/*0v)@p(|.(v-(x\\*q!7F (W'*=o*?J)Mp)px*o1)f.)H'(zo)qo*dn*uL*)3*`/*U'),b*'|)yP*N?)Sz*F^({})*1)HJ)q`*/6(^a(]r(b1(wD*/F*uM*:E):.)rk*Bv)yJ)X+)+/(uf*@i)^H)Qq)7))pX)>J)1/*qL)@W*H/+/s*nG(ej(g(*U7);~*5!kl%prtx%z} *6!()*-%13%68:<%>ADEG%JSU%Y[]%`bd%iklp%tvwy{}~ *7!&'%+-%25%8=>@%BDF%L )<&*C^)L>*6n)vk);o+'l)6|)Ci*)YR*A*)72)*c)vA))UO(^h),A(uA(ak)/D(u@)B-*DD)mC)8;)4[*)F*T^(h8)O9+/u)Pm*B{(fY([M)SR(ic*Y[)cJ))])/G)i>)77)9J)cj)-|)X4)U:)=T)[>)pq)vS)q<)lQ(`>(e8(U@)+4)?c*2`*4Z)6^(g1(`B)_0*Jk*Yx)T6(f|*4^(q**Ky*XT*r`*cz(XK)SI(jW)p_)te)6k)_{)[t)-Q*@D)H[)uX*&Y*6z)CI+0F)8x)v3(oR)tG*t})6!DGHKPU%XZ%\\^`acdfhj%nxy{~ *;!'(+-.2%;>?CEGLPR (i]*5i)mV)pG(cH)n)(\\y(}F*S)*&)([&)ce*~a*y_)ZA)k8)x9)<4)s3)7f*xq*X+(gl*35(U?(oM*:g*=p)*b(_`)kL*T((}T(oD)TQ*xg(wa)ti+'\\*_|*(E(`p)5m*nT(VZ*k*=L*?c(p^)Cr(n?)A^)Ub*U<)Bt)]E)C])OL)FI)56(v/(TI(_7)ZE)E^)S=(^B)HL(tm)Oy)lc)&a*5;+3<)?y)w!rk *~[*Xw(~.(UK(W<(f3(tw)tA(lV)Qt*_U),@)S+)T8*Sh)9H*;!STVWYZ]_%chj%nrw *AE%GI%KN%P )0I)U9)d:)6)*m!Ax (cR*_R)~9(Vs*U1(Uk+1r*m!df (`g)[B*aB)UA*U?(qB)'F)O!2[ )E6(f_*6&*0t(rq*A6),w)6e)Ld*o:)>m)0])G?)s5(UA(Y1))/*v*)(VF)y^)i<(bL*:')=&)y5(|;)S/*u=*^e)R)(Zn(d5)WO)<{)Ad)R7)1E*xW*T[)*u)iD){=)yC(T^*b7)hd)RI(mo*cx)Ss*Y2(cI*Ea)C0*\\K(}M*~;)Wj*=!QRV%Z]%_a%cehj%msu%z|%~ *>!()%-3%:<%AC%EH%OQ%Z\\%`bg%jln%rtx%z|~ *?!(*,- (e3(wQ+3w*YJ(dq(nD*y.)D(*do)Sw(^4)mn)7])dq(`R(a^*/{)^o)o*(d*+0A)K-)uJ*s]*K^*13)`_)b:(^U)E_)k:(sc)=l(mL*Sf*{K)63*.o)1y)_o(sk(V!UN ).X*vy(W6*Sa(_v(uW*.E)5p(Va)@.)5**;M*?z*;x*Gv)ad)YN({p*.l(^c):()E`*3f*;N*IL(]7({1(uO*_B(U`)Rd(^1*LQ*^Y*q}*AI)if*nj*q?)VI*:S),n)2*6@++w(r6*X[(TO(dw*?!./%24%7;>@%GIKLN%QS%_abdf%hlmoqstv%y|} *@!&'*,-/%469:^)G+(js(Tm):s*~d)6.(y+)ig*99)VL)Ho(\\e*1)5g*{k({?(|])9@(i'(e4)nq(^I*A+)E.)H4)PC)6U*^}(e1*82)Vt)m3(US*XN({')ao*BU)B!(p *0Z*FB+1k+2e(}c)Cm*`()FD)DD)5))|C(r])+L)>k)Zp*B!(),.%46%@C%IK%MOQ%SW%\\^`%fh%np%twxz|%~ *C!&'(*%02%57%E )0.(`Q*2C);Z*JN)l&))M)FF)7^*t`(e))c[*Te)R;)rH)z-(f2)s:*xZ*8<*TX)u1)CR)_C)?Q))MD)n;)[S*U8*Tl(oI)QO*Jp)v6)9Z(eV)_/)Rk(r0);0(q3)Ha*6m(hb*)-(ZH*\\V)Vo*YF)_m)9G)V>)Yl*/'*=g)Fv*`;)V{*rl*Se(t})d>*C1*6P)m`*PR)H0(`n*Zp*nk):/*xx*[9(iu(X5)C=(l})1U)V8(`](}N(tO)WE(rC)l-)kr)0E*84*5q)7{)DF*_s)qz*ZA*X4*mt))^(d;(f0)_E*D!acdf%lw%} *E!)*%-/1%69%=@AFHIMNR%TV%Z\\%^`cghmnp%ruwx{%~ *F!'(%*,%.17%9<%?ACF%HMNP%SVX )RG),4([3(VA)+C)8K*8g*`R)G**dB)sA(ei*n6)-H)|R)GP)8V)}f*.y)n&([N)6X(tZ*`G(_k)y;){G(n:)-v*`L)U~(}e(n[(em(]y)X>(mw)9`*xs*6Q*FW*LV*`8(e{(}t*79)7@)5t*5\\+0,*r6*~!8F )IU(ur)7=(i7)8'(gr*Et)U8(vw)k<*Jz)O|(t<*UW),l)Xo)gc*x](T~)_y({C)us)8N)AJ)p/)1K({R(wd(TM*6')Rq)gE(V5)Dn*09)-d)@C)CY).c(uQ(vu*F![]_abfh%jl%oqrtuwxz%|~ *G!&)%/3468%;=%?AC%HJKO%VXZ%\\^`%ch%jmoprsuw%{}~ *H!&(%.0%4 )(n).9(d'*vx*_n)Fx(n0(i()1_(U')[3*/5*:5*=q(vH(W!Ze (}C*.F)Ch*@r(fw)lL*4G(i{+'g(X/)Ww*Tw(|g)3>(cz)nj)Ws*D~)?)*qJ*.S(f?)zR*)a*q=(k(*1P)kD)8.*FY)VD){c)5-)?C(cv):@)S1))3(f`*m[(U9)Rh*TP(}P)@)*9c)H((f!B8 )Q+)Ox(V()8S(cW*8>(WH(Y7(oA)5&*tB)AT)d.(bg(ab)0x*TS)@])ai)Du*MR)u.)t2)A`(l)(f<*n{)d?*H!5679:>@%BDF%IKLNOQ%UW%Y\\%`d%jl%oq%tv%y{%} *I!&'%/1%46%9;%@B%IKN%QS%WZ )yx)0H))T)0b*6o(t;)1\\)aT)_q)YB)RW)dE)MH*K2))u(UM(xu(j<*n=)Tl*)R*s6)5+*.`)ru*Dr(c2*tb*_')Aw)&4(Y))eY(TQ(d\\(t5(ep)98*o)(]m(Vm++P*.>(gc*W}*J2*8W*qA)V1),c(y5)A.*r_)gj)fA(du*6L*{Z*10({a*r!mF *.Y)q8(dX*ow*{n)~l*Lp)XI(UN*1c)x6*TJ)1s(gx(V?*xY))?)L~(\\M(en*Ul*>1)u9*tH(`d(h@(m8*nZ)V+({l)Vi)AC*I![\\%hj%oqrt%vx%z}~ *J!&'%),%13468%>DEHKMOQ%TV%Z^adeghjl%oq%su%y{%~ *K!&(*%/ (|m(zm)FT*3s(iq)|~)>C)I|(V/)OY*G7*uv(c^)80);@*b0)?>*4E*Tt(^e)H1(d.*I0)4=)Sr)TP*U-(}V*BP*9v*nf)O5*_,)?R)/-).N(Yj*I|)@h*67)f<)1z(^@(`+(on)-F*b(*J**df)*g)D4)/Y(vG(]i(_i*4|(bp)S'*sa)aZ(WL(Yw*1-)C{(je*nb)y8*Jt*.}(rw)5(*tD*DN(k_*x[)-t*Su*?u*d+(e6)@6)*~)lY)0=**l(xA*/!+. *^S(jG({Z)1,)?m)g>*K!13%57%;=%@B%EHILMO%RT%VX[\\_%cefkln%twz%| *L!&')+%-/%57%;=@%DH%LN%PR%UX%[]%_ac *`A)oU)qi*.t*u_*BA(zv){:*t.*Iw(b3)a_).5)@5*TF(|Y*~9))))PB)Rb*S!jl *`B*_V(dA)7&+/!v} (fD(Tq*:+)cw*E7)&i*J7)VR*sb(g|(V.*Ss)`2(gh*qX)_a)WC)pi(Tk)tI*FT(~U),3*Nz*x|*q])^i)Sm(tj)9a)q|*J+)ZS*9:(qa)bL(dB)tO*s^(hS)-J)`Y({k*T~*~V)P<(tT+0&)y_)DM)6/(XQ)mE*0r)T`*r))R.(W+)mv(^G)Fj)Z}*a_*6B(uc)i~*L!de%lnoq%~ *M!&'%03%8:%MO%QSUWXZ%t );M(},*aD){W*U.(vN(gW*7y*<+*MT*26)IX(l<*2l)cU*eI(_)(UL*xU)9N(T`(eS)C1*5v(tB)VU(TF(sx(cJ):5*nK(Y&(WE*JA*xp(t]*a6)ys(V~*4t)m5)S0({S(v\\)-A)I-*Du(ZJ)):(UF)sq(Vy*9A)6T)@\\*ap(}~(VS)-]*7?*`p*3a)mO(V:*KY)26)P~).Q(U6)pc)Y:*TG*Sk*T!n5 ),?*22*1[*.h*;J*<'(mu)Pp*w,*r*(vo(e|*nP)W5({|*{C(}>),R*s-*M!uv%~ *N!&'%:=GM%OQ%SUWY%\\^a%df%hj%ln%y{%~ *O!&')%> (d&*:_)LN(x6+0g)+**/i*!./ *;|*G0*__*Xb)pa)-U*xv)uH)@i(h1)7O(XE*7<)ml)+N*sj*ZX*F;(g:)TH)V/)R?)0X(b/)k~)*l(WS)0y).r(}))l.*b4*ms)d~)Sg)X)*cv)CG(e!(P (X3*eD*TU(d~)*k*_S)W.(U{)p[)JU*DR)2A*8&(X;(Yg*`v++0)20)W!g^ *r{(Uu(wL*t,(TT(~+)y1({>*TQ*1L)gC(pi*9R*bG(e^*a&(j[)&=).,)2/)OD)e]*46*PQ*O!?@%^`%hj%~ *P!&'%@B%H )Up(|1*KZ*xd*Uv*~7+0*)WT(^p(]h(p-*J_(dU):S*_&(n)(f\\(nB)fR)Y(*/Y*_m*:?)2f)/Z*rX)C.*.@*Y!1j *mX(~_*(T)CF)1&*qT*2N(U~*bm(bh*r^(]f*_a*As*d1)AE*w.(ze(c,)tm)D')Fp(gt)^Y({g*^g(^Y(nd(g\\)=f)Ar*X!^C *5:*>v*aL*)6(_r*CH)E/)@2)\\.*E?*[v(lX*`X)ot)^Q)b\\*W|)7S(`3)TR*X<)/@(rv)3\\)C<*X`)5j(jS)Wm)Ck*^Q*P!IJ%PS%Z\\%~ *Q!&'%R *n;*qG)qh)F8)Jw(g6(U:)_:*T,);^)?-({<){J(Zj(|F)sI)QA*PA*(H)Sl)ph)?K*_()''(}Z*D,)F;(co)54)|F)XL*/>)L<)|M)-T)Zr),])9D)VK)D;(TN))X*X&(Vk*4D)o&*s9)7E)@v)6A)Sj*Xu)a7*0Q(]k*3d(eI*aM)6[(hD*F2*_**2;*nq*@o*_j)UU)h.)?A)q_)kZ)t\\*7t*Ww*m;(Y/)Dz)m]*T.*tK)8@*oH*r+*?i)84)r()-e)e\\(Uv)/F)>o)7Y)Ou)>:*Q!ST%uw%~ *R!&'%;=%[ ))o)mk*bW*S~*9d)E))>*(f5*FZ)ss*4&*5-)RH(U8*.a*3))q4)I5)PO)6*(Zl(Xf(n|)7q)Ot*Ye(eG)@1*.R).b)8+)9o*7!lm *0V))d)&,(`P)Aj)ya)z9*X()^t)mx)Yv)Si){X(Ts)p^).k*mR*JU*.b)yE*4C*eH(W!-R *8?(fl))&)U.*T0*(U*^^*3u))b(g=)pJ({P)A,*~n)hA)F]*Ev)Co)f=*T!\\? *`H)|f)_])a>)7.)s7(kx(U(*>a)E}(aj*E[*X.*nR)}e*R!\\]%{}~ *S!&'(*%\\inx *T!+4Nm *U)(X1)T=)x.*~E)6V)cH)7g(TY)tK*^V)<]*XZ*&()GC)*s*KJ(uS)*0R(|h*aT)@q)).(X2)Ej([1(X>(o3)+=#2$*U!CD%KM%PSUVX%_a%df%kn%tw%} *V!&'%)-%3568%:=?%EG%IK%_ (Uz(TR(]e(TV),<(cT(T[(V,(Td+'J(z|(lW(Tn)y2(U,(b}(U4(tS)cY(c})Qp(mt*4h*{l)Q3)re+2\\(T|(V3+2U(U!IV (V'*9O(zk(ie(kV(VX(d!CSY[d *uP*X](c)(eR(c!5=M *X\\(c!ur (_!u{ (`!(GMYZfx{v *?`(a!>CBQT (^N*0<(V!OW]V|u (W&(Vr(W!V.] (XF(W!0`bDf (X!@I )>3(X!@A (cx(d0*q!lqp *r'*qy*r!328?JU]bhj~ *s!*4M *a!vz|x *b!2':9<@ *Y|*Z!&'*.%03%57;<>%@BDJL%RT%VY[\\^%ac%jnor%vy{~ *[!'()+%-01348:;A%EH%MO%Z\\]_`cf *b!>6UKDVJMYlhb]aqu *c!+1OKP^\\fps (`'(th(a!cmn (b&(hQ(b!8>X (e<)be)s[),1(_!ho +'G(dl),>)lW))7(o/(p!3+ (rV(s!;DP (n!ehfoujk (o?(n!w~ (o!LhNi_^KPYV (p!7. (oo(p! (ov(p!*_bdc\\B~y (q)(p!ng *[!hjl%prsuw%y{}~ *\\!&'%*-%/1%79;%FIJLMO%UW%ik%~ *]!&' (q!<>. (pw(q!1OJuQ (r!=DYarX *{}+2^)4t*9!@DFVQoKUX^`r *:!&, *9w*:!68Q *9!_~u *:!9:/ *9!p{hqf *:!2< *9k*:!OweR}uJb@FziA *;!&/ *:t*;!)* *:!NC *;!1fpq *:v*!&B *=!ti7Brf[\\M( *<|*>0*=!SD *>!f[dc} *?!89+:) *>!FPs *?!'=? *>!;w *?!r~ *@!(> *?n*@+*?!{pk *@8*?!RjeH *@!=;d )kc*A7*@H*A8*@w*A9*^!/0%OTjv| *_!.1%35%8;=%@C%FHIK%MPQTWZ%^`cghkqrtx} *`!')*,%.2%467?@DFKMP *A!U: *@!WT *A!XGgc]y )s0*A!Bqz *B!JN-5 *Ax*B!TB+_]Vyg *C!)LtRvc *D0),!;E (t!bg *2m(t{(u'(t~(bw(}!'*19 )5h)6!-b~ )7!4DAX )83)7`)8!J\\T )9e):U)9!)2Fl )8~)9!dB )8z)9!ft ):!QW?^ )9|):!=- );X)9!~v );!KG ):!jz );&):k);!,'d )<1);s))),H).])ko),N(cn(e!NZFEXosc (f!OV%XZG (e~(f![]'6 (g!-? (f!{uh (g!EF/ (f!zj (g!H{Xm_}RQ~ (h&(fv(gN(h'(g!fjw (h!+,. (g!TUO (h/(gz(h!0m9rOfEtuacy| (i`(j!/U (i!Bf:N8I5 *b!HILNOQ%SXZ%\\^%`d%fi%koprtv%y{%} *c!&'%),%.02%EG%JL%NQ%[]_%eg%oq (i!0On%p,)U (j!+r (i|(j!QY( (iz(j?(iw(j!v1 (it(k&(j!]^49 (k!1> (ji(kf(jq(k!23 (jt(k-(j!}d (k!6,9: (j!lm (k!/<+ *^~(k!eOSHkjEGnt (l!F'E (ks(l!;PGJ:BtR_Yijs (m!(Dilrv (n!1'5;@FEX ))!Wa\\Yy )*!*+ *c!rtu~ *d!'(%*,-/034:% *U~)(!Xf )-!W[fkmpy} ).!'38@G *J@)-E)d!ruy|} )e!/-:9>T[U^`cm_of *e!ab%~ *f!&'%g )eg)f!*&4 )ev)f!10(5L8?KDc`js )g!&)8 *8;(tK*yn(t!J( *{!8<%AILRUY\\_befh%j )*o)+')*z)+!,;6OKTI *XS)+!hgq~ ),'*73).!OTaZ )/5).y)/6).!lo )/!078 ).!ux )/!*KgXMA?[]%VX%p )0!CVos )1-)0!v\\ket )1!l;1]XFZ4 )2!GMB: )R!op{} )S!4W~ )T))S[)T!LMF, )S`)T!5+O@C )S_)T!(DS *g!qr%vx%~ *h!&'%79%y )U5)T!|a )U!?D )T!\\Ync )U!'I*1 )To)U!KNP/ )V4)Uk)V!AC )UZ)V!67 )U!X\\x_ )Wd)V!jh )W!(X )Vb)W!*[0' )V|)W`)VN)WV)VQ)Wu)X!_?\\ )YJ)X!PwDE )W!|o )X5)Y!wI0x )Zl)Y!z=?USOoLg'Z7 )[!H,- )Z!cT8nu )[!1Z )Z!iHh )[!osr^Xb` )\\^*h!z{%~ *i!&'%TV%~ *j!&') )\\!V4FCOn{km| )]!NWOmi )^!*9 ({!7;LJ\\o )l,*~h);:(|!BL *L\\(|N*[<*Qv*_!Gdfv *`&*_!uzw *`+*_y*`!=(u!xkq (v!F& (u|(v!K2yzQ|WLm (w'(v}(w!MO,>.[ (x)(w!epW} (x7*4p(x!l]9< (y!'T (xt(y!;= (xz(y!ILZ?OAEr (z!'&BGP (|!sz (z!ju ({*(z!acr *~!?ABDIGJKORTZ\\]`be%gijlmoq *.!9;=?BC *k!34%:<%~ *l!&'%: *.!GJXZ%\\cefjnquz{ */!),/023N7;] )FP)G!/@ )Ft)GA)F!sq}|\\ )H6)G!iNQmE )HC)J=)H})I!GH )Hz*o!(4>DILV[aouvx%~ *p!&(%s )IL)Hq)I!3) )J&)Hd)I8)J@)Ia)J/)Ij)J!,S:OgG )I\\)KB)J!VW )KD)J!X52Hjv )K1)J!z| )K!J'7@U )Jd)KV)J\\)Ku)LL)Kc)L!45 )M))Kh)L!a[ )Md)L!mxR )M!R= )L!ZEu )M!@UTm[o )f!Je )P!:;@=KLFSTZc *^!UW[%]_`bacdfhklnqu *p!tu%~ *q!&'%6;NVbgjmor%xz%|~ *r!&-%0479@DEG%IL%PR%TVY[\\ac%gin%z} *s!&' *^!wxy *_!)+ *\\j)5!'37;>=A@H *7`)k!EJUegi )>/)@!789Sb )DW)@!L^I )^`)C5)@!f}z )A&)@~*2<)A!OD1?FQGgt| )B!>4Urs} )C'*X!236;=@EFHIGMUY *N!AD%FH%K )d!3d )c{)d!+4CDIPRTW )7r)8C)9h*s!)+.%02378:%CE%LNOQRTUWX\\_`eghmnpqs%|~ *t!&'%+/%24%689<>%ACFGIN%PT%VXY[%_acd );E)=,*2:)Q!JS]UYegfmux%z )R!(0+19 )>!0Pf )c!kptN *DV(`0*3!|yp *4@)CH*4!A5/18;k%n_FH]Q[ )CN*4!aouxq *5!89 *4v*5')CS*5=*Ue*5!aIWC]sw~ *6!F+,C2;NO?9 (q~(xw*6!ZTc )Ym*6!u| *7E)Cd*7!C4 *t!ef%moprsuw%{~ *u!&'(*%@BCEG%wz *w!'(%+-0%G )/n)0!63@ )/s)0!2< )1+)2!-4 )3!+wk )4!@F{ *3!]\\ )SA)TK)WF)t!+-5>LMF )?M)t!bQRn%pTqZaX^ )u!*I23 )t[)u,)t|)u!(Fwovcx} )v!&5<(W\\Lou )w/)vw)w!=NH^ +4.+2!>@A )q!1DM9GHZbYmfux )r!78.*AO *w!HI%~ *x!&'%N )r!ILftdgsx )s!-.>CK )l!7=KHEXov )m'*0!@IG *Oi*0!P\\Yaif )p!f~ *Ii*m!89:>=?@BCGJHM%OVW^]`_bcegi%moprw{%~ *n!&'(*%,/%13258%:<>?ABD *x!OP%Tknruy *y!*/%TVW[]^b%dg%mp%~ *z!&'%5 *n!CEHIM%OQSVWY]\\`acdg%il%pruw%y| *o!+,*-2357%9=?@C6E%GJMOPS%UW%Z\\_`^bce%mpr%t; )s!uz *sf)y!Me[c~ )'A)y!{z )z!=3 *z!67%:<=?%[]%~ *{!&'(+%79;HMNPSWX^ )z!XVp +1m*{z){6)oz)p!',2= )k!46 )l)+/!prx%| +0!)(-/.01589;=%@BCEHLNQ%SUZ]%chdj )m!68:DAPGWX\\hUTgfzq )n!.31/62N?FLN[lfrnsy *J!BGP[]` *K!'KE.DQ_PiKULJdjO *F!+34/5 *Ek*FU*Ey*F6*E!zsl *F!EI:JLOKe}`gp\\ *G!'1 *F!vsky *G!(k *Fd*G!fgdIY5Wt%ACE%HJ%OQS%VX%[]_a%ikm%su%w *HV*G!qn *H!=' *Gl*H!;u-BE498GR2lnY )~0)}!`qt )~!)6 )}v)~!-,KabsgXc@eW]fo *&3)~|*&!.??A *(,)>D*(!AMLNRblmqw|}xu *)!.? *95)B?*1!N]dtpux} *2)*)O**u*+!KS *-:*.5+1!VR *Xs*Y!+;8X *X!gm *U!RT *c!w}{| *d8+(!;<%~ +)!&'%A *d!65D=CQRFHM`Ydaevw~ *e!()*0/5 *U`+0u*Y_*Z!9S *[!N^ *Y!\\fcak}~ *Z!(, *Y!uv *Z)*Ym*Z!:EF1GI2WKbkmz|q} *[!/5.*2&>67FG?ekqdiz *\\!+0,8: *V!*4<7JF )?=*N!PXTV +)!BC%~ +*!&'%H *N!_ei *O_*R<*u>*t!-73JELSRnqt *u)+3!loq%vx +2!CPR *s!VYZko )sM*s}*g!Ww *h8*iU*j(*k/*jM*l!Jw ++!369%< )zB++!?BD%FHINOR%WY%]_abd%kn%qx%{~ +,&+*!IJ%~ ++!&'%/12478=>@CGJ%MQ^`cmr%v|} +,!,-56;<'%+.%02%478:= *u!gp|} *v!&A=5DF *~!{z +&(+0O+&!'+-2163<=B +'!][_a`ei *yo*z!;\\ *{!*) +&!PRW`\\l^jy +'!'+7; +1![\\ *-.+0!y~ +1!&)0 *k;+1!;=y%{~} +2!'.,*/4gqt~| +3!)*0 +,!>?%~ +-!&'%~ +.!&'%~ +/!&'%ntw~ +0!'+237DGI%KMPTV%Y\\efik%twxz%} +1!'(*%/2%:<>%CE%QS%UWXZ]%ac%fh%jnpqs%uwx| +2!&()+-0%35%=?BD%OQTVWY%[]_%dfh%prsu%{} +3!&(+%/1%;>%jmny%~ +4!&'%+/%14%8 .*f.+!Zv .,!oy .-!;<%>@BCGN%PRSV%X -R!XY%~ -S!&'%N")); + var gbk = src(gbk_us); + return gbk; + }(); + + var gbk_build = GBK$1; + + return gbk_build; + +}(); diff --git a/src/main/java/org/bdware/sc/engine/hook/ConfidentialHandler.java b/src/main/java/org/bdware/sc/engine/hook/ConfidentialHandler.java new file mode 100644 index 0000000..af91bc8 --- /dev/null +++ b/src/main/java/org/bdware/sc/engine/hook/ConfidentialHandler.java @@ -0,0 +1,34 @@ +package org.bdware.sc.engine.hook; + +import org.bdware.sc.JSEngine; +import org.bdware.sc.bean.ContractRequest; +import org.bdware.sc.engine.ConfidentialContractUtil; +import org.bdware.sc.engine.DesktopEngine; +import org.bdware.sc.node.AnnotationHook; +import org.bdware.sc.node.FunctionNode; +import wrp.jdk.nashorn.api.scripting.ScriptObjectMirror; + +public class ConfidentialHandler implements AnnotationHook { + private final FunctionNode fun; + + public ConfidentialHandler(FunctionNode fun) { + this.fun = fun; + } + + @Override + public Object handle(ContractRequest input, JSEngine engine, Object ret) { + try { + DesktopEngine desktopEngine = (DesktopEngine) engine; + ConfidentialContractUtil.copyTemplateToDestination(input); + ScriptObjectMirror globalVars = (ScriptObjectMirror) desktopEngine.get("Global"); + ConfidentialContractUtil.dumpScriptAndStates( + desktopEngine.engine, fun, input, globalVars); + // run in SGX instead of Nashorn if function has @Confidential annotation + ret = ConfidentialContractUtil.executeConfidentialContract(input); + return ret; + } catch (Exception e) { + e.printStackTrace(); + } + return ret; + } +} diff --git a/src/main/java/org/bdware/sc/engine/hook/HomoVisitor.java b/src/main/java/org/bdware/sc/engine/hook/HomoVisitor.java new file mode 100644 index 0000000..97d0f36 --- /dev/null +++ b/src/main/java/org/bdware/sc/engine/hook/HomoVisitor.java @@ -0,0 +1,86 @@ +package org.bdware.sc.engine.hook; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import org.bdware.mockjava.JsonVisitor; +import org.paillier.PaillierCipher; + +import java.math.BigInteger; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; + +public class HomoVisitor extends JsonVisitor { + public static RSAPublicKey publicKey; + JsonElement root; + public static RSAPrivateKey privateKey; + + public HomoVisitor(JsonElement ret) { + root = ret; + } + + @Override + public JsonVisitor visitObject(JsonObject homoConfig) { + if (root.isJsonObject()) { + JsonObject jo = root.getAsJsonObject(); + for (String key : homoConfig.keySet()) { + if (jo.has(key)) { + HomoVisitor visitor = new HomoVisitor(jo.get(key)); + visitor.visit(homoConfig.get(key)); + jo.add(key, visitor.get()); + } + } + } + return this; + } + + @Override + public JsonVisitor visitJsonArray(JsonArray ele) { + if (root.isJsonArray()) { + JsonArray array = root.getAsJsonArray(); + for (int i = 0; i < array.size(); i++) { + HomoVisitor visitor = new HomoVisitor((array.get(i))); + visitor.visit(ele.get(0)); + array.set(i, visitor.get()); + } + } + return this; + } + + public JsonElement get() { + return root; + } + + @Override + public JsonVisitor visitPrimitive(JsonPrimitive primitive) { + if (primitive.isString()) { + String method = primitive.getAsString(); + try { + String result = ""; + if (method.equals("@encrypt")) { + BigInteger i = handleRoot(root.getAsString()); + result = PaillierCipher.encrypt(i, publicKey); + } else if (method.equals("@decrypt")) { + BigInteger i = PaillierCipher.decrypt(root.getAsString(), privateKey); + result = String.valueOf(i); + } else { + result = root.getAsString(); + } + System.out.println(result); + root = new JsonPrimitive(result); + + } catch (Exception e) { + System.out.println(e); + } + } + + return this; + } + + private BigInteger handleRoot(String data) { + double d = Double.parseDouble(data); + long l = (long) d; + return BigInteger.valueOf(l); + } +} diff --git a/src/main/java/org/bdware/sc/engine/hook/HomomorphicDecryptHandler.java b/src/main/java/org/bdware/sc/engine/hook/HomomorphicDecryptHandler.java new file mode 100644 index 0000000..a83ee99 --- /dev/null +++ b/src/main/java/org/bdware/sc/engine/hook/HomomorphicDecryptHandler.java @@ -0,0 +1,73 @@ +package org.bdware.sc.engine.hook; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.bdware.sc.ContractResult; +import org.bdware.sc.JSEngine; +import org.bdware.sc.bean.ContractRequest; +import org.bdware.sc.boundry.JavaScriptEntry; +import org.bdware.sc.node.AnnotationHook; +import org.bdware.sc.node.FunctionNode; +import org.bdware.sc.util.JsonUtil; +import org.paillier.PaillierKeyPair; + +import java.security.interfaces.RSAPrivateKey; + +public class HomomorphicDecryptHandler implements AnnotationHook { + private static final Logger LOGGER = LogManager.getLogger(ObjToJsonHandler.class); + + private final FunctionNode fun; + + public HomomorphicDecryptHandler(FunctionNode fun) { + this.fun = fun; + } + + @Override + public Object handle(ContractRequest input, JSEngine engine, Object ret) { + try { +// GetHomArgs args = +// new GetHomArgs( +// input.getRequester(), this.fun.getSecretID().replaceAll("\"", "")); +// String arg = JsonUtil.toJson(args); + JsonElement homoDecryptConf = this.fun.getHomoDecryptConf(); + if (null != homoDecryptConf && !homoDecryptConf.isJsonNull()) { + String res = + JavaScriptEntry.executeContract( + "keyManager_1", + "getPrivKey", + this.fun.getSecretID().replaceAll("\"", "")); + LOGGER.info("HomomorphicDecryptHandler--------------------------------1: " + res); + ContractResult results = JsonUtil.fromJson(res, ContractResult.class); + String privKeyStr = results.result.getAsString(); + LOGGER.info("HomomorphicEncryptHandler--------------------------------2: " + privKeyStr); + RSAPrivateKey privkey = (RSAPrivateKey) PaillierKeyPair.pemToPrivateKey(privKeyStr); + LOGGER.info("HomomorphicEncryptHandler--------------------------------3: " + privkey); + HomoVisitor.privateKey = privkey; + ret = getDecryptResult(homoDecryptConf, JsonUtil.parseObject(ret)); + if (ret != null) { + return ret; + } + ret = new JsonObject(); + } + return ret; + // return ret; + } catch (Exception e) { + e.printStackTrace(); + } + return ret; + } + + private Object getDecryptResult(JsonElement homoDecryptConf, JsonElement data) { + if (null == homoDecryptConf) { + return data; + } + HomoVisitor visitor = new HomoVisitor(data); + visitor.visit(homoDecryptConf); + + JsonElement root = visitor.get(); + LOGGER.info("HomoRetInvoke: " + root); + return root; + } +} diff --git a/src/main/java/org/bdware/sc/engine/hook/HomomorphicEncryptHandler.java b/src/main/java/org/bdware/sc/engine/hook/HomomorphicEncryptHandler.java new file mode 100644 index 0000000..bcfc695 --- /dev/null +++ b/src/main/java/org/bdware/sc/engine/hook/HomomorphicEncryptHandler.java @@ -0,0 +1,88 @@ +package org.bdware.sc.engine.hook; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.bdware.sc.ContractResult; +import org.bdware.sc.JSEngine; +import org.bdware.sc.bean.ContractRequest; +import org.bdware.sc.boundry.JavaScriptEntry; +import org.bdware.sc.node.AnnotationHook; +import org.bdware.sc.node.FunctionNode; +import org.bdware.sc.util.JsonUtil; +import org.paillier.PaillierKeyPair; + +import java.security.interfaces.RSAPublicKey; + +public class HomomorphicEncryptHandler implements AnnotationHook { + private static final Logger LOGGER = LogManager.getLogger(ObjToJsonHandler.class); + + private final FunctionNode fun; + + public HomomorphicEncryptHandler(FunctionNode fun) { + this.fun = fun; + } + + @Override + public Object handle(ContractRequest input, JSEngine engine, Object ret) { + try { + LOGGER.info( + "HomomorphicEncryptHandler--------------------------------1: " + + input.getRequester()); + LOGGER.info( + "HomomorphicEncryptHandler--------------------------------2: " + + this.fun.getSecretID()); + JsonElement response = (JsonElement) ret; + JsonElement homoEncryptConf = this.fun.getHomoEncryptConf(); + if (homoEncryptConf != null && !homoEncryptConf.isJsonNull()) { + String res = + JavaScriptEntry.executeContract( + "keyManager_1", + "getPubKey", + this.fun.getSecretID().replaceAll("\"", "")); +// String res = +// JavaScriptEntry.executeContract( +// this.fun.getKeyManagerID(), +// "getPubKey", +// this.fun.getSecretID().replaceAll("\"", "")); + LOGGER.info("HomomorphicEncryptHandler--------------------------------4: " + res); + ContractResult results = JsonUtil.fromJson(res, ContractResult.class); + String pubKeyStr = results.result.getAsString(); + LOGGER.info("HomomorphicEncryptHandler--------------------------------5: " + pubKeyStr); + HomoVisitor.publicKey = (RSAPublicKey) PaillierKeyPair.pemToPublicKey(pubKeyStr); +// if (homoEncryptConf.getAsJsonPrimitive().isString()) +// homoEncryptConf = JsonParser.parseString(homoEncryptConf.getAsString()); + LOGGER.info("HomomorphicEncryptHandler--------------------------------6: " + homoEncryptConf); + LOGGER.info("HomomorphicEncryptHandler--------------------------------7: " + ret); + LOGGER.info("HomomorphicEncryptHandler--------------------------------8: " + ret.toString()); + LOGGER.info("HomomorphicEncryptHandler--------------------------------9: " + JsonUtil.toJson(ret)); + ret = getEncryptResult(homoEncryptConf, response); + if (ret != null) { + return ret; + } + ret = new JsonObject(); + } + return ret; + } catch (Exception e) { + e.printStackTrace(); + } + return ret; + } + + private Object getEncryptResult(JsonElement homoEncryptConf, JsonElement data) { +// if (null == homoEncryptConf || homoEncryptConf.getAsString().isEmpty()) { +// return data; +// } + if (null == homoEncryptConf) { + return data; + } + HomoVisitor visitor = new HomoVisitor(data); + visitor.visit(homoEncryptConf); + + JsonElement root = visitor.get(); + System.out.println("HomoRetInvoke: " + root); + LOGGER.info("HomoRetInvoke: " + root); + return root; + } +} diff --git a/src/main/java/org/bdware/sc/engine/hook/MaskHandler.java b/src/main/java/org/bdware/sc/engine/hook/MaskHandler.java new file mode 100644 index 0000000..00afedb --- /dev/null +++ b/src/main/java/org/bdware/sc/engine/hook/MaskHandler.java @@ -0,0 +1,59 @@ +package org.bdware.sc.engine.hook; + +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.bdware.sc.JSEngine; +import org.bdware.sc.bean.ContractRequest; +import org.bdware.sc.bean.ProjectConfig; +import org.bdware.sc.engine.DesktopEngine; +import org.bdware.sc.node.AnnotationHook; + +public class MaskHandler implements AnnotationHook { + private static final Logger LOGGER = LogManager.getLogger(MaskHandler.class); + + @Override + public Object handle(ContractRequest input, JSEngine Engine, Object ret) { + try { + DesktopEngine desktopEngine = (DesktopEngine) Engine; + ProjectConfig projectConfig = desktopEngine.getProjectConfig(); + JsonElement maskConf = projectConfig.getMask(input.getAction()); + LOGGER.info("execute maskConf: " + maskConf); + if (null != maskConf) { + String s1 = ret.toString(); + //budeijin + //"{\"count\":1}" + //{"count":1} + //System.out.println(s1); + s1 = s1.replace("\\", ""); + s1 = s1.substring(1, s1.length() - 1); + //System.out.println(s1); + //System.out.println(JsonParser.parseString(s1)); + MaskVisitor visitor = new MaskVisitor(JsonParser.parseString(s1)); + visitor.visit(maskConf); + ret = visitor.get(); + System.out.println(maskConf); + if (null != ret) { + return ret; + } + ret = JsonParser.parseString(""); + } + return ret; + } catch (Exception e) { + e.printStackTrace(); + return ret; + } + } + + public Object getMaskResult(JsonElement maskConfigInvoke, JsonElement data) { + if (null == maskConfigInvoke || maskConfigInvoke.getAsString().isEmpty()) { + return data; + } + MaskVisitor visitor = new MaskVisitor(data); + visitor.visit(maskConfigInvoke); + JsonElement root = visitor.get(); + LOGGER.info("MaskRetInvoke: " + root); + return root; + } +} diff --git a/src/main/java/org/bdware/sc/engine/hook/MaskVisitor.java b/src/main/java/org/bdware/sc/engine/hook/MaskVisitor.java new file mode 100644 index 0000000..20b932f --- /dev/null +++ b/src/main/java/org/bdware/sc/engine/hook/MaskVisitor.java @@ -0,0 +1,97 @@ +package org.bdware.sc.engine.hook; + +import com.alibaba.datax.transport.transformer.maskingMethods.cryptology.AESEncryptionImpl; +import com.alibaba.datax.transport.transformer.maskingMethods.cryptology.FormatPreservingEncryptionImpl; +import com.alibaba.datax.transport.transformer.maskingMethods.differentialPrivacy.EpsilonDifferentialPrivacyImpl; +import com.alibaba.datax.transport.transformer.maskingMethods.irreversibleInterference.MD5EncryptionImpl; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import org.bdware.mockjava.JsonVisitor; + +public class MaskVisitor extends JsonVisitor { + JsonElement root; + + public MaskVisitor(JsonElement ret) { + root = ret; + } + + @Override + public JsonVisitor visitObject(JsonObject mask) { + if (root.isJsonObject()) { + JsonObject jo = root.getAsJsonObject(); + for (String key : mask.keySet()) { + if (jo.has(key)) { + //TODO + MaskVisitor visitor = new MaskVisitor(jo.get(key)); + visitor.visit(mask.get(key)); + jo.add(key, visitor.get()); + } + } + } + return this; + } + + @Override + public JsonVisitor visitJsonArray(JsonArray ele) { + if (root.isJsonArray()) { + JsonArray array = root.getAsJsonArray(); + for (int i = 0; i < array.size(); i++) { + MaskVisitor visitor = new MaskVisitor(array.get(i)); + visitor.visit(ele.get(0)); + array.set(i, visitor.get()); + } + } + return this; + } + + public JsonElement get() { + return root; + } + + @Override + + public JsonVisitor visitPrimitive(JsonPrimitive primitive) { + // + if (primitive.isString()) { + String method = primitive.getAsString(); + try { + String result = ""; + //md5不需要参数 + if (method.equals("md5")) { + MD5EncryptionImpl masker = new MD5EncryptionImpl(); + result = masker.execute(root.getAsString()); + } else if (method.equals("aes")) { + AESEncryptionImpl masker = new AESEncryptionImpl(); + result = masker.execute(root.getAsString()); + } else if (method.equals("fpe")) { + FormatPreservingEncryptionImpl masker = new FormatPreservingEncryptionImpl(); + result = masker.execute(root.getAsString()); + } + //edp需要精度的参数 + else if (method.equals("edp")) { + EpsilonDifferentialPrivacyImpl masker = new EpsilonDifferentialPrivacyImpl(); + double epsilon = 1; + + result = "" + masker.maskOne(root.getAsDouble(), epsilon); + } else { + result = root.getAsString(); + } + System.out.println(result); + root = new JsonPrimitive(result); + + } catch (Exception e) { + System.out.println(e); + } + } + + + //String result = masker.execute(primitive.toString()); + //System.out.println(result); + + //root = new JsonPrimitive(root.getAsString().substring(0, 2)); + //https://github.com/guohf/DataX-Masking + return this; + } +} diff --git a/src/main/java/org/bdware/sc/engine/hook/MockTemplateHandler.java b/src/main/java/org/bdware/sc/engine/hook/MockTemplateHandler.java new file mode 100644 index 0000000..bcbc083 --- /dev/null +++ b/src/main/java/org/bdware/sc/engine/hook/MockTemplateHandler.java @@ -0,0 +1,26 @@ +package org.bdware.sc.engine.hook; + +import org.bdware.mockjava.MockUtil; +import org.bdware.sc.JSEngine; +import org.bdware.sc.bean.ContractRequest; +import org.bdware.sc.bean.ProjectConfig; +import org.bdware.sc.engine.DesktopEngine; +import org.bdware.sc.node.AnnotationHook; + +public class MockTemplateHandler implements AnnotationHook { + @Override + public Object handle(ContractRequest request, JSEngine engine, Object ret) { + if (request.fromDebug()) { + System.out.println(request.getAction()); + DesktopEngine desktopEngine = (DesktopEngine) engine; + ProjectConfig projectConfig = desktopEngine.getProjectConfig(); + String template = projectConfig.getMock(request.getAction()); + if (template != null && template.length() > 0) { + System.out.println(template); + MockUtil Mock = new MockUtil(); + return Mock.mock(template).toString(); + } + else return ret; //When mock config is null defined just ignore. + } else return ret; + } +} diff --git a/src/main/java/org/bdware/sc/engine/hook/ObjToJsonHandler.java b/src/main/java/org/bdware/sc/engine/hook/ObjToJsonHandler.java new file mode 100644 index 0000000..d1cff64 --- /dev/null +++ b/src/main/java/org/bdware/sc/engine/hook/ObjToJsonHandler.java @@ -0,0 +1,42 @@ +package org.bdware.sc.engine.hook; + +import com.google.gson.JsonElement; +import com.google.gson.JsonNull; +import com.google.gson.JsonPrimitive; +import org.bdware.sc.JSEngine; +import org.bdware.sc.bean.ContractRequest; +import org.bdware.sc.engine.JSONTool; +import org.bdware.sc.node.AnnotationHook; +import wrp.jdk.nashorn.api.scripting.ScriptObjectMirror; + +public class ObjToJsonHandler implements AnnotationHook { +// private static final Logger LOGGER = LogManager.getLogger(ObjToJsonHandler.class); + + @Override + public Object handle(ContractRequest input, JSEngine desktopEngine, Object ret) { + JsonElement je; + if (ret == null) { + je = JsonNull.INSTANCE; + } else if (ret instanceof ScriptObjectMirror) { + ScriptObjectMirror ret2 = (ScriptObjectMirror) ret; + // LOGGER.debug("[before parse to json]" + ret2); + je = JSONTool.copy(ret2); + } else if (ret instanceof jdk.nashorn.api.scripting.ScriptObjectMirror) { + jdk.nashorn.api.scripting.ScriptObjectMirror ret2 = + (jdk.nashorn.api.scripting.ScriptObjectMirror) ret; + // LOGGER.debug("[before parse to json]" + ret2); + je = JSONTool.copy(ret2); + } else if (ret instanceof Number) { + je = new JsonPrimitive((Number) ret); + } else if (ret instanceof Character) { + je = new JsonPrimitive((Character) ret); + } else if (ret instanceof Boolean) { + je = new JsonPrimitive((Boolean) ret); + } else if (ret instanceof String) { + je = new JsonPrimitive((String) ret); + } else { + je = new JsonPrimitive(ret.toString()); + } + return je; + } +} diff --git a/src/main/java/org/bdware/sc/engine/hook/ReadMeHandler.java b/src/main/java/org/bdware/sc/engine/hook/ReadMeHandler.java new file mode 100644 index 0000000..21645c1 --- /dev/null +++ b/src/main/java/org/bdware/sc/engine/hook/ReadMeHandler.java @@ -0,0 +1,67 @@ +package org.bdware.sc.engine.hook; + +import org.bdware.sc.JSEngine; +import org.bdware.sc.bean.ContractRequest; +import org.bdware.sc.engine.DesktopEngine; +import org.bdware.sc.node.AnnotationHook; +import org.commonmark.node.FencedCodeBlock; +import org.commonmark.node.Heading; +import org.commonmark.node.Node; +import org.commonmark.node.Text; +import org.commonmark.parser.Parser; + +public class ReadMeHandler implements AnnotationHook { + String getReadMeData(DesktopEngine desktopEngine, ContractRequest c) { + String fileReadme = + desktopEngine + .getResources() + .loadAsString("/assets/README.md"); // is "/README.md" not"./README.md"!!!! + // System.out.println("fileReadme:" + fileReadme); + if (null == fileReadme) { + return "项目目录下无预览文档"; + } else { + String result = "未能返回调试调用结果"; + String targetFunction = c.getAction(); + try { + Parser parser = Parser.builder().build(); + Node document = parser.parse(fileReadme); + Node visitor = document.getFirstChild(); + while (visitor != null) { + if (visitor instanceof Heading) { + if (((Heading) visitor).getLevel() == 2) { + if (((Text) (visitor.getFirstChild())) + .getLiteral() + .equals(targetFunction)) { + FencedCodeBlock blockResult = + (FencedCodeBlock) + (visitor.getNext() + .getNext() + .getNext() + .getNext() + .getNext() + .getNext() + .getNext()); + result = blockResult.getLiteral(); + break; + } + } + } + visitor = visitor.getNext(); + } + } catch (Exception e) { + e.printStackTrace(); + } + return result; + } + } + + @Override + public Object handle(ContractRequest input, JSEngine engine, Object ret) { + DesktopEngine desktopEngine = (DesktopEngine) engine; + if (input.fromDebug() && (ret == null || ret.equals("emptyMock"))) { + ret = getReadMeData(desktopEngine, input); + System.out.println(ret); + } + return ret; + } +} diff --git a/src/main/java/org/bdware/sc/engine/setArgs/GetHomArgs.java b/src/main/java/org/bdware/sc/engine/setArgs/GetHomArgs.java new file mode 100644 index 0000000..e1d5166 --- /dev/null +++ b/src/main/java/org/bdware/sc/engine/setArgs/GetHomArgs.java @@ -0,0 +1,12 @@ +package org.bdware.sc.engine.setArgs; + +public class GetHomArgs { + public String secretID; + + public GetHomArgs() { + } + + public GetHomArgs(String secretID) { + this.secretID = secretID; + } +} diff --git a/src/main/java/org/bdware/sc/handler/ContractHandler.java b/src/main/java/org/bdware/sc/handler/ContractHandler.java new file mode 100644 index 0000000..1158c6c --- /dev/null +++ b/src/main/java/org/bdware/sc/handler/ContractHandler.java @@ -0,0 +1,298 @@ +package org.bdware.sc.handler; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.bdware.sc.ContractProcess; +import org.bdware.sc.bean.Contract; +import org.bdware.sc.conn.Description; +import org.bdware.sc.conn.MsgHandler; +import org.bdware.sc.conn.ResultCallback; +import org.bdware.sc.conn.ServiceServer; +import org.bdware.sc.get.GetMessage; +import org.bdware.sc.util.JsonUtil; + +import java.util.HashMap; +import java.util.Map; + +public class ContractHandler extends MsgHandler implements Runnable { + private static final Logger LOGGER = LogManager.getLogger(ContractHandler.class); + ContractProcess cs; + String identifier = "null"; + + public ContractHandler(ContractProcess cs) { + this.cs = cs; + } + + public void run() { + System.out.println("ContractHandler: exit in 2 seconds!"); + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + System.exit(0); + } + + @Description("start sync mech") + public void startSync(GetMessage msg, ResultCallback cb) { + cs.startSync(); + cb.onResult("success"); + } + + @Description("stop sync mech") + public void stopSync(GetMessage msg, ResultCallback cb) { + cs.stopSync(); + cb.onResult("success"); + } + + @Description("set ContractRecord file name") + public void setCRFile(GetMessage msg, ResultCallback cb) { + cs.setCRFile(msg.arg); + cb.onResult("success"); + } + + @Description("set contractDir") + public void setDir(GetMessage msg, ResultCallback cb) { + System.out.println("ContractHandler setDir"); + cs.setDir(msg.arg); + cb.onResult("success"); + } + + @Description("getDebug") + public void getDebug(GetMessage msg, ResultCallback cb) { + LOGGER.debug("getDebug"); + cb.onResult(JsonUtil.toJson(cs.isDebug())); + } + + @Description("clearSyncFiles") + public void clearSyncFiles(GetMessage msg, ResultCallback cb) { + cs.clearSyncFiles(msg.arg); + cb.onResult("success"); + } + + @Description("changeDumpPeriod") + public void changeDumpPeriod(GetMessage msg, ResultCallback cb) { + cb.onResult(cs.changeDumpPeriod(msg.arg)); + } + + @Description("getDumpPeriod") + public void getDumpPeriod(GetMessage msg, ResultCallback cb) { + cb.onResult(cs.getDumpPeriod()); + } + + @Description("getCachedTransRecords") + public void getCachedTransRecords(GetMessage msg, ResultCallback cb) { + cb.onResult(cs.getCachedTransRecords(msg.arg)); + } + + @Description("start auto dump") + public void startAutoDump(GetMessage msg, ResultCallback cb) { + cb.onResult(cs.startAutoDump()); + } + + @Description("register manager port") + public void registerMangerPort(GetMessage msg, ResultCallback cb) { + cb.onResult(cs.registerMangerPort(msg.arg)); + } + + @Description("set current ContractBundle") + public void setContractBundle(GetMessage msg, ResultCallback cb) { + cb.onResult(cs.setContractBundle(JsonUtil.fromJson(msg.arg, Contract.class))); + } + + @Description("get current contract name") + public void getContractName(GetMessage msg, ResultCallback cb) { + cb.onResult(cs.getContractName()); + } + + @Description("set current Contract") + public void setContract(GetMessage msg, ResultCallback cb) { + cb.onResult(cs.setContract(JsonUtil.fromJson(msg.arg, Contract.class))); + } + + @Description(value = "execute contract") + public void executeContract(GetMessage msg, ResultCallback cb) { + cb.onResult(cs.executeContract(msg.arg)); + } + + @Description("set DesktopPermission") + public void setDesktopPermission(GetMessage msg, ResultCallback cb) { + String result = cs.setDesktopPermission(msg.arg); + cb.onResult(result); + } + + @Description("change debug Flag") + public void changeDebugFlag(GetMessage msg, ResultCallback cb) { + String result = cs.changeDebugFlag(Boolean.valueOf(msg.arg)); + cb.onResult(result); + } + + @Description("get functionEvaluates ") + public void functionEvaluates(GetMessage msg, ResultCallback cb) { + cb.onResult(cs.evaluatesAnalysis(msg.arg)); + } + + @Description("get memory set") + public void getMemorySet(GetMessage msg, ResultCallback cb) { + cb.onResult(cs.getMemorySet()); + } + + @Description("get logType ") + public void getLogType(GetMessage msg, ResultCallback cb) { + cb.onResult(cs.getLogType(msg.arg)); + } + + @Description("exit Contract!") + public void suicide(GetMessage msg, ResultCallback cb) { + Map ret = new HashMap<>(); + ret.put("status", "success"); + cs.beforeSuicide(); + if (cs.checkSub()) { + ret.put("cleanSub", true); + } + ServiceServer.executor.execute(this); + cb.onResult(JsonUtil.toJson(ret)); + } + + @Description("check alive") + public void ping(GetMessage msg, ResultCallback cb) { + cb.onResult("pong"); + } + + @Description("dump contract process memory") + public void getMemoryDump(GetMessage msg, ResultCallback cb) { + cb.onResult(cs.getMemoryDump(msg.arg)); + } + + @Description("get memory usage") + public void getStorage(GetMessage msg, ResultCallback cb) { + cb.onResult(cs.getStorage()); + } + + @Description("redo by local trans record") + public void redo(GetMessage msg, ResultCallback cb) { + cb.onResult(cs.redo(msg.arg)); + } + + @Description("load dumped memory") + public void loadMemory(GetMessage msg, ResultCallback cb) { + cb.onResult(cs.loadMemoryDump(msg.arg)); + } + + @Description("setDBInfo, the db is used to store local logs") + public void setDBInfo(GetMessage msg, ResultCallback cb) { + cb.onResult(cs.setDBInfo(msg.arg)); + } + + @Description("getUsedMemory") + public void getUsedMemory(GetMessage msg, ResultCallback cb) { + cb.onResult(cs.getUsedMemory("") + ""); + } + + @Description("showPermission") + public void showPermission(GetMessage msg, ResultCallback cb) { + cb.onResult(cs.showPermission()); + } + + @Description("is signature required?") + public void isSigRequired(GetMessage msg, ResultCallback cb) { + cb.onResult(cs.isSigRequired() + ""); + } + + @Description("Get Declared Events") + public void getDeclaredEvents(GetMessage msg, ResultCallback cb) { + cb.onResult(cs.getDeclaredEvents()); + } + + @Description("Get Contract Annotations") + public void getAnnotations(GetMessage msg, ResultCallback cb) { + cb.onResult(cs.getAnnotations()); + } + + @Description("Get Exported Functions") + public void getExportedFunctions(GetMessage msg, ResultCallback cb) { + cb.onResult(cs.getExportedFunctions()); + } + + @Description("Whether current process is contract process, always cmi") + public void isContractProcess(GetMessage msg, ResultCallback cb) { + cb.onResult(cs.cmi); + } + + @Description("get contract") + public void getContract(GetMessage msg, ResultCallback cb) { + cb.onResult(cs.getContract()); + } + + @Description("setPID") + public void setPID(GetMessage msg, ResultCallback cb) { + cs.setPID(msg.arg); + cb.onResult("success"); + } + + @Description("setProjectConfig") + public void setProjectConfig(GetMessage msg, ResultCallback cb) { + LOGGER.debug("ContractHandler: " + msg.arg); + cs.setProjectConfig(msg.arg); + cb.onResult("success"); + } + + @Description("getPID") + public void getPID(GetMessage msg, ResultCallback cb) { + cb.onResult(cs.getPID()); + } + + @Description("requestLogSize") + public void getLogSize(GetMessage msg, ResultCallback cb) { + cb.onResult(cs.logSize() + ""); + } + + @Description("request Log") + public void requestLog(GetMessage msg, ResultCallback cb) { + String[] data = msg.arg.split(","); + cb.onResult(cs.requestLog(Long.parseLong(data[0]), Integer.parseInt(data[1]))); + } + + @Description("request LastLog") + public void requestLastLog(GetMessage msg, ResultCallback cb) { + cb.onResult(cs.requestLast(Integer.parseInt(msg.arg))); + } + + @Description("setIdentifier") + public void setIdentifier(GetMessage msg, ResultCallback cb) { + identifier = msg.arg; + cb.onResult("success"); + } + + @Description("getIdentifier") + public void getIdentifier(GetMessage msg, ResultCallback cb) { + cb.onResult(identifier); + } + + @Description("getControlFlow") + public void getControlFlow(GetMessage msg, ResultCallback cb) { + cb.onResult(cs.getControlFlow(JsonUtil.fromJson(msg.arg, Contract.class))); + } + + @Description("getStateful") + public void getStateful(GetMessage msg, ResultCallback cb) { + cb.onResult(cs.getStateful()); + } + + @Description("parseYpkPermissions") + public void parseYpkPermissions(GetMessage msg, ResultCallback cb) { + cb.onResult(cs.parseYpkPermissions(msg.arg)); + } + + @Description("staticVerify") + public void staticVerify(GetMessage msg, ResultCallback cb) { + cb.onResult(cs.staticVerify(JsonUtil.fromJson(msg.arg, Contract.class))); + } + + @Description("getDependentContracts") + public void getDependentContracts(GetMessage msg, ResultCallback cb) { + cb.onResult(cs.getDependentContracts()); + } + + +} diff --git a/src/main/java/org/bdware/sc/handler/Exitor.java b/src/main/java/org/bdware/sc/handler/Exitor.java new file mode 100644 index 0000000..0db596f --- /dev/null +++ b/src/main/java/org/bdware/sc/handler/Exitor.java @@ -0,0 +1,13 @@ +package org.bdware.sc.handler; + +public class Exitor implements Runnable { + public void run() { + System.out.println("ContractHandler: exit in 2 seconds!"); + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + System.exit(0); + } +} diff --git a/src/main/java/org/bdware/sc/memory/JSEDump.java b/src/main/java/org/bdware/sc/memory/JSEDump.java new file mode 100644 index 0000000..1e10ec9 --- /dev/null +++ b/src/main/java/org/bdware/sc/memory/JSEDump.java @@ -0,0 +1,21 @@ +package org.bdware.sc.memory; + +import java.io.Serializable; + +public class JSEDump implements Serializable { + long invokeID; + long ranSeed; + int numsOfCopies; + + public JSEDump(long id,long ra,int nums){ + invokeID = id; + ranSeed = ra; + numsOfCopies = nums; + } + + public void printContent(){ + System.out.println("invokeID=" + invokeID); + System.out.println("ranSeed=" + ranSeed); + System.out.println("numsOfCopies=" + numsOfCopies); + } +} diff --git a/src/main/java/org/bdware/sc/memory/MOType.java b/src/main/java/org/bdware/sc/memory/MOType.java new file mode 100644 index 0000000..3aff8e6 --- /dev/null +++ b/src/main/java/org/bdware/sc/memory/MOType.java @@ -0,0 +1,40 @@ +package org.bdware.sc.memory; + +import jdk.internal.dynalink.beans.StaticClass; +import wrp.jdk.nashorn.api.scripting.ScriptObjectMirror; + +public enum MOType { + String(true), Int(true), Double(true), Boolean(true),JSObject(false), JSArray(false), JavaObject(false), Method(false), + Undefined(true), JSFunction(false),JSStatic(false); + + private boolean isPrimitive; + + MOType(boolean isPrimitive) { + this.isPrimitive = (isPrimitive); + } + + public static MOType getType(Object obj) { + if (obj == null) + return Undefined; + if (obj instanceof Integer) { + return Int; + } else if (obj instanceof Double) { + return Double; + } else if (obj instanceof String) { + return String; + } else if (obj instanceof ScriptObjectMirror) { + // ------ + return JSObject; + }else if(obj instanceof StaticClass) { + return JSStatic; + }else if(obj instanceof Boolean){ + return Boolean; + } + return JSObject; + } + + public boolean isPrimitive() { + return isPrimitive; + } + +} \ No newline at end of file diff --git a/src/main/java/org/bdware/sc/memory/MemoryArrayObject.java b/src/main/java/org/bdware/sc/memory/MemoryArrayObject.java new file mode 100644 index 0000000..99fc177 --- /dev/null +++ b/src/main/java/org/bdware/sc/memory/MemoryArrayObject.java @@ -0,0 +1,12 @@ +package org.bdware.sc.memory; + +public class MemoryArrayObject extends MemoryJSObject{ + + private static final long serialVersionUID = -5805776423219733634L; + + public MemoryArrayObject(long id) { + super(id); + type = MOType.JSArray; + } + +} diff --git a/src/main/java/org/bdware/sc/memory/MemoryDump.java b/src/main/java/org/bdware/sc/memory/MemoryDump.java new file mode 100644 index 0000000..87ee216 --- /dev/null +++ b/src/main/java/org/bdware/sc/memory/MemoryDump.java @@ -0,0 +1,231 @@ +package org.bdware.sc.memory; + + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import org.bdware.sc.boundry.JavaScriptEntry; +import org.bdware.sc.util.JsonUtil; +import wrp.jdk.nashorn.api.scripting.ScriptObjectMirror; +import wrp.jdk.nashorn.internal.objects.Global; +import wrp.jdk.nashorn.internal.runtime.Context; +import wrp.jdk.nashorn.internal.runtime.PropertyMap; +import wrp.jdk.nashorn.internal.scripts.JO; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + + +public class MemoryDump implements Serializable { + transient long id; + transient Map allocated; //js对象,id + + Map objects; //id,memory对象 + JSEDump jseDump; + + transient Map recreate; + + public MemoryDump() { + objects = new HashMap<>(); + allocated = new HashMap<>(); + id = 0; + getRoot(); + } + + public static MemoryDump loadFromStr(String memDump) { + JsonElement jo = new com.google.gson.JsonParser().parse(memDump); +// JsonElement objs = jo.getAsJsonObject().get("objects"); +// JsonObject map = objs.getAsJsonObject(); + JsonObject map = jo.getAsJsonObject(); + MemoryDump ret = new MemoryDump(); + for (Entry entry : map.entrySet()) { + long id = Long.parseLong(entry.getKey()); + JsonObject obj = entry.getValue().getAsJsonObject(); + MOType type = MOType.valueOf(obj.get("type").getAsString()); + MemoryObject mo = null; + + switch (type) { + case JSObject: + case JSArray: + mo = JsonUtil.fromJson(obj, MemoryJSObject.class); + break; + case JSFunction: + mo = JsonUtil.fromJson(obj, MemoryFunctionObject.class); + break; + case Int: + mo = JsonUtil.fromJson(obj, MemoryObject.class); + mo.data = Integer.parseInt(obj.get("data").getAsString()); + break; + case Boolean: + mo = JsonUtil.fromJson(obj, MemoryObject.class); + mo.data = Boolean.parseBoolean(obj.get("data").getAsString()); + break; + case String: + case Double: + mo = JsonUtil.fromJson(obj, MemoryObject.class); + break; + default: + System.out.println("[MemoryDump] todo, missing type:" + type.toString()); + break; + } + ret.objects.put(id, mo); + } + + return ret; + } + + public Map getObjects() { + return objects; + } + + public void setObjects(Map m) { + this.objects = m; + } + + public MemoryJSObject getRoot() { + if (objects.containsKey(0L)) + return (MemoryJSObject) objects.get(0L); + else { + MemoryJSObject jo = new MemoryJSObject(0); + objects.put((long) 0, jo); + return jo; + } + } + + public long allocate(Object obj) { + if (obj == null) + return -1; + + long currID; + + id++; + currID = id; + if (obj.getClass() == jdk.internal.dynalink.beans.StaticClass.class) { + /* + String obj2 = "jdk.internal.dynalink.beans.StaticClass.class"; + if (allocated.containsKey(obj2)) + return allocated.get(obj2); + allocated.put(obj2, currID); + */ + } else { + if (allocated.containsKey(obj)) + return allocated.get(obj); + allocated.put(obj, currID); + } + + + // 如果是对象 + if (obj.getClass() == ScriptObjectMirror.class) { + ScriptObjectMirror som = (ScriptObjectMirror) obj; + if (som.isFunction()) { + MemoryFunctionObject fo = new MemoryFunctionObject(currID); + objects.put(currID, fo); + for (String str : som.getOwnKeys(true)) { + fo.addField(str, allocate(som.getMember(str))); + } + } else if (som.isArray()) { + MemoryArrayObject ao = new MemoryArrayObject(currID); + objects.put(currID, ao); + for (String str : som.getOwnKeys(true)) { + ao.addField(str, allocate(som.getMember(str))); + } + } else { + MemoryJSObject jo = new MemoryJSObject(currID); + objects.put(currID, jo); + for (String str : som.getOwnKeys(true)) { + jo.addField(str, allocate(som.getMember(str))); + } + } + } else if (obj.getClass() == wrp.jdk.nashorn.internal.runtime.Undefined.class) { + + } else if (obj.getClass() == jdk.internal.dynalink.beans.StaticClass.class) { + //regard as String + +// MemoryObject mo = new MemoryObject(currID); +// mo.type = MOType.String; +// mo.data = "jdk.internal.dynalink.beans.StaticClass"; +// objects.put(currID, mo); + } else { + MOType type = MOType.getType(obj); + if (type.isPrimitive()) { + MemoryObject mo = new MemoryObject(currID); + mo.type = type; + mo.data = obj; + objects.put(currID, mo); + } else + System.out.println("[MemoryDump] Allocat MetType:" + obj.getClass() + " now id=" + currID); + + } + return currID; + } + + public Map recreateObject() { + recreate = new HashMap<>(); + fillRecreate(); + fillJO(); + return recreate; + } + + private void fillJO() { + for (Long key : objects.keySet()) { + MemoryObject mo = objects.get(key); + if (mo == null) + continue; + + switch (mo.type) { + case JSObject: + case JSArray: + MemoryJSObject mjo = (MemoryJSObject) mo; + ScriptObjectMirror jo = (ScriptObjectMirror) recreate.get(key); + for (String field : mjo.fields.keySet()) { + Object temp = recreate.get(mjo.fields.get(field)); + + if (mjo.fields.get(field) >= 0) { + if (field.length() > 0) + jo.setMember(field, temp); + else + jo.setMember(" ", temp); + } + } + break; + default: + break; + } + } + + } + + private void fillRecreate() { + Context.setGlobal(JavaScriptEntry.getEngineGlobal()); + for (Long key : objects.keySet()) { + Object obj = null; + MemoryObject mo = objects.get(key); + if (mo == null) { + continue; + } + switch (mo.type) { + case JSArray: + obj = ScriptObjectMirror.wrap(Global.allocate(new int[0]), JavaScriptEntry.getEngineGlobal()); + break; + case JSObject: + obj = ScriptObjectMirror.wrap(new JO(PropertyMap.newMap()), JavaScriptEntry.getEngineGlobal()); + break; + case JSFunction: + break; + case String: + case Int: + obj = mo.data; + break; + case Double: + obj = Double.parseDouble(mo.data.toString()); + break; + default: + System.out.println("[MemoryDump] todo, missing type:" + mo.type.toString()); + break; + } + + recreate.put(key, obj); + } + } +} \ No newline at end of file diff --git a/src/main/java/org/bdware/sc/memory/MemoryDumpUtil.java b/src/main/java/org/bdware/sc/memory/MemoryDumpUtil.java new file mode 100644 index 0000000..7c9c8c2 --- /dev/null +++ b/src/main/java/org/bdware/sc/memory/MemoryDumpUtil.java @@ -0,0 +1,155 @@ +package org.bdware.sc.memory; + +import org.bdware.sc.boundry.JavaScriptEntry; +import org.bdware.sc.util.JsonUtil; +import wrp.jdk.nashorn.api.scripting.NashornScriptEngine; + +import javax.script.Bindings; +import javax.script.ScriptContext; +import java.io.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; + +public class MemoryDumpUtil { + public static final String STATELESS_MEMORY = "statelessContractMemory"; + public static AtomicInteger checkPointCounter; //用于common模式下的检查点计数 + NashornScriptEngine engine; + String dumpContent; + MemoryDump memoryDump = null; + + public MemoryDumpUtil(NashornScriptEngine en) { + this.engine = en; + } + + public static String getContentFromFile(String path) { + File file = new File(path); + ObjectInputStream reader; + try { + FileInputStream fileout = new FileInputStream(file); + GZIPInputStream gzin = new GZIPInputStream(fileout); + reader = new ObjectInputStream(gzin); + MemoryDump memoryDump = new MemoryDump(); + //memoryDump.objects = (Map) reader.readObject(); + memoryDump = (MemoryDump) reader.readObject(); + reader.close(); + String ret = JsonUtil.toPrettyJson(memoryDump.objects); + ret += ("" + memoryDump.jseDump.invokeID + ";" + memoryDump.jseDump.ranSeed + ";" + memoryDump.jseDump.numsOfCopies + ""); + return ret; + } catch (IOException | ClassNotFoundException e) { + e.printStackTrace(); + } + return null; + } + + /* + public static String getContentFromFile2(String path) { + File file = new File(path); + ObjectInputStream reader; + try { + FileInputStream fileout = new FileInputStream(file); + reader = new ObjectInputStream(fileout); + String ret = (String)reader.readObject(); + reader.close(); + return ret; + } catch (IOException | ClassNotFoundException e) { + e.printStackTrace(); + } + return null; + } + */ + + //stateful 表示合约是有/无状态合约 + public String dumpMemory(String path, boolean stateful) { + synchronized (engine) { + String ret; + memoryDump = new MemoryDump(); + + if (stateful) { + Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE); + MemoryJSObject root = memoryDump.getRoot(); + for (String key : bindings.keySet()) { + Object obj = bindings.get(key); + long id = memoryDump.allocate(obj); + root.addField(key, id); + } + memoryDump.jseDump = new JSEDump(JavaScriptEntry.invokeID, Long.parseLong(JavaScriptEntry.currentSyncUtil.contractID), JavaScriptEntry.numOfCopies); + ret = JsonUtil.toPrettyJson(memoryDump.objects); + } else { //无状态合约 + memoryDump.jseDump = new JSEDump(JavaScriptEntry.invokeID, Long.parseLong(JavaScriptEntry.currentSyncUtil.contractID), JavaScriptEntry.numOfCopies); + memoryDump.objects.clear(); + ret = JsonUtil.toPrettyJson(memoryDump.objects); + } + + ret += "--seperate--"; + ret += (memoryDump.jseDump.invokeID + ";" + memoryDump.jseDump.ranSeed + ";" + memoryDump.jseDump.numsOfCopies); + + if (path == null || path.equals("")) { + return ret; + } + + File mem = new File(path); + File parent = mem.getParentFile(); + if (!parent.exists()) parent.mkdirs(); + ObjectOutputStream writer; + try { + FileOutputStream fileout = new FileOutputStream(mem); + GZIPOutputStream out = new GZIPOutputStream(fileout); + writer = new ObjectOutputStream(out); + //writer.writeObject(memoryDump.objects); + writer.writeObject(memoryDump); + writer.flush(); + writer.close(); + } catch (IOException e) { + e.printStackTrace(); + } + + memoryDump = null; + + return ret; + } + } + + + /* + public String dumpMemory(String path) { + memoryDump = new MemoryDump(); + Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE); + System.out.println("[MemoryDumpUtil] bindings size=" + bindings.size()); + MemoryJSObject root = memoryDump.getRoot(); + for (String key : bindings.keySet()) { + System.out.println("[MemoryDumpUtil] dumpMemory " + key); + Object obj = bindings.get(key); + long id = memoryDump.allocate(obj); + root.addField(key, id); + + System.out.println("[root addFiled] key=" + key + " id=" + id); + } + String ret = JsonUtil.toPrettyJson(memoryDump); + dumpContent = ret; + + if(path == null || path.equals("")) { + return ret; + } + + File mem = new File(path); + File parent = mem.getParentFile(); + if (!parent.exists()) + parent.mkdirs(); + ObjectOutputStream writer; + try { + FileOutputStream fileout = new FileOutputStream(mem); + writer = new ObjectOutputStream(fileout); + writer.writeObject(dumpContent); + + writer.flush(); + writer.close(); + } catch (IOException e) { + e.printStackTrace(); + } + + memoryDump = null; + return ret; + } + */ +} diff --git a/src/main/java/org/bdware/sc/memory/MemoryFunctionObject.java b/src/main/java/org/bdware/sc/memory/MemoryFunctionObject.java new file mode 100644 index 0000000..996f261 --- /dev/null +++ b/src/main/java/org/bdware/sc/memory/MemoryFunctionObject.java @@ -0,0 +1,19 @@ +package org.bdware.sc.memory; + +import java.util.HashMap; +import java.util.Map; + +public class MemoryFunctionObject extends MemoryObject { + private static final long serialVersionUID = 5169037078273981613L; + Map fields; + + public MemoryFunctionObject(long id) { + super(id); + fields = new HashMap<>(); + type = MOType.JSFunction; + } + + public void addField(String key, long id) { + fields.put(key, id); + } +} \ No newline at end of file diff --git a/src/main/java/org/bdware/sc/memory/MemoryJSObject.java b/src/main/java/org/bdware/sc/memory/MemoryJSObject.java new file mode 100644 index 0000000..25ea3f8 --- /dev/null +++ b/src/main/java/org/bdware/sc/memory/MemoryJSObject.java @@ -0,0 +1,19 @@ +package org.bdware.sc.memory; + +import java.util.LinkedHashMap; +import java.util.Map; + +public class MemoryJSObject extends MemoryObject { + private static final long serialVersionUID = -2290414347562477503L; + LinkedHashMap fields; + + public MemoryJSObject(long id) { + super(id); + fields = new LinkedHashMap<>(); + type = MOType.JSObject; + } + + public void addField(String key, long id) { + fields.put(key, id); + } +} \ No newline at end of file diff --git a/src/main/java/org/bdware/sc/memory/MemoryObject.java b/src/main/java/org/bdware/sc/memory/MemoryObject.java new file mode 100644 index 0000000..b848c98 --- /dev/null +++ b/src/main/java/org/bdware/sc/memory/MemoryObject.java @@ -0,0 +1,21 @@ +package org.bdware.sc.memory; + +import org.bdware.sc.util.JsonUtil; + +import java.io.Serializable; + +public class MemoryObject implements Serializable { + + private static final long serialVersionUID = -7830175031856452056L; + public long id; + public MOType type; + Object data; + + public MemoryObject(long id) { + this.id = id; + } + + public String toString() { + return JsonUtil.toJson(this); + } +} diff --git a/src/main/java/org/bdware/sc/memory/MemoryRecoverUtil.java b/src/main/java/org/bdware/sc/memory/MemoryRecoverUtil.java new file mode 100644 index 0000000..5034ea0 --- /dev/null +++ b/src/main/java/org/bdware/sc/memory/MemoryRecoverUtil.java @@ -0,0 +1,160 @@ +package org.bdware.sc.memory; + +import org.bdware.sc.boundry.JavaScriptEntry; +import org.bdware.sc.boundry.Resources; +import org.bdware.sc.util.JsonUtil; +import wrp.jdk.nashorn.api.scripting.NashornScriptEngine; +import wrp.jdk.nashorn.api.scripting.ScriptObjectMirror; + +import javax.script.Bindings; +import javax.script.Invocable; +import javax.script.ScriptContext; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.util.Map; +import java.util.Random; +import java.util.zip.GZIPInputStream; + +public class MemoryRecoverUtil { + NashornScriptEngine engine; + String loadContent; + MemoryDump memoryDump = null; + Resources resource; + + public MemoryRecoverUtil(NashornScriptEngine en, Resources r) { + this.engine = en; + this.resource = r; + } + + //支持传入memory文件路径或者直接是memory的字符串 + public void loadMemory(String path, boolean stateful) { + synchronized (engine) { + File file = new File(path); + try { + if (file.exists()) { + try { + FileInputStream fileout = new FileInputStream(file); + GZIPInputStream gzin = new GZIPInputStream(fileout); + ObjectInputStream reader = new ObjectInputStream(gzin); + +// MemoryDump temp = new MemoryDump(); +// temp.objects = (Map) reader.readObject(); +// String content = JsonUtil.toPrettyJson(temp); + + MemoryDump temp = (MemoryDump) reader.readObject(); + String content = JsonUtil.toPrettyJson(temp.objects); + temp.jseDump.printContent(); + long invokeID = temp.jseDump.invokeID; + int copies = temp.jseDump.numsOfCopies; + long formerInvokeID = JavaScriptEntry.invokeID; + JavaScriptEntry.invokeID = invokeID; + JavaScriptEntry.numOfCopies = copies; + if (JavaScriptEntry.random == null) { + JavaScriptEntry.random = new Random(); + JavaScriptEntry.random.setSeed(temp.jseDump.ranSeed); + } + if (formerInvokeID > invokeID) { + JavaScriptEntry.random = new Random(); + JavaScriptEntry.random.setSeed(temp.jseDump.ranSeed); + for (long i = 0; i < invokeID; i++) { + JavaScriptEntry.random.nextInt(); + } + } else { + for (long i = formerInvokeID; i < invokeID; i++) { + JavaScriptEntry.random.nextInt(); + } + } + + //memoryDump = MemoryDump.loadFromStr(content); + if (stateful) { + memoryDump = temp; + } + reader.close(); + } catch (IOException | ClassNotFoundException e) { + e.printStackTrace(); + } + } else { //直接传入的是字符串 + String[] strs = path.split("--seperate--"); + String content = strs[0]; + String jse = strs[1]; + System.out.println("MemoryRecover从字符串load:\n" + content + "\n" + jse); + String strs2[] = jse.split(";"); + long invokeID = Long.parseLong(strs2[0]); + int copies = Integer.parseInt(strs2[2]); + long formerInvokeID = JavaScriptEntry.invokeID; + String contractID = strs2[1]; + JavaScriptEntry.invokeID = invokeID; + JavaScriptEntry.numOfCopies = copies; + if (JavaScriptEntry.random == null) { + JavaScriptEntry.random = new Random(); + JavaScriptEntry.random.setSeed(Integer.valueOf(contractID)); + } + if (formerInvokeID > invokeID) { + JavaScriptEntry.random = new Random(); + JavaScriptEntry.random.setSeed(Integer.valueOf(contractID)); + for (long i = 0; i < invokeID; i++) { + JavaScriptEntry.random.nextInt(); + } + } else { + for (long i = formerInvokeID; i < invokeID; i++) { + JavaScriptEntry.random.nextInt(); + } + } + + if (stateful) { //有状态合约 + memoryDump = MemoryDump.loadFromStr(content); + } + } + + if (stateful) { + MemoryJSObject root = memoryDump.getRoot(); + Map objects = memoryDump.recreateObject(); + ScriptObjectMirror global = (ScriptObjectMirror) objects.get(0L); + Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE); + for (Object key : global.keySet()) { + if (global.get(key) != null) bindings.put((String) key, global.get(key)); + } + } + this.memoryDump = null; + if (resource != null) + ((Invocable) engine).invokeFunction("defineProp", "Resources", resource); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + /* + public void loadMemory(String path) { + try { + String memory; + File mem = new File(path); + FileInputStream fileout = new FileInputStream(mem); + ObjectInputStream reader = new ObjectInputStream(fileout); + loadContent = (String) reader.readObject(); + // System.out.println("[MemoryRecoverUtil] loadContent : \n" + loadContent); + reader.close(); + memoryDump = MemoryDump.loadFromStr(loadContent); + + + String ret = JsonUtil.toPrettyJson(memoryDump); + MemoryJSObject root = memoryDump.getRoot(); + Map objects = memoryDump.recreateObject(); + ScriptObjectMirror global = (ScriptObjectMirror) objects.get(0L); + Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE); + for (Object key : global.keySet()) { + if (global.get(key) != null) + bindings.put((String) key, global.get(key)); + } + this.memoryDump = null; + if (resource != null) + ((Invocable) engine).invokeFunction("defineProp", "Resources", resource); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + */ +} diff --git a/src/main/java/org/bdware/sc/redo/TransRecordUtil.java b/src/main/java/org/bdware/sc/redo/TransRecordUtil.java new file mode 100644 index 0000000..4762b3b --- /dev/null +++ b/src/main/java/org/bdware/sc/redo/TransRecordUtil.java @@ -0,0 +1,181 @@ +package org.bdware.sc.redo; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.bdware.sc.engine.DesktopEngine; +import org.bdware.sc.engine.SyncMechUtil; + +import java.io.*; +import java.util.Map; +import java.util.TreeMap; + +public class TransRecordUtil { + public static final int RESERVED = 20; //最近的多少次records内存也保存,如果一个节点距离集群当前的seq相差超过这个值,就不从本地恢复,让别的节点现场dump + public static final int DUMP_PERIOD = 50; //每满50次记录,就记录一次全量状态,清一次trans记录 + private static final Logger LOGGER = LogManager.getLogger(TransRecordUtil.class); + public Map cacheTransRecords = new TreeMap(); //TODO 认为其中records一定是seq连续的,否则可能有问题? + //public PriorityQueue transRecords = new PriorityQueue(); + public TransRecord currentTransRecord; + SyncMechUtil syncUtil; + DesktopEngine engine; + String fileName; + + public TransRecordUtil(DesktopEngine en, SyncMechUtil sync) { + this.engine = en; + syncUtil = sync; + } + + public void setFileName(String path) { + fileName = path; + } + + //每次事务开始时初始化 + public void startNext(String fun, String arg, int sequence) { + //logger.debug("TransRecordUtil 开始记录事务"); + currentTransRecord = new TransRecord(fun, arg, sequence); + } + + public void startNext(String fun, String arg) { + //logger.debug("TransRecordUtil 开始记录事务"); + currentTransRecord = new TransRecord(fun, arg); + } + + //每次事务结束时记录 + public synchronized void eachFinish() { + //logger.debug("TransRecordUtil 记录完一个事务 \n" + currentTransRecord.toString()); + cacheTransRecords.put(currentTransRecord.seq, currentTransRecord); + if (cacheTransRecords.size() == RESERVED) { + int temp = 0; + for (Integer i : cacheTransRecords.keySet()) { + temp = i; + break; + } + cacheTransRecords.remove(temp); + } + + appendTransFile(currentTransRecord); //执行前已经定序了,所以trans其实没必要定序 + } + + //追加写入最后一个TransRecord + public void appendTransFile(TransRecord record) { + syncUtil.filedTrans.getAndIncrement(); + + File file = new File(syncUtil.transDir + "/" + fileName); + File parent = file.getParentFile(); + if (parent.isDirectory() && !parent.exists()) { + parent.mkdirs(); + } + try { + FileWriter fw = new FileWriter(file, true); + PrintWriter pw = new PrintWriter(fw); + pw.println(record.toString()); + pw.flush(); + fw.flush(); + pw.close(); + fw.close(); + } catch (IOException e) { + e.printStackTrace(); + } + + //自动触发检查点 + if (syncUtil.filedTrans.get() == DUMP_PERIOD) { + LOGGER.info("自动触发检查点 DUMP_PERIOD=" + DUMP_PERIOD); + file = new File(syncUtil.memoryDir); + if (file.isDirectory()) { + String[] children = file.list(); + for (int i = 0; i < children.length; i++) { + File temp = new File(file, children[i]); + temp.delete(); + } + } + file = new File(syncUtil.traceDir); + if (file.isDirectory()) { + String[] children = file.list(); + for (int i = 0; i < children.length; i++) { + File temp = new File(file, children[i]); + temp.delete(); + } + } + file = new File(syncUtil.transDir); + if (file.isDirectory()) { + String[] children = file.list(); + for (int i = 0; i < children.length; i++) { + File temp = new File(file, children[i]); + temp.delete(); + } + } + + //sync文件删除第2,3行 + file = new File(syncUtil.syncDir + "/" + syncUtil.syncFileName); + String firstLine = ""; + try { + FileReader fr = new FileReader(file); + BufferedReader br = new BufferedReader(fr); + String line = ""; + while ((line = br.readLine()) != null) { + firstLine = line; + break; + } + br.close(); + fr.close(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + file.delete(); + file = new File(syncUtil.syncDir + "/" + syncUtil.syncFileName); + + try { + FileWriter fw = new FileWriter(file, true); + PrintWriter pw = new PrintWriter(fw); + pw.println(firstLine); + pw.flush(); + fw.flush(); + pw.close(); + fw.close(); + } catch (IOException e) { + e.printStackTrace(); + } + + syncUtil.setStartFlag(true); + } + } + + //record executeContract in current trans + public void recordExecutes(String k, String v) { + if (currentTransRecord != null) { + currentTransRecord.executes.put(k, v); + } else { + LOGGER.info("[TransRecordUtil] recordExecutes error!"); + } + } + + public String getCachedTransRecords(int start) { + StringBuilder str = new StringBuilder(); + + //先查看有没有第1个 + if (!cacheTransRecords.containsKey(start)) + return ""; + + synchronized (cacheTransRecords) { + int temp = -1; + int j = start - 1;//确保有从start开始的连续trans,j记录上一个i值 + for (Integer i : cacheTransRecords.keySet()) { + if (i >= start) { + if (i == (j + 1)) { + str.append(cacheTransRecords.get(i).toString() + "\n"); + temp = Math.max(temp, i); + j = i; + } else { + LOGGER.info("i=" + i + " j=" + j + " 不连续"); + return ""; + } + } + } + if (temp != -1) + str.append("==>>" + temp); + } + return str.toString(); + } +} diff --git a/src/main/java/org/bdware/sc/redo/TransRecoverUtil.java b/src/main/java/org/bdware/sc/redo/TransRecoverUtil.java new file mode 100644 index 0000000..70ed12e --- /dev/null +++ b/src/main/java/org/bdware/sc/redo/TransRecoverUtil.java @@ -0,0 +1,100 @@ +package org.bdware.sc.redo; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.bdware.sc.ContractResult; +import org.bdware.sc.bean.ContractRequest; +import org.bdware.sc.engine.DesktopEngine; + +import java.io.*; +import java.util.ArrayList; + +public class TransRecoverUtil { + private static final Logger LOGGER = LogManager.getLogger(TransRecoverUtil.class); + public ArrayList transRecords; + public TransRecord curRecoverRecord; + DesktopEngine engine; + + public TransRecoverUtil(DesktopEngine en) { + this.engine = en; + transRecords = new ArrayList(); + } + + public void setTraceRecords(String fileName) { + TransRecord cur_read = null; + File file = new File(fileName); + + try { + FileReader fr = new FileReader(file); + BufferedReader br = new BufferedReader(fr); + String line = ""; + String[] arrs = null; + while ((line = br.readLine()) != null) { + String[] strs = line.split(";"); + String arg; + if (strs.length < 5) { //调用记录参数为空 + arg = null; + } else { + arg = strs[4]; + } + + if (strs[0].equals("===TransRecord===")) { + if (cur_read != null) { + transRecords.add(cur_read); + System.out.println("恢复时加入 " + cur_read.toString()); + } + if (strs[1].equals("true")) + cur_read = new TransRecord(strs[3], arg, Integer.parseInt(strs[2])); + else + cur_read = new TransRecord(strs[3], arg); + } else { + cur_read.addExecutes(strs[0], strs[1]); + } + } + if (cur_read != null) { + transRecords.add(cur_read); + System.out.println("恢复时加入 " + cur_read.toString()); + } + br.close(); + fr.close(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void recoverFromTransRecord() { + synchronized (engine) { + engine.setRecovering(true); + for (int i = 0; i < transRecords.size(); i++) { + curRecoverRecord = transRecords.get(i); + String funName = curRecoverRecord.getFuncName(); + String arg = curRecoverRecord.getArg(); + + ContractRequest ac = null; + ac = new ContractRequest(); + ac.setAction(funName); + ac.setArg(arg); + ac.needSeq = curRecoverRecord.needSeq; + if (ac.needSeq) { + ac.seq = curRecoverRecord.seq; + LOGGER.info("[TransRecordUtil] redo 重新执行事务 " + ac.seq); + } + System.out.println("[TransRecoverUtil] recover " + ac.needSeq + " " + ac.seq + " " + ac.getAction() + " " + ac.getArg()); + + ContractResult result = engine.executeContract(ac); + + if (result.status != ContractResult.Status.Success) { + System.out.println("[错误]" + result.status); + } + } + engine.setRecovering(false); + } + } + + //TODO + public void recoverFromATransRecord(TransRecord record) { + + } +} \ No newline at end of file diff --git a/src/main/java/org/bdware/sc/syncMech/EstimateUtil.java b/src/main/java/org/bdware/sc/syncMech/EstimateUtil.java new file mode 100644 index 0000000..bb2e992 --- /dev/null +++ b/src/main/java/org/bdware/sc/syncMech/EstimateUtil.java @@ -0,0 +1,24 @@ +package org.bdware.sc.syncMech; + +public class EstimateUtil { + public static final String DUMP_TIME = "dumpTime"; + public static final String DUMP_TIMES = "dumpTimes"; + long dumpTime; //用时 + long dumpTimes; //次数 + long dumpFile; //状态大小,dumpFile的次数也是dumpTimes + + public static final String LOADMEMORY_TIME = "loadMemoryTime"; + public static final String LOADMEMORY_TIMES = "loadMemoryTimes"; + long loadMemoryTime; + long loadMemoryTimes; + + public static final String EXECUTE_TIME = "executeTime"; + public static final String EXECUTE_TIMES = "executeTimes"; + long executeTime; + long executeTimes; + + public static final String REDO_TRANS_FILE = "redoTransFile"; + public static final String REDO_TRANS_TIMES = "redoTransTimes"; + long redoTransFIle; + long redoTransTimes; +} diff --git a/src/main/java/org/bdware/sc/syncMech/SyncRecord.java b/src/main/java/org/bdware/sc/syncMech/SyncRecord.java new file mode 100644 index 0000000..85ca93f --- /dev/null +++ b/src/main/java/org/bdware/sc/syncMech/SyncRecord.java @@ -0,0 +1,44 @@ +package org.bdware.sc.syncMech; + +import java.io.Serializable; + +public class SyncRecord implements Serializable{ + SyncType type; + String fileName; //eg:/memory/2020-... + + public SyncRecord(SyncType t) { + this.type = t; + } + + public SyncRecord(SyncType t,String str){ + type = t; + fileName = str; + } + + public void setType(SyncType ty) { + this.type = ty; + } + + public SyncType getType() { + return this.type; + } + + public void setFileName(String file) { + this.fileName = file; + } + + public String getFileName() { + return this.fileName; + } + + public String getContent() { + StringBuilder str = new StringBuilder(); + str.append(type.toString() + ";" + fileName); + return str.toString(); + } + + public static SyncRecord loadFromString(String str){ + String[] strs = str.split(";"); + return new SyncRecord(SyncType.convert(strs[0]),strs[1]); + } +} diff --git a/src/main/java/org/bdware/sc/syncMech/SyncType.java b/src/main/java/org/bdware/sc/syncMech/SyncType.java new file mode 100644 index 0000000..e07fda7 --- /dev/null +++ b/src/main/java/org/bdware/sc/syncMech/SyncType.java @@ -0,0 +1,20 @@ +package org.bdware.sc.syncMech; + +import java.io.Serializable; + +public enum SyncType implements Serializable{ + Memory, Trace, Trans; + + public static SyncType convert(String str){ + switch (str){ + case "Memory": + return Memory; + case "Trace": + return Trace; + case "Trans": + return Trans; + default: + return null; + } + } +} \ No newline at end of file diff --git a/src/main/java/org/bdware/sc/trace/JS.java b/src/main/java/org/bdware/sc/trace/JS.java new file mode 100644 index 0000000..eb6d3e6 --- /dev/null +++ b/src/main/java/org/bdware/sc/trace/JS.java @@ -0,0 +1,7 @@ +package org.bdware.sc.trace; + +import java.io.Serializable; + +public class JS implements Serializable{ + +} \ No newline at end of file diff --git a/src/main/java/org/bdware/sc/trace/JSArray.java b/src/main/java/org/bdware/sc/trace/JSArray.java new file mode 100644 index 0000000..fd1f235 --- /dev/null +++ b/src/main/java/org/bdware/sc/trace/JSArray.java @@ -0,0 +1,10 @@ +package org.bdware.sc.trace; + +import java.io.Serializable; + +public class JSArray extends JSScript implements Serializable{ + + public JSArray(int id) { + this.objID = id; + } +} diff --git a/src/main/java/org/bdware/sc/trace/JSNull.java b/src/main/java/org/bdware/sc/trace/JSNull.java new file mode 100644 index 0000000..1740fd1 --- /dev/null +++ b/src/main/java/org/bdware/sc/trace/JSNull.java @@ -0,0 +1,7 @@ +package org.bdware.sc.trace; + +import java.io.Serializable; + +public class JSNull extends JS implements Serializable{ + +} diff --git a/src/main/java/org/bdware/sc/trace/JSObject.java b/src/main/java/org/bdware/sc/trace/JSObject.java new file mode 100644 index 0000000..e7d04fa --- /dev/null +++ b/src/main/java/org/bdware/sc/trace/JSObject.java @@ -0,0 +1,14 @@ +package org.bdware.sc.trace; + +import java.io.Serializable; + +/* + * js中对象 + * ScriptObject JO + */ +public class JSObject extends JSScript implements Serializable{ + + public JSObject(int id) { + this.objID = id; + } +} \ No newline at end of file diff --git a/src/main/java/org/bdware/sc/trace/JSScript.java b/src/main/java/org/bdware/sc/trace/JSScript.java new file mode 100644 index 0000000..dd560b7 --- /dev/null +++ b/src/main/java/org/bdware/sc/trace/JSScript.java @@ -0,0 +1,11 @@ +package org.bdware.sc.trace; + +import java.io.Serializable; + +public class JSScript extends JS implements Serializable{ + int objID; + + public int getObjID() { + return this.objID; + } +} \ No newline at end of file diff --git a/src/main/java/org/bdware/sc/trace/JSUndifined.java b/src/main/java/org/bdware/sc/trace/JSUndifined.java new file mode 100644 index 0000000..3d6f1e2 --- /dev/null +++ b/src/main/java/org/bdware/sc/trace/JSUndifined.java @@ -0,0 +1,7 @@ +package org.bdware.sc.trace; + +import java.io.Serializable; + +public class JSUndifined extends JS implements Serializable{ + +} diff --git a/src/main/java/org/bdware/sc/trace/MethodInvokePrinter.java b/src/main/java/org/bdware/sc/trace/MethodInvokePrinter.java new file mode 100644 index 0000000..1151a62 --- /dev/null +++ b/src/main/java/org/bdware/sc/trace/MethodInvokePrinter.java @@ -0,0 +1,77 @@ +package org.bdware.sc.trace; + +import java.io.PrintStream; +import java.util.Set; + +import wrp.jdk.nashorn.internal.runtime.ScriptObject; +import wrp.jdk.nashorn.internal.runtime.ScriptRuntime; +import wrp.jdk.nashorn.internal.runtime.TraceMethod; + +public class MethodInvokePrinter implements TraceMethod { + + PrintStream out; + + public void printObject(final Object arg) { + if (arg instanceof ScriptObject) { + final ScriptObject object = (ScriptObject) arg; + + boolean isFirst = true; + final Set keySet = object.keySet(); + + if (keySet.isEmpty()) { + out.print(ScriptRuntime.safeToString(arg)); + } else { + out.print("{ "); + + for (final Object key : keySet) { + if (!isFirst) { + out.print(", "); + } + + out.print(key); + out.print(":"); + + final Object value = object.get(key); + + if (value instanceof ScriptObject) { + out.print("..."); + } else { + printObject(value); + } + + isFirst = false; + } + + out.print(" }"); + } + } else { + out.print(ScriptRuntime.safeToString(arg)); + } + } + + public void tracePrint(final String tag, int pc, String methodName, final Object[] args, final Object result) { + // boolean isVoid = type().returnType() == void.class; + out.print(tag); + out.print(methodName + "_" + pc + "("); + if (args.length > 0) { + printObject(args[0]); + for (int i = 1; i < args.length; i++) { + final Object arg = args[i]; + out.print(", "); + + if (!(arg instanceof ScriptObject && ((ScriptObject) arg).isScope())) { + printObject(arg); + } else { + out.print("SCOPE"); + } + } + } + out.print(")"); + if (tag.equals("EXIT ")) { + out.print(" --> "); + printObject(result); + } + out.println(); + } + +} diff --git a/src/main/java/org/bdware/sc/trace/ProgramPointCounter.java b/src/main/java/org/bdware/sc/trace/ProgramPointCounter.java new file mode 100644 index 0000000..9025fc3 --- /dev/null +++ b/src/main/java/org/bdware/sc/trace/ProgramPointCounter.java @@ -0,0 +1,212 @@ +package org.bdware.sc.trace; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.sun.mail.iap.ByteArray; +import org.bdware.analysis.CFGraph; +import org.bdware.sc.ContractProcess; +import wrp.jdk.nashorn.internal.runtime.ScriptObject; +import wrp.jdk.nashorn.internal.runtime.ScriptRuntime; +import wrp.jdk.nashorn.internal.runtime.TraceMethod; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.Stack; + +public class ProgramPointCounter extends ContractProcess.Logger implements TraceMethod { + public long gasLimit; + public long extraGas; + // PrintStream out; + ByteArrayOutputStream bo; + HashMap> ppc = new HashMap<>(); + String globalAction; + HashMap cfgMap; + HashMap countMap; + int functionIndex = 0; + public long gasValue = 0; + + public ProgramPointCounter( + ByteArrayOutputStream bo, + ContractProcess cp, + long gasLimit, + int functionIndex, + long gasValue, + long extraGas, + String action, + HashMap countMap) { + super(new PrintStream(bo), cp); + // out = System.out; + this.bo = bo; + globalAction = action; + this.gasLimit = gasLimit - extraGas; + this.functionIndex = functionIndex; + this.countMap = countMap; + this.gasValue = gasValue - extraGas; + this.extraGas = extraGas; + } + + boolean simple = true; + + @Override + public String getOutputStr() { + return bo.toString(); + } + /* + private void printObject(final Object arg) { + if (simple) return; + if (arg instanceof ScriptObject) { + final ScriptObject object = (ScriptObject) arg; + + boolean isFirst = true; + final Set keySet = object.keySet(); + // System.out.println("[keySet:]"); + if (keySet.isEmpty()) { + out.print(ScriptRuntime.safeToString(arg)); + } else { + out.print("{ "); + + for (final Object key : keySet) { + if (!isFirst) { + out.print(", "); + } + + out.print(key); + out.print(":"); + + final Object value = object.get(key); + + if (value instanceof ScriptObject) { + out.print("..."); + } else { + printObject(value); + } + + isFirst = false; + } + + out.print(" }"); + } + } else { + out.print(ScriptRuntime.safeToString(arg)); + } + } + */ + boolean initEnter = false; + Stack pcStack = new Stack<>(); + + @Override + public void tracePrint( + final String tag, int pc, String methodName, final Object[] args, final Object result) { + // System.out.println("!@#$%^&*" + tag + pc + methodName + args + result); + if (!initEnter) { + // System.out.println("[functionIndex]:" + countMap.get(String.valueOf(functionIndex))); + compareValue(String.valueOf(functionIndex)); + initEnter = true; + } + + if (tag.equals("EXIT ")) { + // System.out.println(tag); + if (pc == pcStack.peek()) { + // System.out.println("出栈之前" + pcStack); + pcStack.pop(); + if (countMap.containsKey(String.valueOf(pc))) { + // System.out.println("出栈之后" + pcStack); + compareValue(String.valueOf(pc)); + // System.out.println("弹出之后的消耗" + gasValue); + } + } + } else { + // System.out.println(tag); + pcStack.push(pc); + // System.out.println("入栈" + pcStack); + } + // out.print("[ProgramPointCounter] " + tag); + // out.print(methodName + "_" + pc + "("); + + // if (args.length > 0) { + // printObject(args[0]); + // for (int i = 1; i < args.length; i++) { + // final Object arg = args[i]; + // out.print(", "); + // if (!(arg instanceof ScriptObject && ((ScriptObject) arg).isScope())) { + // printObject(arg); + // } else { + // out.print("SCOPE"); + // } + // } + // } + // out.print(")"); + // if (tag.equals("EXIT ")) { + // out.print(" --> "); + // printObject(result); + // System.out.println("[result:]" + result); + // } + // out.println(); + // System.out.println("[Fee剩余]" + gasValue); + } + + public long cost = 0; + + private void compareValue(String index) { + if (gasValue > gasLimit) { + System.out.println("out of gas"); + throw new IllegalStateException("gas out of limit"); + } + cost = cost + countMap.get(index); + // System.out.println("gasValue --:" + gasValue + " -" + countMap.get(index)); + + gasValue = gasValue - countMap.get(index); + gasLimit = gasLimit - countMap.get(index); + if (gasValue <= 0) { + System.out.println("out of gas"); + throw new IllegalStateException("run out of InsnFee"); + } else if (gasLimit <= 0) { + System.out.println("out of gas"); + throw new IllegalStateException("run over the limit"); + } + } + + @Override + public void println(String s) { + super.println(s); + // System.out.print("[s是:]"+s); + // count++; + // String oldTrace=traceCompare(s); + // +=当前if与之前的if的指令权重或是指令数量。 + // if (count > 10) { + // throw new IllegalStateException("run out of gas"); + // } + try { + JsonObject jo = new JsonParser().parse(s).getAsJsonObject(); + String traceMarkValue = jo.get("traceMark").getAsString(); + String val = jo.get("val").getAsString(); + // System.out.println(countMap); + for (Map.Entry test : countMap.entrySet()) { + if (test.getKey().contains(traceMarkValue)) { + if (Integer.valueOf(val) <= 0 && test.getKey().contains("false")) { + // System.out.println("false" + test.getKey()); + compareValue(test.getKey()); + } else if (Integer.valueOf(val) > 0 && test.getKey().contains("true")) { + // System.out.println("true" + test.getKey()); + compareValue(test.getKey()); + // System.out.println("[gasLimit]"+gasValue+"[gasLimit]"+gasLimit); + } + } + } + // System.out.println("[Gas剩余]" + gasValue); + // System.out.println("[执行消耗Gas]" + cost); + // System.out.println("[额外Gas]" + extraGas); + // System.out.println( + // "[ProgramPointCounter] {\"traceMark\":" + // + traceMarkValue + // + "\"val\":" + // + val + // + "}"); + } catch (IllegalStateException e) { + throw e; + } + } +} diff --git a/src/main/java/org/bdware/sc/trace/Trace.java b/src/main/java/org/bdware/sc/trace/Trace.java new file mode 100644 index 0000000..70384a1 --- /dev/null +++ b/src/main/java/org/bdware/sc/trace/Trace.java @@ -0,0 +1,11 @@ +package org.bdware.sc.trace; + +import java.io.Serializable; + +public class Trace implements Serializable{ + + public String traceContent() { + return "Trace Content"; + } + +} diff --git a/src/main/java/org/bdware/sc/trace/TraceDone.java b/src/main/java/org/bdware/sc/trace/TraceDone.java new file mode 100644 index 0000000..9c499b1 --- /dev/null +++ b/src/main/java/org/bdware/sc/trace/TraceDone.java @@ -0,0 +1,20 @@ +package org.bdware.sc.trace; + +import java.io.Serializable; + +public class TraceDone extends Trace implements Serializable { + int id; + + public TraceDone(int id) { + this.id = id; + } + + public int getID() { + return id; + } + + @Override + public String traceContent() { + return "[TraceDone] allocID:" + id + "\n"; + } +} \ No newline at end of file diff --git a/src/main/java/org/bdware/sc/trace/TraceInitArray.java b/src/main/java/org/bdware/sc/trace/TraceInitArray.java new file mode 100644 index 0000000..56e781b --- /dev/null +++ b/src/main/java/org/bdware/sc/trace/TraceInitArray.java @@ -0,0 +1,51 @@ +package org.bdware.sc.trace; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +/* + * 数组创建时有初始值,进行初始化 + */ +public class TraceInitArray extends Trace implements Serializable{ + int arrayId; //被初始化的数组id + List keys = new ArrayList(); //数组下标可能是整数,对象名等 + List values = new ArrayList(); //数组内内容 + + public TraceInitArray(int id) { + this.arrayId = id; + keys = new ArrayList(); + values = new ArrayList(); + } + + public void put(Object key,Object value) { + keys.add(key); + values.add(value); + } + + public int getLength() { + return values.size(); + } + + public int getArrayId() { + return this.arrayId; + } + + public Object getKey(int i) { + return keys.get(i); + } + + public Object getValue(int i) { + return values.get(i); + } + + @Override + public String traceContent(){ + StringBuilder str = new StringBuilder(); + str.append("[TraceInitArray]\n"); + str.append("ArrayID=" + arrayId + "\n"); + for(int i = 0;i < values.size();i++) + str.append("key=" + keys.get(i) + ";value=" + values.get(i) + "\n"); + return str.toString(); + } +} diff --git a/src/main/java/org/bdware/sc/trace/TraceInitObject.java b/src/main/java/org/bdware/sc/trace/TraceInitObject.java new file mode 100644 index 0000000..b0731b2 --- /dev/null +++ b/src/main/java/org/bdware/sc/trace/TraceInitObject.java @@ -0,0 +1,29 @@ +package org.bdware.sc.trace; + +import java.io.Serializable; + +public class TraceInitObject extends Trace implements Serializable{ + int id; + int id2; + + public TraceInitObject(int id,int id2) { + this.id = id; + this.id2 = id2; + } + + public int getId() { + return id; + } + + public int getId2() { + return id2; + } + + @Override + public String traceContent() { + StringBuilder str = new StringBuilder(); + str.append("[TraceInitObject]\n"); + str.append("id=" + id + " ; id2=" + id2 + "\n"); + return str.toString(); + } +} diff --git a/src/main/java/org/bdware/sc/trace/TraceRecord.java b/src/main/java/org/bdware/sc/trace/TraceRecord.java new file mode 100644 index 0000000..0443332 --- /dev/null +++ b/src/main/java/org/bdware/sc/trace/TraceRecord.java @@ -0,0 +1,38 @@ +package org.bdware.sc.trace; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +public class TraceRecord implements Serializable{ + private static final long serialVersionUID = 34643133713102276L; + + public List traces; + + public TraceRecord() { + traces = new ArrayList(); + } + + + @Override + public String toString() { + StringBuilder str = new StringBuilder(); + for(int i = 0;i < traces.size();i++) { + //str.append("com/yancloud/sc/trace" + i + ":\n"); + str.append(traces.get(i).traceContent() + "\n"); + } + return str.toString(); + } + + + /* + * 加入一条新的trace + */ + public void record(Trace trace) { + traces.add(trace); + } + + public int length() { + return traces.size(); + } +} \ No newline at end of file diff --git a/src/main/java/org/bdware/sc/trace/TraceRecordUtil.java b/src/main/java/org/bdware/sc/trace/TraceRecordUtil.java new file mode 100644 index 0000000..467e685 --- /dev/null +++ b/src/main/java/org/bdware/sc/trace/TraceRecordUtil.java @@ -0,0 +1,249 @@ +package org.bdware.sc.trace; + +import java.io.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; + +import org.bdware.sc.engine.DesktopEngine; + +import jdk.internal.dynalink.CallSiteDescriptor; +import org.bdware.sc.engine.SyncMechUtil; +import wrp.jdk.nashorn.internal.objects.NativeArray; +import wrp.jdk.nashorn.internal.runtime.ConsString; +import wrp.jdk.nashorn.internal.runtime.Context; +import wrp.jdk.nashorn.internal.runtime.JSType; +import wrp.jdk.nashorn.internal.runtime.PropertyMap; +import wrp.jdk.nashorn.internal.runtime.ScriptObject; +import wrp.jdk.nashorn.internal.runtime.TraceSetBehavior; +import wrp.jdk.nashorn.internal.runtime.TraceSetupArray; +import wrp.jdk.nashorn.internal.runtime.TraceSetupScriptObject; +import wrp.jdk.nashorn.internal.runtime.arrays.ArrayData; + +public class TraceRecordUtil { + SyncMechUtil syncUtil; + DesktopEngine engine; + + public ArrayList traceRecords; + + public TraceRecord currentTraceRecord; //当前事务中所有非TraceSet的trace + public Map currentArrayMap; + public Map currentMap; //当前事务中所有TraceSet的精简记录 + + public TraceRecordUtil(DesktopEngine de,SyncMechUtil sync) { + this.engine = de; + this.syncUtil = sync; + } + + public ArrayList getTraceRecords() { + if (traceRecords == null) { + return null; + } + return this.traceRecords; + } + + public TraceRecord getTraceRecord(int c) { + if (traceRecords == null) + return null; + else if (traceRecords.size() <= c) + return null; + else + return traceRecords.get(c); + } + + public String getTraceRecordsContent() { + StringBuilder str = new StringBuilder(); + + for (int i = 0; i < traceRecords.size(); i++) { + str.append("No." + i + "record : \n" + traceRecords.get(i).toString()); + } + + return str.toString(); + } + + public static String getTraceRecordsByFile(String fileName) { + ArrayList traceRecords = null; + File file = new File(fileName); + ObjectInputStream reader; + try { + FileInputStream fileout = new FileInputStream(file); + GZIPInputStream gzin = new GZIPInputStream(fileout); + reader = new ObjectInputStream(gzin); + traceRecords = (ArrayList) reader.readObject(); + reader.close(); + } catch (IOException | ClassNotFoundException e) { + e.printStackTrace(); + } + + StringBuilder str = new StringBuilder(); + for (int i = 0; i < traceRecords.size(); i++) { + str.append("No." + i + "record : \n" + traceRecords.get(i).toString()); + } + return str.toString(); + } + + //添加简化过的TraceSet + public void addSmpSet() { + currentTraceRecord.traces.addAll(currentArrayMap.values()); + currentTraceRecord.traces.addAll(currentMap.values()); + } + + public void saveTraceRecords(String fileName) { + if (traceRecords == null) { + System.out.println("[saveTraceRecords] traceRecords is null,can't save traceRecords to fill!"); + } + + File traceFile = new File(fileName + ".trace"); // trace文件名中不带时间 + File parent = traceFile.getParentFile(); + if (!parent.exists()) + parent.mkdirs(); + + ObjectOutputStream writer; + try { + FileOutputStream fileout = new FileOutputStream(traceFile); + GZIPOutputStream out = new GZIPOutputStream(fileout); + writer = new ObjectOutputStream(out); + writer.writeObject(traceRecords); + writer.flush(); + writer.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void startRecordTrace() { + this.traceRecords = new ArrayList(); +// recording = true; + + //set behavior + Context.TRACESETBEHAVIOR = new TraceSetBehavior() { + + @Override + public void trace(CallSiteDescriptor desc, Object... args) { + int id = ((ScriptObject) args[0]).getObjectID(); + Object key = null; + Object value = null; + + if (args.length == 3) { + key = JSType.toPrimitive(args[1]); + value = args[2]; + } else if (args.length == 2) { + key = desc.getName().split(":")[2]; + value = args[1]; + } + + if (value instanceof Integer || value instanceof String || value instanceof Double) + ; + else if (value instanceof ConsString) + value = value.toString(); + else + value = produceJS(value); + + currentMap.put(new TraceSetIdentifier(id,key),new TraceSet(id,key,value)); + } + }; + + //setup script object + Context.TRACESETUPSCRIPTOBJECT = new TraceSetupScriptObject() { + + @Override + public void trace(ScriptObject arg, PropertyMap map) { + /* + * TraceSetup tracesetup = new TraceSetup((JSScript)produceJS(arg)); + * traceRecord.record(tracesetup); + */ + + TraceSetup tracesetup = new TraceSetup((JSScript) produceJS(arg)); + + /* + * System.out.println("[startRecord] setupScriptObject argID=" + + * arg.getObjectID() + " map=" + map.size()); Iterator keys = + * arg.propertyIterator(); while(keys.hasNext()) { String key = keys.next(); + * System.out.println(key + " ; " + + * map.findProperty(key).getClass().getCanonicalName()); + * tracesetup.add(map.findProperty(key)); } + */ + + currentTraceRecord.record(tracesetup); + } + }; + + //setup array + Context.TRACESETUPARRAY = new TraceSetupArray() { + @Override + public void trace(ArrayData arg, int id) { + TraceInitArray traceinitarray = new TraceInitArray(id); + for (int i = 0; i < arg.length(); i++) { + Object obj = arg.getObject(i); + + if (obj instanceof Integer || obj instanceof String || obj instanceof Double) + ; + else if (obj instanceof ConsString) + obj = obj.toString(); + else + obj = produceJS(obj); + + traceinitarray.put(i, obj); + } + currentArrayMap.put(traceinitarray.getArrayId(), traceinitarray); + } + }; + + /* + * Context.TRACESETGLOBALOBJECTPROTO = new TraceSetGlobalObjectProto() { + * + * @Override public void trace(int id, int id2,List keys,List + * values) { System.out.println("[startRecord] set global object proto id=" + id + * + " id2=" + id2 + " size=" + keys.size()); + * + * + * + * TraceInitObject traceinitobject = new TraceInitObject(id,id2); for(int i = + * 0;i < keys.size();i++) { System.out.println("i=" + i + " key=" + keys.get(i) + * + " value=" + values.get(i)); } currentTraceRecord.record(traceinitobject); } + * + * }; + */ + } + + public void stopRecordTrace() { + Context.TRACESETBEHAVIOR = null; + Context.TRACESETUPARRAY = null; + Context.TRACESETUPSCRIPTOBJECT = null; +// recording = false; + } + + public static JS produceJS(Object arg) { + if (arg == null) { + return new JSNull(); + } else if (arg instanceof NativeArray) { + JSArray arr = new JSArray(((ScriptObject) arg).getObjectID()); + return arr; + } else if (arg instanceof ScriptObject) { + JSObject obj = new JSObject(((ScriptObject) arg).getObjectID()); + return obj; + } else if (arg instanceof wrp.jdk.nashorn.internal.runtime.Undefined) { + return new JSUndifined(); + } else { + System.out.println("[produceJS] arg encounter new type!" + arg.toString() + " " + arg.getClass()); + return new JS(); + } + } + + //每次事务开始时初始化 + public void startNext() { + currentTraceRecord = new TraceRecord(); + currentArrayMap = new LinkedHashMap(); + currentMap = new LinkedHashMap(); + } + + //每次事务结束时记录 + public void eachFinish() { + addSmpSet(); + currentTraceRecord.record(new TraceDone(ScriptObject.getAllocID())); + traceRecords.add(currentTraceRecord); + } +} \ No newline at end of file diff --git a/src/main/java/org/bdware/sc/trace/TraceRecoverUtil.java b/src/main/java/org/bdware/sc/trace/TraceRecoverUtil.java new file mode 100644 index 0000000..ed7117f --- /dev/null +++ b/src/main/java/org/bdware/sc/trace/TraceRecoverUtil.java @@ -0,0 +1,334 @@ +package org.bdware.sc.trace; + +import org.bdware.sc.boundry.JavaScriptEntry; +import org.bdware.sc.engine.DesktopEngine; +import wrp.jdk.nashorn.api.scripting.NashornScriptEngine; +import wrp.jdk.nashorn.api.scripting.ScriptObjectMirror; +import wrp.jdk.nashorn.internal.objects.Global; +import wrp.jdk.nashorn.internal.runtime.Context; +import wrp.jdk.nashorn.internal.runtime.ScriptFunction; +import wrp.jdk.nashorn.internal.runtime.ScriptObject; +import wrp.jdk.nashorn.internal.scripts.JO; + +import javax.script.Bindings; +import javax.script.ScriptContext; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.zip.GZIPInputStream; + +public class TraceRecoverUtil { + DesktopEngine engine; + NashornScriptEngine nashornEngine; + + private ArrayList traceRecords; + + private int recoverFlag; // 表示当前traceRecords中第i个已经恢复 + + // 存储恢复过程中的局部变量 + private Map recoverMap; + + public TraceRecoverUtil(DesktopEngine de) { + this.engine = de; + recoverFlag = -1; + nashornEngine = engine.getNashornEngine(); + } + + public Map getMap() { + return recoverMap; + } + + public ArrayList getTraceRecords() { + if (traceRecords == null) { + return null; + } + return this.traceRecords; + } + + public TraceRecord getTraceRecord(int c) { + if (traceRecords == null) return null; + else if (traceRecords.size() <= c) return null; + else return traceRecords.get(c); + } + + public String getTraceRecordsContent() { + StringBuilder str = new StringBuilder(); + + for (int i = 0; i < traceRecords.size(); i++) { + str.append("No." + i + "record : \n" + traceRecords.get(i).toString()); + } + + return str.toString(); + } + + public void setTraceRecords(String fileName) { + File file = new File(fileName); + ObjectInputStream reader; + try { + FileInputStream fileout = new FileInputStream(file); + GZIPInputStream gzin = new GZIPInputStream(fileout); + reader = new ObjectInputStream(gzin); + traceRecords = (ArrayList) reader.readObject(); + reader.close(); + } catch (IOException | ClassNotFoundException e) { + e.printStackTrace(); + } + } + + public void recoverInit() { + this.recoverMap = new HashMap(); + Bindings bindings = nashornEngine.getBindings(ScriptContext.ENGINE_SCOPE); + System.out.println(bindings); + + for (String key : bindings.keySet()) { + Object obj = bindings.get(key); + if (obj instanceof ScriptObjectMirror) initRecoverMap((ScriptObjectMirror) obj); + } + Context.setGlobal(JavaScriptEntry.getEngineGlobal()); + } + + public String recoverFromTraceRecord() { + System.out.println("[TraceRecoverUtil] recoverFromTraceRecord : "); + + recoverInit(); + Global oldGlobal = Context.getGlobal(); + boolean globalChanged = (oldGlobal != engine.getDesktopGlobal()); + try { + if (globalChanged) { + Context.setGlobal(engine.getDesktopGlobal()); + } + + for (int i = 0; i < traceRecords.size(); i++) { + TraceRecord traceRecord = traceRecords.get(i); + System.out.println(traceRecord.toString()); + + for (int j = 0; j < traceRecord.length(); j++) { + // System.out.println("trace <" + j + ">"); + + Trace trace = traceRecord.traces.get(j); + + if (trace instanceof TraceSetup) { + recoverSetup((TraceSetup) trace); + } else if (trace instanceof TraceSet) { + recoverSet((TraceSet) trace); + } else if (trace instanceof TraceDone) { + // System.out.println("[DesktopEngine] recover TraceDone, before set:" + + // ScriptObject.getAllocID() + // + " -->" + ((TraceDone) trace).getID()); + ScriptObject.setAllocID(((TraceDone) trace).getID()); + } else if (trace instanceof TraceInitArray) { + recoverInitArray((TraceInitArray) trace); + } else if (trace instanceof TraceInitObject) { // un use + recoverInitObject((TraceInitObject) trace); + } + } + + recoverFlag = i; + } + } catch (Exception e) { + + } finally { + Context.setGlobal(oldGlobal); + } + + return "[recoverFromTraceRecord] recover all"; + } + /* + * 通过traceRecord进行恢复 从当前状态恢复到第c次执行之后的状态 + */ + public String recoverFromTraceRecord(int c) { + int oldflag = recoverFlag; + + if (recoverFlag < 0) recoverInit(); + + if (recoverFlag > c) { + System.out.println( + "[recoverFromTraceRecord] recoverFlag now is " + + recoverFlag + + " ,can't recover to " + + c + + " !"); + return "recover from trace failed!"; + } + + if (c >= traceRecords.size()) { + System.out.println( + "[recoverFromTraceRecord] traceRecords' size now is " + + traceRecords.size() + + " ,can't recover to " + + c + + " !"); + return "recover from trace failed!"; + } + + Global oldGlobal = Context.getGlobal(); + boolean globalChanged = (oldGlobal != engine.getDesktopGlobal()); + try { + if (globalChanged) { + Context.setGlobal(engine.getDesktopGlobal()); + } + + for (int i = recoverFlag + 1; i <= c; i++) { + TraceRecord traceRecord = traceRecords.get(i); + + for (int j = 0; j < traceRecord.length(); j++) { + // System.out.println("trace <" + j + ">"); + + Trace trace = traceRecord.traces.get(j); + + if (trace instanceof TraceSetup) { + recoverSetup((TraceSetup) trace); + } else if (trace instanceof TraceSet) { + recoverSet((TraceSet) trace); + } else if (trace instanceof TraceDone) { + // System.out.println("[DesktopEngine] recover TraceDone, before set:" + + // ScriptObject.getAllocID() + // + " -->" + ((TraceDone) trace).getID()); + ScriptObject.setAllocID(((TraceDone) trace).getID()); + } else if (trace instanceof TraceInitArray) { + recoverInitArray((TraceInitArray) trace); + } else if (trace instanceof TraceInitObject) { // un use + recoverInitObject((TraceInitObject) trace); + } + } + + recoverFlag = i; + } + } catch (Exception e) { + + } finally { + Context.setGlobal(oldGlobal); + } + + recoverFlag = c; + + return "[recoverFromTraceRecord] recover from " + oldflag + " to " + c; + } + + public void recoverSetup(TraceSetup trace) { + // System.out.println("[recoverSetup]\n" + trace.traceContent()); + + ScriptObjectMirror obj = null; + int id = -1; + + if (trace.getObj() instanceof JSArray) { + id = ((JSArray) trace.getObj()).getObjID(); + obj = + (ScriptObjectMirror) + ScriptObjectMirror.wrap( + Global.allocate(new int[0]), engine.getDesktopGlobal()); + obj.setObjectID(id); + } else if (trace.getObj() instanceof JSObject) { + + id = ((JSObject) trace.getObj()).getObjID(); + JO so = new JO(JO.getInitialMap()); + so.setObjectID(id); + obj = (ScriptObjectMirror) ScriptObjectMirror.wrap(so, engine.getDesktopGlobal()); + + /* + * System.out.println("[recover setup JSObject] : "); id = ((JSObject) + * trace.getObj()).getObjID(); + * + * PropertyMap map = PropertyMap.newMap(); for(int i = 0;i < + * trace.proLength();i++) { map.addProperty(trace.get(i)); } ScriptObject so = + * new JO(map); + * + * + * + * + * so.setObjectID(id); obj = (ScriptObjectMirror) ScriptObjectMirror.wrap(so, + * JavaScriptEntry.getEngineGlobal()); + */ + + } + recoverMap.put(id, obj); + } + + public void recoverInitArray(TraceInitArray trace) { + // System.out.println("[recoverInitArray]\n" + trace.traceContent()); + + for (int i = 0; i < trace.getLength(); i++) { + TraceSet trace2 = new TraceSet(trace.getArrayId(), trace.getKey(i), trace.getValue(i)); + recoverSet(trace2); + } + } + + public void recoverInitObject(TraceInitObject trace) { + // System.out.println("[recoverInitObject]\n" + trace.traceContent()); + // System.out.println("id=" + trace.getId() + " id2=" + trace.getId2()); + ScriptObject so = getScriptObjectMirrorById(trace.getId()).getScriptObject(); + ScriptObject so2 = (getScriptObjectMirrorById(trace.getId2())).getScriptObject(); + // System.out.println("so=" + so.toString() + " so2=" + so2.toString()); + so.setGlobalObjectProto(so2); + } + + public void recoverSet(TraceSet trace) { + // System.out.println("[recoverSet]\n" + trace.traceContent()); + + ScriptObjectMirror owner = getScriptObjectMirrorById(trace.getOwner()); + Object key = trace.getKey(); + Object value = trace.getValue(); + + // 把JS类型转化为ScriptObjectMirror + if (value instanceof JSObject) + value = getScriptObjectMirrorById(((JSObject) value).getObjID()); + // 目前JSArray和JSObject一样,可能可以简化 + else if (value instanceof JSArray) + value = getScriptObjectMirrorById(((JSArray) value).getObjID()); + else if (value instanceof String || value instanceof Integer || value instanceof Double) ; + else if (value instanceof JSNull) // 数组trace中可能存在null和Undifined类型,赋值时跳过 + return; + else if (value instanceof JSUndifined) { + return; + } else System.out.println("[recoverSet] encounter new value type!" + value.toString()); + + // 修改ScriptObjectMirror中的setMemeber,使它支持所有类型 + owner.setMember2(key, value); + } + + /* + * 将bindings中的变量放入recoverMap 对于函数的scope中的对象以及对象中的对象的情况可以通过递归将所有需要的都放入recoverMap中 + */ + private void initRecoverMap(ScriptObjectMirror obj) { + if (obj == null) return; + if (recoverMap.containsKey(obj.getObjectID())) return; + recoverMap.put(obj.getObjectID(), obj); + + // 全局变量从bindings中获得 + for (String key : obj.getOwnKeys(true)) { + try { + Object value = obj.getMember(key); + if (value instanceof ScriptObjectMirror) { + ScriptObjectMirror svalue = (ScriptObjectMirror) value; + initRecoverMap(svalue); + // 从函数的Scope中获得 + if (svalue.isFunction()) { + ScriptFunction sf = (ScriptFunction) svalue.getScriptObject(); + ScriptObject s = sf.getScope(); + ScriptObjectMirror obj2 = + (ScriptObjectMirror) + ScriptObjectMirror.wrap( + s, JavaScriptEntry.getEngineGlobal()); + initRecoverMap(obj2); + } + } + } catch (Exception e) { + // e.printStackTrace(); + } + } + } + + public ScriptObjectMirror getScriptObjectMirrorById(int id) { + ScriptObjectMirror so = null; + + // 从recoverMap中获得 + if (recoverMap.containsKey(id)) return recoverMap.get(id); + + System.out.println("[getScriptObjectMirrorById] can't find the ScriptObjectMirror by id!"); + return so; + } +} diff --git a/src/main/java/org/bdware/sc/trace/TraceSet.java b/src/main/java/org/bdware/sc/trace/TraceSet.java new file mode 100644 index 0000000..eb741f0 --- /dev/null +++ b/src/main/java/org/bdware/sc/trace/TraceSet.java @@ -0,0 +1,53 @@ +package org.bdware.sc.trace; + +import java.io.Serializable; + +/* + * 记录nashorn中setElem和setProp的trace + * 自定义对象和数组的set不同 + */ +public class TraceSet extends Trace implements Serializable{ + int owner; //该对象的id + Object key; + Object value; + + public TraceSet(int id,Object k,Object v) { + owner = id; + key = k; + value = v; + } + + public void setOwner(int owner) { + this.owner = owner; + } + + public void setKey(Object k) { + this.key = k; + } + + public void setValue(Object v) { + this.value = v; + } + + public int getOwner() { + return this.owner; + } + + public Object getKey() { + return this.key; + } + + public Object getValue() { + return this.value; + } + + @Override + public String traceContent(){ + StringBuilder str = new StringBuilder(); + str.append("[TraceSet]\n"); + str.append("owner=" + owner + "\n"); + str.append("key=" + key.getClass() + " " + key.toString() + "\n"); + str.append("value=" + value.getClass() + " " + value.toString() + "\n"); + return str.toString(); + } +} \ No newline at end of file diff --git a/src/main/java/org/bdware/sc/trace/TraceSetIdentifier.java b/src/main/java/org/bdware/sc/trace/TraceSetIdentifier.java new file mode 100644 index 0000000..08bae52 --- /dev/null +++ b/src/main/java/org/bdware/sc/trace/TraceSetIdentifier.java @@ -0,0 +1,61 @@ +package org.bdware.sc.trace; + +public class TraceSetIdentifier { + int owner; + Object key; + + public TraceSetIdentifier(int id,Object k) { + this.owner = id; + this.key = k; + } + + @Override + public boolean equals(Object obj) { + if(obj == null && this == null) + return true; + else if(obj == null && this != null) + return false; + else if(obj != null && this == null) + return false; + + if(this == obj) + return true; + + TraceSetIdentifier obj2 = (TraceSetIdentifier)obj; + + if(this.owner != obj2.owner) + return false; + + if(this.key instanceof String && obj2.key instanceof String && obj2.key.equals(this.key)) + return true; + else if(this.key instanceof Double && obj2.key instanceof Double && obj2.key.equals(this.key)) + return true; + else + System.out.println("[TraceSetIdentifier] error : encounter new key type : " + this.key.getClass().getName()); + + return false; + } + + @Override + public int hashCode() { + int result = 17,temp = 0; + result = 31 * result + owner; + + if(key instanceof String) { + String k = (String)key; + result = result * 31 + k.hashCode(); + result = result * 31 + temp; + }else if(key instanceof Double) { + double t = (Double)key; + temp = (int)t; + result = result * 31 + temp; + }else { + System.out.println("[TraceSetIdentifier] error : encounter new key type : " + this.key.getClass().getName()); + } + + if(result < 0) + result = -result; + + return result; + } +} diff --git a/src/main/java/org/bdware/sc/trace/TraceSetup.java b/src/main/java/org/bdware/sc/trace/TraceSetup.java new file mode 100644 index 0000000..7675f33 --- /dev/null +++ b/src/main/java/org/bdware/sc/trace/TraceSetup.java @@ -0,0 +1,54 @@ +package org.bdware.sc.trace; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +import wrp.jdk.nashorn.internal.runtime.Property; + +/* + * 记录nashorn中ScriptObject创建的trace + */ +public class TraceSetup extends Trace implements Serializable{ + JSScript obj; //被创建的ScriptObject + List properties; + + public TraceSetup(JSScript o) { + this.obj = o; + properties = new ArrayList(); + } + + public JSScript getObj() { + return this.obj; + } + + public void add(Property p) { + properties.add(p); + } + + public Property get(int i) { + return properties.get(i); + } + + public int proLength() { + return properties.size(); + } + + @Override + public String traceContent(){ + StringBuilder str = new StringBuilder(); + str.append("[TraceSetup]\n"); + if(obj instanceof JSObject) + str.append(((JSObject)obj).getObjID() + "," + ((JSObject)obj).getClass()+ " " + /*map.toString() +*/ "\n"); + else if(obj instanceof JSArray) + str.append(((JSArray)obj).getObjID() + "," + ((JSArray)obj).getClass() + " " +/* map.toString() + */"\n"); + + if(properties.size() > 0) { + str.append("properties : " + "\n"); + for(int i = 0;i < properties.size();i++) + str.append(properties.get(i) + "\n"); + } + + return str.toString(); + } +} \ No newline at end of file diff --git a/src/main/resources/log4j.properties b/src/main/resources/log4j.properties new file mode 100644 index 0000000..f2fb500 --- /dev/null +++ b/src/main/resources/log4j.properties @@ -0,0 +1,8 @@ +### 设置### +log4j.rootLogger = debug,stdout + +### 输出信息到控制抬 ### +log4j.appender.stdout = org.apache.log4j.ConsoleAppender +log4j.appender.stdout.Target = System.out +log4j.appender.stdout.layout = org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{HH:mm:ss.SSS} %m (%F:%L)[%M]%n \ No newline at end of file diff --git a/src/main/resources/log4j2.properties b/src/main/resources/log4j2.properties new file mode 100644 index 0000000..7cb02aa --- /dev/null +++ b/src/main/resources/log4j2.properties @@ -0,0 +1,15 @@ +filter.threshold.type=ThresholdFilter +filter.threshold.level=debug +appender.console.type=Console +appender.console.name=STDOUT +appender.console.layout.type=PatternLayout +appender.console.layout.pattern=%highlight{[%-5p] %d{HH:mm:ss.SSS} %m (%F:%L)[%M]%n}{FATAL=Bright Red,ERROR=Red,WARN=Yellow,INFO=Green,DEBUG=Blue,TRACE=White} +appender.rolling.type=File +appender.rolling.name=log +appender.rolling.append=true +appender.rolling.fileName=./log/ct.log +appender.rolling.layout.type=PatternLayout +appender.rolling.layout.pattern=%d-%m%n +rootLogger.level=info +rootLogger.appenderRef.stdout.ref=STDOUT +rootLogger.appenderRef.log.ref=log \ No newline at end of file diff --git a/src/main/resources/org/bdware/sc/engine/mock-min.js b/src/main/resources/org/bdware/sc/engine/mock-min.js new file mode 100644 index 0000000..6b50407 --- /dev/null +++ b/src/main/resources/org/bdware/sc/engine/mock-min.js @@ -0,0 +1,10 @@ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.Mock=e():t.Mock=e()}(this,function(){return function(t){function e(r){if(n[r])return n[r].exports;var a=n[r]={exports:{},id:r,loaded:!1};return t[r].call(a.exports,a,a.exports,e),a.loaded=!0,a.exports}var n={};return e.m=t,e.c=n,e.p="",e(0)}([function(t,e,n){var r,a=n(1),o=n(3),u=n(5),i=n(20),l=n(23),c=n(25);"undefined"!=typeof window&&(r=n(27));/*! + Mock - 模拟请求 & 模拟数据 + https://github.com/nuysoft/Mock + 墨智 mozhi.gyy@taobao.com nuysoft@gmail.com + */ + var s={Handler:a,Random:u,Util:o,XHR:r,RE:i,toJSONSchema:l,valid:c,heredoc:o.heredoc,setup:function(t){return r.setup(t)},_mocked:{}};s.version="1.0.1-beta3",r&&(r.Mock=s),s.mock=function(t,e,n){return 1===arguments.length?a.gen(t):(2===arguments.length&&(n=e,e=void 0),r&&(window.XMLHttpRequest=r),s._mocked[t+(e||"")]={rurl:t,rtype:e,template:n},s)},t.exports=s},function(module,exports,__webpack_require__){var Constant=__webpack_require__(2),Util=__webpack_require__(3),Parser=__webpack_require__(4),Random=__webpack_require__(5),RE=__webpack_require__(20),Handler={extend:Util.extend};Handler.gen=function(t,e,n){e=void 0==e?"":e+"",n=n||{},n={path:n.path||[Constant.GUID],templatePath:n.templatePath||[Constant.GUID++],currentContext:n.currentContext,templateCurrentContext:n.templateCurrentContext||t,root:n.root||n.currentContext,templateRoot:n.templateRoot||n.templateCurrentContext||t};var r,a=Parser.parse(e),o=Util.type(t);return Handler[o]?(r=Handler[o]({type:o,template:t,name:e,parsedName:e?e.replace(Constant.RE_KEY,"$1"):e,rule:a,context:n}),n.root||(n.root=r),r):t},Handler.extend({array:function(t){var e,n,r=[];if(0===t.template.length)return r;if(t.rule.parameters)if(1===t.rule.min&&void 0===t.rule.max)t.context.path.push(t.name),t.context.templatePath.push(t.name),r=Random.pick(Handler.gen(t.template,void 0,{path:t.context.path,templatePath:t.context.templatePath,currentContext:r,templateCurrentContext:t.template,root:t.context.root||r,templateRoot:t.context.templateRoot||t.template})),t.context.path.pop(),t.context.templatePath.pop();else if(t.rule.parameters[2])t.template.__order_index=t.template.__order_index||0,t.context.path.push(t.name),t.context.templatePath.push(t.name),r=Handler.gen(t.template,void 0,{path:t.context.path,templatePath:t.context.templatePath,currentContext:r,templateCurrentContext:t.template,root:t.context.root||r,templateRoot:t.context.templateRoot||t.template})[t.template.__order_index%t.template.length],t.template.__order_index+=+t.rule.parameters[2],t.context.path.pop(),t.context.templatePath.pop();else for(e=0;e1)return this.getValueByKeyPath(key,options);if(templateContext&&"object"==typeof templateContext&&key in templateContext&&placeholder!==templateContext[key])return templateContext[key]=Handler.gen(templateContext[key],key,{currentContext:obj,templateCurrentContext:templateContext}),templateContext[key];if(!(key in Random||lkey in Random||okey in Random))return placeholder;for(var i=0;i1&&(a=e.context.path.slice(0),a.pop(),a=this.normalizePath(a.concat(r)));try{t=r[r.length-1];for(var o=e.context.root,u=e.context.templateRoot,i=1;i1/(t+e)*t?!n:n):Math.random()>=.5},bool:function(t,e,n){return this.boolean(t,e,n)},natural:function(t,e){return t="undefined"!=typeof t?parseInt(t,10):0,e="undefined"!=typeof e?parseInt(e,10):9007199254740992,Math.round(Math.random()*(e-t))+t},integer:function(t,e){return t="undefined"!=typeof t?parseInt(t,10):-9007199254740992,e="undefined"!=typeof e?parseInt(e,10):9007199254740992,Math.round(Math.random()*(e-t))+t},int:function(t,e){return this.integer(t,e)},float:function(t,e,n,r){n=void 0===n?0:n,n=Math.max(Math.min(n,17),0),r=void 0===r?17:r,r=Math.max(Math.min(r,17),0);for(var a=this.integer(t,e)+".",o=0,u=this.natural(n,r);o1&&r--,o=6*r<1?e+6*(n-e)*r:2*r<1?n:3*r<2?e+(n-e)*(2/3-r)*6:e,a[c]=255*o;return a},hsl2hsv:function(t){var e,n,r=t[0],a=t[1]/100,o=t[2]/100;return o*=2,a*=o<=1?o:2-o,n=(o+a)/2,e=2*a/(o+a),[r,100*e,100*n]},hsv2rgb:function(t){var e=t[0]/60,n=t[1]/100,r=t[2]/100,a=Math.floor(e)%6,o=e-Math.floor(e),u=255*r*(1-n),i=255*r*(1-n*o),l=255*r*(1-n*(1-o));switch(r*=255,a){case 0:return[r,l,u];case 1:return[i,r,u];case 2:return[u,r,l];case 3:return[u,i,r];case 4:return[l,u,r];case 5:return[r,u,i]}},hsv2hsl:function(t){var e,n,r=t[0],a=t[1]/100,o=t[2]/100;return n=(2-a)*o,e=a*o,e/=n<=1?n:2-n,n/=2,[r,100*e,100*n]},rgb2hex:function(t,e,n){return"#"+((256+t<<8|e)<<8|n).toString(16).slice(1)},hex2rgb:function(t){return t="0x"+t.slice(1).replace(t.length>4?t:/./g,"$&$&")|0,[t>>16,t>>8&255,255&t]}}},function(t,e){t.exports={navy:{value:"#000080",nicer:"#001F3F"},blue:{value:"#0000ff",nicer:"#0074D9"},aqua:{value:"#00ffff",nicer:"#7FDBFF"},teal:{value:"#008080",nicer:"#39CCCC"},olive:{value:"#008000",nicer:"#3D9970"},green:{value:"#008000",nicer:"#2ECC40"},lime:{value:"#00ff00",nicer:"#01FF70"},yellow:{value:"#ffff00",nicer:"#FFDC00"},orange:{value:"#ffa500",nicer:"#FF851B"},red:{value:"#ff0000",nicer:"#FF4136"},maroon:{value:"#800000",nicer:"#85144B"},fuchsia:{value:"#ff00ff",nicer:"#F012BE"},purple:{value:"#800080",nicer:"#B10DC9"},silver:{value:"#c0c0c0",nicer:"#DDDDDD"},gray:{value:"#808080",nicer:"#AAAAAA"},black:{value:"#000000",nicer:"#111111"},white:{value:"#FFFFFF",nicer:"#FFFFFF"}}},function(t,e,n){function r(t,e,n,r){return void 0===n?a.natural(t,e):void 0===r?n:a.natural(parseInt(n,10),parseInt(r,10))}var a=n(6),o=n(14);t.exports={paragraph:function(t,e){for(var n=r(3,7,t,e),a=[],o=0;o1&&(e=[].slice.call(arguments,0));var n=t.options,r=n.context.templatePath.join("."),a=t.cache[r]=t.cache[r]||{index:0,array:e};return a.array[a.index++%a.array.length]}}},function(t,e){t.exports={first:function(){var t=["James","John","Robert","Michael","William","David","Richard","Charles","Joseph","Thomas","Christopher","Daniel","Paul","Mark","Donald","George","Kenneth","Steven","Edward","Brian","Ronald","Anthony","Kevin","Jason","Matthew","Gary","Timothy","Jose","Larry","Jeffrey","Frank","Scott","Eric"].concat(["Mary","Patricia","Linda","Barbara","Elizabeth","Jennifer","Maria","Susan","Margaret","Dorothy","Lisa","Nancy","Karen","Betty","Helen","Sandra","Donna","Carol","Ruth","Sharon","Michelle","Laura","Sarah","Kimberly","Deborah","Jessica","Shirley","Cynthia","Angela","Melissa","Brenda","Amy","Anna"]);return this.pick(t)},last:function(){var t=["Smith","Johnson","Williams","Brown","Jones","Miller","Davis","Garcia","Rodriguez","Wilson","Martinez","Anderson","Taylor","Thomas","Hernandez","Moore","Martin","Jackson","Thompson","White","Lopez","Lee","Gonzalez","Harris","Clark","Lewis","Robinson","Walker","Perez","Hall","Young","Allen"];return this.pick(t)},name:function(t){return this.first()+" "+(t?this.first()+" ":"")+this.last()},cfirst:function(){var t="王 李 张 刘 陈 杨 赵 黄 周 吴 徐 孙 胡 朱 高 林 何 郭 马 罗 梁 宋 郑 谢 韩 唐 冯 于 董 萧 程 曹 袁 邓 许 傅 沈 曾 彭 吕 苏 卢 蒋 蔡 贾 丁 魏 薛 叶 阎 余 潘 杜 戴 夏 锺 汪 田 任 姜 范 方 石 姚 谭 廖 邹 熊 金 陆 郝 孔 白 崔 康 毛 邱 秦 江 史 顾 侯 邵 孟 龙 万 段 雷 钱 汤 尹 黎 易 常 武 乔 贺 赖 龚 文".split(" ");return this.pick(t)},clast:function(){var t="伟 芳 娜 秀英 敏 静 丽 强 磊 军 洋 勇 艳 杰 娟 涛 明 超 秀兰 霞 平 刚 桂英".split(" ");return this.pick(t)},cname:function(){return this.cfirst()+this.clast()}}},function(t,e){t.exports={url:function(t,e){return(t||this.protocol())+"://"+(e||this.domain())+"/"+this.word()},protocol:function(){return this.pick("http ftp gopher mailto mid cid news nntp prospero telnet rlogin tn3270 wais".split(" "))},domain:function(t){return this.word()+"."+(t||this.tld())},tld:function(){return this.pick("com net org edu gov int mil cn com.cn net.cn gov.cn org.cn 中国 中国互联.公司 中国互联.网络 tel biz cc tv info name hk mobi asia cd travel pro museum coop aero ad ae af ag ai al am an ao aq ar as at au aw az ba bb bd be bf bg bh bi bj bm bn bo br bs bt bv bw by bz ca cc cf cg ch ci ck cl cm cn co cq cr cu cv cx cy cz de dj dk dm do dz ec ee eg eh es et ev fi fj fk fm fo fr ga gb gd ge gf gh gi gl gm gn gp gr gt gu gw gy hk hm hn hr ht hu id ie il in io iq ir is it jm jo jp ke kg kh ki km kn kp kr kw ky kz la lb lc li lk lr ls lt lu lv ly ma mc md mg mh ml mm mn mo mp mq mr ms mt mv mw mx my mz na nc ne nf ng ni nl no np nr nt nu nz om qa pa pe pf pg ph pk pl pm pn pr pt pw py re ro ru rw sa sb sc sd se sg sh si sj sk sl sm sn so sr st su sy sz tc td tf tg th tj tk tm tn to tp tr tt tv tw tz ua ug uk us uy va vc ve vg vn vu wf ws ye yu za zm zr zw".split(" "))},email:function(t){return this.character("lower")+"."+this.word()+"@"+(t||this.word()+"."+this.tld())},ip:function(){return this.natural(0,255)+"."+this.natural(0,255)+"."+this.natural(0,255)+"."+this.natural(0,255)}}},function(t,e,n){var r=n(18),a=["东北","华北","华东","华中","华南","西南","西北"];t.exports={region:function(){return this.pick(a)},province:function(){return this.pick(r).name},city:function(t){var e=this.pick(r),n=this.pick(e.children);return t?[e.name,n.name].join(" "):n.name},county:function(t){var e=this.pick(r),n=this.pick(e.children),a=this.pick(n.children)||{name:"-"};return t?[e.name,n.name,a.name].join(" "):a.name},zip:function(t){for(var e="",n=0;n<(t||6);n++)e+=this.natural(0,9);return e}}},function(t,e){function n(t){for(var e,n={},r=0;ra;a++)o=t.charAt(a),"\n"===o?(e.seenCR||e.line++,e.column=1,e.seenCR=!1):"\r"===o||"\u2028"===o||"\u2029"===o?(e.line++,e.column=1,e.seenCR=!0):(e.column++,e.seenCR=!1)}return tr!==e&&(tr>e&&(tr=0,er={line:1,column:1,seenCR:!1}),n(er,tr,e),tr=e),er}function b(t){nr>Zn||(Zn>nr&&(nr=Zn,rr=[]),rr.push(t))}function w(t){var e=0;for(t.sort();eZn?(r=t.charAt(Zn),Zn++):(r=null,0===ar&&b(Hn)),null!==r?(Qn=e,n=Sn(r),null===n?(Zn=e,e=n):e=n):(Zn=e,e=kt)):(Zn=e,e=kt),e}function ft(){var e,n,r;return e=Zn,92===t.charCodeAt(Zn)?(n=Dn,Zn++):(n=null,0===ar&&b(qn)),null!==n?(Fn.test(t.charAt(Zn))?(r=t.charAt(Zn),Zn++):(r=null,0===ar&&b(Ln)),null!==r?(Qn=e,n=On(r),null===n?(Zn=e,e=n):e=n):(Zn=e,e=kt)):(Zn=e,e=kt),e}function dt(){var e,n,r,a;if(e=Zn,t.substr(Zn,2)===In?(n=In,Zn+=2):(n=null,0===ar&&b(jn)),null!==n){if(r=[],Nn.test(t.charAt(Zn))?(a=t.charAt(Zn),Zn++):(a=null,0===ar&&b(zn)),null!==a)for(;null!==a;)r.push(a),Nn.test(t.charAt(Zn))?(a=t.charAt(Zn),Zn++):(a=null,0===ar&&b(zn));else r=kt;null!==r?(Qn=e,n=Un(r),null===n?(Zn=e,e=n):e=n):(Zn=e,e=kt)}else Zn=e,e=kt;return e}function mt(){var e,n,r,a;if(e=Zn,t.substr(Zn,2)===Bn?(n=Bn,Zn+=2):(n=null,0===ar&&b(Gn)),null!==n){if(r=[],Xn.test(t.charAt(Zn))?(a=t.charAt(Zn),Zn++):(a=null,0===ar&&b(Kn)),null!==a)for(;null!==a;)r.push(a),Xn.test(t.charAt(Zn))?(a=t.charAt(Zn),Zn++):(a=null,0===ar&&b(Kn));else r=kt;null!==r?(Qn=e,n=Wn(r),null===n?(Zn=e,e=n):e=n):(Zn=e,e=kt)}else Zn=e,e=kt;return e}function vt(){var e,n,r,a;if(e=Zn,t.substr(Zn,2)===Yn?(n=Yn,Zn+=2):(n=null,0===ar&&b($n)),null!==n){if(r=[],Xn.test(t.charAt(Zn))?(a=t.charAt(Zn),Zn++):(a=null,0===ar&&b(Kn)),null!==a)for(;null!==a;)r.push(a),Xn.test(t.charAt(Zn))?(a=t.charAt(Zn),Zn++):(a=null,0===ar&&b(Kn));else r=kt;null!==r?(Qn=e,n=Jn(r),null===n?(Zn=e,e=n):e=n):(Zn=e,e=kt)}else Zn=e,e=kt;return e}function gt(){var e,n;return e=Zn,t.substr(Zn,2)===In?(n=In,Zn+=2):(n=null,0===ar&&b(jn)),null!==n&&(Qn=e,n=Vn()),null===n?(Zn=e,e=n):e=n,e}function xt(){var e,n,r;return e=Zn,92===t.charCodeAt(Zn)?(n=Dn,Zn++):(n=null,0===ar&&b(qn)),null!==n?(t.length>Zn?(r=t.charAt(Zn),Zn++):(r=null,0===ar&&b(Hn)),null!==r?(Qn=e,n=Fe(r),null===n?(Zn=e,e=n):e=n):(Zn=e,e=kt)):(Zn=e,e=kt),e}var yt,bt=arguments.length>1?arguments[1]:{},wt={regexp:C},Ct=C,kt=null,Et="",Rt="|",At='"|"',_t=function(t,e){return e?new r(t,e[1]):t},Mt=function(t,e,n){return new a([t].concat(e).concat([n]))},Pt="^",Tt='"^"',Ht=function(){return new n("start")},St="$",Dt='"$"',qt=function(){return new n("end")},Ft=function(t,e){return new i(t,e)},Lt="Quantifier",Ot=function(t,e){return e&&(t.greedy=!1),t},It="{",jt='"{"',Nt=",",zt='","',Ut="}",Bt='"}"',Gt=function(t,e){return new l(t,e)},Xt=",}",Kt='",}"',Wt=function(t){return new l(t,1/0)},Yt=function(t){return new l(t,t)},$t="+",Jt='"+"',Vt=function(){return new l(1,1/0)},Zt="*",Qt='"*"',te=function(){return new l(0,1/0)},ee="?",ne='"?"',re=function(){return new l(0,1)},ae=/^[0-9]/,oe="[0-9]",ue=function(t){return+t.join("")},ie="(",le='"("',ce=")",se='")"',he=function(t){return t},pe=function(t){return new u(t)},fe="?:",de='"?:"',me=function(t){return new o("non-capture-group",t)},ve="?=",ge='"?="',xe=function(t){return new o("positive-lookahead",t)},ye="?!",be='"?!"',we=function(t){return new o("negative-lookahead",t)},Ce="CharacterSet",ke="[",Ee='"["',Re="]",Ae='"]"',_e=function(t,e){return new c(!!t,e)},Me="CharacterRange",Pe="-",Te='"-"',He=function(t,e){return new s(t,e)},Se="Character",De=/^[^\\\]]/,qe="[^\\\\\\]]",Fe=function(t){return new h(t)},Le=".",Oe='"."',Ie=function(){return new n("any-character")},je="Literal",Ne=/^[^|\\\/.[()?+*$\^]/,ze="[^|\\\\\\/.[()?+*$\\^]",Ue="\\b",Be='"\\\\b"',Ge=function(){return new n("backspace")},Xe=function(){return new n("word-boundary")},Ke="\\B",We='"\\\\B"',Ye=function(){return new n("non-word-boundary")},$e="\\d",Je='"\\\\d"',Ve=function(){return new n("digit")},Ze="\\D",Qe='"\\\\D"',tn=function(){return new n("non-digit")},en="\\f",nn='"\\\\f"',rn=function(){return new n("form-feed")},an="\\n",on='"\\\\n"',un=function(){return new n("line-feed")},ln="\\r",cn='"\\\\r"',sn=function(){return new n("carriage-return")},hn="\\s",pn='"\\\\s"',fn=function(){return new n("white-space")},dn="\\S",mn='"\\\\S"',vn=function(){return new n("non-white-space")},gn="\\t",xn='"\\\\t"',yn=function(){return new n("tab")},bn="\\v",wn='"\\\\v"',Cn=function(){return new n("vertical-tab"); +},kn="\\w",En='"\\\\w"',Rn=function(){return new n("word")},An="\\W",_n='"\\\\W"',Mn=function(){return new n("non-word")},Pn="\\c",Tn='"\\\\c"',Hn="any character",Sn=function(t){return new v(t)},Dn="\\",qn='"\\\\"',Fn=/^[1-9]/,Ln="[1-9]",On=function(t){return new m(t)},In="\\0",jn='"\\\\0"',Nn=/^[0-7]/,zn="[0-7]",Un=function(t){return new d(t.join(""))},Bn="\\x",Gn='"\\\\x"',Xn=/^[0-9a-fA-F]/,Kn="[0-9a-fA-F]",Wn=function(t){return new f(t.join(""))},Yn="\\u",$n='"\\\\u"',Jn=function(t){return new p(t.join(""))},Vn=function(){return new n("null-character")},Zn=0,Qn=0,tr=0,er={line:1,column:1,seenCR:!1},nr=0,rr=[],ar=0;if("startRule"in bt){if(!(bt.startRule in wt))throw new Error("Can't start parsing from rule \""+bt.startRule+'".');Ct=wt[bt.startRule]}if(n.offset=x,n.text=g,yt=Ct(),null!==yt&&Zn===t.length)return yt;throw w(rr),Qn=Math.max(Zn,nr),new e(rr,Qnr)return!0;var u={path:e,type:t,actual:n,expected:r,action:"is greater than",message:o};return u.message=l.message(u),a.push(u),!1},lessThan:function(t,e,n,r,a,o){if(n=r)return!0;var u={path:e,type:t,actual:n,expected:r,action:"is greater than or equal to",message:o};return u.message=l.message(u),a.push(u),!1},lessThanOrEqualTo:function(t,e,n,r,a,o){if(n<=r)return!0;var u={path:e,type:t,actual:n,expected:r,action:"is less than or equal to",message:o};return u.message=l.message(u),a.push(u),!1}};r.Diff=i,r.Assert=l,t.exports=r},function(t,e,n){t.exports=n(28)},function(t,e,n){function r(){this.custom={events:{},requestHeaders:{},responseHeaders:{}}}function a(){function t(){try{return new window._XMLHttpRequest}catch(t){}}function e(){try{return new window._ActiveXObject("Microsoft.XMLHTTP")}catch(t){}}var n=function(){var t=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,e=/^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,n=location.href,r=e.exec(n.toLowerCase())||[];return t.test(r[1])}();return window.ActiveXObject?!n&&t()||e():t()}function o(t){function e(t,e){return"string"===i.type(t)?t===e:"regexp"===i.type(t)?t.test(e):void 0}for(var n in r.Mock._mocked){var a=r.Mock._mocked[n];if((!a.rurl||e(a.rurl,t.url))&&(!a.rtype||e(a.rtype,t.type.toLowerCase())))return a}}function u(t,e){return i.isFunction(t.template)?t.template(e):r.Mock.mock(t.template)}var i=n(3);window._XMLHttpRequest=window.XMLHttpRequest,window._ActiveXObject=window.ActiveXObject;try{new window.Event("custom")}catch(t){window.Event=function(t,e,n,r){var a=document.createEvent("CustomEvent");return a.initCustomEvent(t,e,n,r),a}}var l={UNSENT:0,OPENED:1,HEADERS_RECEIVED:2,LOADING:3,DONE:4},c="readystatechange loadstart progress abort error load timeout loadend".split(" "),s="timeout withCredentials".split(" "),h="readyState responseURL status statusText responseType response responseText responseXML".split(" "),p={100:"Continue",101:"Switching Protocols",200:"OK",201:"Created",202:"Accepted",203:"Non-Authoritative Information",204:"No Content",205:"Reset Content",206:"Partial Content",300:"Multiple Choice",301:"Moved Permanently",302:"Found",303:"See Other",304:"Not Modified",305:"Use Proxy",307:"Temporary Redirect",400:"Bad Request",401:"Unauthorized",402:"Payment Required",403:"Forbidden",404:"Not Found",405:"Method Not Allowed",406:"Not Acceptable",407:"Proxy Authentication Required",408:"Request Timeout",409:"Conflict",410:"Gone",411:"Length Required",412:"Precondition Failed",413:"Request Entity Too Large",414:"Request-URI Too Long",415:"Unsupported Media Type",416:"Requested Range Not Satisfiable",417:"Expectation Failed",422:"Unprocessable Entity",500:"Internal Server Error",501:"Not Implemented",502:"Bad Gateway",503:"Service Unavailable",504:"Gateway Timeout",505:"HTTP Version Not Supported"};r._settings={timeout:"10-100"},r.setup=function(t){return i.extend(r._settings,t),r._settings},i.extend(r,l),i.extend(r.prototype,l),r.prototype.mock=!0,r.prototype.match=!1,i.extend(r.prototype,{open:function(t,e,n,u,l){function p(t){for(var e=0;e \w_ + for (i = 0; i < placeholders.length; i++) { + ph = placeholders[i] + + // 遇到转义斜杠,不需要解析占位符 + if (/^\\/.test(ph)) { + placeholders.splice(i--, 1) + continue + } + + phed = Handler.placeholder(ph, options.context.currentContext, options.context.templateCurrentContext, options) + + // 只有一个占位符,并且没有其他字符 + if (placeholders.length === 1 && ph === result && typeof phed !== typeof result) { // + result = phed + break + + if (Util.isNumeric(phed)) { + result = parseFloat(phed, 10) + break + } + if (/^(true|false)$/.test(phed)) { + result = phed === 'true' ? true : + phed === 'false' ? false : + phed // 已经是布尔值 + break + } + } + result = result.replace(ph, phed) + } + + } else { + // 'ASCII|1-10': '', + // 'ASCII': '', + result = options.rule.range ? Random.string(options.rule.count) : options.template + } + return result + }, + 'function': function(options) { + // ( context, options ) + return options.template.call(options.context.currentContext, options) + }, + 'regexp': function(options) { + var source = '' + + // 'name': /regexp/, + /* jshint -W041 */ + if (options.rule.count == undefined) { + source += options.template.source // regexp.source + } + + // 'name|1-5': /regexp/, + for (var i = 0; i < options.rule.count; i++) { + source += options.template.source + } + + return RE.Handler.gen( + RE.Parser.parse( + source + ) + ) + } + }) + + Handler.extend({ + _all: function() { + var re = {}; + for (var key in Random) re[key.toLowerCase()] = key + return re + }, + // 处理占位符,转换为最终值 + placeholder: function(placeholder, obj, templateContext, options) { + // console.log(options.context.path) + // 1 key, 2 params + Constant.RE_PLACEHOLDER.exec('') + var parts = Constant.RE_PLACEHOLDER.exec(placeholder), + key = parts && parts[1], + lkey = key && key.toLowerCase(), + okey = this._all()[lkey], + params = parts && parts[2] || '' + var pathParts = this.splitPathToArray(key) + + // 解析占位符的参数 + try { + // 1. 尝试保持参数的类型 + /* + #24 [Window Firefox 30.0 引用 占位符 抛错](https://github.com/nuysoft/Mock/issues/24) + [BX9056: 各浏览器下 window.eval 方法的执行上下文存在差异](http://www.w3help.org/zh-cn/causes/BX9056) + 应该属于 Window Firefox 30.0 的 BUG + */ + /* jshint -W061 */ + params = eval('(function(){ return [].splice.call(arguments, 0 ) })(' + params + ')') + } catch (error) { + // 2. 如果失败,只能解析为字符串 + // console.error(error) + // if (error instanceof ReferenceError) params = parts[2].split(/,\s*/); + // else throw error + params = parts[2].split(/,\s*/) + } + + // 占位符优先引用数据模板中的属性 + if (obj && (key in obj)) return obj[key] + + // @index @key + // if (Constant.RE_INDEX.test(key)) return +options.name + // if (Constant.RE_KEY.test(key)) return options.name + + // 绝对路径 or 相对路径 + if ( + key.charAt(0) === '/' || + pathParts.length > 1 + ) return this.getValueByKeyPath(key, options) + + // 递归引用数据模板中的属性 + if (templateContext && + (typeof templateContext === 'object') && + (key in templateContext) && + (placeholder !== templateContext[key]) // fix #15 避免自己依赖自己 + ) { + // 先计算被引用的属性值 + templateContext[key] = Handler.gen(templateContext[key], key, { + currentContext: obj, + templateCurrentContext: templateContext + }) + return templateContext[key] + } + + // 如果未找到,则原样返回 + if (!(key in Random) && !(lkey in Random) && !(okey in Random)) return placeholder + + // 递归解析参数中的占位符 + for (var i = 0; i < params.length; i++) { + Constant.RE_PLACEHOLDER.exec('') + if (Constant.RE_PLACEHOLDER.test(params[i])) { + params[i] = Handler.placeholder(params[i], obj, templateContext, options) + } + } + + var handle = Random[key] || Random[lkey] || Random[okey] + switch (Util.type(handle)) { + case 'array': + // 自动从数组中取一个,例如 @areas + return Random.pick(handle) + case 'function': + // 执行占位符方法(大多数情况) + handle.options = options + var re = handle.apply(Random, params) + if (re === undefined) re = '' // 因为是在字符串中,所以默认为空字符串。 + delete handle.options + return re + } + }, + getValueByKeyPath: function(key, options) { + var originalKey = key + var keyPathParts = this.splitPathToArray(key) + var absolutePathParts = [] + + // 绝对路径 + if (key.charAt(0) === '/') { + absolutePathParts = [options.context.path[0]].concat( + this.normalizePath(keyPathParts) + ) + } else { + // 相对路径 + if (keyPathParts.length > 1) { + absolutePathParts = options.context.path.slice(0) + absolutePathParts.pop() + absolutePathParts = this.normalizePath( + absolutePathParts.concat(keyPathParts) + ) + + } + } + + try { + key = keyPathParts[keyPathParts.length - 1] + var currentContext = options.context.root + var templateCurrentContext = options.context.templateRoot + for (var i = 1; i < absolutePathParts.length - 1; i++) { + currentContext = currentContext[absolutePathParts[i]] + templateCurrentContext = templateCurrentContext[absolutePathParts[i]] + } + // 引用的值已经计算好 + if (currentContext && (key in currentContext)) return currentContext[key] + + // 尚未计算,递归引用数据模板中的属性 + if (templateCurrentContext && + (typeof templateCurrentContext === 'object') && + (key in templateCurrentContext) && + (originalKey !== templateCurrentContext[key]) // fix #15 避免自己依赖自己 + ) { + // 先计算被引用的属性值 + templateCurrentContext[key] = Handler.gen(templateCurrentContext[key], key, { + currentContext: currentContext, + templateCurrentContext: templateCurrentContext + }) + return templateCurrentContext[key] + } + } catch(err) { } + + return '@' + keyPathParts.join('/') + }, + // https://github.com/kissyteam/kissy/blob/master/src/path/src/path.js + normalizePath: function(pathParts) { + var newPathParts = [] + for (var i = 0; i < pathParts.length; i++) { + switch (pathParts[i]) { + case '..': + newPathParts.pop() + break + case '.': + break + default: + newPathParts.push(pathParts[i]) + } + } + return newPathParts + }, + splitPathToArray: function(path) { + var parts = path.split(/\/+/); + if (!parts[parts.length - 1]) parts = parts.slice(0, -1) + if (!parts[0]) parts = parts.slice(1) + return parts; + } + }) + + module.exports = Handler + + /***/ }), + /* 2 */ + /***/ (function(module, exports) { + + /* + ## Constant + + 常量集合。 + */ + /* + RE_KEY + 'name|min-max': value + 'name|count': value + 'name|min-max.dmin-dmax': value + 'name|min-max.dcount': value + 'name|count.dmin-dmax': value + 'name|count.dcount': value + 'name|+step': value + + 1 name, 2 step, 3 range [ min, max ], 4 drange [ dmin, dmax ] + + RE_PLACEHOLDER + placeholder(*) + + [正则查看工具](http://www.regexper.com/) + + #26 生成规则 支持 负数,例如 number|-100-100 + */ + module.exports = { + GUID: 1, + RE_KEY: /(.+)\|(?:\+(\d+)|([\+\-]?\d+-?[\+\-]?\d*)?(?:\.(\d+-?\d*))?)/, + RE_RANGE: /([\+\-]?\d+)-?([\+\-]?\d+)?/, + RE_PLACEHOLDER: /\\*@([^@#%&()\?\s]+)(?:\((.*?)\))?/g + // /\\*@([^@#%&()\?\s\/\.]+)(?:\((.*?)\))?/g + // RE_INDEX: /^index$/, + // RE_KEY: /^key$/ + } + + /***/ }), + /* 3 */ + /***/ (function(module, exports) { + + /* + ## Utilities + */ + var Util = {} + + Util.extend = function extend() { + var target = arguments[0] || {}, + i = 1, + length = arguments.length, + options, name, src, copy, clone + + if (length === 1) { + target = this + i = 0 + } + + for (; i < length; i++) { + options = arguments[i] + if (!options) continue + + for (name in options) { + src = target[name] + copy = options[name] + + if (target === copy) continue + if (copy === undefined) continue + + if (Util.isArray(copy) || Util.isObject(copy)) { + if (Util.isArray(copy)) clone = src && Util.isArray(src) ? src : [] + if (Util.isObject(copy)) clone = src && Util.isObject(src) ? src : {} + + target[name] = Util.extend(clone, copy) + } else { + target[name] = copy + } + } + } + + return target + } + + Util.each = function each(obj, iterator, context) { + var i, key + if (this.type(obj) === 'number') { + for (i = 0; i < obj; i++) { + iterator(i, i) + } + } else if (obj.length === +obj.length) { + for (i = 0; i < obj.length; i++) { + if (iterator.call(context, obj[i], i, obj) === false) break + } + } else { + for (key in obj) { + if (iterator.call(context, obj[key], key, obj) === false) break + } + } + } + + Util.type = function type(obj) { + return (obj === null || obj === undefined) ? String(obj) : Object.prototype.toString.call(obj).match(/\[object (\w+)\]/)[1].toLowerCase() + } + + Util.each('String Object Array RegExp Function'.split(' '), function(value) { + Util['is' + value] = function(obj) { + return Util.type(obj) === value.toLowerCase() + } + }) + + Util.isObjectOrArray = function(value) { + return Util.isObject(value) || Util.isArray(value) + } + + Util.isNumeric = function(value) { + return !isNaN(parseFloat(value)) && isFinite(value) + } + + Util.keys = function(obj) { + var keys = []; + for (var key in obj) { + if (obj.hasOwnProperty(key)) keys.push(key) + } + return keys; + } + Util.values = function(obj) { + var values = []; + for (var key in obj) { + if (obj.hasOwnProperty(key)) values.push(obj[key]) + } + return values; + } + + /* + ### Mock.heredoc(fn) + + * Mock.heredoc(fn) + + 以直观、安全的方式书写(多行)HTML 模板。 + + **使用示例**如下所示: + + var tpl = Mock.heredoc(function() { + /*! + {{email}}{{age}} + + *\/ + }) + + **相关阅读** + * [Creating multiline strings in JavaScript](http://stackoverflow.com/questions/805107/creating-multiline-strings-in-javascript)、 + */ + Util.heredoc = function heredoc(fn) { + // 1. 移除起始的 function(){ /*! + // 2. 移除末尾的 */ } + // 3. 移除起始和末尾的空格 + return fn.toString() + .replace(/^[^\/]+\/\*!?/, '') + .replace(/\*\/[^\/]+$/, '') + .replace(/^[\s\xA0]+/, '').replace(/[\s\xA0]+$/, '') // .trim() + } + + Util.noop = function() {} + + module.exports = Util + + /***/ }), + /* 4 */ + /***/ (function(module, exports, __webpack_require__) { + + /* + ## Parser + + 解析数据模板(属性名部分)。 + + * Parser.parse( name ) + + ```json + { + parameters: [ name, inc, range, decimal ], + rnage: [ min , max ], + + min: min, + max: max, + count : count, + + decimal: decimal, + dmin: dmin, + dmax: dmax, + dcount: dcount + } + ``` + */ + + var Constant = __webpack_require__(2) + var Random = __webpack_require__(5) + + /* jshint -W041 */ + module.exports = { + parse: function(name) { + name = name == undefined ? '' : (name + '') + + var parameters = (name || '').match(Constant.RE_KEY) + + var range = parameters && parameters[3] && parameters[3].match(Constant.RE_RANGE) + var min = range && range[1] && parseInt(range[1], 10) // || 1 + var max = range && range[2] && parseInt(range[2], 10) // || 1 + // repeat || min-max || 1 + // var count = range ? !range[2] && parseInt(range[1], 10) || Random.integer(min, max) : 1 + var count = range ? !range[2] ? parseInt(range[1], 10) : Random.integer(min, max) : undefined + + var decimal = parameters && parameters[4] && parameters[4].match(Constant.RE_RANGE) + var dmin = decimal && decimal[1] && parseInt(decimal[1], 10) // || 0, + var dmax = decimal && decimal[2] && parseInt(decimal[2], 10) // || 0, + // int || dmin-dmax || 0 + var dcount = decimal ? !decimal[2] && parseInt(decimal[1], 10) || Random.integer(dmin, dmax) : undefined + + var result = { + // 1 name, 2 inc, 3 range, 4 decimal + parameters: parameters, + // 1 min, 2 max + range: range, + min: min, + max: max, + // min-max + count: count, + // 是否有 decimal + decimal: decimal, + dmin: dmin, + dmax: dmax, + // dmin-dimax + dcount: dcount + } + + for (var r in result) { + if (result[r] != undefined) return result + } + + return {} + } + } + + /***/ }), + /* 5 */ + /***/ (function(module, exports, __webpack_require__) { + + /* + ## Mock.Random + + 工具类,用于生成各种随机数据。 + */ + + var Util = __webpack_require__(3) + + var Random = { + extend: Util.extend + } + + Random.extend(__webpack_require__(6)) + Random.extend(__webpack_require__(7)) + Random.extend(__webpack_require__(8)) + Random.extend(__webpack_require__(10)) + Random.extend(__webpack_require__(13)) + Random.extend(__webpack_require__(15)) + Random.extend(__webpack_require__(16)) + Random.extend(__webpack_require__(17)) + Random.extend(__webpack_require__(14)) + Random.extend(__webpack_require__(19)) + + module.exports = Random + + /***/ }), + /* 6 */ + /***/ (function(module, exports) { + + /* + ## Basics + */ + module.exports = { + // 返回一个随机的布尔值。 + boolean: function(min, max, cur) { + if (cur !== undefined) { + min = typeof min !== 'undefined' && !isNaN(min) ? parseInt(min, 10) : 1 + max = typeof max !== 'undefined' && !isNaN(max) ? parseInt(max, 10) : 1 + return Math.random() > 1.0 / (min + max) * min ? !cur : cur + } + + return Math.random() >= 0.5 + }, + bool: function(min, max, cur) { + return this.boolean(min, max, cur) + }, + // 返回一个随机的自然数(大于等于 0 的整数)。 + natural: function(min, max) { + min = typeof min !== 'undefined' ? parseInt(min, 10) : 0 + max = typeof max !== 'undefined' ? parseInt(max, 10) : 9007199254740992 // 2^53 + return Math.round(Math.random() * (max - min)) + min + }, + // 返回一个随机的整数。 + integer: function(min, max) { + min = typeof min !== 'undefined' ? parseInt(min, 10) : -9007199254740992 + max = typeof max !== 'undefined' ? parseInt(max, 10) : 9007199254740992 // 2^53 + return Math.round(Math.random() * (max - min)) + min + }, + int: function(min, max) { + return this.integer(min, max) + }, + // 返回一个随机的浮点数。 + float: function(min, max, dmin, dmax) { + dmin = dmin === undefined ? 0 : dmin + dmin = Math.max(Math.min(dmin, 17), 0) + dmax = dmax === undefined ? 17 : dmax + dmax = Math.max(Math.min(dmax, 17), 0) + var ret = this.integer(min, max) + '.'; + for (var i = 0, dcount = this.natural(dmin, dmax); i < dcount; i++) { + ret += ( + // 最后一位不能为 0:如果最后一位为 0,会被 JS 引擎忽略掉。 + (i < dcount - 1) ? this.character('number') : this.character('123456789') + ) + } + return parseFloat(ret, 10) + }, + // 返回一个随机字符。 + character: function(pool) { + var pools = { + lower: 'abcdefghijklmnopqrstuvwxyz', + upper: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', + number: '0123456789', + symbol: '!@#$%^&*()[]' + } + pools.alpha = pools.lower + pools.upper + pools['undefined'] = pools.lower + pools.upper + pools.number + pools.symbol + + pool = pools[('' + pool).toLowerCase()] || pool + return pool.charAt(this.natural(0, pool.length - 1)) + }, + char: function(pool) { + return this.character(pool) + }, + // 返回一个随机字符串。 + string: function(pool, min, max) { + var len + switch (arguments.length) { + case 0: // () + len = this.natural(3, 7) + break + case 1: // ( length ) + len = pool + pool = undefined + break + case 2: + // ( pool, length ) + if (typeof arguments[0] === 'string') { + len = min + } else { + // ( min, max ) + len = this.natural(pool, min) + pool = undefined + } + break + case 3: + len = this.natural(min, max) + break + } + + var text = '' + for (var i = 0; i < len; i++) { + text += this.character(pool) + } + + return text + }, + str: function( /*pool, min, max*/ ) { + return this.string.apply(this, arguments) + }, + // 返回一个整型数组。 + range: function(start, stop, step) { + // range( stop ) + if (arguments.length <= 1) { + stop = start || 0; + start = 0; + } + // range( start, stop ) + step = arguments[2] || 1; + + start = +start + stop = +stop + step = +step + + var len = Math.max(Math.ceil((stop - start) / step), 0); + var idx = 0; + var range = new Array(len); + + while (idx < len) { + range[idx++] = start; + start += step; + } + + return range; + } + } + + /***/ }), + /* 7 */ + /***/ (function(module, exports) { + + /* + ## Date + */ + var patternLetters = { + yyyy: 'getFullYear', + yy: function(date) { + return ('' + date.getFullYear()).slice(2) + }, + y: 'yy', + + MM: function(date) { + var m = date.getMonth() + 1 + return m < 10 ? '0' + m : m + }, + M: function(date) { + return date.getMonth() + 1 + }, + + dd: function(date) { + var d = date.getDate() + return d < 10 ? '0' + d : d + }, + d: 'getDate', + + HH: function(date) { + var h = date.getHours() + return h < 10 ? '0' + h : h + }, + H: 'getHours', + hh: function(date) { + var h = date.getHours() % 12 + return h < 10 ? '0' + h : h + }, + h: function(date) { + return date.getHours() % 12 + }, + + mm: function(date) { + var m = date.getMinutes() + return m < 10 ? '0' + m : m + }, + m: 'getMinutes', + + ss: function(date) { + var s = date.getSeconds() + return s < 10 ? '0' + s : s + }, + s: 'getSeconds', + + SS: function(date) { + var ms = date.getMilliseconds() + return ms < 10 && '00' + ms || ms < 100 && '0' + ms || ms + }, + S: 'getMilliseconds', + + A: function(date) { + return date.getHours() < 12 ? 'AM' : 'PM' + }, + a: function(date) { + return date.getHours() < 12 ? 'am' : 'pm' + }, + T: 'getTime' + } + module.exports = { + // 日期占位符集合。 + _patternLetters: patternLetters, + // 日期占位符正则。 + _rformat: new RegExp((function() { + var re = [] + for (var i in patternLetters) re.push(i) + return '(' + re.join('|') + ')' + })(), 'g'), + // 格式化日期。 + _formatDate: function(date, format) { + return format.replace(this._rformat, function creatNewSubString($0, flag) { + return typeof patternLetters[flag] === 'function' ? patternLetters[flag](date) : + patternLetters[flag] in patternLetters ? creatNewSubString($0, patternLetters[flag]) : + date[patternLetters[flag]]() + }) + }, + // 生成一个随机的 Date 对象。 + _randomDate: function(min, max) { // min, max + min = min === undefined ? new Date(0) : min + max = max === undefined ? new Date() : max + return new Date(Math.random() * (max.getTime() - min.getTime())) + }, + // 返回一个随机的日期字符串。 + date: function(format) { + format = format || 'yyyy-MM-dd' + return this._formatDate(this._randomDate(), format) + }, + // 返回一个随机的时间字符串。 + time: function(format) { + format = format || 'HH:mm:ss' + return this._formatDate(this._randomDate(), format) + }, + // 返回一个随机的日期和时间字符串。 + datetime: function(format) { + format = format || 'yyyy-MM-dd HH:mm:ss' + return this._formatDate(this._randomDate(), format) + }, + // 返回当前的日期和时间字符串。 + now: function(unit, format) { + // now(unit) now(format) + if (arguments.length === 1) { + // now(format) + if (!/year|month|day|hour|minute|second|week/.test(unit)) { + format = unit + unit = '' + } + } + unit = (unit || '').toLowerCase() + format = format || 'yyyy-MM-dd HH:mm:ss' + + var date = new Date() + + /* jshint -W086 */ + // 参考自 http://momentjs.cn/docs/#/manipulating/start-of/ + switch (unit) { + case 'year': + date.setMonth(0) + case 'month': + date.setDate(1) + case 'week': + case 'day': + date.setHours(0) + case 'hour': + date.setMinutes(0) + case 'minute': + date.setSeconds(0) + case 'second': + date.setMilliseconds(0) + } + switch (unit) { + case 'week': + date.setDate(date.getDate() - date.getDay()) + } + + return this._formatDate(date, format) + } + } + + /***/ }), + /* 8 */ + /***/ (function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(module) {/* global document */ + /* + ## Image + */ + module.exports = { + // 常见的广告宽高 + _adSize: [ + '300x250', '250x250', '240x400', '336x280', '180x150', + '720x300', '468x60', '234x60', '88x31', '120x90', + '120x60', '120x240', '125x125', '728x90', '160x600', + '120x600', '300x600' + ], + // 常见的屏幕宽高 + _screenSize: [ + '320x200', '320x240', '640x480', '800x480', '800x480', + '1024x600', '1024x768', '1280x800', '1440x900', '1920x1200', + '2560x1600' + ], + // 常见的视频宽高 + _videoSize: ['720x480', '768x576', '1280x720', '1920x1080'], + /* + 生成一个随机的图片地址。 + + 替代图片源 + http://fpoimg.com/ + 参考自 + http://rensanning.iteye.com/blog/1933310 + http://code.tutsplus.com/articles/the-top-8-placeholders-for-web-designers--net-19485 + */ + image: function(size, background, foreground, format, text) { + // Random.image( size, background, foreground, text ) + if (arguments.length === 4) { + text = format + format = undefined + } + // Random.image( size, background, text ) + if (arguments.length === 3) { + text = foreground + foreground = undefined + } + // Random.image() + if (!size) size = this.pick(this._adSize) + + if (background && ~background.indexOf('#')) background = background.slice(1) + if (foreground && ~foreground.indexOf('#')) foreground = foreground.slice(1) + + // http://dummyimage.com/600x400/cc00cc/470047.png&text=hello + return 'http://dummyimage.com/' + size + + (background ? '/' + background : '') + + (foreground ? '/' + foreground : '') + + (format ? '.' + format : '') + + (text ? '&text=' + text : '') + }, + img: function() { + return this.image.apply(this, arguments) + }, + + /* + BrandColors + http://brandcolors.net/ + A collection of major brand color codes curated by Galen Gidman. + 大牌公司的颜色集合 + + // 获取品牌和颜色 + $('h2').each(function(index, item){ + item = $(item) + console.log('\'' + item.text() + '\'', ':', '\'' + item.next().text() + '\'', ',') + }) + */ + _brandColors: { + '4ormat': '#fb0a2a', + '500px': '#02adea', + 'About.me (blue)': '#00405d', + 'About.me (yellow)': '#ffcc33', + 'Addvocate': '#ff6138', + 'Adobe': '#ff0000', + 'Aim': '#fcd20b', + 'Amazon': '#e47911', + 'Android': '#a4c639', + 'Angie\'s List': '#7fbb00', + 'AOL': '#0060a3', + 'Atlassian': '#003366', + 'Behance': '#053eff', + 'Big Cartel': '#97b538', + 'bitly': '#ee6123', + 'Blogger': '#fc4f08', + 'Boeing': '#0039a6', + 'Booking.com': '#003580', + 'Carbonmade': '#613854', + 'Cheddar': '#ff7243', + 'Code School': '#3d4944', + 'Delicious': '#205cc0', + 'Dell': '#3287c1', + 'Designmoo': '#e54a4f', + 'Deviantart': '#4e6252', + 'Designer News': '#2d72da', + 'Devour': '#fd0001', + 'DEWALT': '#febd17', + 'Disqus (blue)': '#59a3fc', + 'Disqus (orange)': '#db7132', + 'Dribbble': '#ea4c89', + 'Dropbox': '#3d9ae8', + 'Drupal': '#0c76ab', + 'Dunked': '#2a323a', + 'eBay': '#89c507', + 'Ember': '#f05e1b', + 'Engadget': '#00bdf6', + 'Envato': '#528036', + 'Etsy': '#eb6d20', + 'Evernote': '#5ba525', + 'Fab.com': '#dd0017', + 'Facebook': '#3b5998', + 'Firefox': '#e66000', + 'Flickr (blue)': '#0063dc', + 'Flickr (pink)': '#ff0084', + 'Forrst': '#5b9a68', + 'Foursquare': '#25a0ca', + 'Garmin': '#007cc3', + 'GetGlue': '#2d75a2', + 'Gimmebar': '#f70078', + 'GitHub': '#171515', + 'Google Blue': '#0140ca', + 'Google Green': '#16a61e', + 'Google Red': '#dd1812', + 'Google Yellow': '#fcca03', + 'Google+': '#dd4b39', + 'Grooveshark': '#f77f00', + 'Groupon': '#82b548', + 'Hacker News': '#ff6600', + 'HelloWallet': '#0085ca', + 'Heroku (light)': '#c7c5e6', + 'Heroku (dark)': '#6567a5', + 'HootSuite': '#003366', + 'Houzz': '#73ba37', + 'HTML5': '#ec6231', + 'IKEA': '#ffcc33', + 'IMDb': '#f3ce13', + 'Instagram': '#3f729b', + 'Intel': '#0071c5', + 'Intuit': '#365ebf', + 'Kickstarter': '#76cc1e', + 'kippt': '#e03500', + 'Kodery': '#00af81', + 'LastFM': '#c3000d', + 'LinkedIn': '#0e76a8', + 'Livestream': '#cf0005', + 'Lumo': '#576396', + 'Mixpanel': '#a086d3', + 'Meetup': '#e51937', + 'Nokia': '#183693', + 'NVIDIA': '#76b900', + 'Opera': '#cc0f16', + 'Path': '#e41f11', + 'PayPal (dark)': '#1e477a', + 'PayPal (light)': '#3b7bbf', + 'Pinboard': '#0000e6', + 'Pinterest': '#c8232c', + 'PlayStation': '#665cbe', + 'Pocket': '#ee4056', + 'Prezi': '#318bff', + 'Pusha': '#0f71b4', + 'Quora': '#a82400', + 'QUOTE.fm': '#66ceff', + 'Rdio': '#008fd5', + 'Readability': '#9c0000', + 'Red Hat': '#cc0000', + 'Resource': '#7eb400', + 'Rockpack': '#0ba6ab', + 'Roon': '#62b0d9', + 'RSS': '#ee802f', + 'Salesforce': '#1798c1', + 'Samsung': '#0c4da2', + 'Shopify': '#96bf48', + 'Skype': '#00aff0', + 'Snagajob': '#f47a20', + 'Softonic': '#008ace', + 'SoundCloud': '#ff7700', + 'Space Box': '#f86960', + 'Spotify': '#81b71a', + 'Sprint': '#fee100', + 'Squarespace': '#121212', + 'StackOverflow': '#ef8236', + 'Staples': '#cc0000', + 'Status Chart': '#d7584f', + 'Stripe': '#008cdd', + 'StudyBlue': '#00afe1', + 'StumbleUpon': '#f74425', + 'T-Mobile': '#ea0a8e', + 'Technorati': '#40a800', + 'The Next Web': '#ef4423', + 'Treehouse': '#5cb868', + 'Trulia': '#5eab1f', + 'Tumblr': '#34526f', + 'Twitch.tv': '#6441a5', + 'Twitter': '#00acee', + 'TYPO3': '#ff8700', + 'Ubuntu': '#dd4814', + 'Ustream': '#3388ff', + 'Verizon': '#ef1d1d', + 'Vimeo': '#86c9ef', + 'Vine': '#00a478', + 'Virb': '#06afd8', + 'Virgin Media': '#cc0000', + 'Wooga': '#5b009c', + 'WordPress (blue)': '#21759b', + 'WordPress (orange)': '#d54e21', + 'WordPress (grey)': '#464646', + 'Wunderlist': '#2b88d9', + 'XBOX': '#9bc848', + 'XING': '#126567', + 'Yahoo!': '#720e9e', + 'Yandex': '#ffcc00', + 'Yelp': '#c41200', + 'YouTube': '#c4302b', + 'Zalongo': '#5498dc', + 'Zendesk': '#78a300', + 'Zerply': '#9dcc7a', + 'Zootool': '#5e8b1d' + }, + _brandNames: function() { + var brands = []; + for (var b in this._brandColors) { + brands.push(b) + } + return brands + }, + /* + 生成一段随机的 Base64 图片编码。 + + https://github.com/imsky/holder + Holder renders image placeholders entirely on the client side. + + dataImageHolder: function(size) { + return 'holder.js/' + size + }, + */ + dataImage: function(size, text) { + var canvas + if (typeof document !== 'undefined') { + canvas = document.createElement('canvas') + } else { + /* + https://github.com/Automattic/node-canvas + npm install canvas --save + 安装问题: + * http://stackoverflow.com/questions/22953206/gulp-issues-with-cario-install-command-not-found-when-trying-to-installing-canva + * https://github.com/Automattic/node-canvas/issues/415 + * https://github.com/Automattic/node-canvas/wiki/_pages + + PS:node-canvas 的安装过程实在是太繁琐了,所以不放入 package.json 的 dependencies。 + */ + var Canvas = module.require('canvas') + canvas = new Canvas() + } + + var ctx = canvas && canvas.getContext && canvas.getContext("2d") + if (!canvas || !ctx) return '' + + if (!size) size = this.pick(this._adSize) + text = text !== undefined ? text : size + + size = size.split('x') + + var width = parseInt(size[0], 10), + height = parseInt(size[1], 10), + background = this._brandColors[this.pick(this._brandNames())], + foreground = '#FFF', + text_height = 14, + font = 'sans-serif'; + + canvas.width = width + canvas.height = height + ctx.textAlign = 'center' + ctx.textBaseline = 'middle' + ctx.fillStyle = background + ctx.fillRect(0, 0, width, height) + ctx.fillStyle = foreground + ctx.font = 'bold ' + text_height + 'px ' + font + ctx.fillText(text, (width / 2), (height / 2), width) + return canvas.toDataURL('image/png') + } + } + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(9)(module))) + + /***/ }), + /* 9 */ + /***/ (function(module, exports) { + + module.exports = function(module) { + if(!module.webpackPolyfill) { + module.deprecate = function() {}; + module.paths = []; + // module.parent = undefined by default + module.children = []; + module.webpackPolyfill = 1; + } + return module; + } + + + /***/ }), + /* 10 */ + /***/ (function(module, exports, __webpack_require__) { + + /* + ## Color + + http://llllll.li/randomColor/ + A color generator for JavaScript. + randomColor generates attractive colors by default. More specifically, randomColor produces bright colors with a reasonably high saturation. This makes randomColor particularly useful for data visualizations and generative art. + + http://randomcolour.com/ + var bg_colour = Math.floor(Math.random() * 16777215).toString(16); + bg_colour = "#" + ("000000" + bg_colour).slice(-6); + document.bgColor = bg_colour; + + http://martin.ankerl.com/2009/12/09/how-to-create-random-colors-programmatically/ + Creating random colors is actually more difficult than it seems. The randomness itself is easy, but aesthetically pleasing randomness is more difficult. + https://github.com/devongovett/color-generator + + http://www.paulirish.com/2009/random-hex-color-code-snippets/ + Random Hex Color Code Generator in JavaScript + + http://chancejs.com/#color + chance.color() + // => '#79c157' + chance.color({format: 'hex'}) + // => '#d67118' + chance.color({format: 'shorthex'}) + // => '#60f' + chance.color({format: 'rgb'}) + // => 'rgb(110,52,164)' + + http://tool.c7sky.com/webcolor + 网页设计常用色彩搭配表 + + https://github.com/One-com/one-color + An OO-based JavaScript color parser/computation toolkit with support for RGB, HSV, HSL, CMYK, and alpha channels. + API 很赞 + + https://github.com/harthur/color + JavaScript color conversion and manipulation library + + https://github.com/leaverou/css-colors + Share & convert CSS colors + http://leaverou.github.io/css-colors/#slategray + Type a CSS color keyword, #hex, hsl(), rgba(), whatever: + + 色调 hue + http://baike.baidu.com/view/23368.htm + 色调指的是一幅画中画面色彩的总体倾向,是大的色彩效果。 + 饱和度 saturation + http://baike.baidu.com/view/189644.htm + 饱和度是指色彩的鲜艳程度,也称色彩的纯度。饱和度取决于该色中含色成分和消色成分(灰色)的比例。含色成分越大,饱和度越大;消色成分越大,饱和度越小。 + 亮度 brightness + http://baike.baidu.com/view/34773.htm + 亮度是指发光体(反光体)表面发光(反光)强弱的物理量。 + 照度 luminosity + 物体被照亮的程度,采用单位面积所接受的光通量来表示,表示单位为勒[克斯](Lux,lx) ,即 1m / m2 。 + + http://stackoverflow.com/questions/1484506/random-color-generator-in-javascript + var letters = '0123456789ABCDEF'.split('') + var color = '#' + for (var i = 0; i < 6; i++) { + color += letters[Math.floor(Math.random() * 16)] + } + return color + + // 随机生成一个无脑的颜色,格式为 '#RRGGBB'。 + // _brainlessColor() + var color = Math.floor( + Math.random() * + (16 * 16 * 16 * 16 * 16 * 16 - 1) + ).toString(16) + color = "#" + ("000000" + color).slice(-6) + return color.toUpperCase() + */ + + var Convert = __webpack_require__(11) + var DICT = __webpack_require__(12) + + module.exports = { + // 随机生成一个有吸引力的颜色,格式为 '#RRGGBB'。 + color: function(name) { + if (name || DICT[name]) return DICT[name].nicer + return this.hex() + }, + // #DAC0DE + hex: function() { + var hsv = this._goldenRatioColor() + var rgb = Convert.hsv2rgb(hsv) + var hex = Convert.rgb2hex(rgb[0], rgb[1], rgb[2]) + return hex + }, + // rgb(128,255,255) + rgb: function() { + var hsv = this._goldenRatioColor() + var rgb = Convert.hsv2rgb(hsv) + return 'rgb(' + + parseInt(rgb[0], 10) + ', ' + + parseInt(rgb[1], 10) + ', ' + + parseInt(rgb[2], 10) + ')' + }, + // rgba(128,255,255,0.3) + rgba: function() { + var hsv = this._goldenRatioColor() + var rgb = Convert.hsv2rgb(hsv) + return 'rgba(' + + parseInt(rgb[0], 10) + ', ' + + parseInt(rgb[1], 10) + ', ' + + parseInt(rgb[2], 10) + ', ' + + Math.random().toFixed(2) + ')' + }, + // hsl(300,80%,90%) + hsl: function() { + var hsv = this._goldenRatioColor() + var hsl = Convert.hsv2hsl(hsv) + return 'hsl(' + + parseInt(hsl[0], 10) + ', ' + + parseInt(hsl[1], 10) + ', ' + + parseInt(hsl[2], 10) + ')' + }, + // http://martin.ankerl.com/2009/12/09/how-to-create-random-colors-programmatically/ + // https://github.com/devongovett/color-generator/blob/master/index.js + // 随机生成一个有吸引力的颜色。 + _goldenRatioColor: function(saturation, value) { + this._goldenRatio = 0.618033988749895 + this._hue = this._hue || Math.random() + this._hue += this._goldenRatio + this._hue %= 1 + + if (typeof saturation !== "number") saturation = 0.5; + if (typeof value !== "number") value = 0.95; + + return [ + this._hue * 360, + saturation * 100, + value * 100 + ] + } + } + + /***/ }), + /* 11 */ + /***/ (function(module, exports) { + + /* + ## Color Convert + + http://blog.csdn.net/idfaya/article/details/6770414 + 颜色空间RGB与HSV(HSL)的转换 + */ + // https://github.com/harthur/color-convert/blob/master/conversions.js + module.exports = { + rgb2hsl: function rgb2hsl(rgb) { + var r = rgb[0] / 255, + g = rgb[1] / 255, + b = rgb[2] / 255, + min = Math.min(r, g, b), + max = Math.max(r, g, b), + delta = max - min, + h, s, l; + + if (max == min) + h = 0; + else if (r == max) + h = (g - b) / delta; + else if (g == max) + h = 2 + (b - r) / delta; + else if (b == max) + h = 4 + (r - g) / delta; + + h = Math.min(h * 60, 360); + + if (h < 0) + h += 360; + + l = (min + max) / 2; + + if (max == min) + s = 0; + else if (l <= 0.5) + s = delta / (max + min); + else + s = delta / (2 - max - min); + + return [h, s * 100, l * 100]; + }, + rgb2hsv: function rgb2hsv(rgb) { + var r = rgb[0], + g = rgb[1], + b = rgb[2], + min = Math.min(r, g, b), + max = Math.max(r, g, b), + delta = max - min, + h, s, v; + + if (max === 0) + s = 0; + else + s = (delta / max * 1000) / 10; + + if (max == min) + h = 0; + else if (r == max) + h = (g - b) / delta; + else if (g == max) + h = 2 + (b - r) / delta; + else if (b == max) + h = 4 + (r - g) / delta; + + h = Math.min(h * 60, 360); + + if (h < 0) + h += 360; + + v = ((max / 255) * 1000) / 10; + + return [h, s, v]; + }, + hsl2rgb: function hsl2rgb(hsl) { + var h = hsl[0] / 360, + s = hsl[1] / 100, + l = hsl[2] / 100, + t1, t2, t3, rgb, val; + + if (s === 0) { + val = l * 255; + return [val, val, val]; + } + + if (l < 0.5) + t2 = l * (1 + s); + else + t2 = l + s - l * s; + t1 = 2 * l - t2; + + rgb = [0, 0, 0]; + for (var i = 0; i < 3; i++) { + t3 = h + 1 / 3 * -(i - 1); + if (t3 < 0) t3++; + if (t3 > 1) t3--; + + if (6 * t3 < 1) + val = t1 + (t2 - t1) * 6 * t3; + else if (2 * t3 < 1) + val = t2; + else if (3 * t3 < 2) + val = t1 + (t2 - t1) * (2 / 3 - t3) * 6; + else + val = t1; + + rgb[i] = val * 255; + } + + return rgb; + }, + hsl2hsv: function hsl2hsv(hsl) { + var h = hsl[0], + s = hsl[1] / 100, + l = hsl[2] / 100, + sv, v; + l *= 2; + s *= (l <= 1) ? l : 2 - l; + v = (l + s) / 2; + sv = (2 * s) / (l + s); + return [h, sv * 100, v * 100]; + }, + hsv2rgb: function hsv2rgb(hsv) { + var h = hsv[0] / 60 + var s = hsv[1] / 100 + var v = hsv[2] / 100 + var hi = Math.floor(h) % 6 + + var f = h - Math.floor(h) + var p = 255 * v * (1 - s) + var q = 255 * v * (1 - (s * f)) + var t = 255 * v * (1 - (s * (1 - f))) + + v = 255 * v + + switch (hi) { + case 0: + return [v, t, p] + case 1: + return [q, v, p] + case 2: + return [p, v, t] + case 3: + return [p, q, v] + case 4: + return [t, p, v] + case 5: + return [v, p, q] + } + }, + hsv2hsl: function hsv2hsl(hsv) { + var h = hsv[0], + s = hsv[1] / 100, + v = hsv[2] / 100, + sl, l; + + l = (2 - s) * v; + sl = s * v; + sl /= (l <= 1) ? l : 2 - l; + l /= 2; + return [h, sl * 100, l * 100]; + }, + // http://www.140byt.es/keywords/color + rgb2hex: function( + a, // red, as a number from 0 to 255 + b, // green, as a number from 0 to 255 + c // blue, as a number from 0 to 255 + ) { + return "#" + ((256 + a << 8 | b) << 8 | c).toString(16).slice(1) + }, + hex2rgb: function( + a // take a "#xxxxxx" hex string, + ) { + a = '0x' + a.slice(1).replace(a.length > 4 ? a : /./g, '$&$&') | 0; + return [a >> 16, a >> 8 & 255, a & 255] + } + } + + /***/ }), + /* 12 */ + /***/ (function(module, exports) { + + /* + ## Color 字典数据 + + 字典数据来源 [A nicer color palette for the web](http://clrs.cc/) + */ + module.exports = { + // name value nicer + navy: { + value: '#000080', + nicer: '#001F3F' + }, + blue: { + value: '#0000ff', + nicer: '#0074D9' + }, + aqua: { + value: '#00ffff', + nicer: '#7FDBFF' + }, + teal: { + value: '#008080', + nicer: '#39CCCC' + }, + olive: { + value: '#008000', + nicer: '#3D9970' + }, + green: { + value: '#008000', + nicer: '#2ECC40' + }, + lime: { + value: '#00ff00', + nicer: '#01FF70' + }, + yellow: { + value: '#ffff00', + nicer: '#FFDC00' + }, + orange: { + value: '#ffa500', + nicer: '#FF851B' + }, + red: { + value: '#ff0000', + nicer: '#FF4136' + }, + maroon: { + value: '#800000', + nicer: '#85144B' + }, + fuchsia: { + value: '#ff00ff', + nicer: '#F012BE' + }, + purple: { + value: '#800080', + nicer: '#B10DC9' + }, + silver: { + value: '#c0c0c0', + nicer: '#DDDDDD' + }, + gray: { + value: '#808080', + nicer: '#AAAAAA' + }, + black: { + value: '#000000', + nicer: '#111111' + }, + white: { + value: '#FFFFFF', + nicer: '#FFFFFF' + } + } + + /***/ }), + /* 13 */ + /***/ (function(module, exports, __webpack_require__) { + + /* + ## Text + + http://www.lipsum.com/ + */ + var Basic = __webpack_require__(6) + var Helper = __webpack_require__(14) + + function range(defaultMin, defaultMax, min, max) { + return min === undefined ? Basic.natural(defaultMin, defaultMax) : // () + max === undefined ? min : // ( len ) + Basic.natural(parseInt(min, 10), parseInt(max, 10)) // ( min, max ) + } + + module.exports = { + // 随机生成一段文本。 + paragraph: function(min, max) { + var len = range(3, 7, min, max) + var result = [] + for (var i = 0; i < len; i++) { + result.push(this.sentence()) + } + return result.join(' ') + }, + // + cparagraph: function(min, max) { + var len = range(3, 7, min, max) + var result = [] + for (var i = 0; i < len; i++) { + result.push(this.csentence()) + } + return result.join('') + }, + // 随机生成一个句子,第一个单词的首字母大写。 + sentence: function(min, max) { + var len = range(12, 18, min, max) + var result = [] + for (var i = 0; i < len; i++) { + result.push(this.word()) + } + return Helper.capitalize(result.join(' ')) + '.' + }, + // 随机生成一个中文句子。 + csentence: function(min, max) { + var len = range(12, 18, min, max) + var result = [] + for (var i = 0; i < len; i++) { + result.push(this.cword()) + } + + return result.join('') + '。' + }, + // 随机生成一个单词。 + word: function(min, max) { + var len = range(3, 10, min, max) + var result = ''; + for (var i = 0; i < len; i++) { + result += Basic.character('lower') + } + return result + }, + // 随机生成一个或多个汉字。 + cword: function(pool, min, max) { + // 最常用的 500 个汉字 http://baike.baidu.com/view/568436.htm + var DICT_KANZI = '的一是在不了有和人这中大为上个国我以要他时来用们生到作地于出就分对成会可主发年动同工也能下过子说产种面而方后多定行学法所民得经十三之进着等部度家电力里如水化高自二理起小物现实加量都两体制机当使点从业本去把性好应开它合还因由其些然前外天政四日那社义事平形相全表间样与关各重新线内数正心反你明看原又么利比或但质气第向道命此变条只没结解问意建月公无系军很情者最立代想已通并提直题党程展五果料象员革位入常文总次品式活设及管特件长求老头基资边流路级少图山统接知较将组见计别她手角期根论运农指几九区强放决西被干做必战先回则任取据处队南给色光门即保治北造百规热领七海口东导器压志世金增争济阶油思术极交受联什认六共权收证改清己美再采转更单风切打白教速花带安场身车例真务具万每目至达走积示议声报斗完类八离华名确才科张信马节话米整空元况今集温传土许步群广石记需段研界拉林律叫且究观越织装影算低持音众书布复容儿须际商非验连断深难近矿千周委素技备半办青省列习响约支般史感劳便团往酸历市克何除消构府称太准精值号率族维划选标写存候毛亲快效斯院查江型眼王按格养易置派层片始却专状育厂京识适属圆包火住调满县局照参红细引听该铁价严龙飞' + + var len + switch (arguments.length) { + case 0: // () + pool = DICT_KANZI + len = 1 + break + case 1: // ( pool ) + if (typeof arguments[0] === 'string') { + len = 1 + } else { + // ( length ) + len = pool + pool = DICT_KANZI + } + break + case 2: + // ( pool, length ) + if (typeof arguments[0] === 'string') { + len = min + } else { + // ( min, max ) + len = this.natural(pool, min) + pool = DICT_KANZI + } + break + case 3: + len = this.natural(min, max) + break + } + + var result = '' + for (var i = 0; i < len; i++) { + result += pool.charAt(this.natural(0, pool.length - 1)) + } + return result + }, + // 随机生成一句标题,其中每个单词的首字母大写。 + title: function(min, max) { + var len = range(3, 7, min, max) + var result = [] + for (var i = 0; i < len; i++) { + result.push(this.capitalize(this.word())) + } + return result.join(' ') + }, + // 随机生成一句中文标题。 + ctitle: function(min, max) { + var len = range(3, 7, min, max) + var result = [] + for (var i = 0; i < len; i++) { + result.push(this.cword()) + } + return result.join('') + } + } + + /***/ }), + /* 14 */ + /***/ (function(module, exports, __webpack_require__) { + + /* + ## Helpers + */ + + var Util = __webpack_require__(3) + + module.exports = { + // 把字符串的第一个字母转换为大写。 + capitalize: function(word) { + return (word + '').charAt(0).toUpperCase() + (word + '').substr(1) + }, + // 把字符串转换为大写。 + upper: function(str) { + return (str + '').toUpperCase() + }, + // 把字符串转换为小写。 + lower: function(str) { + return (str + '').toLowerCase() + }, + // 从数组中随机选取一个元素,并返回。 + pick: function pick(arr, min, max) { + // pick( item1, item2 ... ) + if (!Util.isArray(arr)) { + arr = [].slice.call(arguments) + min = 1 + max = 1 + } else { + // pick( [ item1, item2 ... ] ) + if (min === undefined) min = 1 + + // pick( [ item1, item2 ... ], count ) + if (max === undefined) max = min + } + + if (min === 1 && max === 1) return arr[this.natural(0, arr.length - 1)] + + // pick( [ item1, item2 ... ], min, max ) + return this.shuffle(arr, min, max) + + // 通过参数个数判断方法签名,扩展性太差!#90 + // switch (arguments.length) { + // case 1: + // // pick( [ item1, item2 ... ] ) + // return arr[this.natural(0, arr.length - 1)] + // case 2: + // // pick( [ item1, item2 ... ], count ) + // max = min + // /* falls through */ + // case 3: + // // pick( [ item1, item2 ... ], min, max ) + // return this.shuffle(arr, min, max) + // } + }, + /* + 打乱数组中元素的顺序,并返回。 + Given an array, scramble the order and return it. + + 其他的实现思路: + // https://code.google.com/p/jslibs/wiki/JavascriptTips + result = result.sort(function() { + return Math.random() - 0.5 + }) + */ + shuffle: function shuffle(arr, min, max) { + arr = arr || [] + var old = arr.slice(0), + result = [], + index = 0, + length = old.length; + for (var i = 0; i < length; i++) { + index = this.natural(0, old.length - 1) + result.push(old[index]) + old.splice(index, 1) + } + switch (arguments.length) { + case 0: + case 1: + return result + case 2: + max = min + /* falls through */ + case 3: + min = parseInt(min, 10) + max = parseInt(max, 10) + return result.slice(0, this.natural(min, max)) + } + }, + /* + * Random.order(item, item) + * Random.order([item, item ...]) + + 顺序获取数组中的元素 + + [JSON导入数组支持数组数据录入](https://github.com/thx/RAP/issues/22) + + 不支持单独调用! + */ + order: function order(array) { + order.cache = order.cache || {} + + if (arguments.length > 1) array = [].slice.call(arguments, 0) + + // options.context.path/templatePath + var options = order.options + var templatePath = options.context.templatePath.join('.') + + var cache = ( + order.cache[templatePath] = order.cache[templatePath] || { + index: 0, + array: array + } + ) + + return cache.array[cache.index++ % cache.array.length] + } + } + + /***/ }), + /* 15 */ + /***/ (function(module, exports) { + + /* + ## Name + + [Beyond the Top 1000 Names](http://www.ssa.gov/oact/babynames/limits.html) + */ + module.exports = { + // 随机生成一个常见的英文名。 + first: function() { + var names = [ + // male + "James", "John", "Robert", "Michael", "William", + "David", "Richard", "Charles", "Joseph", "Thomas", + "Christopher", "Daniel", "Paul", "Mark", "Donald", + "George", "Kenneth", "Steven", "Edward", "Brian", + "Ronald", "Anthony", "Kevin", "Jason", "Matthew", + "Gary", "Timothy", "Jose", "Larry", "Jeffrey", + "Frank", "Scott", "Eric" + ].concat([ + // female + "Mary", "Patricia", "Linda", "Barbara", "Elizabeth", + "Jennifer", "Maria", "Susan", "Margaret", "Dorothy", + "Lisa", "Nancy", "Karen", "Betty", "Helen", + "Sandra", "Donna", "Carol", "Ruth", "Sharon", + "Michelle", "Laura", "Sarah", "Kimberly", "Deborah", + "Jessica", "Shirley", "Cynthia", "Angela", "Melissa", + "Brenda", "Amy", "Anna" + ]) + return this.pick(names) + // or this.capitalize(this.word()) + }, + // 随机生成一个常见的英文姓。 + last: function() { + var names = [ + "Smith", "Johnson", "Williams", "Brown", "Jones", + "Miller", "Davis", "Garcia", "Rodriguez", "Wilson", + "Martinez", "Anderson", "Taylor", "Thomas", "Hernandez", + "Moore", "Martin", "Jackson", "Thompson", "White", + "Lopez", "Lee", "Gonzalez", "Harris", "Clark", + "Lewis", "Robinson", "Walker", "Perez", "Hall", + "Young", "Allen" + ] + return this.pick(names) + // or this.capitalize(this.word()) + }, + // 随机生成一个常见的英文姓名。 + name: function(middle) { + return this.first() + ' ' + + (middle ? this.first() + ' ' : '') + + this.last() + }, + /* + 随机生成一个常见的中文姓。 + [世界常用姓氏排行](http://baike.baidu.com/view/1719115.htm) + [玄派网 - 网络小说创作辅助平台](http://xuanpai.sinaapp.com/) + */ + cfirst: function() { + var names = ( + '王 李 张 刘 陈 杨 赵 黄 周 吴 ' + + '徐 孙 胡 朱 高 林 何 郭 马 罗 ' + + '梁 宋 郑 谢 韩 唐 冯 于 董 萧 ' + + '程 曹 袁 邓 许 傅 沈 曾 彭 吕 ' + + '苏 卢 蒋 蔡 贾 丁 魏 薛 叶 阎 ' + + '余 潘 杜 戴 夏 锺 汪 田 任 姜 ' + + '范 方 石 姚 谭 廖 邹 熊 金 陆 ' + + '郝 孔 白 崔 康 毛 邱 秦 江 史 ' + + '顾 侯 邵 孟 龙 万 段 雷 钱 汤 ' + + '尹 黎 易 常 武 乔 贺 赖 龚 文' + ).split(' ') + return this.pick(names) + }, + /* + 随机生成一个常见的中文名。 + [中国最常见名字前50名_三九算命网](http://www.name999.net/xingming/xingshi/20131004/48.html) + */ + clast: function() { + var names = ( + '伟 芳 娜 秀英 敏 静 丽 强 磊 军 ' + + '洋 勇 艳 杰 娟 涛 明 超 秀兰 霞 ' + + '平 刚 桂英' + ).split(' ') + return this.pick(names) + }, + // 随机生成一个常见的中文姓名。 + cname: function() { + return this.cfirst() + this.clast() + } + } + + /***/ }), + /* 16 */ + /***/ (function(module, exports) { + + /* + ## Web + */ + module.exports = { + /* + 随机生成一个 URL。 + + [URL 规范](http://www.w3.org/Addressing/URL/url-spec.txt) + http Hypertext Transfer Protocol + ftp File Transfer protocol + gopher The Gopher protocol + mailto Electronic mail address + mid Message identifiers for electronic mail + cid Content identifiers for MIME body part + news Usenet news + nntp Usenet news for local NNTP access only + prospero Access using the prospero protocols + telnet rlogin tn3270 Reference to interactive sessions + wais Wide Area Information Servers + */ + url: function(protocol, host) { + return (protocol || this.protocol()) + '://' + // protocol? + (host || this.domain()) + // host? + '/' + this.word() + }, + // 随机生成一个 URL 协议。 + protocol: function() { + return this.pick( + // 协议簇 + 'http ftp gopher mailto mid cid news nntp prospero telnet rlogin tn3270 wais'.split(' ') + ) + }, + // 随机生成一个域名。 + domain: function(tld) { + return this.word() + '.' + (tld || this.tld()) + }, + /* + 随机生成一个顶级域名。 + 国际顶级域名 international top-level domain-names, iTLDs + 国家顶级域名 national top-level domainnames, nTLDs + [域名后缀大全](http://www.163ns.com/zixun/post/4417.html) + */ + tld: function() { // Top Level Domain + return this.pick( + ( + // 域名后缀 + 'com net org edu gov int mil cn ' + + // 国内域名 + 'com.cn net.cn gov.cn org.cn ' + + // 中文国内域名 + '中国 中国互联.公司 中国互联.网络 ' + + // 新国际域名 + 'tel biz cc tv info name hk mobi asia cd travel pro museum coop aero ' + + // 世界各国域名后缀 + 'ad ae af ag ai al am an ao aq ar as at au aw az ba bb bd be bf bg bh bi bj bm bn bo br bs bt bv bw by bz ca cc cf cg ch ci ck cl cm cn co cq cr cu cv cx cy cz de dj dk dm do dz ec ee eg eh es et ev fi fj fk fm fo fr ga gb gd ge gf gh gi gl gm gn gp gr gt gu gw gy hk hm hn hr ht hu id ie il in io iq ir is it jm jo jp ke kg kh ki km kn kp kr kw ky kz la lb lc li lk lr ls lt lu lv ly ma mc md mg mh ml mm mn mo mp mq mr ms mt mv mw mx my mz na nc ne nf ng ni nl no np nr nt nu nz om qa pa pe pf pg ph pk pl pm pn pr pt pw py re ro ru rw sa sb sc sd se sg sh si sj sk sl sm sn so sr st su sy sz tc td tf tg th tj tk tm tn to tp tr tt tv tw tz ua ug uk us uy va vc ve vg vn vu wf ws ye yu za zm zr zw' + ).split(' ') + ) + }, + // 随机生成一个邮件地址。 + email: function(domain) { + return this.character('lower') + '.' + this.word() + '@' + + ( + domain || + (this.word() + '.' + this.tld()) + ) + // return this.character('lower') + '.' + this.last().toLowerCase() + '@' + this.last().toLowerCase() + '.' + this.tld() + // return this.word() + '@' + (domain || this.domain()) + }, + // 随机生成一个 IP 地址。 + ip: function() { + return this.natural(0, 255) + '.' + + this.natural(0, 255) + '.' + + this.natural(0, 255) + '.' + + this.natural(0, 255) + } + } + + /***/ }), + /* 17 */ + /***/ (function(module, exports, __webpack_require__) { + + /* + ## Address + */ + + var DICT = __webpack_require__(18) + var REGION = ['东北', '华北', '华东', '华中', '华南', '西南', '西北'] + + module.exports = { + // 随机生成一个大区。 + region: function() { + return this.pick(REGION) + }, + // 随机生成一个(中国)省(或直辖市、自治区、特别行政区)。 + province: function() { + return this.pick(DICT).name + }, + // 随机生成一个(中国)市。 + city: function(prefix) { + var province = this.pick(DICT) + var city = this.pick(province.children) + return prefix ? [province.name, city.name].join(' ') : city.name + }, + // 随机生成一个(中国)县。 + county: function(prefix) { + var province = this.pick(DICT) + var city = this.pick(province.children) + var county = this.pick(city.children) || { + name: '-' + } + return prefix ? [province.name, city.name, county.name].join(' ') : county.name + }, + // 随机生成一个邮政编码(六位数字)。 + zip: function(len) { + var zip = '' + for (var i = 0; i < (len || 6); i++) zip += this.natural(0, 9) + return zip + } + + // address: function() {}, + // phone: function() {}, + // areacode: function() {}, + // street: function() {}, + // street_suffixes: function() {}, + // street_suffix: function() {}, + // states: function() {}, + // state: function() {}, + } + + /***/ }), + /* 18 */ + /***/ (function(module, exports) { + + /* + ## Address 字典数据 + + 字典数据来源 http://www.atatech.org/articles/30028?rnd=254259856 + + 国标 省(市)级行政区划码表 + + 华北 北京市 天津市 河北省 山西省 内蒙古自治区 + 东北 辽宁省 吉林省 黑龙江省 + 华东 上海市 江苏省 浙江省 安徽省 福建省 江西省 山东省 + 华南 广东省 广西壮族自治区 海南省 + 华中 河南省 湖北省 湖南省 + 西南 重庆市 四川省 贵州省 云南省 西藏自治区 + 西北 陕西省 甘肃省 青海省 宁夏回族自治区 新疆维吾尔自治区 + 港澳台 香港特别行政区 澳门特别行政区 台湾省 + + **排序** + + ```js + var map = {} + _.each(_.keys(REGIONS),function(id){ + map[id] = REGIONS[ID] + }) + JSON.stringify(map) + ``` + */ + var DICT = { + "110000": "北京", + "110100": "北京市", + "110101": "东城区", + "110102": "西城区", + "110105": "朝阳区", + "110106": "丰台区", + "110107": "石景山区", + "110108": "海淀区", + "110109": "门头沟区", + "110111": "房山区", + "110112": "通州区", + "110113": "顺义区", + "110114": "昌平区", + "110115": "大兴区", + "110116": "怀柔区", + "110117": "平谷区", + "110228": "密云县", + "110229": "延庆县", + "110230": "其它区", + "120000": "天津", + "120100": "天津市", + "120101": "和平区", + "120102": "河东区", + "120103": "河西区", + "120104": "南开区", + "120105": "河北区", + "120106": "红桥区", + "120110": "东丽区", + "120111": "西青区", + "120112": "津南区", + "120113": "北辰区", + "120114": "武清区", + "120115": "宝坻区", + "120116": "滨海新区", + "120221": "宁河县", + "120223": "静海县", + "120225": "蓟县", + "120226": "其它区", + "130000": "河北省", + "130100": "石家庄市", + "130102": "长安区", + "130103": "桥东区", + "130104": "桥西区", + "130105": "新华区", + "130107": "井陉矿区", + "130108": "裕华区", + "130121": "井陉县", + "130123": "正定县", + "130124": "栾城县", + "130125": "行唐县", + "130126": "灵寿县", + "130127": "高邑县", + "130128": "深泽县", + "130129": "赞皇县", + "130130": "无极县", + "130131": "平山县", + "130132": "元氏县", + "130133": "赵县", + "130181": "辛集市", + "130182": "藁城市", + "130183": "晋州市", + "130184": "新乐市", + "130185": "鹿泉市", + "130186": "其它区", + "130200": "唐山市", + "130202": "路南区", + "130203": "路北区", + "130204": "古冶区", + "130205": "开平区", + "130207": "丰南区", + "130208": "丰润区", + "130223": "滦县", + "130224": "滦南县", + "130225": "乐亭县", + "130227": "迁西县", + "130229": "玉田县", + "130230": "曹妃甸区", + "130281": "遵化市", + "130283": "迁安市", + "130284": "其它区", + "130300": "秦皇岛市", + "130302": "海港区", + "130303": "山海关区", + "130304": "北戴河区", + "130321": "青龙满族自治县", + "130322": "昌黎县", + "130323": "抚宁县", + "130324": "卢龙县", + "130398": "其它区", + "130400": "邯郸市", + "130402": "邯山区", + "130403": "丛台区", + "130404": "复兴区", + "130406": "峰峰矿区", + "130421": "邯郸县", + "130423": "临漳县", + "130424": "成安县", + "130425": "大名县", + "130426": "涉县", + "130427": "磁县", + "130428": "肥乡县", + "130429": "永年县", + "130430": "邱县", + "130431": "鸡泽县", + "130432": "广平县", + "130433": "馆陶县", + "130434": "魏县", + "130435": "曲周县", + "130481": "武安市", + "130482": "其它区", + "130500": "邢台市", + "130502": "桥东区", + "130503": "桥西区", + "130521": "邢台县", + "130522": "临城县", + "130523": "内丘县", + "130524": "柏乡县", + "130525": "隆尧县", + "130526": "任县", + "130527": "南和县", + "130528": "宁晋县", + "130529": "巨鹿县", + "130530": "新河县", + "130531": "广宗县", + "130532": "平乡县", + "130533": "威县", + "130534": "清河县", + "130535": "临西县", + "130581": "南宫市", + "130582": "沙河市", + "130583": "其它区", + "130600": "保定市", + "130602": "新市区", + "130603": "北市区", + "130604": "南市区", + "130621": "满城县", + "130622": "清苑县", + "130623": "涞水县", + "130624": "阜平县", + "130625": "徐水县", + "130626": "定兴县", + "130627": "唐县", + "130628": "高阳县", + "130629": "容城县", + "130630": "涞源县", + "130631": "望都县", + "130632": "安新县", + "130633": "易县", + "130634": "曲阳县", + "130635": "蠡县", + "130636": "顺平县", + "130637": "博野县", + "130638": "雄县", + "130681": "涿州市", + "130682": "定州市", + "130683": "安国市", + "130684": "高碑店市", + "130699": "其它区", + "130700": "张家口市", + "130702": "桥东区", + "130703": "桥西区", + "130705": "宣化区", + "130706": "下花园区", + "130721": "宣化县", + "130722": "张北县", + "130723": "康保县", + "130724": "沽源县", + "130725": "尚义县", + "130726": "蔚县", + "130727": "阳原县", + "130728": "怀安县", + "130729": "万全县", + "130730": "怀来县", + "130731": "涿鹿县", + "130732": "赤城县", + "130733": "崇礼县", + "130734": "其它区", + "130800": "承德市", + "130802": "双桥区", + "130803": "双滦区", + "130804": "鹰手营子矿区", + "130821": "承德县", + "130822": "兴隆县", + "130823": "平泉县", + "130824": "滦平县", + "130825": "隆化县", + "130826": "丰宁满族自治县", + "130827": "宽城满族自治县", + "130828": "围场满族蒙古族自治县", + "130829": "其它区", + "130900": "沧州市", + "130902": "新华区", + "130903": "运河区", + "130921": "沧县", + "130922": "青县", + "130923": "东光县", + "130924": "海兴县", + "130925": "盐山县", + "130926": "肃宁县", + "130927": "南皮县", + "130928": "吴桥县", + "130929": "献县", + "130930": "孟村回族自治县", + "130981": "泊头市", + "130982": "任丘市", + "130983": "黄骅市", + "130984": "河间市", + "130985": "其它区", + "131000": "廊坊市", + "131002": "安次区", + "131003": "广阳区", + "131022": "固安县", + "131023": "永清县", + "131024": "香河县", + "131025": "大城县", + "131026": "文安县", + "131028": "大厂回族自治县", + "131081": "霸州市", + "131082": "三河市", + "131083": "其它区", + "131100": "衡水市", + "131102": "桃城区", + "131121": "枣强县", + "131122": "武邑县", + "131123": "武强县", + "131124": "饶阳县", + "131125": "安平县", + "131126": "故城县", + "131127": "景县", + "131128": "阜城县", + "131181": "冀州市", + "131182": "深州市", + "131183": "其它区", + "140000": "山西省", + "140100": "太原市", + "140105": "小店区", + "140106": "迎泽区", + "140107": "杏花岭区", + "140108": "尖草坪区", + "140109": "万柏林区", + "140110": "晋源区", + "140121": "清徐县", + "140122": "阳曲县", + "140123": "娄烦县", + "140181": "古交市", + "140182": "其它区", + "140200": "大同市", + "140202": "城区", + "140203": "矿区", + "140211": "南郊区", + "140212": "新荣区", + "140221": "阳高县", + "140222": "天镇县", + "140223": "广灵县", + "140224": "灵丘县", + "140225": "浑源县", + "140226": "左云县", + "140227": "大同县", + "140228": "其它区", + "140300": "阳泉市", + "140302": "城区", + "140303": "矿区", + "140311": "郊区", + "140321": "平定县", + "140322": "盂县", + "140323": "其它区", + "140400": "长治市", + "140421": "长治县", + "140423": "襄垣县", + "140424": "屯留县", + "140425": "平顺县", + "140426": "黎城县", + "140427": "壶关县", + "140428": "长子县", + "140429": "武乡县", + "140430": "沁县", + "140431": "沁源县", + "140481": "潞城市", + "140482": "城区", + "140483": "郊区", + "140485": "其它区", + "140500": "晋城市", + "140502": "城区", + "140521": "沁水县", + "140522": "阳城县", + "140524": "陵川县", + "140525": "泽州县", + "140581": "高平市", + "140582": "其它区", + "140600": "朔州市", + "140602": "朔城区", + "140603": "平鲁区", + "140621": "山阴县", + "140622": "应县", + "140623": "右玉县", + "140624": "怀仁县", + "140625": "其它区", + "140700": "晋中市", + "140702": "榆次区", + "140721": "榆社县", + "140722": "左权县", + "140723": "和顺县", + "140724": "昔阳县", + "140725": "寿阳县", + "140726": "太谷县", + "140727": "祁县", + "140728": "平遥县", + "140729": "灵石县", + "140781": "介休市", + "140782": "其它区", + "140800": "运城市", + "140802": "盐湖区", + "140821": "临猗县", + "140822": "万荣县", + "140823": "闻喜县", + "140824": "稷山县", + "140825": "新绛县", + "140826": "绛县", + "140827": "垣曲县", + "140828": "夏县", + "140829": "平陆县", + "140830": "芮城县", + "140881": "永济市", + "140882": "河津市", + "140883": "其它区", + "140900": "忻州市", + "140902": "忻府区", + "140921": "定襄县", + "140922": "五台县", + "140923": "代县", + "140924": "繁峙县", + "140925": "宁武县", + "140926": "静乐县", + "140927": "神池县", + "140928": "五寨县", + "140929": "岢岚县", + "140930": "河曲县", + "140931": "保德县", + "140932": "偏关县", + "140981": "原平市", + "140982": "其它区", + "141000": "临汾市", + "141002": "尧都区", + "141021": "曲沃县", + "141022": "翼城县", + "141023": "襄汾县", + "141024": "洪洞县", + "141025": "古县", + "141026": "安泽县", + "141027": "浮山县", + "141028": "吉县", + "141029": "乡宁县", + "141030": "大宁县", + "141031": "隰县", + "141032": "永和县", + "141033": "蒲县", + "141034": "汾西县", + "141081": "侯马市", + "141082": "霍州市", + "141083": "其它区", + "141100": "吕梁市", + "141102": "离石区", + "141121": "文水县", + "141122": "交城县", + "141123": "兴县", + "141124": "临县", + "141125": "柳林县", + "141126": "石楼县", + "141127": "岚县", + "141128": "方山县", + "141129": "中阳县", + "141130": "交口县", + "141181": "孝义市", + "141182": "汾阳市", + "141183": "其它区", + "150000": "内蒙古自治区", + "150100": "呼和浩特市", + "150102": "新城区", + "150103": "回民区", + "150104": "玉泉区", + "150105": "赛罕区", + "150121": "土默特左旗", + "150122": "托克托县", + "150123": "和林格尔县", + "150124": "清水河县", + "150125": "武川县", + "150126": "其它区", + "150200": "包头市", + "150202": "东河区", + "150203": "昆都仑区", + "150204": "青山区", + "150205": "石拐区", + "150206": "白云鄂博矿区", + "150207": "九原区", + "150221": "土默特右旗", + "150222": "固阳县", + "150223": "达尔罕茂明安联合旗", + "150224": "其它区", + "150300": "乌海市", + "150302": "海勃湾区", + "150303": "海南区", + "150304": "乌达区", + "150305": "其它区", + "150400": "赤峰市", + "150402": "红山区", + "150403": "元宝山区", + "150404": "松山区", + "150421": "阿鲁科尔沁旗", + "150422": "巴林左旗", + "150423": "巴林右旗", + "150424": "林西县", + "150425": "克什克腾旗", + "150426": "翁牛特旗", + "150428": "喀喇沁旗", + "150429": "宁城县", + "150430": "敖汉旗", + "150431": "其它区", + "150500": "通辽市", + "150502": "科尔沁区", + "150521": "科尔沁左翼中旗", + "150522": "科尔沁左翼后旗", + "150523": "开鲁县", + "150524": "库伦旗", + "150525": "奈曼旗", + "150526": "扎鲁特旗", + "150581": "霍林郭勒市", + "150582": "其它区", + "150600": "鄂尔多斯市", + "150602": "东胜区", + "150621": "达拉特旗", + "150622": "准格尔旗", + "150623": "鄂托克前旗", + "150624": "鄂托克旗", + "150625": "杭锦旗", + "150626": "乌审旗", + "150627": "伊金霍洛旗", + "150628": "其它区", + "150700": "呼伦贝尔市", + "150702": "海拉尔区", + "150703": "扎赉诺尔区", + "150721": "阿荣旗", + "150722": "莫力达瓦达斡尔族自治旗", + "150723": "鄂伦春自治旗", + "150724": "鄂温克族自治旗", + "150725": "陈巴尔虎旗", + "150726": "新巴尔虎左旗", + "150727": "新巴尔虎右旗", + "150781": "满洲里市", + "150782": "牙克石市", + "150783": "扎兰屯市", + "150784": "额尔古纳市", + "150785": "根河市", + "150786": "其它区", + "150800": "巴彦淖尔市", + "150802": "临河区", + "150821": "五原县", + "150822": "磴口县", + "150823": "乌拉特前旗", + "150824": "乌拉特中旗", + "150825": "乌拉特后旗", + "150826": "杭锦后旗", + "150827": "其它区", + "150900": "乌兰察布市", + "150902": "集宁区", + "150921": "卓资县", + "150922": "化德县", + "150923": "商都县", + "150924": "兴和县", + "150925": "凉城县", + "150926": "察哈尔右翼前旗", + "150927": "察哈尔右翼中旗", + "150928": "察哈尔右翼后旗", + "150929": "四子王旗", + "150981": "丰镇市", + "150982": "其它区", + "152200": "兴安盟", + "152201": "乌兰浩特市", + "152202": "阿尔山市", + "152221": "科尔沁右翼前旗", + "152222": "科尔沁右翼中旗", + "152223": "扎赉特旗", + "152224": "突泉县", + "152225": "其它区", + "152500": "锡林郭勒盟", + "152501": "二连浩特市", + "152502": "锡林浩特市", + "152522": "阿巴嘎旗", + "152523": "苏尼特左旗", + "152524": "苏尼特右旗", + "152525": "东乌珠穆沁旗", + "152526": "西乌珠穆沁旗", + "152527": "太仆寺旗", + "152528": "镶黄旗", + "152529": "正镶白旗", + "152530": "正蓝旗", + "152531": "多伦县", + "152532": "其它区", + "152900": "阿拉善盟", + "152921": "阿拉善左旗", + "152922": "阿拉善右旗", + "152923": "额济纳旗", + "152924": "其它区", + "210000": "辽宁省", + "210100": "沈阳市", + "210102": "和平区", + "210103": "沈河区", + "210104": "大东区", + "210105": "皇姑区", + "210106": "铁西区", + "210111": "苏家屯区", + "210112": "东陵区", + "210113": "新城子区", + "210114": "于洪区", + "210122": "辽中县", + "210123": "康平县", + "210124": "法库县", + "210181": "新民市", + "210184": "沈北新区", + "210185": "其它区", + "210200": "大连市", + "210202": "中山区", + "210203": "西岗区", + "210204": "沙河口区", + "210211": "甘井子区", + "210212": "旅顺口区", + "210213": "金州区", + "210224": "长海县", + "210281": "瓦房店市", + "210282": "普兰店市", + "210283": "庄河市", + "210298": "其它区", + "210300": "鞍山市", + "210302": "铁东区", + "210303": "铁西区", + "210304": "立山区", + "210311": "千山区", + "210321": "台安县", + "210323": "岫岩满族自治县", + "210381": "海城市", + "210382": "其它区", + "210400": "抚顺市", + "210402": "新抚区", + "210403": "东洲区", + "210404": "望花区", + "210411": "顺城区", + "210421": "抚顺县", + "210422": "新宾满族自治县", + "210423": "清原满族自治县", + "210424": "其它区", + "210500": "本溪市", + "210502": "平山区", + "210503": "溪湖区", + "210504": "明山区", + "210505": "南芬区", + "210521": "本溪满族自治县", + "210522": "桓仁满族自治县", + "210523": "其它区", + "210600": "丹东市", + "210602": "元宝区", + "210603": "振兴区", + "210604": "振安区", + "210624": "宽甸满族自治县", + "210681": "东港市", + "210682": "凤城市", + "210683": "其它区", + "210700": "锦州市", + "210702": "古塔区", + "210703": "凌河区", + "210711": "太和区", + "210726": "黑山县", + "210727": "义县", + "210781": "凌海市", + "210782": "北镇市", + "210783": "其它区", + "210800": "营口市", + "210802": "站前区", + "210803": "西市区", + "210804": "鲅鱼圈区", + "210811": "老边区", + "210881": "盖州市", + "210882": "大石桥市", + "210883": "其它区", + "210900": "阜新市", + "210902": "海州区", + "210903": "新邱区", + "210904": "太平区", + "210905": "清河门区", + "210911": "细河区", + "210921": "阜新蒙古族自治县", + "210922": "彰武县", + "210923": "其它区", + "211000": "辽阳市", + "211002": "白塔区", + "211003": "文圣区", + "211004": "宏伟区", + "211005": "弓长岭区", + "211011": "太子河区", + "211021": "辽阳县", + "211081": "灯塔市", + "211082": "其它区", + "211100": "盘锦市", + "211102": "双台子区", + "211103": "兴隆台区", + "211121": "大洼县", + "211122": "盘山县", + "211123": "其它区", + "211200": "铁岭市", + "211202": "银州区", + "211204": "清河区", + "211221": "铁岭县", + "211223": "西丰县", + "211224": "昌图县", + "211281": "调兵山市", + "211282": "开原市", + "211283": "其它区", + "211300": "朝阳市", + "211302": "双塔区", + "211303": "龙城区", + "211321": "朝阳县", + "211322": "建平县", + "211324": "喀喇沁左翼蒙古族自治县", + "211381": "北票市", + "211382": "凌源市", + "211383": "其它区", + "211400": "葫芦岛市", + "211402": "连山区", + "211403": "龙港区", + "211404": "南票区", + "211421": "绥中县", + "211422": "建昌县", + "211481": "兴城市", + "211482": "其它区", + "220000": "吉林省", + "220100": "长春市", + "220102": "南关区", + "220103": "宽城区", + "220104": "朝阳区", + "220105": "二道区", + "220106": "绿园区", + "220112": "双阳区", + "220122": "农安县", + "220181": "九台市", + "220182": "榆树市", + "220183": "德惠市", + "220188": "其它区", + "220200": "吉林市", + "220202": "昌邑区", + "220203": "龙潭区", + "220204": "船营区", + "220211": "丰满区", + "220221": "永吉县", + "220281": "蛟河市", + "220282": "桦甸市", + "220283": "舒兰市", + "220284": "磐石市", + "220285": "其它区", + "220300": "四平市", + "220302": "铁西区", + "220303": "铁东区", + "220322": "梨树县", + "220323": "伊通满族自治县", + "220381": "公主岭市", + "220382": "双辽市", + "220383": "其它区", + "220400": "辽源市", + "220402": "龙山区", + "220403": "西安区", + "220421": "东丰县", + "220422": "东辽县", + "220423": "其它区", + "220500": "通化市", + "220502": "东昌区", + "220503": "二道江区", + "220521": "通化县", + "220523": "辉南县", + "220524": "柳河县", + "220581": "梅河口市", + "220582": "集安市", + "220583": "其它区", + "220600": "白山市", + "220602": "浑江区", + "220621": "抚松县", + "220622": "靖宇县", + "220623": "长白朝鲜族自治县", + "220625": "江源区", + "220681": "临江市", + "220682": "其它区", + "220700": "松原市", + "220702": "宁江区", + "220721": "前郭尔罗斯蒙古族自治县", + "220722": "长岭县", + "220723": "乾安县", + "220724": "扶余市", + "220725": "其它区", + "220800": "白城市", + "220802": "洮北区", + "220821": "镇赉县", + "220822": "通榆县", + "220881": "洮南市", + "220882": "大安市", + "220883": "其它区", + "222400": "延边朝鲜族自治州", + "222401": "延吉市", + "222402": "图们市", + "222403": "敦化市", + "222404": "珲春市", + "222405": "龙井市", + "222406": "和龙市", + "222424": "汪清县", + "222426": "安图县", + "222427": "其它区", + "230000": "黑龙江省", + "230100": "哈尔滨市", + "230102": "道里区", + "230103": "南岗区", + "230104": "道外区", + "230106": "香坊区", + "230108": "平房区", + "230109": "松北区", + "230111": "呼兰区", + "230123": "依兰县", + "230124": "方正县", + "230125": "宾县", + "230126": "巴彦县", + "230127": "木兰县", + "230128": "通河县", + "230129": "延寿县", + "230181": "阿城区", + "230182": "双城市", + "230183": "尚志市", + "230184": "五常市", + "230186": "其它区", + "230200": "齐齐哈尔市", + "230202": "龙沙区", + "230203": "建华区", + "230204": "铁锋区", + "230205": "昂昂溪区", + "230206": "富拉尔基区", + "230207": "碾子山区", + "230208": "梅里斯达斡尔族区", + "230221": "龙江县", + "230223": "依安县", + "230224": "泰来县", + "230225": "甘南县", + "230227": "富裕县", + "230229": "克山县", + "230230": "克东县", + "230231": "拜泉县", + "230281": "讷河市", + "230282": "其它区", + "230300": "鸡西市", + "230302": "鸡冠区", + "230303": "恒山区", + "230304": "滴道区", + "230305": "梨树区", + "230306": "城子河区", + "230307": "麻山区", + "230321": "鸡东县", + "230381": "虎林市", + "230382": "密山市", + "230383": "其它区", + "230400": "鹤岗市", + "230402": "向阳区", + "230403": "工农区", + "230404": "南山区", + "230405": "兴安区", + "230406": "东山区", + "230407": "兴山区", + "230421": "萝北县", + "230422": "绥滨县", + "230423": "其它区", + "230500": "双鸭山市", + "230502": "尖山区", + "230503": "岭东区", + "230505": "四方台区", + "230506": "宝山区", + "230521": "集贤县", + "230522": "友谊县", + "230523": "宝清县", + "230524": "饶河县", + "230525": "其它区", + "230600": "大庆市", + "230602": "萨尔图区", + "230603": "龙凤区", + "230604": "让胡路区", + "230605": "红岗区", + "230606": "大同区", + "230621": "肇州县", + "230622": "肇源县", + "230623": "林甸县", + "230624": "杜尔伯特蒙古族自治县", + "230625": "其它区", + "230700": "伊春市", + "230702": "伊春区", + "230703": "南岔区", + "230704": "友好区", + "230705": "西林区", + "230706": "翠峦区", + "230707": "新青区", + "230708": "美溪区", + "230709": "金山屯区", + "230710": "五营区", + "230711": "乌马河区", + "230712": "汤旺河区", + "230713": "带岭区", + "230714": "乌伊岭区", + "230715": "红星区", + "230716": "上甘岭区", + "230722": "嘉荫县", + "230781": "铁力市", + "230782": "其它区", + "230800": "佳木斯市", + "230803": "向阳区", + "230804": "前进区", + "230805": "东风区", + "230811": "郊区", + "230822": "桦南县", + "230826": "桦川县", + "230828": "汤原县", + "230833": "抚远县", + "230881": "同江市", + "230882": "富锦市", + "230883": "其它区", + "230900": "七台河市", + "230902": "新兴区", + "230903": "桃山区", + "230904": "茄子河区", + "230921": "勃利县", + "230922": "其它区", + "231000": "牡丹江市", + "231002": "东安区", + "231003": "阳明区", + "231004": "爱民区", + "231005": "西安区", + "231024": "东宁县", + "231025": "林口县", + "231081": "绥芬河市", + "231083": "海林市", + "231084": "宁安市", + "231085": "穆棱市", + "231086": "其它区", + "231100": "黑河市", + "231102": "爱辉区", + "231121": "嫩江县", + "231123": "逊克县", + "231124": "孙吴县", + "231181": "北安市", + "231182": "五大连池市", + "231183": "其它区", + "231200": "绥化市", + "231202": "北林区", + "231221": "望奎县", + "231222": "兰西县", + "231223": "青冈县", + "231224": "庆安县", + "231225": "明水县", + "231226": "绥棱县", + "231281": "安达市", + "231282": "肇东市", + "231283": "海伦市", + "231284": "其它区", + "232700": "大兴安岭地区", + "232702": "松岭区", + "232703": "新林区", + "232704": "呼中区", + "232721": "呼玛县", + "232722": "塔河县", + "232723": "漠河县", + "232724": "加格达奇区", + "232725": "其它区", + "310000": "上海", + "310100": "上海市", + "310101": "黄浦区", + "310104": "徐汇区", + "310105": "长宁区", + "310106": "静安区", + "310107": "普陀区", + "310108": "闸北区", + "310109": "虹口区", + "310110": "杨浦区", + "310112": "闵行区", + "310113": "宝山区", + "310114": "嘉定区", + "310115": "浦东新区", + "310116": "金山区", + "310117": "松江区", + "310118": "青浦区", + "310120": "奉贤区", + "310230": "崇明县", + "310231": "其它区", + "320000": "江苏省", + "320100": "南京市", + "320102": "玄武区", + "320104": "秦淮区", + "320105": "建邺区", + "320106": "鼓楼区", + "320111": "浦口区", + "320113": "栖霞区", + "320114": "雨花台区", + "320115": "江宁区", + "320116": "六合区", + "320124": "溧水区", + "320125": "高淳区", + "320126": "其它区", + "320200": "无锡市", + "320202": "崇安区", + "320203": "南长区", + "320204": "北塘区", + "320205": "锡山区", + "320206": "惠山区", + "320211": "滨湖区", + "320281": "江阴市", + "320282": "宜兴市", + "320297": "其它区", + "320300": "徐州市", + "320302": "鼓楼区", + "320303": "云龙区", + "320305": "贾汪区", + "320311": "泉山区", + "320321": "丰县", + "320322": "沛县", + "320323": "铜山区", + "320324": "睢宁县", + "320381": "新沂市", + "320382": "邳州市", + "320383": "其它区", + "320400": "常州市", + "320402": "天宁区", + "320404": "钟楼区", + "320405": "戚墅堰区", + "320411": "新北区", + "320412": "武进区", + "320481": "溧阳市", + "320482": "金坛市", + "320483": "其它区", + "320500": "苏州市", + "320505": "虎丘区", + "320506": "吴中区", + "320507": "相城区", + "320508": "姑苏区", + "320581": "常熟市", + "320582": "张家港市", + "320583": "昆山市", + "320584": "吴江区", + "320585": "太仓市", + "320596": "其它区", + "320600": "南通市", + "320602": "崇川区", + "320611": "港闸区", + "320612": "通州区", + "320621": "海安县", + "320623": "如东县", + "320681": "启东市", + "320682": "如皋市", + "320684": "海门市", + "320694": "其它区", + "320700": "连云港市", + "320703": "连云区", + "320705": "新浦区", + "320706": "海州区", + "320721": "赣榆县", + "320722": "东海县", + "320723": "灌云县", + "320724": "灌南县", + "320725": "其它区", + "320800": "淮安市", + "320802": "清河区", + "320803": "淮安区", + "320804": "淮阴区", + "320811": "清浦区", + "320826": "涟水县", + "320829": "洪泽县", + "320830": "盱眙县", + "320831": "金湖县", + "320832": "其它区", + "320900": "盐城市", + "320902": "亭湖区", + "320903": "盐都区", + "320921": "响水县", + "320922": "滨海县", + "320923": "阜宁县", + "320924": "射阳县", + "320925": "建湖县", + "320981": "东台市", + "320982": "大丰市", + "320983": "其它区", + "321000": "扬州市", + "321002": "广陵区", + "321003": "邗江区", + "321023": "宝应县", + "321081": "仪征市", + "321084": "高邮市", + "321088": "江都区", + "321093": "其它区", + "321100": "镇江市", + "321102": "京口区", + "321111": "润州区", + "321112": "丹徒区", + "321181": "丹阳市", + "321182": "扬中市", + "321183": "句容市", + "321184": "其它区", + "321200": "泰州市", + "321202": "海陵区", + "321203": "高港区", + "321281": "兴化市", + "321282": "靖江市", + "321283": "泰兴市", + "321284": "姜堰区", + "321285": "其它区", + "321300": "宿迁市", + "321302": "宿城区", + "321311": "宿豫区", + "321322": "沭阳县", + "321323": "泗阳县", + "321324": "泗洪县", + "321325": "其它区", + "330000": "浙江省", + "330100": "杭州市", + "330102": "上城区", + "330103": "下城区", + "330104": "江干区", + "330105": "拱墅区", + "330106": "西湖区", + "330108": "滨江区", + "330109": "萧山区", + "330110": "余杭区", + "330122": "桐庐县", + "330127": "淳安县", + "330182": "建德市", + "330183": "富阳市", + "330185": "临安市", + "330186": "其它区", + "330200": "宁波市", + "330203": "海曙区", + "330204": "江东区", + "330205": "江北区", + "330206": "北仑区", + "330211": "镇海区", + "330212": "鄞州区", + "330225": "象山县", + "330226": "宁海县", + "330281": "余姚市", + "330282": "慈溪市", + "330283": "奉化市", + "330284": "其它区", + "330300": "温州市", + "330302": "鹿城区", + "330303": "龙湾区", + "330304": "瓯海区", + "330322": "洞头县", + "330324": "永嘉县", + "330326": "平阳县", + "330327": "苍南县", + "330328": "文成县", + "330329": "泰顺县", + "330381": "瑞安市", + "330382": "乐清市", + "330383": "其它区", + "330400": "嘉兴市", + "330402": "南湖区", + "330411": "秀洲区", + "330421": "嘉善县", + "330424": "海盐县", + "330481": "海宁市", + "330482": "平湖市", + "330483": "桐乡市", + "330484": "其它区", + "330500": "湖州市", + "330502": "吴兴区", + "330503": "南浔区", + "330521": "德清县", + "330522": "长兴县", + "330523": "安吉县", + "330524": "其它区", + "330600": "绍兴市", + "330602": "越城区", + "330621": "绍兴县", + "330624": "新昌县", + "330681": "诸暨市", + "330682": "上虞市", + "330683": "嵊州市", + "330684": "其它区", + "330700": "金华市", + "330702": "婺城区", + "330703": "金东区", + "330723": "武义县", + "330726": "浦江县", + "330727": "磐安县", + "330781": "兰溪市", + "330782": "义乌市", + "330783": "东阳市", + "330784": "永康市", + "330785": "其它区", + "330800": "衢州市", + "330802": "柯城区", + "330803": "衢江区", + "330822": "常山县", + "330824": "开化县", + "330825": "龙游县", + "330881": "江山市", + "330882": "其它区", + "330900": "舟山市", + "330902": "定海区", + "330903": "普陀区", + "330921": "岱山县", + "330922": "嵊泗县", + "330923": "其它区", + "331000": "台州市", + "331002": "椒江区", + "331003": "黄岩区", + "331004": "路桥区", + "331021": "玉环县", + "331022": "三门县", + "331023": "天台县", + "331024": "仙居县", + "331081": "温岭市", + "331082": "临海市", + "331083": "其它区", + "331100": "丽水市", + "331102": "莲都区", + "331121": "青田县", + "331122": "缙云县", + "331123": "遂昌县", + "331124": "松阳县", + "331125": "云和县", + "331126": "庆元县", + "331127": "景宁畲族自治县", + "331181": "龙泉市", + "331182": "其它区", + "340000": "安徽省", + "340100": "合肥市", + "340102": "瑶海区", + "340103": "庐阳区", + "340104": "蜀山区", + "340111": "包河区", + "340121": "长丰县", + "340122": "肥东县", + "340123": "肥西县", + "340192": "其它区", + "340200": "芜湖市", + "340202": "镜湖区", + "340203": "弋江区", + "340207": "鸠江区", + "340208": "三山区", + "340221": "芜湖县", + "340222": "繁昌县", + "340223": "南陵县", + "340224": "其它区", + "340300": "蚌埠市", + "340302": "龙子湖区", + "340303": "蚌山区", + "340304": "禹会区", + "340311": "淮上区", + "340321": "怀远县", + "340322": "五河县", + "340323": "固镇县", + "340324": "其它区", + "340400": "淮南市", + "340402": "大通区", + "340403": "田家庵区", + "340404": "谢家集区", + "340405": "八公山区", + "340406": "潘集区", + "340421": "凤台县", + "340422": "其它区", + "340500": "马鞍山市", + "340503": "花山区", + "340504": "雨山区", + "340506": "博望区", + "340521": "当涂县", + "340522": "其它区", + "340600": "淮北市", + "340602": "杜集区", + "340603": "相山区", + "340604": "烈山区", + "340621": "濉溪县", + "340622": "其它区", + "340700": "铜陵市", + "340702": "铜官山区", + "340703": "狮子山区", + "340711": "郊区", + "340721": "铜陵县", + "340722": "其它区", + "340800": "安庆市", + "340802": "迎江区", + "340803": "大观区", + "340811": "宜秀区", + "340822": "怀宁县", + "340823": "枞阳县", + "340824": "潜山县", + "340825": "太湖县", + "340826": "宿松县", + "340827": "望江县", + "340828": "岳西县", + "340881": "桐城市", + "340882": "其它区", + "341000": "黄山市", + "341002": "屯溪区", + "341003": "黄山区", + "341004": "徽州区", + "341021": "歙县", + "341022": "休宁县", + "341023": "黟县", + "341024": "祁门县", + "341025": "其它区", + "341100": "滁州市", + "341102": "琅琊区", + "341103": "南谯区", + "341122": "来安县", + "341124": "全椒县", + "341125": "定远县", + "341126": "凤阳县", + "341181": "天长市", + "341182": "明光市", + "341183": "其它区", + "341200": "阜阳市", + "341202": "颍州区", + "341203": "颍东区", + "341204": "颍泉区", + "341221": "临泉县", + "341222": "太和县", + "341225": "阜南县", + "341226": "颍上县", + "341282": "界首市", + "341283": "其它区", + "341300": "宿州市", + "341302": "埇桥区", + "341321": "砀山县", + "341322": "萧县", + "341323": "灵璧县", + "341324": "泗县", + "341325": "其它区", + "341400": "巢湖市", + "341421": "庐江县", + "341422": "无为县", + "341423": "含山县", + "341424": "和县", + "341500": "六安市", + "341502": "金安区", + "341503": "裕安区", + "341521": "寿县", + "341522": "霍邱县", + "341523": "舒城县", + "341524": "金寨县", + "341525": "霍山县", + "341526": "其它区", + "341600": "亳州市", + "341602": "谯城区", + "341621": "涡阳县", + "341622": "蒙城县", + "341623": "利辛县", + "341624": "其它区", + "341700": "池州市", + "341702": "贵池区", + "341721": "东至县", + "341722": "石台县", + "341723": "青阳县", + "341724": "其它区", + "341800": "宣城市", + "341802": "宣州区", + "341821": "郎溪县", + "341822": "广德县", + "341823": "泾县", + "341824": "绩溪县", + "341825": "旌德县", + "341881": "宁国市", + "341882": "其它区", + "350000": "福建省", + "350100": "福州市", + "350102": "鼓楼区", + "350103": "台江区", + "350104": "仓山区", + "350105": "马尾区", + "350111": "晋安区", + "350121": "闽侯县", + "350122": "连江县", + "350123": "罗源县", + "350124": "闽清县", + "350125": "永泰县", + "350128": "平潭县", + "350181": "福清市", + "350182": "长乐市", + "350183": "其它区", + "350200": "厦门市", + "350203": "思明区", + "350205": "海沧区", + "350206": "湖里区", + "350211": "集美区", + "350212": "同安区", + "350213": "翔安区", + "350214": "其它区", + "350300": "莆田市", + "350302": "城厢区", + "350303": "涵江区", + "350304": "荔城区", + "350305": "秀屿区", + "350322": "仙游县", + "350323": "其它区", + "350400": "三明市", + "350402": "梅列区", + "350403": "三元区", + "350421": "明溪县", + "350423": "清流县", + "350424": "宁化县", + "350425": "大田县", + "350426": "尤溪县", + "350427": "沙县", + "350428": "将乐县", + "350429": "泰宁县", + "350430": "建宁县", + "350481": "永安市", + "350482": "其它区", + "350500": "泉州市", + "350502": "鲤城区", + "350503": "丰泽区", + "350504": "洛江区", + "350505": "泉港区", + "350521": "惠安县", + "350524": "安溪县", + "350525": "永春县", + "350526": "德化县", + "350527": "金门县", + "350581": "石狮市", + "350582": "晋江市", + "350583": "南安市", + "350584": "其它区", + "350600": "漳州市", + "350602": "芗城区", + "350603": "龙文区", + "350622": "云霄县", + "350623": "漳浦县", + "350624": "诏安县", + "350625": "长泰县", + "350626": "东山县", + "350627": "南靖县", + "350628": "平和县", + "350629": "华安县", + "350681": "龙海市", + "350682": "其它区", + "350700": "南平市", + "350702": "延平区", + "350721": "顺昌县", + "350722": "浦城县", + "350723": "光泽县", + "350724": "松溪县", + "350725": "政和县", + "350781": "邵武市", + "350782": "武夷山市", + "350783": "建瓯市", + "350784": "建阳市", + "350785": "其它区", + "350800": "龙岩市", + "350802": "新罗区", + "350821": "长汀县", + "350822": "永定县", + "350823": "上杭县", + "350824": "武平县", + "350825": "连城县", + "350881": "漳平市", + "350882": "其它区", + "350900": "宁德市", + "350902": "蕉城区", + "350921": "霞浦县", + "350922": "古田县", + "350923": "屏南县", + "350924": "寿宁县", + "350925": "周宁县", + "350926": "柘荣县", + "350981": "福安市", + "350982": "福鼎市", + "350983": "其它区", + "360000": "江西省", + "360100": "南昌市", + "360102": "东湖区", + "360103": "西湖区", + "360104": "青云谱区", + "360105": "湾里区", + "360111": "青山湖区", + "360121": "南昌县", + "360122": "新建县", + "360123": "安义县", + "360124": "进贤县", + "360128": "其它区", + "360200": "景德镇市", + "360202": "昌江区", + "360203": "珠山区", + "360222": "浮梁县", + "360281": "乐平市", + "360282": "其它区", + "360300": "萍乡市", + "360302": "安源区", + "360313": "湘东区", + "360321": "莲花县", + "360322": "上栗县", + "360323": "芦溪县", + "360324": "其它区", + "360400": "九江市", + "360402": "庐山区", + "360403": "浔阳区", + "360421": "九江县", + "360423": "武宁县", + "360424": "修水县", + "360425": "永修县", + "360426": "德安县", + "360427": "星子县", + "360428": "都昌县", + "360429": "湖口县", + "360430": "彭泽县", + "360481": "瑞昌市", + "360482": "其它区", + "360483": "共青城市", + "360500": "新余市", + "360502": "渝水区", + "360521": "分宜县", + "360522": "其它区", + "360600": "鹰潭市", + "360602": "月湖区", + "360622": "余江县", + "360681": "贵溪市", + "360682": "其它区", + "360700": "赣州市", + "360702": "章贡区", + "360721": "赣县", + "360722": "信丰县", + "360723": "大余县", + "360724": "上犹县", + "360725": "崇义县", + "360726": "安远县", + "360727": "龙南县", + "360728": "定南县", + "360729": "全南县", + "360730": "宁都县", + "360731": "于都县", + "360732": "兴国县", + "360733": "会昌县", + "360734": "寻乌县", + "360735": "石城县", + "360781": "瑞金市", + "360782": "南康市", + "360783": "其它区", + "360800": "吉安市", + "360802": "吉州区", + "360803": "青原区", + "360821": "吉安县", + "360822": "吉水县", + "360823": "峡江县", + "360824": "新干县", + "360825": "永丰县", + "360826": "泰和县", + "360827": "遂川县", + "360828": "万安县", + "360829": "安福县", + "360830": "永新县", + "360881": "井冈山市", + "360882": "其它区", + "360900": "宜春市", + "360902": "袁州区", + "360921": "奉新县", + "360922": "万载县", + "360923": "上高县", + "360924": "宜丰县", + "360925": "靖安县", + "360926": "铜鼓县", + "360981": "丰城市", + "360982": "樟树市", + "360983": "高安市", + "360984": "其它区", + "361000": "抚州市", + "361002": "临川区", + "361021": "南城县", + "361022": "黎川县", + "361023": "南丰县", + "361024": "崇仁县", + "361025": "乐安县", + "361026": "宜黄县", + "361027": "金溪县", + "361028": "资溪县", + "361029": "东乡县", + "361030": "广昌县", + "361031": "其它区", + "361100": "上饶市", + "361102": "信州区", + "361121": "上饶县", + "361122": "广丰县", + "361123": "玉山县", + "361124": "铅山县", + "361125": "横峰县", + "361126": "弋阳县", + "361127": "余干县", + "361128": "鄱阳县", + "361129": "万年县", + "361130": "婺源县", + "361181": "德兴市", + "361182": "其它区", + "370000": "山东省", + "370100": "济南市", + "370102": "历下区", + "370103": "市中区", + "370104": "槐荫区", + "370105": "天桥区", + "370112": "历城区", + "370113": "长清区", + "370124": "平阴县", + "370125": "济阳县", + "370126": "商河县", + "370181": "章丘市", + "370182": "其它区", + "370200": "青岛市", + "370202": "市南区", + "370203": "市北区", + "370211": "黄岛区", + "370212": "崂山区", + "370213": "李沧区", + "370214": "城阳区", + "370281": "胶州市", + "370282": "即墨市", + "370283": "平度市", + "370285": "莱西市", + "370286": "其它区", + "370300": "淄博市", + "370302": "淄川区", + "370303": "张店区", + "370304": "博山区", + "370305": "临淄区", + "370306": "周村区", + "370321": "桓台县", + "370322": "高青县", + "370323": "沂源县", + "370324": "其它区", + "370400": "枣庄市", + "370402": "市中区", + "370403": "薛城区", + "370404": "峄城区", + "370405": "台儿庄区", + "370406": "山亭区", + "370481": "滕州市", + "370482": "其它区", + "370500": "东营市", + "370502": "东营区", + "370503": "河口区", + "370521": "垦利县", + "370522": "利津县", + "370523": "广饶县", + "370591": "其它区", + "370600": "烟台市", + "370602": "芝罘区", + "370611": "福山区", + "370612": "牟平区", + "370613": "莱山区", + "370634": "长岛县", + "370681": "龙口市", + "370682": "莱阳市", + "370683": "莱州市", + "370684": "蓬莱市", + "370685": "招远市", + "370686": "栖霞市", + "370687": "海阳市", + "370688": "其它区", + "370700": "潍坊市", + "370702": "潍城区", + "370703": "寒亭区", + "370704": "坊子区", + "370705": "奎文区", + "370724": "临朐县", + "370725": "昌乐县", + "370781": "青州市", + "370782": "诸城市", + "370783": "寿光市", + "370784": "安丘市", + "370785": "高密市", + "370786": "昌邑市", + "370787": "其它区", + "370800": "济宁市", + "370802": "市中区", + "370811": "任城区", + "370826": "微山县", + "370827": "鱼台县", + "370828": "金乡县", + "370829": "嘉祥县", + "370830": "汶上县", + "370831": "泗水县", + "370832": "梁山县", + "370881": "曲阜市", + "370882": "兖州市", + "370883": "邹城市", + "370884": "其它区", + "370900": "泰安市", + "370902": "泰山区", + "370903": "岱岳区", + "370921": "宁阳县", + "370923": "东平县", + "370982": "新泰市", + "370983": "肥城市", + "370984": "其它区", + "371000": "威海市", + "371002": "环翠区", + "371081": "文登市", + "371082": "荣成市", + "371083": "乳山市", + "371084": "其它区", + "371100": "日照市", + "371102": "东港区", + "371103": "岚山区", + "371121": "五莲县", + "371122": "莒县", + "371123": "其它区", + "371200": "莱芜市", + "371202": "莱城区", + "371203": "钢城区", + "371204": "其它区", + "371300": "临沂市", + "371302": "兰山区", + "371311": "罗庄区", + "371312": "河东区", + "371321": "沂南县", + "371322": "郯城县", + "371323": "沂水县", + "371324": "苍山县", + "371325": "费县", + "371326": "平邑县", + "371327": "莒南县", + "371328": "蒙阴县", + "371329": "临沭县", + "371330": "其它区", + "371400": "德州市", + "371402": "德城区", + "371421": "陵县", + "371422": "宁津县", + "371423": "庆云县", + "371424": "临邑县", + "371425": "齐河县", + "371426": "平原县", + "371427": "夏津县", + "371428": "武城县", + "371481": "乐陵市", + "371482": "禹城市", + "371483": "其它区", + "371500": "聊城市", + "371502": "东昌府区", + "371521": "阳谷县", + "371522": "莘县", + "371523": "茌平县", + "371524": "东阿县", + "371525": "冠县", + "371526": "高唐县", + "371581": "临清市", + "371582": "其它区", + "371600": "滨州市", + "371602": "滨城区", + "371621": "惠民县", + "371622": "阳信县", + "371623": "无棣县", + "371624": "沾化县", + "371625": "博兴县", + "371626": "邹平县", + "371627": "其它区", + "371700": "菏泽市", + "371702": "牡丹区", + "371721": "曹县", + "371722": "单县", + "371723": "成武县", + "371724": "巨野县", + "371725": "郓城县", + "371726": "鄄城县", + "371727": "定陶县", + "371728": "东明县", + "371729": "其它区", + "410000": "河南省", + "410100": "郑州市", + "410102": "中原区", + "410103": "二七区", + "410104": "管城回族区", + "410105": "金水区", + "410106": "上街区", + "410108": "惠济区", + "410122": "中牟县", + "410181": "巩义市", + "410182": "荥阳市", + "410183": "新密市", + "410184": "新郑市", + "410185": "登封市", + "410188": "其它区", + "410200": "开封市", + "410202": "龙亭区", + "410203": "顺河回族区", + "410204": "鼓楼区", + "410205": "禹王台区", + "410211": "金明区", + "410221": "杞县", + "410222": "通许县", + "410223": "尉氏县", + "410224": "开封县", + "410225": "兰考县", + "410226": "其它区", + "410300": "洛阳市", + "410302": "老城区", + "410303": "西工区", + "410304": "瀍河回族区", + "410305": "涧西区", + "410306": "吉利区", + "410307": "洛龙区", + "410322": "孟津县", + "410323": "新安县", + "410324": "栾川县", + "410325": "嵩县", + "410326": "汝阳县", + "410327": "宜阳县", + "410328": "洛宁县", + "410329": "伊川县", + "410381": "偃师市", + "410400": "平顶山市", + "410402": "新华区", + "410403": "卫东区", + "410404": "石龙区", + "410411": "湛河区", + "410421": "宝丰县", + "410422": "叶县", + "410423": "鲁山县", + "410425": "郏县", + "410481": "舞钢市", + "410482": "汝州市", + "410483": "其它区", + "410500": "安阳市", + "410502": "文峰区", + "410503": "北关区", + "410505": "殷都区", + "410506": "龙安区", + "410522": "安阳县", + "410523": "汤阴县", + "410526": "滑县", + "410527": "内黄县", + "410581": "林州市", + "410582": "其它区", + "410600": "鹤壁市", + "410602": "鹤山区", + "410603": "山城区", + "410611": "淇滨区", + "410621": "浚县", + "410622": "淇县", + "410623": "其它区", + "410700": "新乡市", + "410702": "红旗区", + "410703": "卫滨区", + "410704": "凤泉区", + "410711": "牧野区", + "410721": "新乡县", + "410724": "获嘉县", + "410725": "原阳县", + "410726": "延津县", + "410727": "封丘县", + "410728": "长垣县", + "410781": "卫辉市", + "410782": "辉县市", + "410783": "其它区", + "410800": "焦作市", + "410802": "解放区", + "410803": "中站区", + "410804": "马村区", + "410811": "山阳区", + "410821": "修武县", + "410822": "博爱县", + "410823": "武陟县", + "410825": "温县", + "410881": "济源市", + "410882": "沁阳市", + "410883": "孟州市", + "410884": "其它区", + "410900": "濮阳市", + "410902": "华龙区", + "410922": "清丰县", + "410923": "南乐县", + "410926": "范县", + "410927": "台前县", + "410928": "濮阳县", + "410929": "其它区", + "411000": "许昌市", + "411002": "魏都区", + "411023": "许昌县", + "411024": "鄢陵县", + "411025": "襄城县", + "411081": "禹州市", + "411082": "长葛市", + "411083": "其它区", + "411100": "漯河市", + "411102": "源汇区", + "411103": "郾城区", + "411104": "召陵区", + "411121": "舞阳县", + "411122": "临颍县", + "411123": "其它区", + "411200": "三门峡市", + "411202": "湖滨区", + "411221": "渑池县", + "411222": "陕县", + "411224": "卢氏县", + "411281": "义马市", + "411282": "灵宝市", + "411283": "其它区", + "411300": "南阳市", + "411302": "宛城区", + "411303": "卧龙区", + "411321": "南召县", + "411322": "方城县", + "411323": "西峡县", + "411324": "镇平县", + "411325": "内乡县", + "411326": "淅川县", + "411327": "社旗县", + "411328": "唐河县", + "411329": "新野县", + "411330": "桐柏县", + "411381": "邓州市", + "411382": "其它区", + "411400": "商丘市", + "411402": "梁园区", + "411403": "睢阳区", + "411421": "民权县", + "411422": "睢县", + "411423": "宁陵县", + "411424": "柘城县", + "411425": "虞城县", + "411426": "夏邑县", + "411481": "永城市", + "411482": "其它区", + "411500": "信阳市", + "411502": "浉河区", + "411503": "平桥区", + "411521": "罗山县", + "411522": "光山县", + "411523": "新县", + "411524": "商城县", + "411525": "固始县", + "411526": "潢川县", + "411527": "淮滨县", + "411528": "息县", + "411529": "其它区", + "411600": "周口市", + "411602": "川汇区", + "411621": "扶沟县", + "411622": "西华县", + "411623": "商水县", + "411624": "沈丘县", + "411625": "郸城县", + "411626": "淮阳县", + "411627": "太康县", + "411628": "鹿邑县", + "411681": "项城市", + "411682": "其它区", + "411700": "驻马店市", + "411702": "驿城区", + "411721": "西平县", + "411722": "上蔡县", + "411723": "平舆县", + "411724": "正阳县", + "411725": "确山县", + "411726": "泌阳县", + "411727": "汝南县", + "411728": "遂平县", + "411729": "新蔡县", + "411730": "其它区", + "420000": "湖北省", + "420100": "武汉市", + "420102": "江岸区", + "420103": "江汉区", + "420104": "硚口区", + "420105": "汉阳区", + "420106": "武昌区", + "420107": "青山区", + "420111": "洪山区", + "420112": "东西湖区", + "420113": "汉南区", + "420114": "蔡甸区", + "420115": "江夏区", + "420116": "黄陂区", + "420117": "新洲区", + "420118": "其它区", + "420200": "黄石市", + "420202": "黄石港区", + "420203": "西塞山区", + "420204": "下陆区", + "420205": "铁山区", + "420222": "阳新县", + "420281": "大冶市", + "420282": "其它区", + "420300": "十堰市", + "420302": "茅箭区", + "420303": "张湾区", + "420321": "郧县", + "420322": "郧西县", + "420323": "竹山县", + "420324": "竹溪县", + "420325": "房县", + "420381": "丹江口市", + "420383": "其它区", + "420500": "宜昌市", + "420502": "西陵区", + "420503": "伍家岗区", + "420504": "点军区", + "420505": "猇亭区", + "420506": "夷陵区", + "420525": "远安县", + "420526": "兴山县", + "420527": "秭归县", + "420528": "长阳土家族自治县", + "420529": "五峰土家族自治县", + "420581": "宜都市", + "420582": "当阳市", + "420583": "枝江市", + "420584": "其它区", + "420600": "襄阳市", + "420602": "襄城区", + "420606": "樊城区", + "420607": "襄州区", + "420624": "南漳县", + "420625": "谷城县", + "420626": "保康县", + "420682": "老河口市", + "420683": "枣阳市", + "420684": "宜城市", + "420685": "其它区", + "420700": "鄂州市", + "420702": "梁子湖区", + "420703": "华容区", + "420704": "鄂城区", + "420705": "其它区", + "420800": "荆门市", + "420802": "东宝区", + "420804": "掇刀区", + "420821": "京山县", + "420822": "沙洋县", + "420881": "钟祥市", + "420882": "其它区", + "420900": "孝感市", + "420902": "孝南区", + "420921": "孝昌县", + "420922": "大悟县", + "420923": "云梦县", + "420981": "应城市", + "420982": "安陆市", + "420984": "汉川市", + "420985": "其它区", + "421000": "荆州市", + "421002": "沙市区", + "421003": "荆州区", + "421022": "公安县", + "421023": "监利县", + "421024": "江陵县", + "421081": "石首市", + "421083": "洪湖市", + "421087": "松滋市", + "421088": "其它区", + "421100": "黄冈市", + "421102": "黄州区", + "421121": "团风县", + "421122": "红安县", + "421123": "罗田县", + "421124": "英山县", + "421125": "浠水县", + "421126": "蕲春县", + "421127": "黄梅县", + "421181": "麻城市", + "421182": "武穴市", + "421183": "其它区", + "421200": "咸宁市", + "421202": "咸安区", + "421221": "嘉鱼县", + "421222": "通城县", + "421223": "崇阳县", + "421224": "通山县", + "421281": "赤壁市", + "421283": "其它区", + "421300": "随州市", + "421302": "曾都区", + "421321": "随县", + "421381": "广水市", + "421382": "其它区", + "422800": "恩施土家族苗族自治州", + "422801": "恩施市", + "422802": "利川市", + "422822": "建始县", + "422823": "巴东县", + "422825": "宣恩县", + "422826": "咸丰县", + "422827": "来凤县", + "422828": "鹤峰县", + "422829": "其它区", + "429004": "仙桃市", + "429005": "潜江市", + "429006": "天门市", + "429021": "神农架林区", + "430000": "湖南省", + "430100": "长沙市", + "430102": "芙蓉区", + "430103": "天心区", + "430104": "岳麓区", + "430105": "开福区", + "430111": "雨花区", + "430121": "长沙县", + "430122": "望城区", + "430124": "宁乡县", + "430181": "浏阳市", + "430182": "其它区", + "430200": "株洲市", + "430202": "荷塘区", + "430203": "芦淞区", + "430204": "石峰区", + "430211": "天元区", + "430221": "株洲县", + "430223": "攸县", + "430224": "茶陵县", + "430225": "炎陵县", + "430281": "醴陵市", + "430282": "其它区", + "430300": "湘潭市", + "430302": "雨湖区", + "430304": "岳塘区", + "430321": "湘潭县", + "430381": "湘乡市", + "430382": "韶山市", + "430383": "其它区", + "430400": "衡阳市", + "430405": "珠晖区", + "430406": "雁峰区", + "430407": "石鼓区", + "430408": "蒸湘区", + "430412": "南岳区", + "430421": "衡阳县", + "430422": "衡南县", + "430423": "衡山县", + "430424": "衡东县", + "430426": "祁东县", + "430481": "耒阳市", + "430482": "常宁市", + "430483": "其它区", + "430500": "邵阳市", + "430502": "双清区", + "430503": "大祥区", + "430511": "北塔区", + "430521": "邵东县", + "430522": "新邵县", + "430523": "邵阳县", + "430524": "隆回县", + "430525": "洞口县", + "430527": "绥宁县", + "430528": "新宁县", + "430529": "城步苗族自治县", + "430581": "武冈市", + "430582": "其它区", + "430600": "岳阳市", + "430602": "岳阳楼区", + "430603": "云溪区", + "430611": "君山区", + "430621": "岳阳县", + "430623": "华容县", + "430624": "湘阴县", + "430626": "平江县", + "430681": "汨罗市", + "430682": "临湘市", + "430683": "其它区", + "430700": "常德市", + "430702": "武陵区", + "430703": "鼎城区", + "430721": "安乡县", + "430722": "汉寿县", + "430723": "澧县", + "430724": "临澧县", + "430725": "桃源县", + "430726": "石门县", + "430781": "津市市", + "430782": "其它区", + "430800": "张家界市", + "430802": "永定区", + "430811": "武陵源区", + "430821": "慈利县", + "430822": "桑植县", + "430823": "其它区", + "430900": "益阳市", + "430902": "资阳区", + "430903": "赫山区", + "430921": "南县", + "430922": "桃江县", + "430923": "安化县", + "430981": "沅江市", + "430982": "其它区", + "431000": "郴州市", + "431002": "北湖区", + "431003": "苏仙区", + "431021": "桂阳县", + "431022": "宜章县", + "431023": "永兴县", + "431024": "嘉禾县", + "431025": "临武县", + "431026": "汝城县", + "431027": "桂东县", + "431028": "安仁县", + "431081": "资兴市", + "431082": "其它区", + "431100": "永州市", + "431102": "零陵区", + "431103": "冷水滩区", + "431121": "祁阳县", + "431122": "东安县", + "431123": "双牌县", + "431124": "道县", + "431125": "江永县", + "431126": "宁远县", + "431127": "蓝山县", + "431128": "新田县", + "431129": "江华瑶族自治县", + "431130": "其它区", + "431200": "怀化市", + "431202": "鹤城区", + "431221": "中方县", + "431222": "沅陵县", + "431223": "辰溪县", + "431224": "溆浦县", + "431225": "会同县", + "431226": "麻阳苗族自治县", + "431227": "新晃侗族自治县", + "431228": "芷江侗族自治县", + "431229": "靖州苗族侗族自治县", + "431230": "通道侗族自治县", + "431281": "洪江市", + "431282": "其它区", + "431300": "娄底市", + "431302": "娄星区", + "431321": "双峰县", + "431322": "新化县", + "431381": "冷水江市", + "431382": "涟源市", + "431383": "其它区", + "433100": "湘西土家族苗族自治州", + "433101": "吉首市", + "433122": "泸溪县", + "433123": "凤凰县", + "433124": "花垣县", + "433125": "保靖县", + "433126": "古丈县", + "433127": "永顺县", + "433130": "龙山县", + "433131": "其它区", + "440000": "广东省", + "440100": "广州市", + "440103": "荔湾区", + "440104": "越秀区", + "440105": "海珠区", + "440106": "天河区", + "440111": "白云区", + "440112": "黄埔区", + "440113": "番禺区", + "440114": "花都区", + "440115": "南沙区", + "440116": "萝岗区", + "440183": "增城市", + "440184": "从化市", + "440189": "其它区", + "440200": "韶关市", + "440203": "武江区", + "440204": "浈江区", + "440205": "曲江区", + "440222": "始兴县", + "440224": "仁化县", + "440229": "翁源县", + "440232": "乳源瑶族自治县", + "440233": "新丰县", + "440281": "乐昌市", + "440282": "南雄市", + "440283": "其它区", + "440300": "深圳市", + "440303": "罗湖区", + "440304": "福田区", + "440305": "南山区", + "440306": "宝安区", + "440307": "龙岗区", + "440308": "盐田区", + "440309": "其它区", + "440320": "光明新区", + "440321": "坪山新区", + "440322": "大鹏新区", + "440323": "龙华新区", + "440400": "珠海市", + "440402": "香洲区", + "440403": "斗门区", + "440404": "金湾区", + "440488": "其它区", + "440500": "汕头市", + "440507": "龙湖区", + "440511": "金平区", + "440512": "濠江区", + "440513": "潮阳区", + "440514": "潮南区", + "440515": "澄海区", + "440523": "南澳县", + "440524": "其它区", + "440600": "佛山市", + "440604": "禅城区", + "440605": "南海区", + "440606": "顺德区", + "440607": "三水区", + "440608": "高明区", + "440609": "其它区", + "440700": "江门市", + "440703": "蓬江区", + "440704": "江海区", + "440705": "新会区", + "440781": "台山市", + "440783": "开平市", + "440784": "鹤山市", + "440785": "恩平市", + "440786": "其它区", + "440800": "湛江市", + "440802": "赤坎区", + "440803": "霞山区", + "440804": "坡头区", + "440811": "麻章区", + "440823": "遂溪县", + "440825": "徐闻县", + "440881": "廉江市", + "440882": "雷州市", + "440883": "吴川市", + "440884": "其它区", + "440900": "茂名市", + "440902": "茂南区", + "440903": "茂港区", + "440923": "电白县", + "440981": "高州市", + "440982": "化州市", + "440983": "信宜市", + "440984": "其它区", + "441200": "肇庆市", + "441202": "端州区", + "441203": "鼎湖区", + "441223": "广宁县", + "441224": "怀集县", + "441225": "封开县", + "441226": "德庆县", + "441283": "高要市", + "441284": "四会市", + "441285": "其它区", + "441300": "惠州市", + "441302": "惠城区", + "441303": "惠阳区", + "441322": "博罗县", + "441323": "惠东县", + "441324": "龙门县", + "441325": "其它区", + "441400": "梅州市", + "441402": "梅江区", + "441421": "梅县", + "441422": "大埔县", + "441423": "丰顺县", + "441424": "五华县", + "441426": "平远县", + "441427": "蕉岭县", + "441481": "兴宁市", + "441482": "其它区", + "441500": "汕尾市", + "441502": "城区", + "441521": "海丰县", + "441523": "陆河县", + "441581": "陆丰市", + "441582": "其它区", + "441600": "河源市", + "441602": "源城区", + "441621": "紫金县", + "441622": "龙川县", + "441623": "连平县", + "441624": "和平县", + "441625": "东源县", + "441626": "其它区", + "441700": "阳江市", + "441702": "江城区", + "441721": "阳西县", + "441723": "阳东县", + "441781": "阳春市", + "441782": "其它区", + "441800": "清远市", + "441802": "清城区", + "441821": "佛冈县", + "441823": "阳山县", + "441825": "连山壮族瑶族自治县", + "441826": "连南瑶族自治县", + "441827": "清新区", + "441881": "英德市", + "441882": "连州市", + "441883": "其它区", + "441900": "东莞市", + "442000": "中山市", + "442101": "东沙群岛", + "445100": "潮州市", + "445102": "湘桥区", + "445121": "潮安区", + "445122": "饶平县", + "445186": "其它区", + "445200": "揭阳市", + "445202": "榕城区", + "445221": "揭东区", + "445222": "揭西县", + "445224": "惠来县", + "445281": "普宁市", + "445285": "其它区", + "445300": "云浮市", + "445302": "云城区", + "445321": "新兴县", + "445322": "郁南县", + "445323": "云安县", + "445381": "罗定市", + "445382": "其它区", + "450000": "广西壮族自治区", + "450100": "南宁市", + "450102": "兴宁区", + "450103": "青秀区", + "450105": "江南区", + "450107": "西乡塘区", + "450108": "良庆区", + "450109": "邕宁区", + "450122": "武鸣县", + "450123": "隆安县", + "450124": "马山县", + "450125": "上林县", + "450126": "宾阳县", + "450127": "横县", + "450128": "其它区", + "450200": "柳州市", + "450202": "城中区", + "450203": "鱼峰区", + "450204": "柳南区", + "450205": "柳北区", + "450221": "柳江县", + "450222": "柳城县", + "450223": "鹿寨县", + "450224": "融安县", + "450225": "融水苗族自治县", + "450226": "三江侗族自治县", + "450227": "其它区", + "450300": "桂林市", + "450302": "秀峰区", + "450303": "叠彩区", + "450304": "象山区", + "450305": "七星区", + "450311": "雁山区", + "450321": "阳朔县", + "450322": "临桂区", + "450323": "灵川县", + "450324": "全州县", + "450325": "兴安县", + "450326": "永福县", + "450327": "灌阳县", + "450328": "龙胜各族自治县", + "450329": "资源县", + "450330": "平乐县", + "450331": "荔浦县", + "450332": "恭城瑶族自治县", + "450333": "其它区", + "450400": "梧州市", + "450403": "万秀区", + "450405": "长洲区", + "450406": "龙圩区", + "450421": "苍梧县", + "450422": "藤县", + "450423": "蒙山县", + "450481": "岑溪市", + "450482": "其它区", + "450500": "北海市", + "450502": "海城区", + "450503": "银海区", + "450512": "铁山港区", + "450521": "合浦县", + "450522": "其它区", + "450600": "防城港市", + "450602": "港口区", + "450603": "防城区", + "450621": "上思县", + "450681": "东兴市", + "450682": "其它区", + "450700": "钦州市", + "450702": "钦南区", + "450703": "钦北区", + "450721": "灵山县", + "450722": "浦北县", + "450723": "其它区", + "450800": "贵港市", + "450802": "港北区", + "450803": "港南区", + "450804": "覃塘区", + "450821": "平南县", + "450881": "桂平市", + "450882": "其它区", + "450900": "玉林市", + "450902": "玉州区", + "450903": "福绵区", + "450921": "容县", + "450922": "陆川县", + "450923": "博白县", + "450924": "兴业县", + "450981": "北流市", + "450982": "其它区", + "451000": "百色市", + "451002": "右江区", + "451021": "田阳县", + "451022": "田东县", + "451023": "平果县", + "451024": "德保县", + "451025": "靖西县", + "451026": "那坡县", + "451027": "凌云县", + "451028": "乐业县", + "451029": "田林县", + "451030": "西林县", + "451031": "隆林各族自治县", + "451032": "其它区", + "451100": "贺州市", + "451102": "八步区", + "451119": "平桂管理区", + "451121": "昭平县", + "451122": "钟山县", + "451123": "富川瑶族自治县", + "451124": "其它区", + "451200": "河池市", + "451202": "金城江区", + "451221": "南丹县", + "451222": "天峨县", + "451223": "凤山县", + "451224": "东兰县", + "451225": "罗城仫佬族自治县", + "451226": "环江毛南族自治县", + "451227": "巴马瑶族自治县", + "451228": "都安瑶族自治县", + "451229": "大化瑶族自治县", + "451281": "宜州市", + "451282": "其它区", + "451300": "来宾市", + "451302": "兴宾区", + "451321": "忻城县", + "451322": "象州县", + "451323": "武宣县", + "451324": "金秀瑶族自治县", + "451381": "合山市", + "451382": "其它区", + "451400": "崇左市", + "451402": "江州区", + "451421": "扶绥县", + "451422": "宁明县", + "451423": "龙州县", + "451424": "大新县", + "451425": "天等县", + "451481": "凭祥市", + "451482": "其它区", + "460000": "海南省", + "460100": "海口市", + "460105": "秀英区", + "460106": "龙华区", + "460107": "琼山区", + "460108": "美兰区", + "460109": "其它区", + "460200": "三亚市", + "460300": "三沙市", + "460321": "西沙群岛", + "460322": "南沙群岛", + "460323": "中沙群岛的岛礁及其海域", + "469001": "五指山市", + "469002": "琼海市", + "469003": "儋州市", + "469005": "文昌市", + "469006": "万宁市", + "469007": "东方市", + "469025": "定安县", + "469026": "屯昌县", + "469027": "澄迈县", + "469028": "临高县", + "469030": "白沙黎族自治县", + "469031": "昌江黎族自治县", + "469033": "乐东黎族自治县", + "469034": "陵水黎族自治县", + "469035": "保亭黎族苗族自治县", + "469036": "琼中黎族苗族自治县", + "471005": "其它区", + "500000": "重庆", + "500100": "重庆市", + "500101": "万州区", + "500102": "涪陵区", + "500103": "渝中区", + "500104": "大渡口区", + "500105": "江北区", + "500106": "沙坪坝区", + "500107": "九龙坡区", + "500108": "南岸区", + "500109": "北碚区", + "500110": "万盛区", + "500111": "双桥区", + "500112": "渝北区", + "500113": "巴南区", + "500114": "黔江区", + "500115": "长寿区", + "500222": "綦江区", + "500223": "潼南县", + "500224": "铜梁县", + "500225": "大足区", + "500226": "荣昌县", + "500227": "璧山县", + "500228": "梁平县", + "500229": "城口县", + "500230": "丰都县", + "500231": "垫江县", + "500232": "武隆县", + "500233": "忠县", + "500234": "开县", + "500235": "云阳县", + "500236": "奉节县", + "500237": "巫山县", + "500238": "巫溪县", + "500240": "石柱土家族自治县", + "500241": "秀山土家族苗族自治县", + "500242": "酉阳土家族苗族自治县", + "500243": "彭水苗族土家族自治县", + "500381": "江津区", + "500382": "合川区", + "500383": "永川区", + "500384": "南川区", + "500385": "其它区", + "510000": "四川省", + "510100": "成都市", + "510104": "锦江区", + "510105": "青羊区", + "510106": "金牛区", + "510107": "武侯区", + "510108": "成华区", + "510112": "龙泉驿区", + "510113": "青白江区", + "510114": "新都区", + "510115": "温江区", + "510121": "金堂县", + "510122": "双流县", + "510124": "郫县", + "510129": "大邑县", + "510131": "蒲江县", + "510132": "新津县", + "510181": "都江堰市", + "510182": "彭州市", + "510183": "邛崃市", + "510184": "崇州市", + "510185": "其它区", + "510300": "自贡市", + "510302": "自流井区", + "510303": "贡井区", + "510304": "大安区", + "510311": "沿滩区", + "510321": "荣县", + "510322": "富顺县", + "510323": "其它区", + "510400": "攀枝花市", + "510402": "东区", + "510403": "西区", + "510411": "仁和区", + "510421": "米易县", + "510422": "盐边县", + "510423": "其它区", + "510500": "泸州市", + "510502": "江阳区", + "510503": "纳溪区", + "510504": "龙马潭区", + "510521": "泸县", + "510522": "合江县", + "510524": "叙永县", + "510525": "古蔺县", + "510526": "其它区", + "510600": "德阳市", + "510603": "旌阳区", + "510623": "中江县", + "510626": "罗江县", + "510681": "广汉市", + "510682": "什邡市", + "510683": "绵竹市", + "510684": "其它区", + "510700": "绵阳市", + "510703": "涪城区", + "510704": "游仙区", + "510722": "三台县", + "510723": "盐亭县", + "510724": "安县", + "510725": "梓潼县", + "510726": "北川羌族自治县", + "510727": "平武县", + "510781": "江油市", + "510782": "其它区", + "510800": "广元市", + "510802": "利州区", + "510811": "昭化区", + "510812": "朝天区", + "510821": "旺苍县", + "510822": "青川县", + "510823": "剑阁县", + "510824": "苍溪县", + "510825": "其它区", + "510900": "遂宁市", + "510903": "船山区", + "510904": "安居区", + "510921": "蓬溪县", + "510922": "射洪县", + "510923": "大英县", + "510924": "其它区", + "511000": "内江市", + "511002": "市中区", + "511011": "东兴区", + "511024": "威远县", + "511025": "资中县", + "511028": "隆昌县", + "511029": "其它区", + "511100": "乐山市", + "511102": "市中区", + "511111": "沙湾区", + "511112": "五通桥区", + "511113": "金口河区", + "511123": "犍为县", + "511124": "井研县", + "511126": "夹江县", + "511129": "沐川县", + "511132": "峨边彝族自治县", + "511133": "马边彝族自治县", + "511181": "峨眉山市", + "511182": "其它区", + "511300": "南充市", + "511302": "顺庆区", + "511303": "高坪区", + "511304": "嘉陵区", + "511321": "南部县", + "511322": "营山县", + "511323": "蓬安县", + "511324": "仪陇县", + "511325": "西充县", + "511381": "阆中市", + "511382": "其它区", + "511400": "眉山市", + "511402": "东坡区", + "511421": "仁寿县", + "511422": "彭山县", + "511423": "洪雅县", + "511424": "丹棱县", + "511425": "青神县", + "511426": "其它区", + "511500": "宜宾市", + "511502": "翠屏区", + "511521": "宜宾县", + "511522": "南溪区", + "511523": "江安县", + "511524": "长宁县", + "511525": "高县", + "511526": "珙县", + "511527": "筠连县", + "511528": "兴文县", + "511529": "屏山县", + "511530": "其它区", + "511600": "广安市", + "511602": "广安区", + "511603": "前锋区", + "511621": "岳池县", + "511622": "武胜县", + "511623": "邻水县", + "511681": "华蓥市", + "511683": "其它区", + "511700": "达州市", + "511702": "通川区", + "511721": "达川区", + "511722": "宣汉县", + "511723": "开江县", + "511724": "大竹县", + "511725": "渠县", + "511781": "万源市", + "511782": "其它区", + "511800": "雅安市", + "511802": "雨城区", + "511821": "名山区", + "511822": "荥经县", + "511823": "汉源县", + "511824": "石棉县", + "511825": "天全县", + "511826": "芦山县", + "511827": "宝兴县", + "511828": "其它区", + "511900": "巴中市", + "511902": "巴州区", + "511903": "恩阳区", + "511921": "通江县", + "511922": "南江县", + "511923": "平昌县", + "511924": "其它区", + "512000": "资阳市", + "512002": "雁江区", + "512021": "安岳县", + "512022": "乐至县", + "512081": "简阳市", + "512082": "其它区", + "513200": "阿坝藏族羌族自治州", + "513221": "汶川县", + "513222": "理县", + "513223": "茂县", + "513224": "松潘县", + "513225": "九寨沟县", + "513226": "金川县", + "513227": "小金县", + "513228": "黑水县", + "513229": "马尔康县", + "513230": "壤塘县", + "513231": "阿坝县", + "513232": "若尔盖县", + "513233": "红原县", + "513234": "其它区", + "513300": "甘孜藏族自治州", + "513321": "康定县", + "513322": "泸定县", + "513323": "丹巴县", + "513324": "九龙县", + "513325": "雅江县", + "513326": "道孚县", + "513327": "炉霍县", + "513328": "甘孜县", + "513329": "新龙县", + "513330": "德格县", + "513331": "白玉县", + "513332": "石渠县", + "513333": "色达县", + "513334": "理塘县", + "513335": "巴塘县", + "513336": "乡城县", + "513337": "稻城县", + "513338": "得荣县", + "513339": "其它区", + "513400": "凉山彝族自治州", + "513401": "西昌市", + "513422": "木里藏族自治县", + "513423": "盐源县", + "513424": "德昌县", + "513425": "会理县", + "513426": "会东县", + "513427": "宁南县", + "513428": "普格县", + "513429": "布拖县", + "513430": "金阳县", + "513431": "昭觉县", + "513432": "喜德县", + "513433": "冕宁县", + "513434": "越西县", + "513435": "甘洛县", + "513436": "美姑县", + "513437": "雷波县", + "513438": "其它区", + "520000": "贵州省", + "520100": "贵阳市", + "520102": "南明区", + "520103": "云岩区", + "520111": "花溪区", + "520112": "乌当区", + "520113": "白云区", + "520121": "开阳县", + "520122": "息烽县", + "520123": "修文县", + "520151": "观山湖区", + "520181": "清镇市", + "520182": "其它区", + "520200": "六盘水市", + "520201": "钟山区", + "520203": "六枝特区", + "520221": "水城县", + "520222": "盘县", + "520223": "其它区", + "520300": "遵义市", + "520302": "红花岗区", + "520303": "汇川区", + "520321": "遵义县", + "520322": "桐梓县", + "520323": "绥阳县", + "520324": "正安县", + "520325": "道真仡佬族苗族自治县", + "520326": "务川仡佬族苗族自治县", + "520327": "凤冈县", + "520328": "湄潭县", + "520329": "余庆县", + "520330": "习水县", + "520381": "赤水市", + "520382": "仁怀市", + "520383": "其它区", + "520400": "安顺市", + "520402": "西秀区", + "520421": "平坝县", + "520422": "普定县", + "520423": "镇宁布依族苗族自治县", + "520424": "关岭布依族苗族自治县", + "520425": "紫云苗族布依族自治县", + "520426": "其它区", + "522200": "铜仁市", + "522201": "碧江区", + "522222": "江口县", + "522223": "玉屏侗族自治县", + "522224": "石阡县", + "522225": "思南县", + "522226": "印江土家族苗族自治县", + "522227": "德江县", + "522228": "沿河土家族自治县", + "522229": "松桃苗族自治县", + "522230": "万山区", + "522231": "其它区", + "522300": "黔西南布依族苗族自治州", + "522301": "兴义市", + "522322": "兴仁县", + "522323": "普安县", + "522324": "晴隆县", + "522325": "贞丰县", + "522326": "望谟县", + "522327": "册亨县", + "522328": "安龙县", + "522329": "其它区", + "522400": "毕节市", + "522401": "七星关区", + "522422": "大方县", + "522423": "黔西县", + "522424": "金沙县", + "522425": "织金县", + "522426": "纳雍县", + "522427": "威宁彝族回族苗族自治县", + "522428": "赫章县", + "522429": "其它区", + "522600": "黔东南苗族侗族自治州", + "522601": "凯里市", + "522622": "黄平县", + "522623": "施秉县", + "522624": "三穗县", + "522625": "镇远县", + "522626": "岑巩县", + "522627": "天柱县", + "522628": "锦屏县", + "522629": "剑河县", + "522630": "台江县", + "522631": "黎平县", + "522632": "榕江县", + "522633": "从江县", + "522634": "雷山县", + "522635": "麻江县", + "522636": "丹寨县", + "522637": "其它区", + "522700": "黔南布依族苗族自治州", + "522701": "都匀市", + "522702": "福泉市", + "522722": "荔波县", + "522723": "贵定县", + "522725": "瓮安县", + "522726": "独山县", + "522727": "平塘县", + "522728": "罗甸县", + "522729": "长顺县", + "522730": "龙里县", + "522731": "惠水县", + "522732": "三都水族自治县", + "522733": "其它区", + "530000": "云南省", + "530100": "昆明市", + "530102": "五华区", + "530103": "盘龙区", + "530111": "官渡区", + "530112": "西山区", + "530113": "东川区", + "530121": "呈贡区", + "530122": "晋宁县", + "530124": "富民县", + "530125": "宜良县", + "530126": "石林彝族自治县", + "530127": "嵩明县", + "530128": "禄劝彝族苗族自治县", + "530129": "寻甸回族彝族自治县", + "530181": "安宁市", + "530182": "其它区", + "530300": "曲靖市", + "530302": "麒麟区", + "530321": "马龙县", + "530322": "陆良县", + "530323": "师宗县", + "530324": "罗平县", + "530325": "富源县", + "530326": "会泽县", + "530328": "沾益县", + "530381": "宣威市", + "530382": "其它区", + "530400": "玉溪市", + "530402": "红塔区", + "530421": "江川县", + "530422": "澄江县", + "530423": "通海县", + "530424": "华宁县", + "530425": "易门县", + "530426": "峨山彝族自治县", + "530427": "新平彝族傣族自治县", + "530428": "元江哈尼族彝族傣族自治县", + "530429": "其它区", + "530500": "保山市", + "530502": "隆阳区", + "530521": "施甸县", + "530522": "腾冲县", + "530523": "龙陵县", + "530524": "昌宁县", + "530525": "其它区", + "530600": "昭通市", + "530602": "昭阳区", + "530621": "鲁甸县", + "530622": "巧家县", + "530623": "盐津县", + "530624": "大关县", + "530625": "永善县", + "530626": "绥江县", + "530627": "镇雄县", + "530628": "彝良县", + "530629": "威信县", + "530630": "水富县", + "530631": "其它区", + "530700": "丽江市", + "530702": "古城区", + "530721": "玉龙纳西族自治县", + "530722": "永胜县", + "530723": "华坪县", + "530724": "宁蒗彝族自治县", + "530725": "其它区", + "530800": "普洱市", + "530802": "思茅区", + "530821": "宁洱哈尼族彝族自治县", + "530822": "墨江哈尼族自治县", + "530823": "景东彝族自治县", + "530824": "景谷傣族彝族自治县", + "530825": "镇沅彝族哈尼族拉祜族自治县", + "530826": "江城哈尼族彝族自治县", + "530827": "孟连傣族拉祜族佤族自治县", + "530828": "澜沧拉祜族自治县", + "530829": "西盟佤族自治县", + "530830": "其它区", + "530900": "临沧市", + "530902": "临翔区", + "530921": "凤庆县", + "530922": "云县", + "530923": "永德县", + "530924": "镇康县", + "530925": "双江拉祜族佤族布朗族傣族自治县", + "530926": "耿马傣族佤族自治县", + "530927": "沧源佤族自治县", + "530928": "其它区", + "532300": "楚雄彝族自治州", + "532301": "楚雄市", + "532322": "双柏县", + "532323": "牟定县", + "532324": "南华县", + "532325": "姚安县", + "532326": "大姚县", + "532327": "永仁县", + "532328": "元谋县", + "532329": "武定县", + "532331": "禄丰县", + "532332": "其它区", + "532500": "红河哈尼族彝族自治州", + "532501": "个旧市", + "532502": "开远市", + "532522": "蒙自市", + "532523": "屏边苗族自治县", + "532524": "建水县", + "532525": "石屏县", + "532526": "弥勒市", + "532527": "泸西县", + "532528": "元阳县", + "532529": "红河县", + "532530": "金平苗族瑶族傣族自治县", + "532531": "绿春县", + "532532": "河口瑶族自治县", + "532533": "其它区", + "532600": "文山壮族苗族自治州", + "532621": "文山市", + "532622": "砚山县", + "532623": "西畴县", + "532624": "麻栗坡县", + "532625": "马关县", + "532626": "丘北县", + "532627": "广南县", + "532628": "富宁县", + "532629": "其它区", + "532800": "西双版纳傣族自治州", + "532801": "景洪市", + "532822": "勐海县", + "532823": "勐腊县", + "532824": "其它区", + "532900": "大理白族自治州", + "532901": "大理市", + "532922": "漾濞彝族自治县", + "532923": "祥云县", + "532924": "宾川县", + "532925": "弥渡县", + "532926": "南涧彝族自治县", + "532927": "巍山彝族回族自治县", + "532928": "永平县", + "532929": "云龙县", + "532930": "洱源县", + "532931": "剑川县", + "532932": "鹤庆县", + "532933": "其它区", + "533100": "德宏傣族景颇族自治州", + "533102": "瑞丽市", + "533103": "芒市", + "533122": "梁河县", + "533123": "盈江县", + "533124": "陇川县", + "533125": "其它区", + "533300": "怒江傈僳族自治州", + "533321": "泸水县", + "533323": "福贡县", + "533324": "贡山独龙族怒族自治县", + "533325": "兰坪白族普米族自治县", + "533326": "其它区", + "533400": "迪庆藏族自治州", + "533421": "香格里拉县", + "533422": "德钦县", + "533423": "维西傈僳族自治县", + "533424": "其它区", + "540000": "西藏自治区", + "540100": "拉萨市", + "540102": "城关区", + "540121": "林周县", + "540122": "当雄县", + "540123": "尼木县", + "540124": "曲水县", + "540125": "堆龙德庆县", + "540126": "达孜县", + "540127": "墨竹工卡县", + "540128": "其它区", + "542100": "昌都地区", + "542121": "昌都县", + "542122": "江达县", + "542123": "贡觉县", + "542124": "类乌齐县", + "542125": "丁青县", + "542126": "察雅县", + "542127": "八宿县", + "542128": "左贡县", + "542129": "芒康县", + "542132": "洛隆县", + "542133": "边坝县", + "542134": "其它区", + "542200": "山南地区", + "542221": "乃东县", + "542222": "扎囊县", + "542223": "贡嘎县", + "542224": "桑日县", + "542225": "琼结县", + "542226": "曲松县", + "542227": "措美县", + "542228": "洛扎县", + "542229": "加查县", + "542231": "隆子县", + "542232": "错那县", + "542233": "浪卡子县", + "542234": "其它区", + "542300": "日喀则地区", + "542301": "日喀则市", + "542322": "南木林县", + "542323": "江孜县", + "542324": "定日县", + "542325": "萨迦县", + "542326": "拉孜县", + "542327": "昂仁县", + "542328": "谢通门县", + "542329": "白朗县", + "542330": "仁布县", + "542331": "康马县", + "542332": "定结县", + "542333": "仲巴县", + "542334": "亚东县", + "542335": "吉隆县", + "542336": "聂拉木县", + "542337": "萨嘎县", + "542338": "岗巴县", + "542339": "其它区", + "542400": "那曲地区", + "542421": "那曲县", + "542422": "嘉黎县", + "542423": "比如县", + "542424": "聂荣县", + "542425": "安多县", + "542426": "申扎县", + "542427": "索县", + "542428": "班戈县", + "542429": "巴青县", + "542430": "尼玛县", + "542431": "其它区", + "542432": "双湖县", + "542500": "阿里地区", + "542521": "普兰县", + "542522": "札达县", + "542523": "噶尔县", + "542524": "日土县", + "542525": "革吉县", + "542526": "改则县", + "542527": "措勤县", + "542528": "其它区", + "542600": "林芝地区", + "542621": "林芝县", + "542622": "工布江达县", + "542623": "米林县", + "542624": "墨脱县", + "542625": "波密县", + "542626": "察隅县", + "542627": "朗县", + "542628": "其它区", + "610000": "陕西省", + "610100": "西安市", + "610102": "新城区", + "610103": "碑林区", + "610104": "莲湖区", + "610111": "灞桥区", + "610112": "未央区", + "610113": "雁塔区", + "610114": "阎良区", + "610115": "临潼区", + "610116": "长安区", + "610122": "蓝田县", + "610124": "周至县", + "610125": "户县", + "610126": "高陵县", + "610127": "其它区", + "610200": "铜川市", + "610202": "王益区", + "610203": "印台区", + "610204": "耀州区", + "610222": "宜君县", + "610223": "其它区", + "610300": "宝鸡市", + "610302": "渭滨区", + "610303": "金台区", + "610304": "陈仓区", + "610322": "凤翔县", + "610323": "岐山县", + "610324": "扶风县", + "610326": "眉县", + "610327": "陇县", + "610328": "千阳县", + "610329": "麟游县", + "610330": "凤县", + "610331": "太白县", + "610332": "其它区", + "610400": "咸阳市", + "610402": "秦都区", + "610403": "杨陵区", + "610404": "渭城区", + "610422": "三原县", + "610423": "泾阳县", + "610424": "乾县", + "610425": "礼泉县", + "610426": "永寿县", + "610427": "彬县", + "610428": "长武县", + "610429": "旬邑县", + "610430": "淳化县", + "610431": "武功县", + "610481": "兴平市", + "610482": "其它区", + "610500": "渭南市", + "610502": "临渭区", + "610521": "华县", + "610522": "潼关县", + "610523": "大荔县", + "610524": "合阳县", + "610525": "澄城县", + "610526": "蒲城县", + "610527": "白水县", + "610528": "富平县", + "610581": "韩城市", + "610582": "华阴市", + "610583": "其它区", + "610600": "延安市", + "610602": "宝塔区", + "610621": "延长县", + "610622": "延川县", + "610623": "子长县", + "610624": "安塞县", + "610625": "志丹县", + "610626": "吴起县", + "610627": "甘泉县", + "610628": "富县", + "610629": "洛川县", + "610630": "宜川县", + "610631": "黄龙县", + "610632": "黄陵县", + "610633": "其它区", + "610700": "汉中市", + "610702": "汉台区", + "610721": "南郑县", + "610722": "城固县", + "610723": "洋县", + "610724": "西乡县", + "610725": "勉县", + "610726": "宁强县", + "610727": "略阳县", + "610728": "镇巴县", + "610729": "留坝县", + "610730": "佛坪县", + "610731": "其它区", + "610800": "榆林市", + "610802": "榆阳区", + "610821": "神木县", + "610822": "府谷县", + "610823": "横山县", + "610824": "靖边县", + "610825": "定边县", + "610826": "绥德县", + "610827": "米脂县", + "610828": "佳县", + "610829": "吴堡县", + "610830": "清涧县", + "610831": "子洲县", + "610832": "其它区", + "610900": "安康市", + "610902": "汉滨区", + "610921": "汉阴县", + "610922": "石泉县", + "610923": "宁陕县", + "610924": "紫阳县", + "610925": "岚皋县", + "610926": "平利县", + "610927": "镇坪县", + "610928": "旬阳县", + "610929": "白河县", + "610930": "其它区", + "611000": "商洛市", + "611002": "商州区", + "611021": "洛南县", + "611022": "丹凤县", + "611023": "商南县", + "611024": "山阳县", + "611025": "镇安县", + "611026": "柞水县", + "611027": "其它区", + "620000": "甘肃省", + "620100": "兰州市", + "620102": "城关区", + "620103": "七里河区", + "620104": "西固区", + "620105": "安宁区", + "620111": "红古区", + "620121": "永登县", + "620122": "皋兰县", + "620123": "榆中县", + "620124": "其它区", + "620200": "嘉峪关市", + "620300": "金昌市", + "620302": "金川区", + "620321": "永昌县", + "620322": "其它区", + "620400": "白银市", + "620402": "白银区", + "620403": "平川区", + "620421": "靖远县", + "620422": "会宁县", + "620423": "景泰县", + "620424": "其它区", + "620500": "天水市", + "620502": "秦州区", + "620503": "麦积区", + "620521": "清水县", + "620522": "秦安县", + "620523": "甘谷县", + "620524": "武山县", + "620525": "张家川回族自治县", + "620526": "其它区", + "620600": "武威市", + "620602": "凉州区", + "620621": "民勤县", + "620622": "古浪县", + "620623": "天祝藏族自治县", + "620624": "其它区", + "620700": "张掖市", + "620702": "甘州区", + "620721": "肃南裕固族自治县", + "620722": "民乐县", + "620723": "临泽县", + "620724": "高台县", + "620725": "山丹县", + "620726": "其它区", + "620800": "平凉市", + "620802": "崆峒区", + "620821": "泾川县", + "620822": "灵台县", + "620823": "崇信县", + "620824": "华亭县", + "620825": "庄浪县", + "620826": "静宁县", + "620827": "其它区", + "620900": "酒泉市", + "620902": "肃州区", + "620921": "金塔县", + "620922": "瓜州县", + "620923": "肃北蒙古族自治县", + "620924": "阿克塞哈萨克族自治县", + "620981": "玉门市", + "620982": "敦煌市", + "620983": "其它区", + "621000": "庆阳市", + "621002": "西峰区", + "621021": "庆城县", + "621022": "环县", + "621023": "华池县", + "621024": "合水县", + "621025": "正宁县", + "621026": "宁县", + "621027": "镇原县", + "621028": "其它区", + "621100": "定西市", + "621102": "安定区", + "621121": "通渭县", + "621122": "陇西县", + "621123": "渭源县", + "621124": "临洮县", + "621125": "漳县", + "621126": "岷县", + "621127": "其它区", + "621200": "陇南市", + "621202": "武都区", + "621221": "成县", + "621222": "文县", + "621223": "宕昌县", + "621224": "康县", + "621225": "西和县", + "621226": "礼县", + "621227": "徽县", + "621228": "两当县", + "621229": "其它区", + "622900": "临夏回族自治州", + "622901": "临夏市", + "622921": "临夏县", + "622922": "康乐县", + "622923": "永靖县", + "622924": "广河县", + "622925": "和政县", + "622926": "东乡族自治县", + "622927": "积石山保安族东乡族撒拉族自治县", + "622928": "其它区", + "623000": "甘南藏族自治州", + "623001": "合作市", + "623021": "临潭县", + "623022": "卓尼县", + "623023": "舟曲县", + "623024": "迭部县", + "623025": "玛曲县", + "623026": "碌曲县", + "623027": "夏河县", + "623028": "其它区", + "630000": "青海省", + "630100": "西宁市", + "630102": "城东区", + "630103": "城中区", + "630104": "城西区", + "630105": "城北区", + "630121": "大通回族土族自治县", + "630122": "湟中县", + "630123": "湟源县", + "630124": "其它区", + "632100": "海东市", + "632121": "平安县", + "632122": "民和回族土族自治县", + "632123": "乐都区", + "632126": "互助土族自治县", + "632127": "化隆回族自治县", + "632128": "循化撒拉族自治县", + "632129": "其它区", + "632200": "海北藏族自治州", + "632221": "门源回族自治县", + "632222": "祁连县", + "632223": "海晏县", + "632224": "刚察县", + "632225": "其它区", + "632300": "黄南藏族自治州", + "632321": "同仁县", + "632322": "尖扎县", + "632323": "泽库县", + "632324": "河南蒙古族自治县", + "632325": "其它区", + "632500": "海南藏族自治州", + "632521": "共和县", + "632522": "同德县", + "632523": "贵德县", + "632524": "兴海县", + "632525": "贵南县", + "632526": "其它区", + "632600": "果洛藏族自治州", + "632621": "玛沁县", + "632622": "班玛县", + "632623": "甘德县", + "632624": "达日县", + "632625": "久治县", + "632626": "玛多县", + "632627": "其它区", + "632700": "玉树藏族自治州", + "632721": "玉树市", + "632722": "杂多县", + "632723": "称多县", + "632724": "治多县", + "632725": "囊谦县", + "632726": "曲麻莱县", + "632727": "其它区", + "632800": "海西蒙古族藏族自治州", + "632801": "格尔木市", + "632802": "德令哈市", + "632821": "乌兰县", + "632822": "都兰县", + "632823": "天峻县", + "632824": "其它区", + "640000": "宁夏回族自治区", + "640100": "银川市", + "640104": "兴庆区", + "640105": "西夏区", + "640106": "金凤区", + "640121": "永宁县", + "640122": "贺兰县", + "640181": "灵武市", + "640182": "其它区", + "640200": "石嘴山市", + "640202": "大武口区", + "640205": "惠农区", + "640221": "平罗县", + "640222": "其它区", + "640300": "吴忠市", + "640302": "利通区", + "640303": "红寺堡区", + "640323": "盐池县", + "640324": "同心县", + "640381": "青铜峡市", + "640382": "其它区", + "640400": "固原市", + "640402": "原州区", + "640422": "西吉县", + "640423": "隆德县", + "640424": "泾源县", + "640425": "彭阳县", + "640426": "其它区", + "640500": "中卫市", + "640502": "沙坡头区", + "640521": "中宁县", + "640522": "海原县", + "640523": "其它区", + "650000": "新疆维吾尔自治区", + "650100": "乌鲁木齐市", + "650102": "天山区", + "650103": "沙依巴克区", + "650104": "新市区", + "650105": "水磨沟区", + "650106": "头屯河区", + "650107": "达坂城区", + "650109": "米东区", + "650121": "乌鲁木齐县", + "650122": "其它区", + "650200": "克拉玛依市", + "650202": "独山子区", + "650203": "克拉玛依区", + "650204": "白碱滩区", + "650205": "乌尔禾区", + "650206": "其它区", + "652100": "吐鲁番地区", + "652101": "吐鲁番市", + "652122": "鄯善县", + "652123": "托克逊县", + "652124": "其它区", + "652200": "哈密地区", + "652201": "哈密市", + "652222": "巴里坤哈萨克自治县", + "652223": "伊吾县", + "652224": "其它区", + "652300": "昌吉回族自治州", + "652301": "昌吉市", + "652302": "阜康市", + "652323": "呼图壁县", + "652324": "玛纳斯县", + "652325": "奇台县", + "652327": "吉木萨尔县", + "652328": "木垒哈萨克自治县", + "652329": "其它区", + "652700": "博尔塔拉蒙古自治州", + "652701": "博乐市", + "652702": "阿拉山口市", + "652722": "精河县", + "652723": "温泉县", + "652724": "其它区", + "652800": "巴音郭楞蒙古自治州", + "652801": "库尔勒市", + "652822": "轮台县", + "652823": "尉犁县", + "652824": "若羌县", + "652825": "且末县", + "652826": "焉耆回族自治县", + "652827": "和静县", + "652828": "和硕县", + "652829": "博湖县", + "652830": "其它区", + "652900": "阿克苏地区", + "652901": "阿克苏市", + "652922": "温宿县", + "652923": "库车县", + "652924": "沙雅县", + "652925": "新和县", + "652926": "拜城县", + "652927": "乌什县", + "652928": "阿瓦提县", + "652929": "柯坪县", + "652930": "其它区", + "653000": "克孜勒苏柯尔克孜自治州", + "653001": "阿图什市", + "653022": "阿克陶县", + "653023": "阿合奇县", + "653024": "乌恰县", + "653025": "其它区", + "653100": "喀什地区", + "653101": "喀什市", + "653121": "疏附县", + "653122": "疏勒县", + "653123": "英吉沙县", + "653124": "泽普县", + "653125": "莎车县", + "653126": "叶城县", + "653127": "麦盖提县", + "653128": "岳普湖县", + "653129": "伽师县", + "653130": "巴楚县", + "653131": "塔什库尔干塔吉克自治县", + "653132": "其它区", + "653200": "和田地区", + "653201": "和田市", + "653221": "和田县", + "653222": "墨玉县", + "653223": "皮山县", + "653224": "洛浦县", + "653225": "策勒县", + "653226": "于田县", + "653227": "民丰县", + "653228": "其它区", + "654000": "伊犁哈萨克自治州", + "654002": "伊宁市", + "654003": "奎屯市", + "654021": "伊宁县", + "654022": "察布查尔锡伯自治县", + "654023": "霍城县", + "654024": "巩留县", + "654025": "新源县", + "654026": "昭苏县", + "654027": "特克斯县", + "654028": "尼勒克县", + "654029": "其它区", + "654200": "塔城地区", + "654201": "塔城市", + "654202": "乌苏市", + "654221": "额敏县", + "654223": "沙湾县", + "654224": "托里县", + "654225": "裕民县", + "654226": "和布克赛尔蒙古自治县", + "654227": "其它区", + "654300": "阿勒泰地区", + "654301": "阿勒泰市", + "654321": "布尔津县", + "654322": "富蕴县", + "654323": "福海县", + "654324": "哈巴河县", + "654325": "青河县", + "654326": "吉木乃县", + "654327": "其它区", + "659001": "石河子市", + "659002": "阿拉尔市", + "659003": "图木舒克市", + "659004": "五家渠市", + "710000": "台湾", + "710100": "台北市", + "710101": "中正区", + "710102": "大同区", + "710103": "中山区", + "710104": "松山区", + "710105": "大安区", + "710106": "万华区", + "710107": "信义区", + "710108": "士林区", + "710109": "北投区", + "710110": "内湖区", + "710111": "南港区", + "710112": "文山区", + "710113": "其它区", + "710200": "高雄市", + "710201": "新兴区", + "710202": "前金区", + "710203": "芩雅区", + "710204": "盐埕区", + "710205": "鼓山区", + "710206": "旗津区", + "710207": "前镇区", + "710208": "三民区", + "710209": "左营区", + "710210": "楠梓区", + "710211": "小港区", + "710212": "其它区", + "710241": "苓雅区", + "710242": "仁武区", + "710243": "大社区", + "710244": "冈山区", + "710245": "路竹区", + "710246": "阿莲区", + "710247": "田寮区", + "710248": "燕巢区", + "710249": "桥头区", + "710250": "梓官区", + "710251": "弥陀区", + "710252": "永安区", + "710253": "湖内区", + "710254": "凤山区", + "710255": "大寮区", + "710256": "林园区", + "710257": "鸟松区", + "710258": "大树区", + "710259": "旗山区", + "710260": "美浓区", + "710261": "六龟区", + "710262": "内门区", + "710263": "杉林区", + "710264": "甲仙区", + "710265": "桃源区", + "710266": "那玛夏区", + "710267": "茂林区", + "710268": "茄萣区", + "710300": "台南市", + "710301": "中西区", + "710302": "东区", + "710303": "南区", + "710304": "北区", + "710305": "安平区", + "710306": "安南区", + "710307": "其它区", + "710339": "永康区", + "710340": "归仁区", + "710341": "新化区", + "710342": "左镇区", + "710343": "玉井区", + "710344": "楠西区", + "710345": "南化区", + "710346": "仁德区", + "710347": "关庙区", + "710348": "龙崎区", + "710349": "官田区", + "710350": "麻豆区", + "710351": "佳里区", + "710352": "西港区", + "710353": "七股区", + "710354": "将军区", + "710355": "学甲区", + "710356": "北门区", + "710357": "新营区", + "710358": "后壁区", + "710359": "白河区", + "710360": "东山区", + "710361": "六甲区", + "710362": "下营区", + "710363": "柳营区", + "710364": "盐水区", + "710365": "善化区", + "710366": "大内区", + "710367": "山上区", + "710368": "新市区", + "710369": "安定区", + "710400": "台中市", + "710401": "中区", + "710402": "东区", + "710403": "南区", + "710404": "西区", + "710405": "北区", + "710406": "北屯区", + "710407": "西屯区", + "710408": "南屯区", + "710409": "其它区", + "710431": "太平区", + "710432": "大里区", + "710433": "雾峰区", + "710434": "乌日区", + "710435": "丰原区", + "710436": "后里区", + "710437": "石冈区", + "710438": "东势区", + "710439": "和平区", + "710440": "新社区", + "710441": "潭子区", + "710442": "大雅区", + "710443": "神冈区", + "710444": "大肚区", + "710445": "沙鹿区", + "710446": "龙井区", + "710447": "梧栖区", + "710448": "清水区", + "710449": "大甲区", + "710450": "外埔区", + "710451": "大安区", + "710500": "金门县", + "710507": "金沙镇", + "710508": "金湖镇", + "710509": "金宁乡", + "710510": "金城镇", + "710511": "烈屿乡", + "710512": "乌坵乡", + "710600": "南投县", + "710614": "南投市", + "710615": "中寮乡", + "710616": "草屯镇", + "710617": "国姓乡", + "710618": "埔里镇", + "710619": "仁爱乡", + "710620": "名间乡", + "710621": "集集镇", + "710622": "水里乡", + "710623": "鱼池乡", + "710624": "信义乡", + "710625": "竹山镇", + "710626": "鹿谷乡", + "710700": "基隆市", + "710701": "仁爱区", + "710702": "信义区", + "710703": "中正区", + "710704": "中山区", + "710705": "安乐区", + "710706": "暖暖区", + "710707": "七堵区", + "710708": "其它区", + "710800": "新竹市", + "710801": "东区", + "710802": "北区", + "710803": "香山区", + "710804": "其它区", + "710900": "嘉义市", + "710901": "东区", + "710902": "西区", + "710903": "其它区", + "711100": "新北市", + "711130": "万里区", + "711131": "金山区", + "711132": "板桥区", + "711133": "汐止区", + "711134": "深坑区", + "711135": "石碇区", + "711136": "瑞芳区", + "711137": "平溪区", + "711138": "双溪区", + "711139": "贡寮区", + "711140": "新店区", + "711141": "坪林区", + "711142": "乌来区", + "711143": "永和区", + "711144": "中和区", + "711145": "土城区", + "711146": "三峡区", + "711147": "树林区", + "711148": "莺歌区", + "711149": "三重区", + "711150": "新庄区", + "711151": "泰山区", + "711152": "林口区", + "711153": "芦洲区", + "711154": "五股区", + "711155": "八里区", + "711156": "淡水区", + "711157": "三芝区", + "711158": "石门区", + "711200": "宜兰县", + "711214": "宜兰市", + "711215": "头城镇", + "711216": "礁溪乡", + "711217": "壮围乡", + "711218": "员山乡", + "711219": "罗东镇", + "711220": "三星乡", + "711221": "大同乡", + "711222": "五结乡", + "711223": "冬山乡", + "711224": "苏澳镇", + "711225": "南澳乡", + "711226": "钓鱼台", + "711300": "新竹县", + "711314": "竹北市", + "711315": "湖口乡", + "711316": "新丰乡", + "711317": "新埔镇", + "711318": "关西镇", + "711319": "芎林乡", + "711320": "宝山乡", + "711321": "竹东镇", + "711322": "五峰乡", + "711323": "横山乡", + "711324": "尖石乡", + "711325": "北埔乡", + "711326": "峨眉乡", + "711400": "桃园县", + "711414": "中坜市", + "711415": "平镇市", + "711416": "龙潭乡", + "711417": "杨梅市", + "711418": "新屋乡", + "711419": "观音乡", + "711420": "桃园市", + "711421": "龟山乡", + "711422": "八德市", + "711423": "大溪镇", + "711424": "复兴乡", + "711425": "大园乡", + "711426": "芦竹乡", + "711500": "苗栗县", + "711519": "竹南镇", + "711520": "头份镇", + "711521": "三湾乡", + "711522": "南庄乡", + "711523": "狮潭乡", + "711524": "后龙镇", + "711525": "通霄镇", + "711526": "苑里镇", + "711527": "苗栗市", + "711528": "造桥乡", + "711529": "头屋乡", + "711530": "公馆乡", + "711531": "大湖乡", + "711532": "泰安乡", + "711533": "铜锣乡", + "711534": "三义乡", + "711535": "西湖乡", + "711536": "卓兰镇", + "711700": "彰化县", + "711727": "彰化市", + "711728": "芬园乡", + "711729": "花坛乡", + "711730": "秀水乡", + "711731": "鹿港镇", + "711732": "福兴乡", + "711733": "线西乡", + "711734": "和美镇", + "711735": "伸港乡", + "711736": "员林镇", + "711737": "社头乡", + "711738": "永靖乡", + "711739": "埔心乡", + "711740": "溪湖镇", + "711741": "大村乡", + "711742": "埔盐乡", + "711743": "田中镇", + "711744": "北斗镇", + "711745": "田尾乡", + "711746": "埤头乡", + "711747": "溪州乡", + "711748": "竹塘乡", + "711749": "二林镇", + "711750": "大城乡", + "711751": "芳苑乡", + "711752": "二水乡", + "711900": "嘉义县", + "711919": "番路乡", + "711920": "梅山乡", + "711921": "竹崎乡", + "711922": "阿里山乡", + "711923": "中埔乡", + "711924": "大埔乡", + "711925": "水上乡", + "711926": "鹿草乡", + "711927": "太保市", + "711928": "朴子市", + "711929": "东石乡", + "711930": "六脚乡", + "711931": "新港乡", + "711932": "民雄乡", + "711933": "大林镇", + "711934": "溪口乡", + "711935": "义竹乡", + "711936": "布袋镇", + "712100": "云林县", + "712121": "斗南镇", + "712122": "大埤乡", + "712123": "虎尾镇", + "712124": "土库镇", + "712125": "褒忠乡", + "712126": "东势乡", + "712127": "台西乡", + "712128": "仑背乡", + "712129": "麦寮乡", + "712130": "斗六市", + "712131": "林内乡", + "712132": "古坑乡", + "712133": "莿桐乡", + "712134": "西螺镇", + "712135": "二仑乡", + "712136": "北港镇", + "712137": "水林乡", + "712138": "口湖乡", + "712139": "四湖乡", + "712140": "元长乡", + "712400": "屏东县", + "712434": "屏东市", + "712435": "三地门乡", + "712436": "雾台乡", + "712437": "玛家乡", + "712438": "九如乡", + "712439": "里港乡", + "712440": "高树乡", + "712441": "盐埔乡", + "712442": "长治乡", + "712443": "麟洛乡", + "712444": "竹田乡", + "712445": "内埔乡", + "712446": "万丹乡", + "712447": "潮州镇", + "712448": "泰武乡", + "712449": "来义乡", + "712450": "万峦乡", + "712451": "崁顶乡", + "712452": "新埤乡", + "712453": "南州乡", + "712454": "林边乡", + "712455": "东港镇", + "712456": "琉球乡", + "712457": "佳冬乡", + "712458": "新园乡", + "712459": "枋寮乡", + "712460": "枋山乡", + "712461": "春日乡", + "712462": "狮子乡", + "712463": "车城乡", + "712464": "牡丹乡", + "712465": "恒春镇", + "712466": "满州乡", + "712500": "台东县", + "712517": "台东市", + "712518": "绿岛乡", + "712519": "兰屿乡", + "712520": "延平乡", + "712521": "卑南乡", + "712522": "鹿野乡", + "712523": "关山镇", + "712524": "海端乡", + "712525": "池上乡", + "712526": "东河乡", + "712527": "成功镇", + "712528": "长滨乡", + "712529": "金峰乡", + "712530": "大武乡", + "712531": "达仁乡", + "712532": "太麻里乡", + "712600": "花莲县", + "712615": "花莲市", + "712616": "新城乡", + "712617": "太鲁阁", + "712618": "秀林乡", + "712619": "吉安乡", + "712620": "寿丰乡", + "712621": "凤林镇", + "712622": "光复乡", + "712623": "丰滨乡", + "712624": "瑞穗乡", + "712625": "万荣乡", + "712626": "玉里镇", + "712627": "卓溪乡", + "712628": "富里乡", + "712700": "澎湖县", + "712707": "马公市", + "712708": "西屿乡", + "712709": "望安乡", + "712710": "七美乡", + "712711": "白沙乡", + "712712": "湖西乡", + "712800": "连江县", + "712805": "南竿乡", + "712806": "北竿乡", + "712807": "莒光乡", + "712808": "东引乡", + "810000": "香港特别行政区", + "810100": "香港岛", + "810101": "中西区", + "810102": "湾仔", + "810103": "东区", + "810104": "南区", + "810200": "九龙", + "810201": "九龙城区", + "810202": "油尖旺区", + "810203": "深水埗区", + "810204": "黄大仙区", + "810205": "观塘区", + "810300": "新界", + "810301": "北区", + "810302": "大埔区", + "810303": "沙田区", + "810304": "西贡区", + "810305": "元朗区", + "810306": "屯门区", + "810307": "荃湾区", + "810308": "葵青区", + "810309": "离岛区", + "820000": "澳门特别行政区", + "820100": "澳门半岛", + "820200": "离岛", + "990000": "海外", + "990100": "海外" + } + + // id pid/parentId name children + function tree(list) { + var mapped = {} + for (var i = 0, item; i < list.length; i++) { + item = list[i] + if (!item || !item.id) continue + mapped[item.id] = item + } + + var result = [] + for (var ii = 0; ii < list.length; ii++) { + item = list[ii] + + if (!item) continue + /* jshint -W041 */ + if (item.pid == undefined && item.parentId == undefined) { + result.push(item) + continue + } + var parent = mapped[item.pid] || mapped[item.parentId] + if (!parent) continue + if (!parent.children) parent.children = [] + parent.children.push(item) + } + return result + } + + var DICT_FIXED = function() { + var fixed = [] + for (var id in DICT) { + var pid = id.slice(2, 6) === '0000' ? undefined : + id.slice(4, 6) == '00' ? (id.slice(0, 2) + '0000') : + id.slice(0, 4) + '00' + fixed.push({ + id: id, + pid: pid, + name: DICT[id] + }) + } + return tree(fixed) + }() + + module.exports = DICT_FIXED + + /***/ }), + /* 19 */ + /***/ (function(module, exports, __webpack_require__) { + + /* + ## Miscellaneous + */ + var DICT = __webpack_require__(18) + module.exports = { + // Dice + d4: function() { + return this.natural(1, 4) + }, + d6: function() { + return this.natural(1, 6) + }, + d8: function() { + return this.natural(1, 8) + }, + d12: function() { + return this.natural(1, 12) + }, + d20: function() { + return this.natural(1, 20) + }, + d100: function() { + return this.natural(1, 100) + }, + /* + 随机生成一个 GUID。 + + http://www.broofa.com/2008/09/javascript-uuid-function/ + [UUID 规范](http://www.ietf.org/rfc/rfc4122.txt) + UUIDs (Universally Unique IDentifier) + GUIDs (Globally Unique IDentifier) + The formal definition of the UUID string representation is provided by the following ABNF [7]: + UUID = time-low "-" time-mid "-" + time-high-and-version "-" + clock-seq-and-reserved + clock-seq-low "-" node + time-low = 4hexOctet + time-mid = 2hexOctet + time-high-and-version = 2hexOctet + clock-seq-and-reserved = hexOctet + clock-seq-low = hexOctet + node = 6hexOctet + hexOctet = hexDigit hexDigit + hexDigit = + "0" / "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9" / + "a" / "b" / "c" / "d" / "e" / "f" / + "A" / "B" / "C" / "D" / "E" / "F" + + https://github.com/victorquinn/chancejs/blob/develop/chance.js#L1349 + */ + guid: function() { + var pool = "abcdefABCDEF1234567890", + guid = this.string(pool, 8) + '-' + + this.string(pool, 4) + '-' + + this.string(pool, 4) + '-' + + this.string(pool, 4) + '-' + + this.string(pool, 12); + return guid + }, + uuid: function() { + return this.guid() + }, + /* + 随机生成一个 18 位身份证。 + + [身份证](http://baike.baidu.com/view/1697.htm#4) + 地址码 6 + 出生日期码 8 + 顺序码 3 + 校验码 1 + [《中华人民共和国行政区划代码》国家标准(GB/T2260)](http://zhidao.baidu.com/question/1954561.html) + */ + id: function() { + var id, + sum = 0, + rank = [ + "7", "9", "10", "5", "8", "4", "2", "1", "6", "3", "7", "9", "10", "5", "8", "4", "2" + ], + last = [ + "1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2" + ] + + id = this.pick(DICT).id + + this.date('yyyyMMdd') + + this.string('number', 3) + + for (var i = 0; i < id.length; i++) { + sum += id[i] * rank[i]; + } + id += last[sum % 11]; + + return id + }, + + /* + 生成一个全局的自增整数。 + 类似自增主键(auto increment primary key)。 + */ + increment: function() { + var key = 0 + return function(step) { + return key += (+step || 1) // step? + } + }(), + inc: function(step) { + return this.increment(step) + } + } + + /***/ }), + /* 20 */ + /***/ (function(module, exports, __webpack_require__) { + + var Parser = __webpack_require__(21) + var Handler = __webpack_require__(22) + module.exports = { + Parser: Parser, + Handler: Handler + } + + /***/ }), + /* 21 */ + /***/ (function(module, exports) { + + // https://github.com/nuysoft/regexp + // forked from https://github.com/ForbesLindesay/regexp + + function parse(n) { + if ("string" != typeof n) { + var l = new TypeError("The regexp to parse must be represented as a string."); + throw l; + } + return index = 1, cgs = {}, parser.parse(n); + } + + function Token(n) { + this.type = n, this.offset = Token.offset(), this.text = Token.text(); + } + + function Alternate(n, l) { + Token.call(this, "alternate"), this.left = n, this.right = l; + } + + function Match(n) { + Token.call(this, "match"), this.body = n.filter(Boolean); + } + + function Group(n, l) { + Token.call(this, n), this.body = l; + } + + function CaptureGroup(n) { + Group.call(this, "capture-group"), this.index = cgs[this.offset] || (cgs[this.offset] = index++), + this.body = n; + } + + function Quantified(n, l) { + Token.call(this, "quantified"), this.body = n, this.quantifier = l; + } + + function Quantifier(n, l) { + Token.call(this, "quantifier"), this.min = n, this.max = l, this.greedy = !0; + } + + function CharSet(n, l) { + Token.call(this, "charset"), this.invert = n, this.body = l; + } + + function CharacterRange(n, l) { + Token.call(this, "range"), this.start = n, this.end = l; + } + + function Literal(n) { + Token.call(this, "literal"), this.body = n, this.escaped = this.body != this.text; + } + + function Unicode(n) { + Token.call(this, "unicode"), this.code = n.toUpperCase(); + } + + function Hex(n) { + Token.call(this, "hex"), this.code = n.toUpperCase(); + } + + function Octal(n) { + Token.call(this, "octal"), this.code = n.toUpperCase(); + } + + function BackReference(n) { + Token.call(this, "back-reference"), this.code = n.toUpperCase(); + } + + function ControlCharacter(n) { + Token.call(this, "control-character"), this.code = n.toUpperCase(); + } + + var parser = function() { + function n(n, l) { + function u() { + this.constructor = n; + } + u.prototype = l.prototype, n.prototype = new u(); + } + function l(n, l, u, t, r) { + function e(n, l) { + function u(n) { + function l(n) { + return n.charCodeAt(0).toString(16).toUpperCase(); + } + return n.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\x08/g, "\\b").replace(/\t/g, "\\t").replace(/\n/g, "\\n").replace(/\f/g, "\\f").replace(/\r/g, "\\r").replace(/[\x00-\x07\x0B\x0E\x0F]/g, function(n) { + return "\\x0" + l(n); + }).replace(/[\x10-\x1F\x80-\xFF]/g, function(n) { + return "\\x" + l(n); + }).replace(/[\u0180-\u0FFF]/g, function(n) { + return "\\u0" + l(n); + }).replace(/[\u1080-\uFFFF]/g, function(n) { + return "\\u" + l(n); + }); + } + var t, r; + switch (n.length) { + case 0: + t = "end of input"; + break; + + case 1: + t = n[0]; + break; + + default: + t = n.slice(0, -1).join(", ") + " or " + n[n.length - 1]; + } + return r = l ? '"' + u(l) + '"' : "end of input", "Expected " + t + " but " + r + " found."; + } + this.expected = n, this.found = l, this.offset = u, this.line = t, this.column = r, + this.name = "SyntaxError", this.message = e(n, l); + } + function u(n) { + function u() { + return n.substring(Lt, qt); + } + function t() { + return Lt; + } + function r(l) { + function u(l, u, t) { + var r, e; + for (r = u; t > r; r++) e = n.charAt(r), "\n" === e ? (l.seenCR || l.line++, l.column = 1, + l.seenCR = !1) : "\r" === e || "\u2028" === e || "\u2029" === e ? (l.line++, l.column = 1, + l.seenCR = !0) : (l.column++, l.seenCR = !1); + } + return Mt !== l && (Mt > l && (Mt = 0, Dt = { + line: 1, + column: 1, + seenCR: !1 + }), u(Dt, Mt, l), Mt = l), Dt; + } + function e(n) { + Ht > qt || (qt > Ht && (Ht = qt, Ot = []), Ot.push(n)); + } + function o(n) { + var l = 0; + for (n.sort(); l < n.length; ) n[l - 1] === n[l] ? n.splice(l, 1) : l++; + } + function c() { + var l, u, t, r, o; + return l = qt, u = i(), null !== u ? (t = qt, 124 === n.charCodeAt(qt) ? (r = fl, + qt++) : (r = null, 0 === Wt && e(sl)), null !== r ? (o = c(), null !== o ? (r = [ r, o ], + t = r) : (qt = t, t = il)) : (qt = t, t = il), null === t && (t = al), null !== t ? (Lt = l, + u = hl(u, t), null === u ? (qt = l, l = u) : l = u) : (qt = l, l = il)) : (qt = l, + l = il), l; + } + function i() { + var n, l, u, t, r; + if (n = qt, l = f(), null === l && (l = al), null !== l) if (u = qt, Wt++, t = d(), + Wt--, null === t ? u = al : (qt = u, u = il), null !== u) { + for (t = [], r = h(), null === r && (r = a()); null !== r; ) t.push(r), r = h(), + null === r && (r = a()); + null !== t ? (r = s(), null === r && (r = al), null !== r ? (Lt = n, l = dl(l, t, r), + null === l ? (qt = n, n = l) : n = l) : (qt = n, n = il)) : (qt = n, n = il); + } else qt = n, n = il; else qt = n, n = il; + return n; + } + function a() { + var n; + return n = x(), null === n && (n = Q(), null === n && (n = B())), n; + } + function f() { + var l, u; + return l = qt, 94 === n.charCodeAt(qt) ? (u = pl, qt++) : (u = null, 0 === Wt && e(vl)), + null !== u && (Lt = l, u = wl()), null === u ? (qt = l, l = u) : l = u, l; + } + function s() { + var l, u; + return l = qt, 36 === n.charCodeAt(qt) ? (u = Al, qt++) : (u = null, 0 === Wt && e(Cl)), + null !== u && (Lt = l, u = gl()), null === u ? (qt = l, l = u) : l = u, l; + } + function h() { + var n, l, u; + return n = qt, l = a(), null !== l ? (u = d(), null !== u ? (Lt = n, l = bl(l, u), + null === l ? (qt = n, n = l) : n = l) : (qt = n, n = il)) : (qt = n, n = il), n; + } + function d() { + var n, l, u; + return Wt++, n = qt, l = p(), null !== l ? (u = k(), null === u && (u = al), null !== u ? (Lt = n, + l = Tl(l, u), null === l ? (qt = n, n = l) : n = l) : (qt = n, n = il)) : (qt = n, + n = il), Wt--, null === n && (l = null, 0 === Wt && e(kl)), n; + } + function p() { + var n; + return n = v(), null === n && (n = w(), null === n && (n = A(), null === n && (n = C(), + null === n && (n = g(), null === n && (n = b()))))), n; + } + function v() { + var l, u, t, r, o, c; + return l = qt, 123 === n.charCodeAt(qt) ? (u = xl, qt++) : (u = null, 0 === Wt && e(yl)), + null !== u ? (t = T(), null !== t ? (44 === n.charCodeAt(qt) ? (r = ml, qt++) : (r = null, + 0 === Wt && e(Rl)), null !== r ? (o = T(), null !== o ? (125 === n.charCodeAt(qt) ? (c = Fl, + qt++) : (c = null, 0 === Wt && e(Ql)), null !== c ? (Lt = l, u = Sl(t, o), null === u ? (qt = l, + l = u) : l = u) : (qt = l, l = il)) : (qt = l, l = il)) : (qt = l, l = il)) : (qt = l, + l = il)) : (qt = l, l = il), l; + } + function w() { + var l, u, t, r; + return l = qt, 123 === n.charCodeAt(qt) ? (u = xl, qt++) : (u = null, 0 === Wt && e(yl)), + null !== u ? (t = T(), null !== t ? (n.substr(qt, 2) === Ul ? (r = Ul, qt += 2) : (r = null, + 0 === Wt && e(El)), null !== r ? (Lt = l, u = Gl(t), null === u ? (qt = l, l = u) : l = u) : (qt = l, + l = il)) : (qt = l, l = il)) : (qt = l, l = il), l; + } + function A() { + var l, u, t, r; + return l = qt, 123 === n.charCodeAt(qt) ? (u = xl, qt++) : (u = null, 0 === Wt && e(yl)), + null !== u ? (t = T(), null !== t ? (125 === n.charCodeAt(qt) ? (r = Fl, qt++) : (r = null, + 0 === Wt && e(Ql)), null !== r ? (Lt = l, u = Bl(t), null === u ? (qt = l, l = u) : l = u) : (qt = l, + l = il)) : (qt = l, l = il)) : (qt = l, l = il), l; + } + function C() { + var l, u; + return l = qt, 43 === n.charCodeAt(qt) ? (u = jl, qt++) : (u = null, 0 === Wt && e($l)), + null !== u && (Lt = l, u = ql()), null === u ? (qt = l, l = u) : l = u, l; + } + function g() { + var l, u; + return l = qt, 42 === n.charCodeAt(qt) ? (u = Ll, qt++) : (u = null, 0 === Wt && e(Ml)), + null !== u && (Lt = l, u = Dl()), null === u ? (qt = l, l = u) : l = u, l; + } + function b() { + var l, u; + return l = qt, 63 === n.charCodeAt(qt) ? (u = Hl, qt++) : (u = null, 0 === Wt && e(Ol)), + null !== u && (Lt = l, u = Wl()), null === u ? (qt = l, l = u) : l = u, l; + } + function k() { + var l; + return 63 === n.charCodeAt(qt) ? (l = Hl, qt++) : (l = null, 0 === Wt && e(Ol)), + l; + } + function T() { + var l, u, t; + if (l = qt, u = [], zl.test(n.charAt(qt)) ? (t = n.charAt(qt), qt++) : (t = null, + 0 === Wt && e(Il)), null !== t) for (;null !== t; ) u.push(t), zl.test(n.charAt(qt)) ? (t = n.charAt(qt), + qt++) : (t = null, 0 === Wt && e(Il)); else u = il; + return null !== u && (Lt = l, u = Jl(u)), null === u ? (qt = l, l = u) : l = u, + l; + } + function x() { + var l, u, t, r; + return l = qt, 40 === n.charCodeAt(qt) ? (u = Kl, qt++) : (u = null, 0 === Wt && e(Nl)), + null !== u ? (t = R(), null === t && (t = F(), null === t && (t = m(), null === t && (t = y()))), + null !== t ? (41 === n.charCodeAt(qt) ? (r = Pl, qt++) : (r = null, 0 === Wt && e(Vl)), + null !== r ? (Lt = l, u = Xl(t), null === u ? (qt = l, l = u) : l = u) : (qt = l, + l = il)) : (qt = l, l = il)) : (qt = l, l = il), l; + } + function y() { + var n, l; + return n = qt, l = c(), null !== l && (Lt = n, l = Yl(l)), null === l ? (qt = n, + n = l) : n = l, n; + } + function m() { + var l, u, t; + return l = qt, n.substr(qt, 2) === Zl ? (u = Zl, qt += 2) : (u = null, 0 === Wt && e(_l)), + null !== u ? (t = c(), null !== t ? (Lt = l, u = nu(t), null === u ? (qt = l, l = u) : l = u) : (qt = l, + l = il)) : (qt = l, l = il), l; + } + function R() { + var l, u, t; + return l = qt, n.substr(qt, 2) === lu ? (u = lu, qt += 2) : (u = null, 0 === Wt && e(uu)), + null !== u ? (t = c(), null !== t ? (Lt = l, u = tu(t), null === u ? (qt = l, l = u) : l = u) : (qt = l, + l = il)) : (qt = l, l = il), l; + } + function F() { + var l, u, t; + return l = qt, n.substr(qt, 2) === ru ? (u = ru, qt += 2) : (u = null, 0 === Wt && e(eu)), + null !== u ? (t = c(), null !== t ? (Lt = l, u = ou(t), null === u ? (qt = l, l = u) : l = u) : (qt = l, + l = il)) : (qt = l, l = il), l; + } + function Q() { + var l, u, t, r, o; + if (Wt++, l = qt, 91 === n.charCodeAt(qt) ? (u = iu, qt++) : (u = null, 0 === Wt && e(au)), + null !== u) if (94 === n.charCodeAt(qt) ? (t = pl, qt++) : (t = null, 0 === Wt && e(vl)), + null === t && (t = al), null !== t) { + for (r = [], o = S(), null === o && (o = U()); null !== o; ) r.push(o), o = S(), + null === o && (o = U()); + null !== r ? (93 === n.charCodeAt(qt) ? (o = fu, qt++) : (o = null, 0 === Wt && e(su)), + null !== o ? (Lt = l, u = hu(t, r), null === u ? (qt = l, l = u) : l = u) : (qt = l, + l = il)) : (qt = l, l = il); + } else qt = l, l = il; else qt = l, l = il; + return Wt--, null === l && (u = null, 0 === Wt && e(cu)), l; + } + function S() { + var l, u, t, r; + return Wt++, l = qt, u = U(), null !== u ? (45 === n.charCodeAt(qt) ? (t = pu, qt++) : (t = null, + 0 === Wt && e(vu)), null !== t ? (r = U(), null !== r ? (Lt = l, u = wu(u, r), null === u ? (qt = l, + l = u) : l = u) : (qt = l, l = il)) : (qt = l, l = il)) : (qt = l, l = il), Wt--, + null === l && (u = null, 0 === Wt && e(du)), l; + } + function U() { + var n, l; + return Wt++, n = G(), null === n && (n = E()), Wt--, null === n && (l = null, 0 === Wt && e(Au)), + n; + } + function E() { + var l, u; + return l = qt, Cu.test(n.charAt(qt)) ? (u = n.charAt(qt), qt++) : (u = null, 0 === Wt && e(gu)), + null !== u && (Lt = l, u = bu(u)), null === u ? (qt = l, l = u) : l = u, l; + } + function G() { + var n; + return n = L(), null === n && (n = Y(), null === n && (n = H(), null === n && (n = O(), + null === n && (n = W(), null === n && (n = z(), null === n && (n = I(), null === n && (n = J(), + null === n && (n = K(), null === n && (n = N(), null === n && (n = P(), null === n && (n = V(), + null === n && (n = X(), null === n && (n = _(), null === n && (n = nl(), null === n && (n = ll(), + null === n && (n = ul(), null === n && (n = tl()))))))))))))))))), n; + } + function B() { + var n; + return n = j(), null === n && (n = q(), null === n && (n = $())), n; + } + function j() { + var l, u; + return l = qt, 46 === n.charCodeAt(qt) ? (u = ku, qt++) : (u = null, 0 === Wt && e(Tu)), + null !== u && (Lt = l, u = xu()), null === u ? (qt = l, l = u) : l = u, l; + } + function $() { + var l, u; + return Wt++, l = qt, mu.test(n.charAt(qt)) ? (u = n.charAt(qt), qt++) : (u = null, + 0 === Wt && e(Ru)), null !== u && (Lt = l, u = bu(u)), null === u ? (qt = l, l = u) : l = u, + Wt--, null === l && (u = null, 0 === Wt && e(yu)), l; + } + function q() { + var n; + return n = M(), null === n && (n = D(), null === n && (n = Y(), null === n && (n = H(), + null === n && (n = O(), null === n && (n = W(), null === n && (n = z(), null === n && (n = I(), + null === n && (n = J(), null === n && (n = K(), null === n && (n = N(), null === n && (n = P(), + null === n && (n = V(), null === n && (n = X(), null === n && (n = Z(), null === n && (n = _(), + null === n && (n = nl(), null === n && (n = ll(), null === n && (n = ul(), null === n && (n = tl()))))))))))))))))))), + n; + } + function L() { + var l, u; + return l = qt, n.substr(qt, 2) === Fu ? (u = Fu, qt += 2) : (u = null, 0 === Wt && e(Qu)), + null !== u && (Lt = l, u = Su()), null === u ? (qt = l, l = u) : l = u, l; + } + function M() { + var l, u; + return l = qt, n.substr(qt, 2) === Fu ? (u = Fu, qt += 2) : (u = null, 0 === Wt && e(Qu)), + null !== u && (Lt = l, u = Uu()), null === u ? (qt = l, l = u) : l = u, l; + } + function D() { + var l, u; + return l = qt, n.substr(qt, 2) === Eu ? (u = Eu, qt += 2) : (u = null, 0 === Wt && e(Gu)), + null !== u && (Lt = l, u = Bu()), null === u ? (qt = l, l = u) : l = u, l; + } + function H() { + var l, u; + return l = qt, n.substr(qt, 2) === ju ? (u = ju, qt += 2) : (u = null, 0 === Wt && e($u)), + null !== u && (Lt = l, u = qu()), null === u ? (qt = l, l = u) : l = u, l; + } + function O() { + var l, u; + return l = qt, n.substr(qt, 2) === Lu ? (u = Lu, qt += 2) : (u = null, 0 === Wt && e(Mu)), + null !== u && (Lt = l, u = Du()), null === u ? (qt = l, l = u) : l = u, l; + } + function W() { + var l, u; + return l = qt, n.substr(qt, 2) === Hu ? (u = Hu, qt += 2) : (u = null, 0 === Wt && e(Ou)), + null !== u && (Lt = l, u = Wu()), null === u ? (qt = l, l = u) : l = u, l; + } + function z() { + var l, u; + return l = qt, n.substr(qt, 2) === zu ? (u = zu, qt += 2) : (u = null, 0 === Wt && e(Iu)), + null !== u && (Lt = l, u = Ju()), null === u ? (qt = l, l = u) : l = u, l; + } + function I() { + var l, u; + return l = qt, n.substr(qt, 2) === Ku ? (u = Ku, qt += 2) : (u = null, 0 === Wt && e(Nu)), + null !== u && (Lt = l, u = Pu()), null === u ? (qt = l, l = u) : l = u, l; + } + function J() { + var l, u; + return l = qt, n.substr(qt, 2) === Vu ? (u = Vu, qt += 2) : (u = null, 0 === Wt && e(Xu)), + null !== u && (Lt = l, u = Yu()), null === u ? (qt = l, l = u) : l = u, l; + } + function K() { + var l, u; + return l = qt, n.substr(qt, 2) === Zu ? (u = Zu, qt += 2) : (u = null, 0 === Wt && e(_u)), + null !== u && (Lt = l, u = nt()), null === u ? (qt = l, l = u) : l = u, l; + } + function N() { + var l, u; + return l = qt, n.substr(qt, 2) === lt ? (u = lt, qt += 2) : (u = null, 0 === Wt && e(ut)), + null !== u && (Lt = l, u = tt()), null === u ? (qt = l, l = u) : l = u, l; + } + function P() { + var l, u; + return l = qt, n.substr(qt, 2) === rt ? (u = rt, qt += 2) : (u = null, 0 === Wt && e(et)), + null !== u && (Lt = l, u = ot()), null === u ? (qt = l, l = u) : l = u, l; + } + function V() { + var l, u; + return l = qt, n.substr(qt, 2) === ct ? (u = ct, qt += 2) : (u = null, 0 === Wt && e(it)), + null !== u && (Lt = l, u = at()), null === u ? (qt = l, l = u) : l = u, l; + } + function X() { + var l, u; + return l = qt, n.substr(qt, 2) === ft ? (u = ft, qt += 2) : (u = null, 0 === Wt && e(st)), + null !== u && (Lt = l, u = ht()), null === u ? (qt = l, l = u) : l = u, l; + } + function Y() { + var l, u, t; + return l = qt, n.substr(qt, 2) === dt ? (u = dt, qt += 2) : (u = null, 0 === Wt && e(pt)), + null !== u ? (n.length > qt ? (t = n.charAt(qt), qt++) : (t = null, 0 === Wt && e(vt)), + null !== t ? (Lt = l, u = wt(t), null === u ? (qt = l, l = u) : l = u) : (qt = l, + l = il)) : (qt = l, l = il), l; + } + function Z() { + var l, u, t; + return l = qt, 92 === n.charCodeAt(qt) ? (u = At, qt++) : (u = null, 0 === Wt && e(Ct)), + null !== u ? (gt.test(n.charAt(qt)) ? (t = n.charAt(qt), qt++) : (t = null, 0 === Wt && e(bt)), + null !== t ? (Lt = l, u = kt(t), null === u ? (qt = l, l = u) : l = u) : (qt = l, + l = il)) : (qt = l, l = il), l; + } + function _() { + var l, u, t, r; + if (l = qt, n.substr(qt, 2) === Tt ? (u = Tt, qt += 2) : (u = null, 0 === Wt && e(xt)), + null !== u) { + if (t = [], yt.test(n.charAt(qt)) ? (r = n.charAt(qt), qt++) : (r = null, 0 === Wt && e(mt)), + null !== r) for (;null !== r; ) t.push(r), yt.test(n.charAt(qt)) ? (r = n.charAt(qt), + qt++) : (r = null, 0 === Wt && e(mt)); else t = il; + null !== t ? (Lt = l, u = Rt(t), null === u ? (qt = l, l = u) : l = u) : (qt = l, + l = il); + } else qt = l, l = il; + return l; + } + function nl() { + var l, u, t, r; + if (l = qt, n.substr(qt, 2) === Ft ? (u = Ft, qt += 2) : (u = null, 0 === Wt && e(Qt)), + null !== u) { + if (t = [], St.test(n.charAt(qt)) ? (r = n.charAt(qt), qt++) : (r = null, 0 === Wt && e(Ut)), + null !== r) for (;null !== r; ) t.push(r), St.test(n.charAt(qt)) ? (r = n.charAt(qt), + qt++) : (r = null, 0 === Wt && e(Ut)); else t = il; + null !== t ? (Lt = l, u = Et(t), null === u ? (qt = l, l = u) : l = u) : (qt = l, + l = il); + } else qt = l, l = il; + return l; + } + function ll() { + var l, u, t, r; + if (l = qt, n.substr(qt, 2) === Gt ? (u = Gt, qt += 2) : (u = null, 0 === Wt && e(Bt)), + null !== u) { + if (t = [], St.test(n.charAt(qt)) ? (r = n.charAt(qt), qt++) : (r = null, 0 === Wt && e(Ut)), + null !== r) for (;null !== r; ) t.push(r), St.test(n.charAt(qt)) ? (r = n.charAt(qt), + qt++) : (r = null, 0 === Wt && e(Ut)); else t = il; + null !== t ? (Lt = l, u = jt(t), null === u ? (qt = l, l = u) : l = u) : (qt = l, + l = il); + } else qt = l, l = il; + return l; + } + function ul() { + var l, u; + return l = qt, n.substr(qt, 2) === Tt ? (u = Tt, qt += 2) : (u = null, 0 === Wt && e(xt)), + null !== u && (Lt = l, u = $t()), null === u ? (qt = l, l = u) : l = u, l; + } + function tl() { + var l, u, t; + return l = qt, 92 === n.charCodeAt(qt) ? (u = At, qt++) : (u = null, 0 === Wt && e(Ct)), + null !== u ? (n.length > qt ? (t = n.charAt(qt), qt++) : (t = null, 0 === Wt && e(vt)), + null !== t ? (Lt = l, u = bu(t), null === u ? (qt = l, l = u) : l = u) : (qt = l, + l = il)) : (qt = l, l = il), l; + } + var rl, el = arguments.length > 1 ? arguments[1] : {}, ol = { + regexp: c + }, cl = c, il = null, al = "", fl = "|", sl = '"|"', hl = function(n, l) { + return l ? new Alternate(n, l[1]) : n; + }, dl = function(n, l, u) { + return new Match([ n ].concat(l).concat([ u ])); + }, pl = "^", vl = '"^"', wl = function() { + return new Token("start"); + }, Al = "$", Cl = '"$"', gl = function() { + return new Token("end"); + }, bl = function(n, l) { + return new Quantified(n, l); + }, kl = "Quantifier", Tl = function(n, l) { + return l && (n.greedy = !1), n; + }, xl = "{", yl = '"{"', ml = ",", Rl = '","', Fl = "}", Ql = '"}"', Sl = function(n, l) { + return new Quantifier(n, l); + }, Ul = ",}", El = '",}"', Gl = function(n) { + return new Quantifier(n, 1/0); + }, Bl = function(n) { + return new Quantifier(n, n); + }, jl = "+", $l = '"+"', ql = function() { + return new Quantifier(1, 1/0); + }, Ll = "*", Ml = '"*"', Dl = function() { + return new Quantifier(0, 1/0); + }, Hl = "?", Ol = '"?"', Wl = function() { + return new Quantifier(0, 1); + }, zl = /^[0-9]/, Il = "[0-9]", Jl = function(n) { + return +n.join(""); + }, Kl = "(", Nl = '"("', Pl = ")", Vl = '")"', Xl = function(n) { + return n; + }, Yl = function(n) { + return new CaptureGroup(n); + }, Zl = "?:", _l = '"?:"', nu = function(n) { + return new Group("non-capture-group", n); + }, lu = "?=", uu = '"?="', tu = function(n) { + return new Group("positive-lookahead", n); + }, ru = "?!", eu = '"?!"', ou = function(n) { + return new Group("negative-lookahead", n); + }, cu = "CharacterSet", iu = "[", au = '"["', fu = "]", su = '"]"', hu = function(n, l) { + return new CharSet(!!n, l); + }, du = "CharacterRange", pu = "-", vu = '"-"', wu = function(n, l) { + return new CharacterRange(n, l); + }, Au = "Character", Cu = /^[^\\\]]/, gu = "[^\\\\\\]]", bu = function(n) { + return new Literal(n); + }, ku = ".", Tu = '"."', xu = function() { + return new Token("any-character"); + }, yu = "Literal", mu = /^[^|\\\/.[()?+*$\^]/, Ru = "[^|\\\\\\/.[()?+*$\\^]", Fu = "\\b", Qu = '"\\\\b"', Su = function() { + return new Token("backspace"); + }, Uu = function() { + return new Token("word-boundary"); + }, Eu = "\\B", Gu = '"\\\\B"', Bu = function() { + return new Token("non-word-boundary"); + }, ju = "\\d", $u = '"\\\\d"', qu = function() { + return new Token("digit"); + }, Lu = "\\D", Mu = '"\\\\D"', Du = function() { + return new Token("non-digit"); + }, Hu = "\\f", Ou = '"\\\\f"', Wu = function() { + return new Token("form-feed"); + }, zu = "\\n", Iu = '"\\\\n"', Ju = function() { + return new Token("line-feed"); + }, Ku = "\\r", Nu = '"\\\\r"', Pu = function() { + return new Token("carriage-return"); + }, Vu = "\\s", Xu = '"\\\\s"', Yu = function() { + return new Token("white-space"); + }, Zu = "\\S", _u = '"\\\\S"', nt = function() { + return new Token("non-white-space"); + }, lt = "\\t", ut = '"\\\\t"', tt = function() { + return new Token("tab"); + }, rt = "\\v", et = '"\\\\v"', ot = function() { + return new Token("vertical-tab"); + }, ct = "\\w", it = '"\\\\w"', at = function() { + return new Token("word"); + }, ft = "\\W", st = '"\\\\W"', ht = function() { + return new Token("non-word"); + }, dt = "\\c", pt = '"\\\\c"', vt = "any character", wt = function(n) { + return new ControlCharacter(n); + }, At = "\\", Ct = '"\\\\"', gt = /^[1-9]/, bt = "[1-9]", kt = function(n) { + return new BackReference(n); + }, Tt = "\\0", xt = '"\\\\0"', yt = /^[0-7]/, mt = "[0-7]", Rt = function(n) { + return new Octal(n.join("")); + }, Ft = "\\x", Qt = '"\\\\x"', St = /^[0-9a-fA-F]/, Ut = "[0-9a-fA-F]", Et = function(n) { + return new Hex(n.join("")); + }, Gt = "\\u", Bt = '"\\\\u"', jt = function(n) { + return new Unicode(n.join("")); + }, $t = function() { + return new Token("null-character"); + }, qt = 0, Lt = 0, Mt = 0, Dt = { + line: 1, + column: 1, + seenCR: !1 + }, Ht = 0, Ot = [], Wt = 0; + if ("startRule" in el) { + if (!(el.startRule in ol)) throw new Error("Can't start parsing from rule \"" + el.startRule + '".'); + cl = ol[el.startRule]; + } + if (Token.offset = t, Token.text = u, rl = cl(), null !== rl && qt === n.length) return rl; + throw o(Ot), Lt = Math.max(qt, Ht), new l(Ot, Lt < n.length ? n.charAt(Lt) : null, Lt, r(Lt).line, r(Lt).column); + } + return n(l, Error), { + SyntaxError: l, + parse: u + }; + }(), index = 1, cgs = {}; + + module.exports = parser + + /***/ }), + /* 22 */ + /***/ (function(module, exports, __webpack_require__) { + + /* + ## RegExp Handler + + https://github.com/ForbesLindesay/regexp + https://github.com/dmajda/pegjs + http://www.regexper.com/ + + 每个节点的结构 + { + type: '', + offset: number, + text: '', + body: {}, + escaped: true/false + } + + type 可选值 + alternate | 选择 + match 匹配 + capture-group () 捕获组 + non-capture-group (?:...) 非捕获组 + positive-lookahead (?=p) 零宽正向先行断言 + negative-lookahead (?!p) 零宽负向先行断言 + quantified a* 重复节点 + quantifier * 量词 + charset [] 字符集 + range {m, n} 范围 + literal a 直接量字符 + unicode \uxxxx Unicode + hex \x 十六进制 + octal 八进制 + back-reference \n 反向引用 + control-character \cX 控制字符 + + // Token + start ^ 开头 + end $ 结尾 + any-character . 任意字符 + backspace [\b] 退格直接量 + word-boundary \b 单词边界 + non-word-boundary \B 非单词边界 + digit \d ASCII 数字,[0-9] + non-digit \D 非 ASCII 数字,[^0-9] + form-feed \f 换页符 + line-feed \n 换行符 + carriage-return \r 回车符 + white-space \s 空白符 + non-white-space \S 非空白符 + tab \t 制表符 + vertical-tab \v 垂直制表符 + word \w ASCII 字符,[a-zA-Z0-9] + non-word \W 非 ASCII 字符,[^a-zA-Z0-9] + null-character \o NUL 字符 + */ + + var Util = __webpack_require__(3) + var Random = __webpack_require__(5) + /* + + */ + var Handler = { + extend: Util.extend + } + + // http://en.wikipedia.org/wiki/ASCII#ASCII_printable_code_chart + /*var ASCII_CONTROL_CODE_CHART = { + '@': ['\u0000'], + A: ['\u0001'], + B: ['\u0002'], + C: ['\u0003'], + D: ['\u0004'], + E: ['\u0005'], + F: ['\u0006'], + G: ['\u0007', '\a'], + H: ['\u0008', '\b'], + I: ['\u0009', '\t'], + J: ['\u000A', '\n'], + K: ['\u000B', '\v'], + L: ['\u000C', '\f'], + M: ['\u000D', '\r'], + N: ['\u000E'], + O: ['\u000F'], + P: ['\u0010'], + Q: ['\u0011'], + R: ['\u0012'], + S: ['\u0013'], + T: ['\u0014'], + U: ['\u0015'], + V: ['\u0016'], + W: ['\u0017'], + X: ['\u0018'], + Y: ['\u0019'], + Z: ['\u001A'], + '[': ['\u001B', '\e'], + '\\': ['\u001C'], + ']': ['\u001D'], + '^': ['\u001E'], + '_': ['\u001F'] + }*/ + + // ASCII printable code chart + // var LOWER = 'abcdefghijklmnopqrstuvwxyz' + // var UPPER = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + // var NUMBER = '0123456789' + // var SYMBOL = ' !"#$%&\'()*+,-./' + ':;<=>?@' + '[\\]^_`' + '{|}~' + var LOWER = ascii(97, 122) + var UPPER = ascii(65, 90) + var NUMBER = ascii(48, 57) + var OTHER = ascii(32, 47) + ascii(58, 64) + ascii(91, 96) + ascii(123, 126) // 排除 95 _ ascii(91, 94) + ascii(96, 96) + var PRINTABLE = ascii(32, 126) + var SPACE = ' \f\n\r\t\v\u00A0\u2028\u2029' + var CHARACTER_CLASSES = { + '\\w': LOWER + UPPER + NUMBER + '_', // ascii(95, 95) + '\\W': OTHER.replace('_', ''), + '\\s': SPACE, + '\\S': function() { + var result = PRINTABLE + for (var i = 0; i < SPACE.length; i++) { + result = result.replace(SPACE[i], '') + } + return result + }(), + '\\d': NUMBER, + '\\D': LOWER + UPPER + OTHER + } + + function ascii(from, to) { + var result = '' + for (var i = from; i <= to; i++) { + result += String.fromCharCode(i) + } + return result + } + + // var ast = RegExpParser.parse(regexp.source) + Handler.gen = function(node, result, cache) { + cache = cache || { + guid: 1 + } + return Handler[node.type] ? Handler[node.type](node, result, cache) : + Handler.token(node, result, cache) + } + + Handler.extend({ + /* jshint unused:false */ + token: function(node, result, cache) { + switch (node.type) { + case 'start': + case 'end': + return '' + case 'any-character': + return Random.character() + case 'backspace': + return '' + case 'word-boundary': // TODO + return '' + case 'non-word-boundary': // TODO + break + case 'digit': + return Random.pick( + NUMBER.split('') + ) + case 'non-digit': + return Random.pick( + (LOWER + UPPER + OTHER).split('') + ) + case 'form-feed': + break + case 'line-feed': + return node.body || node.text + case 'carriage-return': + break + case 'white-space': + return Random.pick( + SPACE.split('') + ) + case 'non-white-space': + return Random.pick( + (LOWER + UPPER + NUMBER).split('') + ) + case 'tab': + break + case 'vertical-tab': + break + case 'word': // \w [a-zA-Z0-9] + return Random.pick( + (LOWER + UPPER + NUMBER).split('') + ) + case 'non-word': // \W [^a-zA-Z0-9] + return Random.pick( + OTHER.replace('_', '').split('') + ) + case 'null-character': + break + } + return node.body || node.text + }, + /* + { + type: 'alternate', + offset: 0, + text: '', + left: { + boyd: [] + }, + right: { + boyd: [] + } + } + */ + alternate: function(node, result, cache) { + // node.left/right {} + return this.gen( + Random.boolean() ? node.left : node.right, + result, + cache + ) + }, + /* + { + type: 'match', + offset: 0, + text: '', + body: [] + } + */ + match: function(node, result, cache) { + result = '' + // node.body [] + for (var i = 0; i < node.body.length; i++) { + result += this.gen(node.body[i], result, cache) + } + return result + }, + // () + 'capture-group': function(node, result, cache) { + // node.body {} + result = this.gen(node.body, result, cache) + cache[cache.guid++] = result + return result + }, + // (?:...) + 'non-capture-group': function(node, result, cache) { + // node.body {} + return this.gen(node.body, result, cache) + }, + // (?=p) + 'positive-lookahead': function(node, result, cache) { + // node.body + return this.gen(node.body, result, cache) + }, + // (?!p) + 'negative-lookahead': function(node, result, cache) { + // node.body + return '' + }, + /* + { + type: 'quantified', + offset: 3, + text: 'c*', + body: { + type: 'literal', + offset: 3, + text: 'c', + body: 'c', + escaped: false + }, + quantifier: { + type: 'quantifier', + offset: 4, + text: '*', + min: 0, + max: Infinity, + greedy: true + } + } + */ + quantified: function(node, result, cache) { + result = '' + // node.quantifier {} + var count = this.quantifier(node.quantifier); + // node.body {} + for (var i = 0; i < count; i++) { + result += this.gen(node.body, result, cache) + } + return result + }, + /* + quantifier: { + type: 'quantifier', + offset: 4, + text: '*', + min: 0, + max: Infinity, + greedy: true + } + */ + quantifier: function(node, result, cache) { + var min = Math.max(node.min, 0) + var max = isFinite(node.max) ? node.max : + min + Random.integer(3, 7) + return Random.integer(min, max) + }, + /* + + */ + charset: function(node, result, cache) { + // node.invert + if (node.invert) return this['invert-charset'](node, result, cache) + + // node.body [] + var literal = Random.pick(node.body) + return this.gen(literal, result, cache) + }, + 'invert-charset': function(node, result, cache) { + var pool = PRINTABLE + for (var i = 0, item; i < node.body.length; i++) { + item = node.body[i] + switch (item.type) { + case 'literal': + pool = pool.replace(item.body, '') + break + case 'range': + var min = this.gen(item.start, result, cache).charCodeAt() + var max = this.gen(item.end, result, cache).charCodeAt() + for (var ii = min; ii <= max; ii++) { + pool = pool.replace(String.fromCharCode(ii), '') + } + /* falls through */ + default: + var characters = CHARACTER_CLASSES[item.text] + if (characters) { + for (var iii = 0; iii <= characters.length; iii++) { + pool = pool.replace(characters[iii], '') + } + } + } + } + return Random.pick(pool.split('')) + }, + range: function(node, result, cache) { + // node.start, node.end + var min = this.gen(node.start, result, cache).charCodeAt() + var max = this.gen(node.end, result, cache).charCodeAt() + return String.fromCharCode( + Random.integer(min, max) + ) + }, + literal: function(node, result, cache) { + return node.escaped ? node.body : node.text + }, + // Unicode \u + unicode: function(node, result, cache) { + return String.fromCharCode( + parseInt(node.code, 16) + ) + }, + // 十六进制 \xFF + hex: function(node, result, cache) { + return String.fromCharCode( + parseInt(node.code, 16) + ) + }, + // 八进制 \0 + octal: function(node, result, cache) { + return String.fromCharCode( + parseInt(node.code, 8) + ) + }, + // 反向引用 + 'back-reference': function(node, result, cache) { + return cache[node.code] || '' + }, + /* + http://en.wikipedia.org/wiki/C0_and_C1_control_codes + */ + CONTROL_CHARACTER_MAP: function() { + var CONTROL_CHARACTER = '@ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \\ ] ^ _'.split(' ') + var CONTROL_CHARACTER_UNICODE = '\u0000 \u0001 \u0002 \u0003 \u0004 \u0005 \u0006 \u0007 \u0008 \u0009 \u000A \u000B \u000C \u000D \u000E \u000F \u0010 \u0011 \u0012 \u0013 \u0014 \u0015 \u0016 \u0017 \u0018 \u0019 \u001A \u001B \u001C \u001D \u001E \u001F'.split(' ') + var map = {} + for (var i = 0; i < CONTROL_CHARACTER.length; i++) { + map[CONTROL_CHARACTER[i]] = CONTROL_CHARACTER_UNICODE[i] + } + return map + }(), + 'control-character': function(node, result, cache) { + return this.CONTROL_CHARACTER_MAP[node.code] + } + }) + + module.exports = Handler + + /***/ }), + /* 23 */ + /***/ (function(module, exports, __webpack_require__) { + + module.exports = __webpack_require__(24) + + /***/ }), + /* 24 */ + /***/ (function(module, exports, __webpack_require__) { + + /* + ## toJSONSchema + + 把 Mock.js 风格的数据模板转换成 JSON Schema。 + + > [JSON Schema](http://json-schema.org/) + */ + var Constant = __webpack_require__(2) + var Util = __webpack_require__(3) + var Parser = __webpack_require__(4) + + function toJSONSchema(template, name, path /* Internal Use Only */ ) { + // type rule properties items + path = path || [] + var result = { + name: typeof name === 'string' ? name.replace(Constant.RE_KEY, '$1') : name, + template: template, + type: Util.type(template), // 可能不准确,例如 { 'name|1': [{}, {} ...] } + rule: Parser.parse(name) + } + result.path = path.slice(0) + result.path.push(name === undefined ? 'ROOT' : result.name) + + switch (result.type) { + case 'array': + result.items = [] + Util.each(template, function(value, index) { + result.items.push( + toJSONSchema(value, index, result.path) + ) + }) + break + case 'object': + result.properties = [] + Util.each(template, function(value, name) { + result.properties.push( + toJSONSchema(value, name, result.path) + ) + }) + break + } + + return result + + } + + module.exports = toJSONSchema + + + /***/ }), + /* 25 */ + /***/ (function(module, exports, __webpack_require__) { + + module.exports = __webpack_require__(26) + + /***/ }), + /* 26 */ + /***/ (function(module, exports, __webpack_require__) { + + /* + ## valid(template, data) + + 校验真实数据 data 是否与数据模板 template 匹配。 + + 实现思路: + 1. 解析规则。 + 先把数据模板 template 解析为更方便机器解析的 JSON-Schame + name 属性名 + type 属性值类型 + template 属性值模板 + properties 对象属性数组 + items 数组元素数组 + rule 属性值生成规则 + 2. 递归验证规则。 + 然后用 JSON-Schema 校验真实数据,校验项包括属性名、值类型、值、值生成规则。 + + 提示信息 + https://github.com/fge/json-schema-validator/blob/master/src/main/resources/com/github/fge/jsonschema/validator/validation.properties + [JSON-Schama validator](http://json-schema-validator.herokuapp.com/) + [Regexp Demo](http://demos.forbeslindesay.co.uk/regexp/) + */ + var Constant = __webpack_require__(2) + var Util = __webpack_require__(3) + var toJSONSchema = __webpack_require__(23) + + function valid(template, data) { + var schema = toJSONSchema(template) + var result = Diff.diff(schema, data) + for (var i = 0; i < result.length; i++) { + // console.log(template, data) + // console.warn(Assert.message(result[i])) + } + return result + } + + /* + ## name + 有生成规则:比较解析后的 name + 无生成规则:直接比较 + ## type + 无类型转换:直接比较 + 有类型转换:先试着解析 template,然后再检查? + ## value vs. template + 基本类型 + 无生成规则:直接比较 + 有生成规则: + number + min-max.dmin-dmax + min-max.dcount + count.dmin-dmax + count.dcount + +step + 整数部分 + 小数部分 + boolean + string + min-max + count + ## properties + 对象 + 有生成规则:检测期望的属性个数,继续递归 + 无生成规则:检测全部的属性个数,继续递归 + ## items + 数组 + 有生成规则: + `'name|1': [{}, {} ...]` 其中之一,继续递归 + `'name|+1': [{}, {} ...]` 顺序检测,继续递归 + `'name|min-max': [{}, {} ...]` 检测个数,继续递归 + `'name|count': [{}, {} ...]` 检测个数,继续递归 + 无生成规则:检测全部的元素个数,继续递归 + */ + var Diff = { + diff: function diff(schema, data, name /* Internal Use Only */ ) { + var result = [] + + // 先检测名称 name 和类型 type,如果匹配,才有必要继续检测 + if ( + this.name(schema, data, name, result) && + this.type(schema, data, name, result) + ) { + this.value(schema, data, name, result) + this.properties(schema, data, name, result) + this.items(schema, data, name, result) + } + + return result + }, + /* jshint unused:false */ + name: function(schema, data, name, result) { + var length = result.length + + Assert.equal('name', schema.path, name + '', schema.name + '', result) + + return result.length === length + }, + type: function(schema, data, name, result) { + var length = result.length + + switch (schema.type) { + case 'string': + // 跳过含有『占位符』的属性值,因为『占位符』返回值的类型可能和模板不一致,例如 '@int' 会返回一个整形值 + if (schema.template.match(Constant.RE_PLACEHOLDER)) return true + break + case 'array': + if (schema.rule.parameters) { + // name|count: array + if (schema.rule.min !== undefined && schema.rule.max === undefined) { + // 跳过 name|1: array,因为最终值的类型(很可能)不是数组,也不一定与 `array` 中的类型一致 + if (schema.rule.count === 1) return true + } + // 跳过 name|+inc: array + if (schema.rule.parameters[2]) return true + } + break + case 'function': + // 跳过 `'name': function`,因为函数可以返回任何类型的值。 + return true + } + + Assert.equal('type', schema.path, Util.type(data), schema.type, result) + + return result.length === length + }, + value: function(schema, data, name, result) { + var length = result.length + + var rule = schema.rule + var templateType = schema.type + if (templateType === 'object' || templateType === 'array' || templateType === 'function') return true + + // 无生成规则 + if (!rule.parameters) { + switch (templateType) { + case 'regexp': + Assert.match('value', schema.path, data, schema.template, result) + return result.length === length + case 'string': + // 同样跳过含有『占位符』的属性值,因为『占位符』的返回值会通常会与模板不一致 + if (schema.template.match(Constant.RE_PLACEHOLDER)) return result.length === length + break + } + Assert.equal('value', schema.path, data, schema.template, result) + return result.length === length + } + + // 有生成规则 + var actualRepeatCount + switch (templateType) { + case 'number': + var parts = (data + '').split('.') + parts[0] = +parts[0] + + // 整数部分 + // |min-max + if (rule.min !== undefined && rule.max !== undefined) { + Assert.greaterThanOrEqualTo('value', schema.path, parts[0], Math.min(rule.min, rule.max), result) + // , 'numeric instance is lower than the required minimum (minimum: {expected}, found: {actual})') + Assert.lessThanOrEqualTo('value', schema.path, parts[0], Math.max(rule.min, rule.max), result) + } + // |count + if (rule.min !== undefined && rule.max === undefined) { + Assert.equal('value', schema.path, parts[0], rule.min, result, '[value] ' + name) + } + + // 小数部分 + if (rule.decimal) { + // |dmin-dmax + if (rule.dmin !== undefined && rule.dmax !== undefined) { + Assert.greaterThanOrEqualTo('value', schema.path, parts[1].length, rule.dmin, result) + Assert.lessThanOrEqualTo('value', schema.path, parts[1].length, rule.dmax, result) + } + // |dcount + if (rule.dmin !== undefined && rule.dmax === undefined) { + Assert.equal('value', schema.path, parts[1].length, rule.dmin, result) + } + } + + break + + case 'boolean': + break + + case 'string': + // 'aaa'.match(/a/g) + actualRepeatCount = data.match(new RegExp(schema.template, 'g')) + actualRepeatCount = actualRepeatCount ? actualRepeatCount.length : 0 + + // |min-max + if (rule.min !== undefined && rule.max !== undefined) { + Assert.greaterThanOrEqualTo('repeat count', schema.path, actualRepeatCount, rule.min, result) + Assert.lessThanOrEqualTo('repeat count', schema.path, actualRepeatCount, rule.max, result) + } + // |count + if (rule.min !== undefined && rule.max === undefined) { + Assert.equal('repeat count', schema.path, actualRepeatCount, rule.min, result) + } + + break + + case 'regexp': + actualRepeatCount = data.match(new RegExp(schema.template.source.replace(/^\^|\$$/g, ''), 'g')) + actualRepeatCount = actualRepeatCount ? actualRepeatCount.length : 0 + + // |min-max + if (rule.min !== undefined && rule.max !== undefined) { + Assert.greaterThanOrEqualTo('repeat count', schema.path, actualRepeatCount, rule.min, result) + Assert.lessThanOrEqualTo('repeat count', schema.path, actualRepeatCount, rule.max, result) + } + // |count + if (rule.min !== undefined && rule.max === undefined) { + Assert.equal('repeat count', schema.path, actualRepeatCount, rule.min, result) + } + break + } + + return result.length === length + }, + properties: function(schema, data, name, result) { + var length = result.length + + var rule = schema.rule + var keys = Util.keys(data) + if (!schema.properties) return + + // 无生成规则 + if (!schema.rule.parameters) { + Assert.equal('properties length', schema.path, keys.length, schema.properties.length, result) + } else { + // 有生成规则 + // |min-max + if (rule.min !== undefined && rule.max !== undefined) { + Assert.greaterThanOrEqualTo('properties length', schema.path, keys.length, Math.min(rule.min, rule.max), result) + Assert.lessThanOrEqualTo('properties length', schema.path, keys.length, Math.max(rule.min, rule.max), result) + } + // |count + if (rule.min !== undefined && rule.max === undefined) { + // |1, |>1 + if (rule.count !== 1) Assert.equal('properties length', schema.path, keys.length, rule.min, result) + } + } + + if (result.length !== length) return false + + for (var i = 0; i < keys.length; i++) { + result.push.apply( + result, + this.diff( + function() { + var property + Util.each(schema.properties, function(item /*, index*/ ) { + if (item.name === keys[i]) property = item + }) + return property || schema.properties[i] + }(), + data[keys[i]], + keys[i] + ) + ) + } + + return result.length === length + }, + items: function(schema, data, name, result) { + var length = result.length + + if (!schema.items) return + + var rule = schema.rule + + // 无生成规则 + if (!schema.rule.parameters) { + Assert.equal('items length', schema.path, data.length, schema.items.length, result) + } else { + // 有生成规则 + // |min-max + if (rule.min !== undefined && rule.max !== undefined) { + Assert.greaterThanOrEqualTo('items', schema.path, data.length, (Math.min(rule.min, rule.max) * schema.items.length), result, + '[{utype}] array is too short: {path} must have at least {expected} elements but instance has {actual} elements') + Assert.lessThanOrEqualTo('items', schema.path, data.length, (Math.max(rule.min, rule.max) * schema.items.length), result, + '[{utype}] array is too long: {path} must have at most {expected} elements but instance has {actual} elements') + } + // |count + if (rule.min !== undefined && rule.max === undefined) { + // |1, |>1 + if (rule.count === 1) return result.length === length + else Assert.equal('items length', schema.path, data.length, (rule.min * schema.items.length), result) + } + // |+inc + if (rule.parameters[2]) return result.length === length + } + + if (result.length !== length) return false + + for (var i = 0; i < data.length; i++) { + result.push.apply( + result, + this.diff( + schema.items[i % schema.items.length], + data[i], + i % schema.items.length + ) + ) + } + + return result.length === length + } + } + + /* + 完善、友好的提示信息 + + Equal, not equal to, greater than, less than, greater than or equal to, less than or equal to + 路径 验证类型 描述 + + Expect path.name is less than or equal to expected, but path.name is actual. + + Expect path.name is less than or equal to expected, but path.name is actual. + Expect path.name is greater than or equal to expected, but path.name is actual. + + */ + var Assert = { + message: function(item) { + return (item.message || + '[{utype}] Expect {path}\'{ltype} {action} {expected}, but is {actual}') + .replace('{utype}', item.type.toUpperCase()) + .replace('{ltype}', item.type.toLowerCase()) + .replace('{path}', Util.isArray(item.path) && item.path.join('.') || item.path) + .replace('{action}', item.action) + .replace('{expected}', item.expected) + .replace('{actual}', item.actual) + }, + equal: function(type, path, actual, expected, result, message) { + if (actual === expected) return true + switch (type) { + case 'type': + // 正则模板 === 字符串最终值 + if (expected === 'regexp' && actual === 'string') return true + break + } + + var item = { + path: path, + type: type, + actual: actual, + expected: expected, + action: 'is equal to', + message: message + } + item.message = Assert.message(item) + result.push(item) + return false + }, + // actual matches expected + match: function(type, path, actual, expected, result, message) { + if (expected.test(actual)) return true + + var item = { + path: path, + type: type, + actual: actual, + expected: expected, + action: 'matches', + message: message + } + item.message = Assert.message(item) + result.push(item) + return false + }, + notEqual: function(type, path, actual, expected, result, message) { + if (actual !== expected) return true + var item = { + path: path, + type: type, + actual: actual, + expected: expected, + action: 'is not equal to', + message: message + } + item.message = Assert.message(item) + result.push(item) + return false + }, + greaterThan: function(type, path, actual, expected, result, message) { + if (actual > expected) return true + var item = { + path: path, + type: type, + actual: actual, + expected: expected, + action: 'is greater than', + message: message + } + item.message = Assert.message(item) + result.push(item) + return false + }, + lessThan: function(type, path, actual, expected, result, message) { + if (actual < expected) return true + var item = { + path: path, + type: type, + actual: actual, + expected: expected, + action: 'is less to', + message: message + } + item.message = Assert.message(item) + result.push(item) + return false + }, + greaterThanOrEqualTo: function(type, path, actual, expected, result, message) { + if (actual >= expected) return true + var item = { + path: path, + type: type, + actual: actual, + expected: expected, + action: 'is greater than or equal to', + message: message + } + item.message = Assert.message(item) + result.push(item) + return false + }, + lessThanOrEqualTo: function(type, path, actual, expected, result, message) { + if (actual <= expected) return true + var item = { + path: path, + type: type, + actual: actual, + expected: expected, + action: 'is less than or equal to', + message: message + } + item.message = Assert.message(item) + result.push(item) + return false + } + } + + valid.Diff = Diff + valid.Assert = Assert + + module.exports = valid + + /***/ }), + /* 27 */ + /***/ (function(module, exports, __webpack_require__) { + + module.exports = __webpack_require__(28) + + /***/ }), + /* 28 */ + /***/ (function(module, exports, __webpack_require__) { + + /* global window, document, location, Event, setTimeout */ + /* + ## MockXMLHttpRequest + + 期望的功能: + 1. 完整地覆盖原生 XHR 的行为 + 2. 完整地模拟原生 XHR 的行为 + 3. 在发起请求时,自动检测是否需要拦截 + 4. 如果不必拦截,则执行原生 XHR 的行为 + 5. 如果需要拦截,则执行虚拟 XHR 的行为 + 6. 兼容 XMLHttpRequest 和 ActiveXObject + new window.XMLHttpRequest() + new window.ActiveXObject("Microsoft.XMLHTTP") + + 关键方法的逻辑: + * new 此时尚无法确定是否需要拦截,所以创建原生 XHR 对象是必须的。 + * open 此时可以取到 URL,可以决定是否进行拦截。 + * send 此时已经确定了请求方式。 + + 规范: + http://xhr.spec.whatwg.org/ + http://www.w3.org/TR/XMLHttpRequest2/ + + 参考实现: + https://github.com/philikon/MockHttpRequest/blob/master/lib/mock.js + https://github.com/trek/FakeXMLHttpRequest/blob/master/fake_xml_http_request.js + https://github.com/ilinsky/xmlhttprequest/blob/master/XMLHttpRequest.js + https://github.com/firebug/firebug-lite/blob/master/content/lite/xhr.js + https://github.com/thx/RAP/blob/master/lab/rap.plugin.xinglie.js + + **需不需要全面重写 XMLHttpRequest?** + http://xhr.spec.whatwg.org/#interface-xmlhttprequest + 关键属性 readyState、status、statusText、response、responseText、responseXML 是 readonly,所以,试图通过修改这些状态,来模拟响应是不可行的。 + 因此,唯一的办法是模拟整个 XMLHttpRequest,就像 jQuery 对事件模型的封装。 + + // Event handlers + onloadstart loadstart + onprogress progress + onabort abort + onerror error + onload load + ontimeout timeout + onloadend loadend + onreadystatechange readystatechange + */ + + var Util = __webpack_require__(3) + + // 备份原生 XMLHttpRequest + window._XMLHttpRequest = window.XMLHttpRequest + window._ActiveXObject = window.ActiveXObject + + /* + PhantomJS + TypeError: '[object EventConstructor]' is not a constructor (evaluating 'new Event("readystatechange")') + + https://github.com/bluerail/twitter-bootstrap-rails-confirm/issues/18 + https://github.com/ariya/phantomjs/issues/11289 + */ + try { + new window.Event('custom') + } catch (exception) { + window.Event = function(type, bubbles, cancelable, detail) { + var event = document.createEvent('CustomEvent') // MUST be 'CustomEvent' + event.initCustomEvent(type, bubbles, cancelable, detail) + return event + } + } + + var XHR_STATES = { + // The object has been constructed. + UNSENT: 0, + // The open() method has been successfully invoked. + OPENED: 1, + // All redirects (if any) have been followed and all HTTP headers of the response have been received. + HEADERS_RECEIVED: 2, + // The response's body is being received. + LOADING: 3, + // The data transfer has been completed or something went wrong during the transfer (e.g. infinite redirects). + DONE: 4 + } + + var XHR_EVENTS = 'readystatechange loadstart progress abort error load timeout loadend'.split(' ') + var XHR_REQUEST_PROPERTIES = 'timeout withCredentials'.split(' ') + var XHR_RESPONSE_PROPERTIES = 'readyState responseURL status statusText responseType response responseText responseXML'.split(' ') + + // https://github.com/trek/FakeXMLHttpRequest/blob/master/fake_xml_http_request.js#L32 + var HTTP_STATUS_CODES = { + 100: "Continue", + 101: "Switching Protocols", + 200: "OK", + 201: "Created", + 202: "Accepted", + 203: "Non-Authoritative Information", + 204: "No Content", + 205: "Reset Content", + 206: "Partial Content", + 300: "Multiple Choice", + 301: "Moved Permanently", + 302: "Found", + 303: "See Other", + 304: "Not Modified", + 305: "Use Proxy", + 307: "Temporary Redirect", + 400: "Bad Request", + 401: "Unauthorized", + 402: "Payment Required", + 403: "Forbidden", + 404: "Not Found", + 405: "Method Not Allowed", + 406: "Not Acceptable", + 407: "Proxy Authentication Required", + 408: "Request Timeout", + 409: "Conflict", + 410: "Gone", + 411: "Length Required", + 412: "Precondition Failed", + 413: "Request Entity Too Large", + 414: "Request-URI Too Long", + 415: "Unsupported Media Type", + 416: "Requested Range Not Satisfiable", + 417: "Expectation Failed", + 422: "Unprocessable Entity", + 500: "Internal Server Error", + 501: "Not Implemented", + 502: "Bad Gateway", + 503: "Service Unavailable", + 504: "Gateway Timeout", + 505: "HTTP Version Not Supported" + } + + /* + MockXMLHttpRequest + */ + + function MockXMLHttpRequest() { + // 初始化 custom 对象,用于存储自定义属性 + this.custom = { + events: {}, + requestHeaders: {}, + responseHeaders: {} + } + } + + MockXMLHttpRequest._settings = { + timeout: '10-100', + /* + timeout: 50, + timeout: '10-100', + */ + } + + MockXMLHttpRequest.setup = function(settings) { + Util.extend(MockXMLHttpRequest._settings, settings) + return MockXMLHttpRequest._settings + } + + Util.extend(MockXMLHttpRequest, XHR_STATES) + Util.extend(MockXMLHttpRequest.prototype, XHR_STATES) + + // 标记当前对象为 MockXMLHttpRequest + MockXMLHttpRequest.prototype.mock = true + + // 是否拦截 Ajax 请求 + MockXMLHttpRequest.prototype.match = false + + // 初始化 Request 相关的属性和方法 + Util.extend(MockXMLHttpRequest.prototype, { + // https://xhr.spec.whatwg.org/#the-open()-method + // Sets the request method, request URL, and synchronous flag. + open: function(method, url, async, username, password) { + var that = this + + Util.extend(this.custom, { + method: method, + url: url, + async: typeof async === 'boolean' ? async : true, + username: username, + password: password, + options: { + url: url, + type: method + } + }) + + this.custom.timeout = function(timeout) { + if (typeof timeout === 'number') return timeout + if (typeof timeout === 'string' && !~timeout.indexOf('-')) return parseInt(timeout, 10) + if (typeof timeout === 'string' && ~timeout.indexOf('-')) { + var tmp = timeout.split('-') + var min = parseInt(tmp[0], 10) + var max = parseInt(tmp[1], 10) + return Math.round(Math.random() * (max - min)) + min + } + }(MockXMLHttpRequest._settings.timeout) + + // 查找与请求参数匹配的数据模板 + var item = find(this.custom.options) + + function handle(event) { + // 同步属性 NativeXMLHttpRequest => MockXMLHttpRequest + for (var i = 0; i < XHR_RESPONSE_PROPERTIES.length; i++) { + try { + that[XHR_RESPONSE_PROPERTIES[i]] = xhr[XHR_RESPONSE_PROPERTIES[i]] + } catch (e) {} + } + // 触发 MockXMLHttpRequest 上的同名事件 + that.dispatchEvent(new Event(event.type /*, false, false, that*/ )) + } + + // 如果未找到匹配的数据模板,则采用原生 XHR 发送请求。 + if (!item) { + // 创建原生 XHR 对象,调用原生 open(),监听所有原生事件 + var xhr = createNativeXMLHttpRequest() + this.custom.xhr = xhr + + // 初始化所有事件,用于监听原生 XHR 对象的事件 + for (var i = 0; i < XHR_EVENTS.length; i++) { + xhr.addEventListener(XHR_EVENTS[i], handle) + } + + // xhr.open() + if (username) xhr.open(method, url, async, username, password) + else xhr.open(method, url, async) + + // 同步属性 MockXMLHttpRequest => NativeXMLHttpRequest + for (var j = 0; j < XHR_REQUEST_PROPERTIES.length; j++) { + try { + xhr[XHR_REQUEST_PROPERTIES[j]] = that[XHR_REQUEST_PROPERTIES[j]] + } catch (e) {} + } + + return + } + + // 找到了匹配的数据模板,开始拦截 XHR 请求 + this.match = true + this.custom.template = item + this.readyState = MockXMLHttpRequest.OPENED + this.dispatchEvent(new Event('readystatechange' /*, false, false, this*/ )) + }, + // https://xhr.spec.whatwg.org/#the-setrequestheader()-method + // Combines a header in author request headers. + setRequestHeader: function(name, value) { + // 原生 XHR + if (!this.match) { + this.custom.xhr.setRequestHeader(name, value) + return + } + + // 拦截 XHR + var requestHeaders = this.custom.requestHeaders + if (requestHeaders[name]) requestHeaders[name] += ',' + value + else requestHeaders[name] = value + }, + timeout: 0, + withCredentials: false, + upload: {}, + // https://xhr.spec.whatwg.org/#the-send()-method + // Initiates the request. + send: function send(data) { + var that = this + this.custom.options.body = data + + // 原生 XHR + if (!this.match) { + this.custom.xhr.send(data) + return + } + + // 拦截 XHR + + // X-Requested-With header + this.setRequestHeader('X-Requested-With', 'MockXMLHttpRequest') + + // loadstart The fetch initiates. + this.dispatchEvent(new Event('loadstart' /*, false, false, this*/ )) + + if (this.custom.async) setTimeout(done, this.custom.timeout) // 异步 + else done() // 同步 + + function done() { + that.readyState = MockXMLHttpRequest.HEADERS_RECEIVED + that.dispatchEvent(new Event('readystatechange' /*, false, false, that*/ )) + that.readyState = MockXMLHttpRequest.LOADING + that.dispatchEvent(new Event('readystatechange' /*, false, false, that*/ )) + + that.status = 200 + that.statusText = HTTP_STATUS_CODES[200] + + // fix #92 #93 by @qddegtya + that.response = that.responseText = JSON.stringify( + convert(that.custom.template, that.custom.options), + null, 4 + ) + + that.readyState = MockXMLHttpRequest.DONE + that.dispatchEvent(new Event('readystatechange' /*, false, false, that*/ )) + that.dispatchEvent(new Event('load' /*, false, false, that*/ )); + that.dispatchEvent(new Event('loadend' /*, false, false, that*/ )); + } + }, + // https://xhr.spec.whatwg.org/#the-abort()-method + // Cancels any network activity. + abort: function abort() { + // 原生 XHR + if (!this.match) { + this.custom.xhr.abort() + return + } + + // 拦截 XHR + this.readyState = MockXMLHttpRequest.UNSENT + this.dispatchEvent(new Event('abort', false, false, this)) + this.dispatchEvent(new Event('error', false, false, this)) + } + }) + + // 初始化 Response 相关的属性和方法 + Util.extend(MockXMLHttpRequest.prototype, { + responseURL: '', + status: MockXMLHttpRequest.UNSENT, + statusText: '', + // https://xhr.spec.whatwg.org/#the-getresponseheader()-method + getResponseHeader: function(name) { + // 原生 XHR + if (!this.match) { + return this.custom.xhr.getResponseHeader(name) + } + + // 拦截 XHR + return this.custom.responseHeaders[name.toLowerCase()] + }, + // https://xhr.spec.whatwg.org/#the-getallresponseheaders()-method + // http://www.utf8-chartable.de/ + getAllResponseHeaders: function() { + // 原生 XHR + if (!this.match) { + return this.custom.xhr.getAllResponseHeaders() + } + + // 拦截 XHR + var responseHeaders = this.custom.responseHeaders + var headers = '' + for (var h in responseHeaders) { + if (!responseHeaders.hasOwnProperty(h)) continue + headers += h + ': ' + responseHeaders[h] + '\r\n' + } + return headers + }, + overrideMimeType: function( /*mime*/ ) {}, + responseType: '', // '', 'text', 'arraybuffer', 'blob', 'document', 'json' + response: null, + responseText: '', + responseXML: null + }) + + // EventTarget + Util.extend(MockXMLHttpRequest.prototype, { + addEventListener: function addEventListener(type, handle) { + var events = this.custom.events + if (!events[type]) events[type] = [] + events[type].push(handle) + }, + removeEventListener: function removeEventListener(type, handle) { + var handles = this.custom.events[type] || [] + for (var i = 0; i < handles.length; i++) { + if (handles[i] === handle) { + handles.splice(i--, 1) + } + } + }, + dispatchEvent: function dispatchEvent(event) { + var handles = this.custom.events[event.type] || [] + for (var i = 0; i < handles.length; i++) { + handles[i].call(this, event) + } + + var ontype = 'on' + event.type + if (this[ontype]) this[ontype](event) + } + }) + + // Inspired by jQuery + function createNativeXMLHttpRequest() { + var isLocal = function() { + var rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/ + var rurl = /^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/ + var ajaxLocation = location.href + var ajaxLocParts = rurl.exec(ajaxLocation.toLowerCase()) || [] + return rlocalProtocol.test(ajaxLocParts[1]) + }() + + return window.ActiveXObject ? + (!isLocal && createStandardXHR() || createActiveXHR()) : createStandardXHR() + + function createStandardXHR() { + try { + return new window._XMLHttpRequest(); + } catch (e) {} + } + + function createActiveXHR() { + try { + return new window._ActiveXObject("Microsoft.XMLHTTP"); + } catch (e) {} + } + } + + + // 查找与请求参数匹配的数据模板:URL,Type + function find(options) { + + for (var sUrlType in MockXMLHttpRequest.Mock._mocked) { + var item = MockXMLHttpRequest.Mock._mocked[sUrlType] + if ( + (!item.rurl || match(item.rurl, options.url)) && + (!item.rtype || match(item.rtype, options.type.toLowerCase())) + ) { + // console.log('[mock]', options.url, '>', item.rurl) + return item + } + } + + function match(expected, actual) { + if (Util.type(expected) === 'string') { + return expected === actual + } + if (Util.type(expected) === 'regexp') { + return expected.test(actual) + } + } + + } + + // 数据模板 => 响应数据 + function convert(item, options) { + return Util.isFunction(item.template) ? + item.template(options) : MockXMLHttpRequest.Mock.mock(item.template) + } + + module.exports = MockXMLHttpRequest + + /***/ }) + /******/ ]) +}); +; \ No newline at end of file diff --git a/src/main/resources/org/bdware/sc/engine/yancloud_desktop.js b/src/main/resources/org/bdware/sc/engine/yancloud_desktop.js new file mode 100644 index 0000000..8b553d5 --- /dev/null +++ b/src/main/resources/org/bdware/sc/engine/yancloud_desktop.js @@ -0,0 +1,25 @@ +var YancloudUtil = org.bdware.sc.boundry.JavaScriptEntry; +var DOMUtil = org.bdware.sc.boundry.utils.DOMUtil; +var LedgerUtil = org.bdware.sc.boundry.utils.LedgerUtil; +var Global = {}; +var Indexes = {}; +Indexes.timeIndex = org.bdware.sc.boundry.TimeIndex; +Global.version = "V0.90_20200510"; +var defineProp = function (key, val) { + Global[key] = val; +} +var executeContract = function (contractid, action, arg) { + return YancloudUtil.executeContract(contractid, action, arg); +} + +var executeContractByDOI = function (contractDOI, action, arg) { + return YancloudUtil.executeContractByDOI(contractDOI, action, arg); +} + +var getAuthInfo = function () { + return YancloudUtil.getAuthInfo(); +} + +var setAuthInfo = function (authInfo) { + return YancloudUtil.setAuthInfo(authInfo); +} \ No newline at end of file diff --git a/src/test/data-mask/maskingJobs/DataXTest.java b/src/test/data-mask/maskingJobs/DataXTest.java new file mode 100644 index 0000000..253fada --- /dev/null +++ b/src/test/data-mask/maskingJobs/DataXTest.java @@ -0,0 +1,25 @@ +package maskingJobs; + +import org.junit.Test; + +import java.io.*; + +public class DataXTest { + @Test + public void dataXHomeTest() throws IOException { + MaskingJob mj = new MaskingJob(); + StringBuffer content = new StringBuffer(); + String s = null; + File directory = new File(""); + String path = directory.getCanonicalPath(); + try { + BufferedReader bf = new BufferedReader(new FileReader("./src/test/data-mask/maskingJobs/config.json")); + while((s = bf.readLine()) != null) { + content.append(s.trim()); + } + s = content.toString(); + } catch (Exception e) {} + String ans = mj.getMaskedData(s).getAsString(); + System.out.println(ans); + } +} diff --git a/src/test/java/org/bdware/analysis/DataBaseProcess.java b/src/test/java/org/bdware/analysis/DataBaseProcess.java new file mode 100644 index 0000000..6745eec --- /dev/null +++ b/src/test/java/org/bdware/analysis/DataBaseProcess.java @@ -0,0 +1,43 @@ +package org.bdware.analysis; + +public class DataBaseProcess { + public static void main(String[] args) { +// long timeJava; +// try { +// // start a process before +// long startJava = System.currentTimeMillis(); +// // authentication: user, dbname, pwd +// MongoCredential credential = MongoCredential.createCredential("yancloud-dbuser", "yancloud", +// "yancloud-112".toCharArray()); +// // connect to mongodb server +// ServerAddress addr = new ServerAddress("39.106.118.0", 27017); +// List credentials = new ArrayList(); +// credentials.add(credential); +// // connect to mongodb database +// // MongoClient mongoClient = new MongoClient(addr, +// // Arrays.asList(credential)); +// MongoClient mongoClient = new MongoClient(addr, credentials); +// MongoDatabase mongoDatabase = mongoClient.getDatabase("yancloud"); +// // list all the documents of collection +// MongoCollection collection = mongoDatabase.getCollection("containers"); +// FindIterable findIterable = collection.find(); +// MongoCursor mongoCursor = findIterable.iterator(); +// StringBuilder stringBuilder = new StringBuilder(); +// while (mongoCursor.hasNext()) { +// stringBuilder.append(mongoCursor.next().toJson()); +// } +// System.out.println(stringBuilder); +// timeJava = System.currentTimeMillis() - startJava; +// System.out.println("DataBaseTest of Java: " + timeJava + "\n\t"); +// mongoClient.close(); +// mongoClient = null; +// +// /* +// * findIterable.forEach(new Block() { public void apply(Document _doc) +// * { System.out.println(_doc.toJson()); } }); +// */ +// } catch (Exception e) { +// e.printStackTrace(); +// } + } +} diff --git a/src/test/java/org/bdware/analysis/dynamic/NaiveDynamicTaintAnalysisTest.java b/src/test/java/org/bdware/analysis/dynamic/NaiveDynamicTaintAnalysisTest.java new file mode 100644 index 0000000..85e423c --- /dev/null +++ b/src/test/java/org/bdware/analysis/dynamic/NaiveDynamicTaintAnalysisTest.java @@ -0,0 +1,57 @@ +package org.bdware.analysis.dynamic; + +import org.bdware.analysis.taint.TaintCFG; +import org.bdware.analysis.taint.TaintResult; +import org.bdware.sc.compiler.YJSCompiler; +import org.bdware.sc.engine.DesktopEngine; +import org.bdware.sc.node.ContractNode; +import org.bdware.sc.node.FunctionNode; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.MethodNode; + +import java.io.FileInputStream; +import java.util.HashMap; +import java.util.Map; + +public class NaiveDynamicTaintAnalysisTest extends NaiveDynamicTaintAnalysis { + public NaiveDynamicTaintAnalysisTest(TaintCFG cfg, TracedFile tf) { + super(cfg, tf); + } + + public static void main(String[] args) throws Exception { + String path = "/Users/hulingxuan/git/SmartContract/output/main.yjs"; + String tracePath = "/Users/hulingxuan/git/SmartContract/output/main.trace"; + ContractNode contractNode = null; + YJSCompiler compiler = new YJSCompiler(); + contractNode = compiler.compile(new FileInputStream(path), null); + DesktopEngine engine = new DesktopEngine(); + engine.loadContract(null,contractNode, false); + Map clzs = engine.dumpClass(); + Map methods = new HashMap<>(); + for (byte[] clz : clzs.values()) { + ClassNode classNode = new ClassNode(); + ClassReader cr = new ClassReader(clz); + cr.accept(classNode, ClassReader.EXPAND_FRAMES); + for (MethodNode mn : classNode.methods) { + methods.put(mn.name, mn); + } + } + // for (FunctionNode fn : contractNode.getFunctions()) { + // funNameList.add(fn.functionName); + // } + for (FunctionNode fn : contractNode.getFunctions()) { + MethodNode mn = methods.get(fn.functionName); + if (mn != null) { + TaintResult.nLocals = mn.maxLocals; + TaintResult.nStack = mn.maxStack; + TaintCFG cfg = new TaintCFG(mn); + cfg.printSelf(); + TracedFile tf = new TracedFile(new FileInputStream(tracePath)); + cfg.getLabelOrder(); + NaiveDynamicTaintAnalysis analysis = new NaiveDynamicTaintAnalysis(cfg, tf); + analysis.analysis(); + } + } + } +} diff --git a/src/test/java/org/bdware/analysis/dynamic/test/FSAnalysisTest.java b/src/test/java/org/bdware/analysis/dynamic/test/FSAnalysisTest.java new file mode 100644 index 0000000..9892c82 --- /dev/null +++ b/src/test/java/org/bdware/analysis/dynamic/test/FSAnalysisTest.java @@ -0,0 +1,16 @@ +package org.bdware.analysis.dynamic.test; + +import org.bdware.sc.analysis.dynamic.FSAnalysis; +import org.bdware.sc.bean.Contract; +import org.bdware.sc.util.FileUtil; + +public class FSAnalysisTest { + public static void main(String[] args) throws Exception { + Contract contract = new Contract(); + FSAnalysis.isDebug = true; + String content = + FileUtil.getFileContent("/Users/hulingxuan/git/SmartContract/contractExamples/fsanlysis.yjs"); + contract.setScript(null == content ? "" : content); + FSAnalysis.staticVerify(contract); + } +} diff --git a/src/test/java/org/bdware/analysis/example/MultiSourceTaintAyalysisTest.java b/src/test/java/org/bdware/analysis/example/MultiSourceTaintAyalysisTest.java new file mode 100644 index 0000000..577ed8e --- /dev/null +++ b/src/test/java/org/bdware/analysis/example/MultiSourceTaintAyalysisTest.java @@ -0,0 +1,114 @@ +package org.bdware.analysis.example; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import org.bdware.analysis.BasicBlock; +import org.bdware.analysis.FrontCF; +import org.bdware.analysis.taint.TaintBB; +import org.bdware.analysis.taint.TaintCFG; +import org.bdware.analysis.taint.TaintResult; +import org.bdware.sc.ContractResult; +import org.bdware.sc.compiler.YJSCompiler; +import org.bdware.sc.engine.DesktopEngine; +import org.bdware.sc.node.ContractNode; +import org.bdware.sc.node.FunctionNode; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.MethodNode; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.zip.ZipFile; + +public class MultiSourceTaintAyalysisTest extends MultiSourceTaintAnalysis { + public MultiSourceTaintAyalysisTest(TaintCFG cfg) { + super(cfg); + } + + public static void main(String[] args) throws Exception { + long start = System.currentTimeMillis(); + // String clzPath = + // "./output/traceTest/wrp/jdk/nashorn/internal/scripts/Script$Recompilation$7$23A$contract_main_yjs7.class"; + + // String path = + // "/Users/damei/Documents/Project/DataContract/SmartContract/contractExamples/traceTest/main.yjs"; + String path = + "/Users/damei/Documents/Project/DataContract/SmartContract/contractExamples/Test.yjs"; + + ContractNode contractNode = null; + YJSCompiler compiler = new YJSCompiler(); + + // contractNode = compiler.compile(new FileInputStream(path), "contract_main.yjs"); + // contractNode = compiler.compile(new FileInputStream(path), "DORepo.yjs"); + contractNode = + compiler.compile( + new ZipFile( + "/Users/huaqiancai/BDWare/BDContract/front-agent/./BDWareProjectDir/publicCompiled/StaticAnalysisExample_2020-07-09-00.ypk")) + .mergeContractNode(); + DesktopEngine engine = new DesktopEngine(); // engine.loadJar(zf); + ContractResult result2 = engine.loadContract(null,contractNode, false); + System.out.println("----LoadResult------"); + System.out.println(new Gson().toJson(result2)); + Map clzs = engine.dumpClass(); + Map methods = new HashMap<>(); + System.out.println("[ContractManager] load bytecode:"); + for (byte[] clz : clzs.values()) { + ClassNode classNode = new ClassNode(); + ClassReader cr = new ClassReader(clz); + cr.accept(classNode, ClassReader.EXPAND_FRAMES); + for (MethodNode mn : classNode.methods) { + methods.put(mn.name, mn); + System.out.println("[ContractManager] putMethod:" + mn.name); + } + } + Map result = new HashMap<>(); + for (FunctionNode fn : contractNode.getFunctions()) { + MethodNode mn = methods.get(fn.functionName); + if (mn != null) { + TaintResult.nLocals = mn.maxLocals; + TaintResult.nStack = mn.maxStack; + TaintCFG cfg = new TaintCFG(mn); + + // DependencyAnalysis + + // if(fn.functionName.equals("depTest")) + // depAnalysis(cfg); + + + + + + TaintResult.printer.setLabelOrder(cfg.getLabelOrder()); + MultiSourceTaintAnalysis analysis = new MultiSourceTaintAnalysis(cfg); + analysis.analysis(); + Map> map = MultiSourceTaintAnalysis.depAnalysis(cfg); + FrontCF frontCF = new FrontCF(cfg); + String[] data = fn.plainText().split("\n"); + for (int i = 0; i < cfg.getBasicBlockSize(); i++) { + BasicBlock bb = cfg.getBasicBlockAt(i); + String decompiled = ""; + if (bb.lineNum - 1 < data.length && bb.lineNum > 0) { + decompiled = data[bb.lineNum - 1]; + } + List ids = map.get(i); + frontCF.addBB(bb, decompiled, ids, cfg); + Set suc = cfg.getSucBlocks(bb); + for (BasicBlock sucBB : suc) frontCF.addEdge(bb, sucBB); + } + TaintBB bb = cfg.getLastBlock(); + cfg.printSelf(); + // printTest + // if(fn.functionName.equals("setDBInfo")) + // cfg.printSelf(); + + if (bb != null) result.put(fn.functionName, bb.getResultWithTaintBit()); + System.out.println("[ContractManager] verifyDone:" + fn.functionName); + } + } + System.out.println(new GsonBuilder().setPrettyPrinting().create().toJson(result)); + long end = System.currentTimeMillis(); + System.out.println(end - start); + } +} diff --git a/src/test/java/org/bdware/analysis/example/NaiveTaintAnalysisTest.java b/src/test/java/org/bdware/analysis/example/NaiveTaintAnalysisTest.java new file mode 100644 index 0000000..3440378 --- /dev/null +++ b/src/test/java/org/bdware/analysis/example/NaiveTaintAnalysisTest.java @@ -0,0 +1,78 @@ +package org.bdware.analysis.example; + +import org.bdware.analysis.taint.TaintCFG; +import org.bdware.analysis.taint.TaintResult; +import org.bdware.sc.compiler.YJSCompiler; +import org.bdware.sc.engine.DesktopEngine; +import org.bdware.sc.node.ContractNode; +import org.bdware.sc.node.FunctionNode; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.MethodNode; + +import java.io.FileInputStream; +import java.util.HashMap; +import java.util.Map; + +public class NaiveTaintAnalysisTest extends NaiveTaintAnalysis { + public NaiveTaintAnalysisTest(TaintCFG cfg) { + super(cfg); + } + + public static void main(String[] args) throws Exception { + String path = "/Users/hulingxuan/git/SmartContract/output/main.yjs"; + // String tracePath = "/Users/hulingxuan/git/SmartContract/output/main.trace"; + ContractNode contractNode = null; + YJSCompiler compiler = new YJSCompiler(); + contractNode = compiler.compile(new FileInputStream(path), null); + DesktopEngine engine = new DesktopEngine(); + engine.loadContract(null,contractNode, false); + Map clzs = engine.dumpClass(); + Map methods = new HashMap<>(); + for (byte[] clz : clzs.values()) { + ClassNode classNode = new ClassNode(); + ClassReader cr = new ClassReader(clz); + cr.accept(classNode, ClassReader.EXPAND_FRAMES); + for (MethodNode mn : classNode.methods) { + methods.put(mn.name, mn); + } + } + // for (FunctionNode fn : contractNode.getFunctions()) { + // funNameList.add(fn.functionName); + // } + for (FunctionNode fn : contractNode.getFunctions()) { + MethodNode mn = methods.get(fn.functionName); + if (mn != null) { + TaintResult.nLocals = mn.maxLocals; + TaintResult.nStack = mn.maxStack; + TaintCFG cfg = new TaintCFG(mn); + // cfg.printSelf(); + // TracedFile tf = new TracedFile(new FileInputStream(tracePath)); + cfg.getLabelOrder(); + NaiveTaintAnalysis analysis = new NaiveTaintAnalysis(cfg); + analysis.analysis(); + cfg.printSelf(); + } + } + // String clzPath = + // "./output/traceTest/wrp/jdk/nashorn/internal/scripts/Script$Recompilation$7$23A$contract_main_yjs7.class"; + // // String clzPath = + // // + // "/Users/damei/Documents/Project/DataContract/SmartContract/output/traceTest/wrp/jdk/nashorn/internal/scripts/Script$Recompilation$5$23A$contract_main_yjs5.class"; + // ClassReader cr = new ClassReader(new FileInputStream(clzPath)); + // ClassNode cn = new ClassNode(); + // TaintResult.nLocals = 15; + // TaintResult.nStack = 5; + // cr.accept(cn, ClassReader.EXPAND_FRAMES); + // for (MethodNode mn : cn.methods) { + // if (mn.name.equals("statAge")) { + // System.out.println("[NaiveTaintAnalysis] Matched Method:" + mn.name + mn.desc); + // TaintCFG cfg = new TaintCFG(mn); + // TaintResult.printer.setLabelOrder(cfg.getLabelOrder()); + // NaiveTaintAnalysis analysis = new NaiveTaintAnalysis(cfg); + // analysis.analysis(); + // cfg.printSelf(); + // } + // } + } +} diff --git a/src/test/java/org/bdware/analysis/gas/PPCountTest.java b/src/test/java/org/bdware/analysis/gas/PPCountTest.java new file mode 100644 index 0000000..b2305a0 --- /dev/null +++ b/src/test/java/org/bdware/analysis/gas/PPCountTest.java @@ -0,0 +1,76 @@ +package org.bdware.analysis.gas; + +import org.bdware.analysis.BasicBlock; +import org.bdware.analysis.CFGraph; +import org.bdware.sc.compiler.YJSCompiler; +import org.bdware.sc.engine.DesktopEngine; +import org.bdware.sc.node.ContractNode; +import org.bdware.sc.node.FunctionNode; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.MethodNode; + +import java.io.FileInputStream; +import java.util.HashMap; +import java.util.Map; + +public class PPCountTest extends PPCount { + public PPCountTest(CFGraph cfg, int flag) { + super(cfg, flag); + } + + public static void main(String[] args) throws Exception { + String path = "/Users/hulingxuan/git/SmartContract/output/main.yjs"; + + ContractNode contractNode = null; + YJSCompiler compiler = new YJSCompiler(); + contractNode = compiler.compile(new FileInputStream(path), null); + DesktopEngine engine = new DesktopEngine(); + engine.loadContract(null, contractNode, false); + + Map clzs = engine.dumpClass(); + Map methods = new HashMap<>(); + for (byte[] clz : clzs.values()) { + ClassNode classNode = new ClassNode(); + ClassReader cr = new ClassReader(clz); + cr.accept(classNode, ClassReader.EXPAND_FRAMES); + for (MethodNode mn : classNode.methods) { + methods.put(mn.name, mn); + } + } + int flag = 0; + for (FunctionNode fn : contractNode.getFunctions()) { + functionList.add(fn.functionName); + // flag++; + MethodNode mn = methods.get("log"); + if (mn != null) { + CFGraph cfg = + new CFGraph(mn) { + @Override + public BasicBlock getBasicBlock(int id) { + return new BasicBlock(id); + } + }; + cfg.getLabelOrder(); + PPCount countFee = new PPCount(cfg, flag); + + // countFee.analysis(); + // cfg.printSelf(); + } + } + + System.out.println(callFunction); + System.out.println(branchCount); + System.out.println(BlockInsn); + System.out.println(ppMap); + Evaluates feEvaluates = new Evaluates(); + System.out.println(feEvaluates.getCallFee()); + + // System.out.println(callFunction); + // System.out.println(branchCount); + // System.out.println(BlockInsn); + // System.out.println(ppMap); + // Evaluates feEvaluates = new Evaluates(callFunction); + // System.out.println(feEvaluates.getCallFee()); + } +} diff --git a/src/test/java/org/bdware/analysis/gas/Test.java b/src/test/java/org/bdware/analysis/gas/Test.java new file mode 100644 index 0000000..e0f34bc --- /dev/null +++ b/src/test/java/org/bdware/analysis/gas/Test.java @@ -0,0 +1,56 @@ +package org.bdware.analysis.gas; + +import org.bdware.sc.compiler.YJSCompiler; +import org.bdware.sc.engine.DesktopEngine; +import org.bdware.sc.node.ContractNode; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.MethodNode; + +import java.io.FileInputStream; +import java.util.HashMap; +import java.util.Map; + +public class Test { + public static void main(String[] args) throws Exception { + String path = "/Users/hulingxuan/git/SmartContract/output/main.yjs"; + String tracePath = "/Users/hulingxuan/git/SmartContract/output/main.trace"; + ContractNode contractNode = null; + YJSCompiler compiler = new YJSCompiler(); + contractNode = compiler.compile(new FileInputStream(path), null); + DesktopEngine engine = new DesktopEngine(); + engine.loadContract(null, contractNode, false); + Map clzs = engine.dumpClass(); + Map methods = new HashMap<>(); + for (byte[] clz : clzs.values()) { + ClassNode classNode = new ClassNode(); + ClassReader cr = new ClassReader(clz); + cr.accept(classNode, ClassReader.EXPAND_FRAMES); + for (MethodNode mn : classNode.methods) { + methods.put(mn.name, mn); + } + } + // for (FunctionNode fn : contractNode.getFunctions()) { + // funNameList.add(fn.functionName); + // } + // CollectAnalysis collection = null; + // for (FunctionNode fn : contractNode.getFunctions()) { + // MethodNode mn = methods.get(fn.functionName); + // if (mn != null) { + // TaintResult.nLocals = mn.maxLocals; + // TaintResult.nStack = mn.maxStack; + // TaintCFG cfg = new TaintCFG(mn); + // // cfg.printSelf(); + // TracedFile tf = new TracedFile(new FileInputStream(tracePath)); + // cfg.getLabelOrder(); + // collection = new CollectAnalysis(cfg, tf); + // collection.analysis(); + // } + // } + // System.out.println(CollectAnalysis.branchCount); + // System.out.println(varInsnCount); + // System.out.println(callFunction); + // Evaluates forecast = new Evaluates(callFunction, varInsnCount, branchCount, "log"); + // System.out.println(forecast.getSum()); + } +} diff --git a/src/test/java/org/bdware/sc/blockdb/test/ElasticDBUtilTest.java b/src/test/java/org/bdware/sc/blockdb/test/ElasticDBUtilTest.java new file mode 100644 index 0000000..c1814be --- /dev/null +++ b/src/test/java/org/bdware/sc/blockdb/test/ElasticDBUtilTest.java @@ -0,0 +1,24 @@ +package org.bdware.sc.blockdb.test; + +import org.bdware.bdledger.api.grpc.Client; + +public class ElasticDBUtilTest { + public static void main(String[] args) { + Client ci = new Client("127.0.0.1", 18095); + System.out.println(ci.clientVersionSync()); +// long start = System.currentTimeMillis(); +// ElasticDBUtil util = new ElasticDBUtil(); +// //System.out.println(util.Create_DB()); +// for (int i=0;i<10000000;i++) { +// Transaction trans = new Transaction(); +// trans.data = ("eee1688b9d431ee448d97ed1dbdb62339b1b68d3"+i).getBytes(); +// trans.hash = ("aee1688b9d431ee448d97ed1dbdb62339"+i).getBytes(); +// util.Put(trans); +// } +// //Map condition = new HashMap<>(); +// //condition.put("data", "hello10"); +// //util.Get(condition); +// long end = System.currentTimeMillis(); +// System.out.println("consume time =>"+(end-start)); + } +} diff --git a/src/test/java/org/bdware/sc/blockdb/test/SQLiteTest.java b/src/test/java/org/bdware/sc/blockdb/test/SQLiteTest.java new file mode 100644 index 0000000..130203a --- /dev/null +++ b/src/test/java/org/bdware/sc/blockdb/test/SQLiteTest.java @@ -0,0 +1,23 @@ +package org.bdware.sc.blockdb.test; + +public class SQLiteTest { + public static void main(String[] args) { +// SqliteDBUtil db = SqliteDBUtil.connect("testdb"); +// Block block = db.getBlock("bb68c4a00b251ea350bbb28052eb44b565749586", "480af5c0c74eb471b671edb49bc9db93dc3456e4"); +// DataInputStream in = new DataInputStream(new ByteArrayInputStream(block.blockheader.prevblockID)); +// byte[] b1 = new byte[20]; +// byte[] b2 = new byte[20]; +// byte[] b3 = new byte[20]; +// try { +// in.read(b1); +// in.read(b2); +// in.read(b3); +// } catch (IOException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } +// System.out.print(HashUtil.byteArray2Str(b1)); +// System.out.println(HashUtil.byteArray2Str(b2)); +// System.out.println(HashUtil.byteArray2Str(b3)); + } +} diff --git a/src/test/java/org/bdware/sc/boundry/test/ACIndexTest.java b/src/test/java/org/bdware/sc/boundry/test/ACIndexTest.java new file mode 100644 index 0000000..b492e60 --- /dev/null +++ b/src/test/java/org/bdware/sc/boundry/test/ACIndexTest.java @@ -0,0 +1,41 @@ +package org.bdware.sc.boundry.test; + +import org.bdware.sc.boundry.AccountIndex; +import org.bdware.sc.boundry.JavaScriptEntry; +import org.bdware.sc.engine.DesktopEngine; +import wrp.jdk.nashorn.api.scripting.ScriptObjectMirror; +import wrp.jdk.nashorn.internal.objects.Global; +import wrp.jdk.nashorn.internal.runtime.Context; +import wrp.jdk.nashorn.internal.runtime.ScriptObject; + +public class ACIndexTest { + public static void main(String[] args) { + AccountIndex index = AccountIndex.createIndex(); + DesktopEngine engine = new DesktopEngine(); + engine.getDesktopGlobal(); + Context.setGlobal(JavaScriptEntry.getEngineGlobal()); + ScriptObjectMirror mir = (ScriptObjectMirror) ScriptObjectMirror.wrap(Global.allocate(new int[0]), engine.getDesktopGlobal()); + mir.setMember("account", "ac1"); + mir.setMember("file", "time"); + mir.setMember("dataLength", "32"); + ScriptObject obj = index.createFile(mir); + System.out.println(obj); + mir.clear(); + for (int i = 0; i < 10000000; i++) { + mir.setMember("account", "ac1"); + mir.setMember("file", "time"); + mir.setMember("content", "61c1dc1d49ccd251b2f73567c776b4607dd36b12fa64e49e7ca53630102d0389"); + mir.setMember("date", 1578042000 + i); + obj = index.manullyIndex(mir); + } + long start = System.currentTimeMillis(); + mir.clear(); + mir.setMember("account", "ac1"); + mir.setMember("file", "time"); + mir.setMember("startTime", 1578042000); + mir.setMember("endTime", 1578042060); + obj = index.requestByTime(mir); + long end = System.currentTimeMillis(); + System.out.println(end - start); + } +} diff --git a/src/test/java/org/bdware/sc/boundry/test/HttpPostTest.java b/src/test/java/org/bdware/sc/boundry/test/HttpPostTest.java new file mode 100644 index 0000000..ba0f93e --- /dev/null +++ b/src/test/java/org/bdware/sc/boundry/test/HttpPostTest.java @@ -0,0 +1,116 @@ +package org.bdware.sc.boundry.test; + +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.Scanner; + +public class HttpPostTest { + public static String querySection(String str) throws Exception { + str = "http://162.105.138.123/net25/" + str; + URL url = new URL(str); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + InputStream input = connection.getInputStream(); + Scanner sc = new Scanner(input, "GB2312"); + StringBuilder sb = new StringBuilder(); + while (sc.hasNextLine()) { + sb.append(sc.nextLine()).append("\n"); + } + sc.close(); + return sb.toString(); + } + + private static String buildProcess(ProcessBuilder builder) throws IOException { + // new String(text.getBytes("ISO-8859-1"),"GBK") + Process process = builder.start(); + Scanner scanner = new Scanner(process.getInputStream(), "ISO-8859-1"); + StringBuilder stringBuilder = new StringBuilder(); + while (scanner.hasNextLine()) { + stringBuilder.append(scanner.nextLine()).append("\n"); + } + return new String(stringBuilder.toString().getBytes(StandardCharsets.ISO_8859_1), "GB2312"); + } + + public static String get24Html(String url) { + ProcessBuilder builder = new ProcessBuilder("curl", url, "-H", "Connection: keep-alive", "-H", + "Cache-Control: max-age=0", "-H", "Origin: http://162.105.138.123", "-H", + "Upgrade-Insecure-Requests: 1", "-H", "Content-Type: application/x-www-form-urlencoded", "-H", + "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36", + "-H", + "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", + "-H", "Referer: http://162.105.138.123/net25/query.asp", "-H", "Accept-Encoding: gzip, deflate", "-H", + "Accept-Language: zh-CN,zh;q=0.9", "-H", + "Cookie: setstring=%CB%CE%CC%E5%2FBLACK%2F4%2F%C1%A5%CA%E9%2FBLUE%2F2%2F%CB%CE%CC%E5%2Fgreen%2F3%2F%C1%A5%CA%E9%2FBLUE%2F2; clientadd=10%2E1%2E12%2E68; serveradd=162%2E105%2E138%2E123; ASPSESSIONIDAQQTRBDT=HHKDBDKBHGLMACLALGIFGKPO", + "--compressed"); + try { + return buildProcess(builder); + } catch (Exception e) { + e.printStackTrace(); + } + return "failed"; + } + + public static String getCatalogHtml(String key) { + ProcessBuilder builder = new ProcessBuilder("curl", "http://162.105.138.123/net25/readns-25.htm", "-H", + "Connection: keep-alive", "-H", "Cache-Control: max-age=0", "-H", "Origin: http://162.105.138.123", + "-H", "Upgrade-Insecure-Requests: 1", "-H", "Content-Type: application/x-www-form-urlencoded", "-H", + "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36", + "-H", + "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", + "-H", "Referer: http://162.105.138.123/net25/query.asp", "-H", "Accept-Encoding: gzip, deflate", "-H", + "Accept-Language: zh-CN,zh;q=0.9", "-H", + "Cookie: setstring=%CB%CE%CC%E5%2FBLACK%2F4%2F%C1%A5%CA%E9%2FBLUE%2F2%2F%CB%CE%CC%E5%2Fgreen%2F3%2F%C1%A5%CA%E9%2FBLUE%2F2; clientadd=10%2E1%2E12%2E68; serveradd=162%2E105%2E138%2E123; ASPSESSIONIDAQQTRBDT=HHKDBDKBHGLMACLALGIFGKPO", + "--compressed"); + try { + return buildProcess(builder); + } catch (Exception e) { + e.printStackTrace(); + } + return "failed"; + } + + public static String query24(String keyword) { + ProcessBuilder builder = new ProcessBuilder("curl", "http://162.105.138.123/net25/readwhole.asp", "-H", + "Connection: keep-alive", "-H", "Cache-Control: max-age=0", "-H", "Origin: http://162.105.138.123", + "-H", "Upgrade-Insecure-Requests: 1", "-H", "Content-Type: application/x-www-form-urlencoded", "-H", + "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36", + "-H", + "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3", + "-H", "Referer: http://162.105.138.123/net25/query.asp", "-H", "Accept-Encoding: gzip, deflate", "-H", + "Accept-Language: zh-CN,zh;q=0.9", "-H", + "Cookie: setstring=%CB%CE%CC%E5%2FBLACK%2F4%2F%C1%A5%CA%E9%2FBLUE%2F2%2F%CB%CE%CC%E5%2Fgreen%2F3%2F%C1%A5%CA%E9%2FBLUE%2F2; clientadd=10%2E1%2E12%2E68; serveradd=162%2E105%2E138%2E123; ASPSESSIONIDAQQTRBDT=HHKDBDKBHGLMACLALGIFGKPO", + "--data", + "query=_keyword&B1=%BC%EC+%CB%F7&colid=2.0&colid=2.1&colid=2.14&colid=2.25&colid=2.34&colid=2.65&colid=2.136&colid=2.138" + .replace("_keyword", keyword), + "--compressed"); + try { + return buildProcess(builder); + } catch (Exception e) { + e.printStackTrace(); + } + return "failed"; + } + + public static void main(String[] args) throws Exception { +// String data = getCatalogHtml(null); +// FileOutputStream fout = new FileOutputStream("./output/shiji.txt"); +// Document doc = Jsoup.parse(data); +// Element body = doc.select("body").get(0); +// for (int i = 0; i < body.children().size(); i++) { +// Element ele = body.child(i); +// +// if (ele.tagName().equals("span")) +// System.out.println(ele.text()); +// } + + System.out.println(querySection("aa")); + } + + static class Item { + String title; + String url; + } +} diff --git a/src/test/java/org/bdware/sc/boundry/test/YancloudUtilTest.java b/src/test/java/org/bdware/sc/boundry/test/YancloudUtilTest.java new file mode 100644 index 0000000..61c5c78 --- /dev/null +++ b/src/test/java/org/bdware/sc/boundry/test/YancloudUtilTest.java @@ -0,0 +1,27 @@ +package org.bdware.sc.boundry.test; + +import java.util.Scanner; + +public class YancloudUtilTest { + public static void main(String[] arg) { + Scanner sc = new Scanner(System.in); + String bufLine = ""; + for (String line; (line = sc.nextLine()) != null; ) { + if (line.length() > 2) { + bufLine = line; + } + if (line.length() < 2) { + line = bufLine; + } + final String data = line; + new Thread(() -> { + System.out.println(data); + // long start = System.currentTimeMillis(); + + // String ret = JavaScriptEntry.httpGet(data).substring(0, 100); + // System.out.println(System.currentTimeMillis() - start + " " + + // ret); + }).start(); + } + } +} diff --git a/src/test/java/org/bdware/sc/boundry/utils/test/AESUtilTest.java b/src/test/java/org/bdware/sc/boundry/utils/test/AESUtilTest.java new file mode 100644 index 0000000..ec0b39a --- /dev/null +++ b/src/test/java/org/bdware/sc/boundry/utils/test/AESUtilTest.java @@ -0,0 +1,19 @@ +package org.bdware.sc.boundry.utils.test; + +import org.bdware.sc.boundry.utils.AESUtil; +import wrp.jdk.nashorn.internal.runtime.ScriptObject; + +public class AESUtilTest { + public static void main(String[] args) throws Exception { + String skey = AESUtil.generateKey(256); + System.out.println(skey); + String hw = "Hello World!"; + ScriptObject so = AESUtil.encrypt(skey, hw); + String iv = so.get("iv").toString(); + String cipherText = so.get("cipherText").toString(); + System.out.println(iv); + System.out.println(cipherText); + String result = AESUtil.decrypt(skey, cipherText, iv); + System.out.println(result); + } +} diff --git a/src/test/java/org/bdware/sc/boundry/utils/test/LedgerUtilTest.java b/src/test/java/org/bdware/sc/boundry/utils/test/LedgerUtilTest.java new file mode 100644 index 0000000..9ea3f7e --- /dev/null +++ b/src/test/java/org/bdware/sc/boundry/utils/test/LedgerUtilTest.java @@ -0,0 +1,12 @@ +package org.bdware.sc.boundry.utils.test; + +import org.bdware.bdledger.api.grpc.Client; + +public class LedgerUtilTest { + public static void main(String[] arg) { + Client c = new Client("39.108.56.240", 18091); + // c.sendTransactionSync("test", TransactionType.RECORD, arg2, arg3, arg4) + System.out.println(c.clientVersionSync().getVersion()); + System.out.println(c.getLedgersSync().toString()); + } +} diff --git a/src/test/java/org/bdware/sc/boundry/utils/test/SQLUtilTest.java b/src/test/java/org/bdware/sc/boundry/utils/test/SQLUtilTest.java new file mode 100644 index 0000000..f2c51e7 --- /dev/null +++ b/src/test/java/org/bdware/sc/boundry/utils/test/SQLUtilTest.java @@ -0,0 +1,46 @@ +package org.bdware.sc.boundry.utils.test; + +import java.sql.*; + +public class SQLUtilTest { + public static void main(String[] args) { + Connection con; + String driver = "com.mysql.cj.jdbc.Driver"; + String url = "jdbc:mysql://39.106.6.6:3306/haiou"; + // MySQL配置时的用户名 + String user = "haiou"; + // MySQL配置时的密码 + String password = "haiou"; + // 遍历查询结果集 + try { + // 加载驱动程序 + Class.forName(driver); + // 1.getConnection()方法,连接MySQL数据库!! + con = DriverManager.getConnection(url, user, password); + + if (!con.isClosed()) System.out.println("Succeeded connecting to the Database!"); + // 2.创建statement类对象,用来执行SQL语句!! + Statement statement = con.createStatement(); + + String sql = "select * from catering limit 0,10"; + // 3.ResultSet类,用来存放获取的结果集!! + ResultSet rs = statement.executeQuery(sql); + ResultSetMetaData metaData = rs.getMetaData(); + System.out.println("FetchedSize:" + rs.getFetchSize()); + String job = null; + String id = null; + + for (int i = 1; i <= metaData.getColumnCount(); i++) { + // int columnType = metaData.getColumnType(i); + System.out.println( + metaData.getColumnTypeName(i) + " --> " + metaData.getColumnName(i)); + } + while (rs.next()) { + // 输出结果 + System.out.println(id + "777\t" + job); + } + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/src/test/java/org/bdware/sc/engine/hook/test/MaskVisitorTest.java b/src/test/java/org/bdware/sc/engine/hook/test/MaskVisitorTest.java new file mode 100644 index 0000000..751a4f5 --- /dev/null +++ b/src/test/java/org/bdware/sc/engine/hook/test/MaskVisitorTest.java @@ -0,0 +1,21 @@ +package org.bdware.sc.engine.hook.test; + +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; +import org.bdware.sc.engine.hook.MaskVisitor; + +public class MaskVisitorTest { + public static void main(String[] args) { + String mask = "[{\"score\":\"md5\",\"name\":\"fpe\",\"grade\":\"edp\",\"number\":\"aes\",\"info\":{\"age\":\"edp\",\"sex\":\"md5\"}}]"; + String data = "[{\"score\":11,\"name\":\"ccq\",\"grade\":98.5,\"number\":2001210533,\"info\":{\"age\":\"18\",\"sex\":\"m\"}},{\"score\":11,\"name\":\"ccq\",\"grade\":98.5,\"number\":2001210533}]"; + + String m1 = "{\"score\":\"edp\",\"name\":\"md5\"}"; + String d1 = "{\"score\":\"95\",\"name\":\"zzz\"}"; + JsonElement je = JsonParser.parseString(data); + JsonElement maskje = JsonParser.parseString(mask); + MaskVisitor visitor = new MaskVisitor(je); + visitor.visit(maskje); + JsonElement root = visitor.get(); + System.out.println(root.toString()); + } +} diff --git a/src/test/java/org/bdware/sc/engine/test/MockUtilTest.java b/src/test/java/org/bdware/sc/engine/test/MockUtilTest.java new file mode 100644 index 0000000..54262ee --- /dev/null +++ b/src/test/java/org/bdware/sc/engine/test/MockUtilTest.java @@ -0,0 +1,42 @@ +package org.bdware.sc.engine.test; + +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; +import org.bdware.sc.engine.MockUtil; +import org.bdware.sc.util.MockSchemaParser; + +public class MockUtilTest { + public static void main(String[] args) { + // "{'result|min-max':1}":min-max之间的一个数字 如:"{'result|1-100':1}" 返回: {"result":21} + // "{'result':'@integer(1,100)'}"; 返回一个整数:{"result":5171830293164278} + // "{'result':'@string'}" 返回一个字符串 {"result":"2ejKET"} + // "{'result':'@datetime'}" "{'result':'@date'}" "{'result':'@time'}" + // "{'result':'@cname'}" "{'result':'@name'}" "{'result':'@first'}" "{'result':'@last'}" + // "{'result':'@email'}" "{'result':'@ip'}" {'result':'@url'}" + // "{'result':'@province'}" "{'result':'@city'}" "{'result':'@county'}" + // {'id':'@integer','email':'@email','password':'@string','name':'@name'} + // String template="{'result|1-100':1}"; + /// + // Object res = mock("'@email'"); + // if (res instanceof ScriptObjectMirror) + // System.out.println(JSONTool.copy((ScriptObjectMirror) res)); + // else System.out.println(res); + // System.out.println(res); + // "{'list|1-5':[{'id|+1':1,'data':'@datetime','nickname': '@cname','email':'@email'}]} + String str = "\"{\\\"score\\\":1}\""; + str = "{\"status\":\"success\", \"data\":[{\"score\":1, \"list\":[4,5,6]}]}"; + String str1 = "[{\"score\":1}]"; + MockSchemaParser parser = new MockSchemaParser(); + JsonElement ele = JsonParser.parseString(str); + System.out.println(ele.toString()); + parser.visit(ele); + JsonElement ele2 = parser.get(); + System.out.println(ele2); + Object ret = MockUtil.mock(ele2.toString()); + +// System.out.println( +// (JSONTool.copy((jdk.nashorn.api.scripting.ScriptObjectMirror) mock(ele2.toString()))).toString()); + + System.out.println(MockUtil.mock("'@string'")); + } +} diff --git a/src/test/java/org/bdware/sc/parser/YJSParserTest.java b/src/test/java/org/bdware/sc/parser/YJSParserTest.java new file mode 100644 index 0000000..ee652ad --- /dev/null +++ b/src/test/java/org/bdware/sc/parser/YJSParserTest.java @@ -0,0 +1,78 @@ +package org.bdware.sc.parser; + +import com.google.gson.Gson; +import org.antlr.v4.runtime.ANTLRInputStream; +import org.antlr.v4.runtime.CommonTokenStream; +import org.antlr.v4.runtime.DiagnosticErrorListener; +import org.bdware.sc.ContractResult; +import org.bdware.sc.bean.ContractRequest; +import org.bdware.sc.compiler.YJSCompiler; +import org.bdware.sc.compiler.YJSErrorListener; +import org.bdware.sc.engine.DesktopEngine; +import org.bdware.sc.node.ContractNode; +import org.junit.Test; + +import java.io.*; + +public class YJSParserTest { + @Test + public void YJSParserElseTest(){ + InputStream resource = YJSParserTest.class.getClassLoader().getResourceAsStream("module1.yjs"); + JavaScriptLexer lexer = null; + try { + lexer = new JavaScriptLexer(new ANTLRInputStream(resource)); + + lexer.setUseStrictDefault(true); + CommonTokenStream cts = new CommonTokenStream(lexer); + YJSErrorListener errorListener = new YJSErrorListener(); + // 语法分析 + YJSParser parser = new YJSParser(cts); + parser.removeErrorListeners(); + parser.addErrorListener(errorListener); + parser.addErrorListener(new DiagnosticErrorListener()); + YJSParser.ProgramContext tree = parser.program(); + for (String str:errorListener.getResultList()) + System.out.println(str); + } catch (IOException e) { + e.printStackTrace(); + } + } + + @Test + public void functionTest(){ + InputStream resource = YJSParserTest.class.getClassLoader().getResourceAsStream("function.yjs"); + JavaScriptLexer lexer = null; + try { + lexer = new JavaScriptLexer(new ANTLRInputStream(resource)); + + lexer.setUseStrictDefault(true); + CommonTokenStream cts = new CommonTokenStream(lexer); + YJSErrorListener errorListener = new YJSErrorListener(); + // 语法分析 + YJSParser parser = new YJSParser(cts); + parser.removeErrorListeners(); + parser.addErrorListener(errorListener); + parser.addErrorListener(new DiagnosticErrorListener()); + YJSParser.ProgramContext tree = parser.program(); + for (String str:errorListener.getResultList()) + System.out.println(str); + } catch (IOException e) { + e.printStackTrace(); + } + + } + + @Test + public void YJSParserTest() throws FileNotFoundException {//测试执行 engine 的 executeContract方法 + InputStream resource = new FileInputStream("../front-agent/BDWareProjectDir/public/ARouteExample/ARouteExample.yjs"); + YJSCompiler compiler = new YJSCompiler(); + try { + ContractNode cn = compiler.compile(resource, "rrr.yjs"); + DesktopEngine engine = new DesktopEngine(); + System.out.println(new Gson().toJson(cn)); + } catch (IOException e) { + e.printStackTrace(); + } + } + +} diff --git a/src/test/java/org/bdware/sc/test/DateTest.java b/src/test/java/org/bdware/sc/test/DateTest.java new file mode 100644 index 0000000..10b5e00 --- /dev/null +++ b/src/test/java/org/bdware/sc/test/DateTest.java @@ -0,0 +1,16 @@ +package org.bdware.sc.test; + +import org.junit.Test; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + +public class DateTest { + @Test + public void run() throws ParseException { + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); + Date date = format.parse("2021-03-31"); + System.out.println(date.getTime()); + } +} diff --git a/src/test/java/org/bdware/sc/test/ExecuteContractTest.java b/src/test/java/org/bdware/sc/test/ExecuteContractTest.java new file mode 100644 index 0000000..2c3f25e --- /dev/null +++ b/src/test/java/org/bdware/sc/test/ExecuteContractTest.java @@ -0,0 +1,99 @@ +package org.bdware.sc.test; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.bdware.sc.boundry.utils.HttpUtil; +import wrp.jdk.nashorn.internal.runtime.ScriptObject; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.PrintStream; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicInteger; + +public class ExecuteContractTest { + public static ExecutorService executor = Executors.newFixedThreadPool(100); + static int repeat = 100000; + static Counter c = new Counter(); + + public static void main(String[] args) throws Exception { + String testDir = "./scripts/test/"; + File f = new File(testDir); + if (!f.exists()) f.mkdirs(); + String[] confs = + new String[]{ + "HelloAtMac", + "AnalysisAtMac", + "TFAtMac", + "HelloAtAli", + "AnalysisAtAli", + "TFAtAli" + }; + // http://59.110.5.194:8080/ + String[] urls = + new String[]{ + "http://127.0.0.1:18000/SCIDE/CMManager?action=executeContract&&contractID=HelloAtMac&operation=get&arg=world", + "http://127.0.0.1:18000/SCIDE/CMManager?action=executeContract&&contractID=AppDataContractAtMac&operation=connectDBAndQuery&arg=%7B%22type%22%3A%22takeout%22%2C%22detail%22%3A%22overall%22%2C%22district%22%3A%22%E5%AF%86%E4%BA%91%22%7D&requestID=1576408475257_93", + "http://127.0.0.1:18000/SCIDE/CMManager?action=executeContract&&contractID=ImageMatcherAtMac&operation=testLocal&arg=%2Fimgs%2Fcup.jpg", + "http://59.110.5.194:8080/SCIDE/CMManager?action=executeContract&&contractID=HelloAt59&operation=get&arg=world", + "http://59.110.5.194:8080/SCIDE/CMManager?action=executeContract&&contractID=AppDataContractAt59&operation=connectDBAndQuery&arg=%7B%22type%22%3A%22takeout%22%2C%22detail%22%3A%22overall%22%2C%22district%22%3A%22%E5%AF%86%E4%BA%91%22%7D&requestID=1576408475257_93", + "http://59.110.5.194:8080/SCIDE/CMManager?action=executeContract&&contractID=ImageMatcherAt59&operation=testLocal&arg=%2Fimgs%2Fcup.jpg" + }; + + // String[] urls = new String[] { + // + // "http://127.0.0.1:18000/SCIDE/CMManager?action=executeContract&&contractID=HelloAt59&operation=get&arg=world", + // + // "http://127.0.0.1:18000/SCIDE/CMManager?action=executeContract&&contractID=AppDataContractAt59&operation=connectDBAndQuery&arg=%7B%22type%22%3A%22takeout%22%2C%22detail%22%3A%22overall%22%2C%22district%22%3A%22%E5%AF%86%E4%BA%91%22%7D&requestID=1576408475257_93", + // + // "http://127.0.0.1:18000/SCIDE/CMManager?action=executeContract&&contractID=ImageMatcherAt59&operation=testLocal&arg=%2Fimgs%2Fcup.jpg", + // + // "http://59.110.5.194:8080/SCIDE/CMManager?action=executeContract&&contractID=HelloAtMac&operation=get&arg=world", + // + // "http://59.110.5.194:8080/SCIDE/CMManager?action=executeContract&&contractID=AppDataContractAtMac&operation=connectDBAndQuery&arg=%7B%22type%22%3A%22takeout%22%2C%22detail%22%3A%22overall%22%2C%22district%22%3A%22%E5%AF%86%E4%BA%91%22%7D&requestID=1576408475257_93", + // + // "http://59.110.5.194:8080/SCIDE/CMManager?action=executeContract&&contractID=ImageMatcherAtMac&operation=testLocal&arg=%2Fimgs%2Fcup.jpg" }; + + String output = "./scripts/test/executeContract_cross.txt"; + FileOutputStream fout = new FileOutputStream(output, true); + for (int i = 0; i < 1; i++) { + test(confs[i], urls[i], new PrintStream(fout)); // new PrintStream(fout) + } + int pre = 0; + for (; ; ) { + Thread.sleep(1000); + int curr = c.busy.get() + c.success.get(); + System.out.println(new Gson().toJson(c) + " --> " + (curr - pre) + " " + curr); + pre = curr; + } + // fout.close(); + // System.exit(0); + + } + + private static void test(final String conf, final String url, final PrintStream out) { + + for (int i = 0; i < repeat; i++) { + executor.execute(() -> { + ScriptObject r = HttpUtil.get(url); + + // System.out.println("http result:" + r.response); + if (r.get("response").toString().contains("busy")) + c.busy.incrementAndGet(); + else c.success.incrementAndGet(); + JsonObject jo = + JsonParser.parseString(r.get("response").toString()) + .getAsJsonObject(); + int exeTime = jo.get("executeTime").getAsInt(); + out.println(conf + "\t" + exeTime); + }); + } + } + + static class Counter { + AtomicInteger busy = new AtomicInteger(0); + AtomicInteger success = new AtomicInteger(0); + } +} diff --git a/src/test/java/org/bdware/sc/test/PermissionStubDocGenerator.java b/src/test/java/org/bdware/sc/test/PermissionStubDocGenerator.java new file mode 100644 index 0000000..d8e468c --- /dev/null +++ b/src/test/java/org/bdware/sc/test/PermissionStubDocGenerator.java @@ -0,0 +1,68 @@ +package org.bdware.sc.test; + +import org.bdware.sc.compiler.PermissionStub; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Parameter; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; + +public class PermissionStubDocGenerator { + + public static void main(String[] args) { + Class clz = org.bdware.sc.boundry.utils.FileUtil.class; + System.out.println("load class " + clz.getCanonicalName()); + clz = org.bdware.sc.boundry.utils.LedgerUtil.class; + System.out.println("load class " + clz.getCanonicalName()); + clz = org.bdware.sc.boundry.utils.HttpUtil.class; + System.out.println("load class " + clz.getCanonicalName()); + clz = org.bdware.sc.boundry.utils.DOIPUtil.class; + System.out.println("load class " + clz.getCanonicalName()); + clz = org.bdware.sc.boundry.utils.SQLUtil.class; + System.out.println("load class " + clz.getCanonicalName()); + clz = org.bdware.sc.boundry.utils.RocksDBUtil.class; + System.out.println("load class " + clz.getCanonicalName()); + clz = org.bdware.sc.boundry.utils.CMUtil.class; + System.out.println("load class " + clz.getCanonicalName()); + clz = org.bdware.sc.boundry.utils.SM2Util.class; + System.out.println("load class " + clz.getCanonicalName()); + clz = org.bdware.sc.boundry.utils.AsyncUtil.class; + System.out.println("load class " + clz.getCanonicalName()); + + Method[] methods = clz.getDeclaredMethods(); + PermissionStub stub = clz.getAnnotation(PermissionStub.class); + List methodList = Arrays.asList(methods); + methodList.sort(Comparator.comparing(Method::getName)); + System.out.println("## " + stub.permission() + "util\n"); + System.out.printf( + "可以使用@Permission(\"%s\")来引入%s对象。%n", + stub.permission(), stub.permission() + "util"); + System.out.printf( + "```\n@Permission(\"%s\")\ncontract %sExample{\n ...\n}\n```\n%n", + stub.permission(), stub.permission()); + + for (Method m : methods) { + if (Modifier.isStatic(m.getModifiers())) { + System.out.println("### " + m.getName() + "\n"); + Parameter[] parameters = m.getParameters(); + System.out.println("\n#### 参数\n"); + System.out.println("| 序号 | 参数 | 说明 |"); + System.out.println("|---|---|---|"); + int i = 1; + for (Parameter p : parameters) { + System.out.printf( + "| %d | %s | %s |%n", + i, p.getName(), p.getType().getCanonicalName()); + i++; + } + System.out.println("\n#### 使用示例\n"); + System.out.println("```javascript"); + System.out.println( + "var ret = " + stub.permission() + "Util." + m.getName() + "();"); + System.out.println("```"); + } + } + } +} diff --git a/src/test/java/org/bdware/sc/test/StartContractTest.java b/src/test/java/org/bdware/sc/test/StartContractTest.java new file mode 100644 index 0000000..bcd8d62 --- /dev/null +++ b/src/test/java/org/bdware/sc/test/StartContractTest.java @@ -0,0 +1,58 @@ +package org.bdware.sc.test; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.bdware.sc.boundry.utils.HttpUtil; +import wrp.jdk.nashorn.internal.runtime.ScriptObject; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.PrintStream; + +public class StartContractTest { + public static void main(String[] args) throws Exception { + String testDir = "./scripts/test/"; + File f = new File(testDir); + if (!f.exists()) f.mkdirs(); + String[] confs = + new String[] { + "HelloAtMac", + "AnalysisAtMac", + "TFAtMac", + "HelloAtAli", + "AnalysisAtAli", + "TFAtAli" + }; + // http://59.110.5.194:8080/ + String[] urls = + new String[] { + "http://127.0.0.1:18000/SCIDE/CMManager?action=startContractBatched&fileList=[A2.yjs]", + "http://127.0.0.1:18000/SCIDE/CMManager?action=startContractBatched&fileList=[EleAnalysis.yjs]", + "http://127.0.0.1:18000/SCIDE/CMManager?action=startContract&owner=04266aa345154d8e224990e33dd47a3203dd927d8c4f6420f63fbab063d9ecb8c4d58751e81940f2092dc4609de22a1980f4d8df39730ba0ddd453e3fa3b7b2a6b&requestID=1576403183009&contractid=Hello&script=empty&path=/Tensorflow/imagematch.yjs&signature=815490e34a3c85bcfe54a740f91e8739cfd6e5daa6c73084de758705e754a43bb245c5c23ff9f46c2a99cc0d627d4cf1da583e20073e85455f6cb10c63bef86b", + "http://59.110.5.194:8080/SCIDE/CMManager?action=startContractBatched&fileList=[A2.yjs]", + "http://59.110.5.194:8080/SCIDE/CMManager?action=startContractBatched&fileList=[EleAnalysis.yjs]", + "http://59.110.5.194:8080/SCIDE/CMManager?action=startContract&owner=04266aa345154d8e224990e33dd47a3203dd927d8c4f6420f63fbab063d9ecb8c4d58751e81940f2092dc4609de22a1980f4d8df39730ba0ddd453e3fa3b7b2a6b&requestID=1576403183009&contractid=Hello&script=empty&path=/Tensorflow/imagematch.yjs&signature=815490e34a3c85bcfe54a740f91e8739cfd6e5daa6c73084de758705e754a43bb245c5c23ff9f46c2a99cc0d627d4cf1da583e20073e85455f6cb10c63bef86b" + }; + + String output = "./scripts/test/startContract.txt"; + FileOutputStream fout = new FileOutputStream(output, true); + for (int i = 0; i < urls.length; i++) { + test(confs[i], urls[i], System.out); // new PrintStream(fout) + } + fout.close(); + System.exit(0); + } + + static int repeat = 1; + + private static void test(String conf, String url, PrintStream out) { + for (int i = 0; i < repeat; i++) { + ScriptObject result = HttpUtil.get(url); + System.out.println("http result:" + result.get("response")); + JsonObject jo = + new JsonParser().parse(result.get("response").toString()).getAsJsonObject(); + int exeTime = jo.get("executeTime").getAsInt(); + out.println(conf + "\t" + exeTime); + } + } +} diff --git a/src/test/java/org/bdware/sc/test/setMaskTest.java b/src/test/java/org/bdware/sc/test/setMaskTest.java new file mode 100644 index 0000000..454b01c --- /dev/null +++ b/src/test/java/org/bdware/sc/test/setMaskTest.java @@ -0,0 +1,147 @@ +package org.bdware.sc.test; + +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; +import org.bdware.sc.http.HttpUtil; +import org.junit.Test; + +import java.io.File; +import java.net.URLEncoder; +import java.util.HashMap; +import java.util.Map; +import java.io.File; +import java.io.IOException; +import java.io.StringWriter; +import java.net.URLEncoder; +import java.sql.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +public class setMaskTest { + @Test + public void test1(){ + + String url="http://127.0.0.1:21030/SCIDE/CMManager?action=setMask"; + String contractID="Hello1"; + String operation="hello1"; + String maskInfo="\"md5\""; + maskInfo=""; + String pubkey="04c111cde30c257eb9d891653e2a25eb15df5239dd9882389e8daeffd4b16f65f30b30688b58d3e2eaf25ce5a529a601e4924581b55cedf78d94d17864b73c51a7"; + System.out.println(url); + String sign="30440220138c8ae1956f6af19ddb24b9a0fe5cf9cc4f8ecd25537a8b5c4dcd5f30a4f985022026475279687ccdfb112cbcc307e573333d80f45386281def4df54b8b7532ed79"; + //url+="&contractID="+contractID+"&operation="+operation+"&maskInfo="+maskInfo+"&pubkey="+pubkey+"&signature="+sign; + url+="&contractID="+contractID+"&operation="+operation+"&maskInfo="+maskInfo; + //url="http://127.0.0.1:21030/SCIDE/CMManager?action=setMask&&pubkey=04c111cde30c257eb9d891653e2a25eb15df5239dd9882389e8daeffd4b16f65f30b30688b58d3e2eaf25ce5a529a601e4924581b55cedf78d94d17864b73c51a7&signature=304602210082f33a4cdbf483428c701753eb08ca430f855d52df18547a367fe14ee638761f022100cab7fa189b03248b54f3cb679d7df6c2548f6743256cad6ee772c532bb34bdf9"; + //url="http://127.0.0.1:21030/SCIDE/CMManager?action=ping"; + //url="http://127.0.0.1:21030/SCIDE/CMManager?action=setMask"+"&contractID="+contractID+"&maskInfo="+maskInfo; + //url="http://127.0.0.1:21030/SCIDE/CMManager?action=ping"; + System.out.println(url); + System.out.println(HttpUtil.httpGet(url.toString())); + String resp = HttpUtil.httpGet(url.toString()).get("response").toString(); + System.out.println(resp); + } + @Test + public void testSetMock(){ + + String url="http://127.0.0.1:21030/SCIDE/CMManager?action=setMock"; + String contractID="Hello1"; + String operation="hello1"; + String mockInfo="\"@string\""; + //String mockInfo=""; + String pubkey="04c111cde30c257eb9d891653e2a25eb15df5239dd9882389e8daeffd4b16f65f30b30688b58d3e2eaf25ce5a529a601e4924581b55cedf78d94d17864b73c51a7"; + System.out.println(url); + String sign="30440220138c8ae1956f6af19ddb24b9a0fe5cf9cc4f8ecd25537a8b5c4dcd5f30a4f985022026475279687ccdfb112cbcc307e573333d80f45386281def4df54b8b7532ed79"; + //url+="&contractID="+contractID+"&operation="+operation+"&maskInfo="+maskInfo+"&pubkey="+pubkey+"&signature="+sign; + url+="&contractID="+contractID+"&operation="+operation+"&mockInfo="+mockInfo; + //url="http://127.0.0.1:21030/SCIDE/CMManager?action=setMask&&pubkey=04c111cde30c257eb9d891653e2a25eb15df5239dd9882389e8daeffd4b16f65f30b30688b58d3e2eaf25ce5a529a601e4924581b55cedf78d94d17864b73c51a7&signature=304602210082f33a4cdbf483428c701753eb08ca430f855d52df18547a367fe14ee638761f022100cab7fa189b03248b54f3cb679d7df6c2548f6743256cad6ee772c532bb34bdf9"; + //url="http://127.0.0.1:21030/SCIDE/CMManager?action=ping"; + //url="http://127.0.0.1:21030/SCIDE/CMManager?action=setMask"+"&contractID="+contractID+"&maskInfo="+maskInfo; + //url="http://127.0.0.1:21030/SCIDE/CMManager?action=ping"; + System.out.println(url); + System.out.println(HttpUtil.httpGet(url.toString())); + String resp = HttpUtil.httpGet(url.toString()).get("response").toString(); + System.out.println(resp); + } + @Test + public void testGetMock(){ + + String url="http://127.0.0.1:21030/SCIDE/CMManager?action=getMock"; + String contractID="Hello1"; + String operation="hello1"; + String mockInfo="@string"; + String pubkey="04c111cde30c257eb9d891653e2a25eb15df5239dd9882389e8daeffd4b16f65f30b30688b58d3e2eaf25ce5a529a601e4924581b55cedf78d94d17864b73c51a7"; + System.out.println(url); + String sign="30440220138c8ae1956f6af19ddb24b9a0fe5cf9cc4f8ecd25537a8b5c4dcd5f30a4f985022026475279687ccdfb112cbcc307e573333d80f45386281def4df54b8b7532ed79"; + //url+="&contractID="+contractID+"&operation="+operation+"&maskInfo="+maskInfo+"&pubkey="+pubkey+"&signature="+sign; + url+="&contractID="+contractID+"&operation="+operation; + //url="http://127.0.0.1:21030/SCIDE/CMManager?action=setMask&&pubkey=04c111cde30c257eb9d891653e2a25eb15df5239dd9882389e8daeffd4b16f65f30b30688b58d3e2eaf25ce5a529a601e4924581b55cedf78d94d17864b73c51a7&signature=304602210082f33a4cdbf483428c701753eb08ca430f855d52df18547a367fe14ee638761f022100cab7fa189b03248b54f3cb679d7df6c2548f6743256cad6ee772c532bb34bdf9"; + //url="http://127.0.0.1:21030/SCIDE/CMManager?action=ping"; + //url="http://127.0.0.1:21030/SCIDE/CMManager?action=setMask"+"&contractID="+contractID+"&maskInfo="+maskInfo; + //url="http://127.0.0.1:21030/SCIDE/CMManager?action=ping"; + System.out.println(url); + System.out.println(HttpUtil.httpGet(url.toString())); + String resp = HttpUtil.httpGet(url.toString()).get("response").toString(); + System.out.println(resp); + } + @Test + public void test3(){ + + String url="http://127.0.0.1:21030/SCIDE/CMManager?action=setMask"; + String contractID="Hello"; + String operation="hello3"; + String maskInfo=""; + String pubkey="04c111cde30c257eb9d891653e2a25eb15df5239dd9882389e8daeffd4b16f65f30b30688b58d3e2eaf25ce5a529a601e4924581b55cedf78d94d17864b73c51a7"; + System.out.println(url); + String sign="30440220138c8ae1956f6af19ddb24b9a0fe5cf9cc4f8ecd25537a8b5c4dcd5f30a4f985022026475279687ccdfb112cbcc307e573333d80f45386281def4df54b8b7532ed79"; + //url+="&contractID="+contractID+"&operation="+operation+"&maskInfo="+maskInfo+"&pubkey="+pubkey+"&signature="+sign; + url+="&contractID="+contractID+"&operation="+operation+"&maskInfo="+maskInfo; + //url="http://127.0.0.1:21030/SCIDE/CMManager?action=setMask&&pubkey=04c111cde30c257eb9d891653e2a25eb15df5239dd9882389e8daeffd4b16f65f30b30688b58d3e2eaf25ce5a529a601e4924581b55cedf78d94d17864b73c51a7&signature=304602210082f33a4cdbf483428c701753eb08ca430f855d52df18547a367fe14ee638761f022100cab7fa189b03248b54f3cb679d7df6c2548f6743256cad6ee772c532bb34bdf9"; + //url="http://127.0.0.1:21030/SCIDE/CMManager?action=ping"; + //url="http://127.0.0.1:21030/SCIDE/CMManager?action=setMask"+"&contractID="+contractID+"&maskInfo="+maskInfo; + //url="http://127.0.0.1:21030/SCIDE/CMManager?action=ping"; + System.out.println(url); + System.out.println(HttpUtil.httpGet(url.toString())); + String resp = HttpUtil.httpGet(url.toString()).get("response").toString(); + System.out.println(resp); + } + @Test + public void test2(){ + String s1="{\"score\":\"md5\",\"name\":\"aes\"}"; + JsonElement je1=JsonParser.parseString("{\"score\":\"md5\",\"name\":\"aes\"}"); + System.out.println(je1); + } + @Test + public void testHangUp(){ + String url="http://127.0.0.1:21030/SCIDE/CMManager?action="; + String contractID="Hello"; + String urlHangUp=url+"hangUpContractProcess&contractID="+contractID; + String urlResume=url+"resumeContractProcess&contractID="+contractID; + System.out.println(urlHangUp); + String resp1 = HttpUtil.httpGet(urlHangUp.toString()).get("response").toString(); + System.out.println(resp1); + + //String operation="hello3"; + } + @Test + public void testResume(){ + String url="http://127.0.0.1:21030/SCIDE/CMManager?action="; + String contractID="Hello"; + String urlHangUp=url+"hangUpContractProcess&contractID="+contractID; + String urlResume=url+"resumeContractProcess&contractID="+contractID; + System.out.println(urlResume); + String resp2 = HttpUtil.httpGet(urlResume.toString()).get("response").toString(); + System.out.println(resp2); + + //String operation="hello3"; + } + @Test + public void testMysql(){ + String contractID="AAA12BMySQL"; + String url="http://127.0.0.1:21030/SCIDE/CMManager?action=getMask"+"&contractID="+contractID+"&requestID=1"; + + System.out.println(url); + String resp = HttpUtil.httpGet(url.toString()).get("response").toString(); + System.out.println(resp); + } +} diff --git a/src/test/java/org/bdware/sc/test/synctest/JudgeStatus.java b/src/test/java/org/bdware/sc/test/synctest/JudgeStatus.java new file mode 100644 index 0000000..6f6e799 --- /dev/null +++ b/src/test/java/org/bdware/sc/test/synctest/JudgeStatus.java @@ -0,0 +1,30 @@ +package org.bdware.sc.test.synctest; + +import org.bdware.sc.memory.MemoryDumpUtil; + +public class JudgeStatus { + static String yjsPath = "/Users/zhangyixuan/Lab/new/BDContract/cp/build/output/yjs.jar"; + + public static void main(String[] args) { + String path = "/Users/zhangyixuan/Lab/new/BDContract/front-agent/BDWareProjectDir/memory/"; + String contractName = "ContractExecutor"; + path += (contractName + "/"); + + String path1 = ""; + String path2 = ""; + + + String content1 = MemoryDumpUtil.getContentFromFile(path + path1); + String content2 = MemoryDumpUtil.getContentFromFile(path + path2); + + System.out.println(content1 + "\n\n"); + System.out.println(content2 + "\n\n"); + + + if(content1.equals(content2)) + System.out.println("Success!"); + else + System.out.println("Failed!"); + } + +} diff --git a/src/test/java/org/bdware/sc/test/synctest/MemoryDumpRecoverTest.java b/src/test/java/org/bdware/sc/test/synctest/MemoryDumpRecoverTest.java new file mode 100644 index 0000000..69834d8 --- /dev/null +++ b/src/test/java/org/bdware/sc/test/synctest/MemoryDumpRecoverTest.java @@ -0,0 +1,67 @@ +package org.bdware.sc.test.synctest; + +import java.io.*; +import java.util.Scanner; + +public class MemoryDumpRecoverTest { + + public static void main(String[] args) throws IOException { + //memoryRecover("AppData"); + //memoryRecover("Test"); + } + + public static String file2Str(String file) { + StringBuilder sb = new StringBuilder(); + try { + Scanner sc = new Scanner(new FileInputStream(file)); + for (; sc.hasNextLine();) { + sb.append(sc.nextLine()).append("\n"); + } + } catch (Exception e) { + e.printStackTrace(); + } + return sb.toString(); + } + +/* //仅支持public路径下测试 + public static void memoryRecover(String contractName) { + String name = contractName + "/" + contractName; + + //启动合约 + ContractManager cm2 = new ContractManager(); + cm2.yjsPath = JudgeStatus.yjsPath; + Contract c = new Contract(); + c.setType(ContractType.Sole); + String id = "169412582"; + c.setID(id); + c.setScript(RedoRecoverTest.file2Str("/Users/zhangyixuan/Lab/newProject/BDContract/front-agent/BDWareProjectDir/public/" + name + ".yjs")); + String key = "{\"publicKey\":\"041d7b4818817736b3d64305675f04e9a00a12ce23c72e6740f83785edcffec6bae2c178fbc934f66d72e26f89a2e7a2c966dc3f0a8e415663c9b933af7a2e9ff8\",\"privateKey\":\"18505919022281880113072981827955639221458448578012075254857346196103069175443\"}"; + SM2KeyPair pair = SM2KeyPair.fromJson(key); + c.doSignature(pair); + System.out.println("<<>> : " + cm2.startContractAndRedirect(c, null)); + + + + + //loadMemory + long time1 = System.currentTimeMillis(); + File mem = new File("./cp/recoverTestFiles/memory/" + contractName + ".txt"); + String res = cm2.loadMemory(contractName, mem.getAbsolutePath()); + long time2 = System.currentTimeMillis(); + try { + Thread.sleep(3000); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + System.out.println("<<>> : " + res); + double cost = ((double)time2 - (double)time1)/1000; + System.out.println("load memory 用时" + cost + "s"); + + + String content1 = MemoryDumpUtil.getContentFromFile(mem.getAbsolutePath()); + String content2 = cm2.dumpContract(contractName, ""); + System.out.println("load之后dump : \n" + content2 + "\n\n"); + System.out.println(content1.equals(content2)); + }*/ +} diff --git a/src/test/java/org/bdware/sc/test/synctest/MemoryDumpTest.java b/src/test/java/org/bdware/sc/test/synctest/MemoryDumpTest.java new file mode 100644 index 0000000..c069ef9 --- /dev/null +++ b/src/test/java/org/bdware/sc/test/synctest/MemoryDumpTest.java @@ -0,0 +1,62 @@ +package org.bdware.sc.test.synctest; + +import java.io.*; + +public class MemoryDumpTest { + public static void main(String[] args) throws IOException { + //memoryRecord("Z_Test_pub2","Z_Test_pub2-1"); + //memoryRecord("Test","Test1"); + } + +/* //仅支持public路径下测试 + public static void memoryRecord(String contractName,String argsFileName) { + String name = contractName + "/" + contractName; + + //启动合约 + ContractManager cm1 = new ContractManager(); + cm1.yjsPath = JudgeStatus.yjsPath; + Contract c = new Contract(); + c.setType(ContractType.Sole); + String id = "169412582"; + c.setID(id); + c.setScript(RedoRecoverTest.file2Str("/Users/zhangyixuan/Lab/newProject/BDContract/front-agent/BDWareProjectDir/public/" + name + ".yjs")); + String key = "{\"publicKey\":\"041d7b4818817736b3d64305675f04e9a00a12ce23c72e6740f83785edcffec6bae2c178fbc934f66d72e26f89a2e7a2c966dc3f0a8e415663c9b933af7a2e9ff8\",\"privateKey\":\"18505919022281880113072981827955639221458448578012075254857346196103069175443\"}"; + SM2KeyPair pair = SM2KeyPair.fromJson(key); + c.doSignature(pair); + System.out.println("<<>> : " + cm1.startContractAndRedirect(c, null)); + + + + //执行事务 + int count = 0; + ContractRequest cor = new ContractRequest(); + cor.setContractID(contractName); + cor.doSignature(pair); + File file = new File("./cp/recoverTestFiles/affairs/" + contractName + "/" + argsFileName); + try { + FileReader fr = new FileReader(file); + BufferedReader br = new BufferedReader(fr); + String s = null; + while((s=br.readLine()) != null) { + String[] strs = s.split(" "); + cor.setAction(strs[0]); + cor.setArg(strs[1]); + System.out.println("<<> NO." + (++count) + " [Result]" + cm1.execute(cor,null)); + } + } catch (IOException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + + + //memoryDump + long time1 = System.currentTimeMillis(); + File mem = new File("./cp/recoverTestFiles/memory/" + contractName + ".txt"); + String memory = cm1.dumpContract(contractName,mem.getAbsolutePath()); + System.out.println("memory\n" + memory); + long time2 = System.currentTimeMillis(); + double cost = ((double)time2 - (double)time1)/1000; + System.out.println("共" + count + "项事务,dump memory 用时" + cost + "s"); + }*/ +} + diff --git a/src/test/java/org/bdware/sc/test/synctest/PrintMemory.java b/src/test/java/org/bdware/sc/test/synctest/PrintMemory.java new file mode 100644 index 0000000..5afa3b9 --- /dev/null +++ b/src/test/java/org/bdware/sc/test/synctest/PrintMemory.java @@ -0,0 +1,18 @@ +package org.bdware.sc.test.synctest; + +import org.bdware.sc.memory.MemoryDumpUtil; + +public class PrintMemory { + + public static void main(String[] args){ + printMemory(); + } + + public static void printMemory(){ + String path = "/Users/zhangyixuan/Lab/new/BDContract/front-agent/BDWareProjectDir/ADSPDir/-1676897265/memory/2020-08-15-22:04:17_175580150"; + + String path2 = "/Users/zhangyixuan/Lab/new/BDContract/front-agent/BDWareProjectDir/memory/mathOperation/2021-01-30.15:38:13"; + String content = MemoryDumpUtil.getContentFromFile(path2); + System.out.println(content); + } +} diff --git a/src/test/java/org/bdware/sc/test/synctest/PrintTraceRecords.java b/src/test/java/org/bdware/sc/test/synctest/PrintTraceRecords.java new file mode 100644 index 0000000..77db8f6 --- /dev/null +++ b/src/test/java/org/bdware/sc/test/synctest/PrintTraceRecords.java @@ -0,0 +1,19 @@ +package org.bdware.sc.test.synctest; + +import org.bdware.sc.trace.TraceRecordUtil; + +public class PrintTraceRecords { + + public static void main(String[] args) { +// String path = "/Users/zhangyixuan/Lab/new/BDContract/front-agent/BDWareProjectDir/trace/"; +// String contractName = "Test"; +// path += (contractName + "/"); +// +// String path1 = ""; +// +// String content = TraceRecordUtil.getTraceRecordsByFile(path + path1); +// System.out.println(content); + } + +} + diff --git a/src/test/java/org/bdware/sc/test/synctest/PrintTransRecords.java b/src/test/java/org/bdware/sc/test/synctest/PrintTransRecords.java new file mode 100644 index 0000000..e85fd3a --- /dev/null +++ b/src/test/java/org/bdware/sc/test/synctest/PrintTransRecords.java @@ -0,0 +1,18 @@ +package org.bdware.sc.test.synctest; + +import org.bdware.sc.redo.TransRecordUtil; +import org.bdware.sc.trace.TraceRecordUtil; + +public class PrintTransRecords { + public static void main(String[] args) { +// String path = "/Users/zhangyixuan/Lab/new/BDContract/front-agent/BDWareProjectDir/trans/"; +// String contractName = "Test"; +// path += (contractName + "/"); +// +// String path1 = ""; +// +// String content = TransRecordUtil.getTransRecordsByFile(path + path1); +// System.out.println(content); + } + +} diff --git a/src/test/java/org/bdware/sc/test/synctest/RedoRecordTest.java b/src/test/java/org/bdware/sc/test/synctest/RedoRecordTest.java new file mode 100644 index 0000000..45e5982 --- /dev/null +++ b/src/test/java/org/bdware/sc/test/synctest/RedoRecordTest.java @@ -0,0 +1,68 @@ +package org.bdware.sc.test.synctest; + +public class RedoRecordTest { + + public static void main(String[] args) { + transRecord("Z_Test_pub1","Z_Test_pub1-1"); + } + + //仅支持public路径下测试 + public static void transRecord(String contractName,String argsFileName) { +// String name = contractName + "/" + contractName; +// +// //启动合约 +// ContractManager cm1 = new ContractManager(); +// cm1.yjsPath = JudgeStatus.yjsPath; +// Contract c = new Contract(); +// c.setType(ContractType.Sole); +// String id = "169412582"; +// c.setID(id); +// c.setScript(RedoRecoverTest.file2Str("/Users/zhangyixuan/Lab/BDWareHttp/BDWareProjectDir/public/" + name + ".yjs")); +// String key = "{\"publicKey\":\"041d7b4818817736b3d64305675f04e9a00a12ce23c72e6740f83785edcffec6bae2c178fbc934f66d72e26f89a2e7a2c966dc3f0a8e415663c9b933af7a2e9ff8\",\"privateKey\":\"18505919022281880113072981827955639221458448578012075254857346196103069175443\"}"; +// SM2KeyPair pair = SM2KeyPair.fromJson(key); +// c.doSignature(pair); +// System.out.println("<<>> : " + cm1.startContractAndRedirect(c, null)); +// cm1.engineStartTransRecord(contractName); +// +// +// //执行事务 +// int count = 0; +// ContractRequest cor = new ContractRequest(); +// cor.setContractID(contractName); +// cor.doSignature(pair); +// File file = new File("./cp/recoverTestFiles/affairs/" + contractName + "/" + argsFileName); +// try { +// FileReader fr = new FileReader(file); +// BufferedReader br = new BufferedReader(fr); +// String s = null; +// while((s=br.readLine()) != null) { +// String[] strs = s.split(" "); +// cor.setAction(strs[0]); +// cor.setArg(strs[1]); +// System.out.println("<<> NO." + (++count) + " [Result]" + cm1.execute(cor)); +// } +// } catch (IOException e1) { +// // TODO Auto-generated catch block +// e1.printStackTrace(); +// } +// +// +// +// +// //记录最终状态 +// cm1.saveTransRecords(contractName,"./cp/recoverTestFiles/trans/" + contractName); +// System.out.println("<<>> : \n" + cm1.engineTransRecords2String(contractName)); +// +// +// File mem = new File("./cp/recoverTestFiles/memory/" + contractName + ".txt"); +// String memory1 = cm1.dumpContract(contractName,mem.getAbsolutePath()); +// if(memory1.equals("{\"status\":\"Error\",\"result\":\"Timeout!\"}")) { +// System.out.println("<<>> failed"); +// return; +// } +// System.out.println("<<>>" + memory1); +// System.out.println("共" +count + "项事务记录"); + } + +} + diff --git a/src/test/java/org/bdware/sc/test/synctest/RedoRecoverTest.java b/src/test/java/org/bdware/sc/test/synctest/RedoRecoverTest.java new file mode 100644 index 0000000..a16425e --- /dev/null +++ b/src/test/java/org/bdware/sc/test/synctest/RedoRecoverTest.java @@ -0,0 +1,104 @@ +package org.bdware.sc.test.synctest; + +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Scanner; + +public class RedoRecoverTest { + + public static void main(String[] args) throws IOException { + transRecover("Z_Test_pub1","Z_Test_pub1-1"); + } + + public static void transRecover(String contractName,String argsFileName) { +// //获得之前的状态 +// ObjectInputStream reader; +// String memory = null; +// try { +// FileInputStream fileout = new FileInputStream("./cp/recoverTestFiles/memory/" + contractName + ".txt"); +// GZIPInputStream gzin = new GZIPInputStream(fileout); +// reader = new ObjectInputStream(gzin); +// MemoryDump md = new MemoryDump(); +// md.setObjects((Map) reader.readObject());; +// reader.close(); +// memory = new GsonBuilder().setPrettyPrinting().create().toJson(md); +// } catch (IOException | ClassNotFoundException e) { +// e.printStackTrace(); +// } +// +// +// +// +// //读取文件中内容; +// int count = 0; +// try { +// File file = new File("./cp/recoverTestFiles/affairs/" + contractName + "/" + argsFileName); +// FileReader fr = new FileReader(file); +// BufferedReader br = new BufferedReader(fr); +// String s = null; +// while((s=br.readLine()) != null) { +// count++; +// } +// } catch (IOException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } +// +// +// +// //启动 +// String name = contractName + "/" + contractName; +// ContractManager cm2 = new ContractManager(); +// cm2.yjsPath = JudgeStatus.yjsPath; +// Contract c = new Contract(); +// c.setType(ContractType.Sole); +// String id = "169412583"; +// c.setID(id); +// c.setScript(MemoryDumpRecoverTest .file2Str("/Users/zhangyixuan/Lab/newProject/BDContract/front-agent/BDWareProjectDir/public/" + name + ".yjs")); +// String key = "{\"publicKey\":\"041d7b4818817736b3d64305675f04e9a00a12ce23c72e6740f83785edcffec6bae2c178fbc934f66d72e26f89a2e7a2c966dc3f0a8e415663c9b933af7a2e9ff8\",\"privateKey\":\"18505919022281880113072981827955639221458448578012075254857346196103069175443\"}"; +// SM2KeyPair pair = SM2KeyPair.fromJson(key); +// c.doSignature(pair); +// System.out.println("Start a contract : " + cm2.startContractAndRedirect(c, System.out)); +// +// +// //recover +// long time1 = System.currentTimeMillis(); +// String traceFile = "./cp/recoverTestFiles/trans/" + contractName + ".trans"; +// cm2.setTransRecords(contractName,traceFile); +// cm2.recoverFromTransRecord(contractName,(count - 1) + ""); +// long time2 = System.currentTimeMillis(); +// double cost = ((double)time2 - (double)time1)/1000; +// +// +// //对比 +// String memory2 = cm2.dumpContract(contractName,""); +// System.out.println("<<>>" + memory2); +// if(memory.equals(memory2)) { +// System.out.println("####################\n####################\n####################"); +// System.out.println("Trans count = " + count + " Contract " + contractName + " recover success!"); +// System.out.println("####################\n####################\n####################"); +// } +// else { +// System.out.println("!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!"); +// System.out.println("Trans count = " + count + " Contract " + contractName + " recover failed!"); +// System.out.println("!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!"); +// +// } +// System.out.println("共" + count + "项事务恢复,用时" + cost + "s"); + } + + + + public static String file2Str(String file) { + StringBuilder sb = new StringBuilder(); + try { + Scanner sc = new Scanner(new FileInputStream(file)); + for (; sc.hasNextLine();) { + sb.append(sc.nextLine()).append("\n"); + } + } catch (Exception e) { + e.printStackTrace(); + } + return sb.toString(); + } +} diff --git a/src/test/java/org/bdware/sc/test/synctest/TraceRecordTest.java b/src/test/java/org/bdware/sc/test/synctest/TraceRecordTest.java new file mode 100644 index 0000000..03b2345 --- /dev/null +++ b/src/test/java/org/bdware/sc/test/synctest/TraceRecordTest.java @@ -0,0 +1,73 @@ +package org.bdware.sc.test.synctest; + +import java.io.IOException; + +public class TraceRecordTest { + + public static void main(String[] args) throws IOException { + traceRecord("Test","Test1"); + //traceRecord("BDCoin","BDCoin1"); + //traceRecord("AppData","AppData-3"); + //traceRecord("AppData","AppData-7"); + //traceRecord("Z_Test_pub2","Z_Test_pub2-1"); + } + + //仅支持public路径下测试 + public static void traceRecord(String contractName,String argsFileName) { +// String name = contractName + "/" + contractName; +// +// //启动合约 +// ContractManager cm1 = new ContractManager(); +// cm1.yjsPath = JudgeStatus.yjsPath; +// Contract c = new Contract(); +// c.setType(ContractType.Sole); +// String id = "169412582"; +// c.setID(id); +// c.setScript(RedoRecoverTest.file2Str("/Users/zhangyixuan/Lab/newProject/BDContract/front-agent/BDWareProjectDir/public/" + name + ".yjs")); +// String key = "{\"publicKey\":\"041d7b4818817736b3d64305675f04e9a00a12ce23c72e6740f83785edcffec6bae2c178fbc934f66d72e26f89a2e7a2c966dc3f0a8e415663c9b933af7a2e9ff8\",\"privateKey\":\"18505919022281880113072981827955639221458448578012075254857346196103069175443\"}"; +// SM2KeyPair pair = SM2KeyPair.fromJson(key); +// c.doSignature(pair); +// System.out.println("<<>> : " + cm1.startContractAndRedirect(c, System.out)); +// cm1.startSync(contractName); +// cm1.changeSyncType(contractName, "Trace"); +// +// +// //执行事务 +// int count = 0; +// ContractRequest cor = new ContractRequest(); +// cor.setContractID(contractName); +// cor.doSignature(pair); +// File file = new File("./cp/recoverTestFiles/affairs/" + contractName + "/" + argsFileName); +// try { +// FileReader fr = new FileReader(file); +// BufferedReader br = new BufferedReader(fr); +// String s = null; +// while((s=br.readLine()) != null) { +// String[] strs = s.split(" "); +// cor.setAction(strs[0]); +// cor.setArg(strs[1]); +// System.out.println("<<> NO." + (++count) + " [Result]" + cm1.execute(cor)); +// } +// } catch (IOException e1) { +// // TODO Auto-generated catch block +// e1.printStackTrace(); +// } +// +// +// +// +// //记录最终状态 +// cm1.saveTraceRecords(contractName,"./cp/recoverTestFiles/trace/" + contractName); +// System.out.println("<<>> : \n" + cm1.engineTraceRecords2String(contractName)); +// +// +// File mem = new File("./cp/recoverTestFiles/memory/" + contractName + ".txt"); +// String memory1 = cm1.dumpContract(contractName,mem.getAbsolutePath()); +// if(memory1.equals("{\"status\":\"Error\",\"result\":\"Timeout!\"}")) { +// System.out.println("<<>> failed"); +// return; +// } +// System.out.println("<<>>" + memory1); +// System.out.println("共" +count + "项事务记录"); + } +} diff --git a/src/test/java/org/bdware/sc/test/synctest/TraceRecoverTest.java b/src/test/java/org/bdware/sc/test/synctest/TraceRecoverTest.java new file mode 100644 index 0000000..6cca439 --- /dev/null +++ b/src/test/java/org/bdware/sc/test/synctest/TraceRecoverTest.java @@ -0,0 +1,79 @@ +package org.bdware.sc.test.synctest; + +import java.io.IOException; + +public class TraceRecoverTest { + + public static void main(String[] args) throws IOException { + traceRecover("Test","Test1"); + //traceRecover("BDCoin","BDCoin1"); + //traceRecover("Z_Test_pub2","Z_Test_pub2-1"); + //traceRecover("AppData","AppData-3"); + //traceRecover("AppData","AppData-7"); + } + + public static void traceRecover(String contractName,String argsFileName) { +// //获得之前的状态 +// File f = new File("./cp/recoverTestFiles/memory/" + contractName + ".txt"); +// String memory = MemoryDumpUtil.getContentFromFile(f.getAbsolutePath()); +// +// +// +// //读取文件中内容; +// int count = 0; +// try { +// File file = new File("./cp/recoverTestFiles/affairs/" + contractName + "/" + argsFileName); +// FileReader fr = new FileReader(file); +// BufferedReader br = new BufferedReader(fr); +// String s = null; +// while((s=br.readLine()) != null) { +// count++; +// } +// } catch (IOException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } +// +// +// +// //启动 +// String name = contractName + "/" + contractName; +// ContractManager cm2 = new ContractManager(); +// cm2.yjsPath = JudgeStatus.yjsPath; +// Contract c = new Contract(); +// c.setType(ContractType.Sole); +// String id = "169412583"; +// c.setID(id); +// c.setScript(MemoryDumpRecoverTest.file2Str("/Users/zhangyixuan/Lab/newProject/BDContract/front-agent/BDWareProjectDir/public/" + name + ".yjs")); +// String key = "{\"publicKey\":\"041d7b4818817736b3d64305675f04e9a00a12ce23c72e6740f83785edcffec6bae2c178fbc934f66d72e26f89a2e7a2c966dc3f0a8e415663c9b933af7a2e9ff8\",\"privateKey\":\"18505919022281880113072981827955639221458448578012075254857346196103069175443\"}"; +// SM2KeyPair pair = SM2KeyPair.fromJson(key); +// c.doSignature(pair); +// System.out.println("<<>> : " + cm2.startContractAndRedirect(c, System.out)); +// +// +// //recover +// long time1 = System.currentTimeMillis(); +// String traceFile = "./cp/recoverTestFiles/trace/" + contractName + ".trace"; +// cm2.setTraceRecords(contractName,traceFile); +// cm2.recoverFromTraceRecord(contractName,(count - 1) + ""); +// long time2 = System.currentTimeMillis(); +// double cost = ((double)time2 - (double)time1)/1000; +// +// +// //对比 +// String memory2 = cm2.dumpContract(contractName,""); +// System.out.println("<<>>" + memory2); +// if(memory.equals(memory2)) { +// System.out.println("####################\n####################\n####################"); +// System.out.println("Trans count = " + count + " Contract " + contractName + " recover success!"); +// System.out.println("####################\n####################\n####################"); +// } +// else { +// System.out.println("!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!"); +// System.out.println("Trans count = " + count + " Contract " + contractName + " recover failed!"); +// System.out.println("!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!\n!!!!!!!!!!!!!!!!!!!!!"); +// +// } +// System.out.println("共" + count + "项事务恢复,用时" + cost + "s"); + } +} diff --git a/src/test/java/org/bdware/sc/test/synctest/TransRecordTest.java b/src/test/java/org/bdware/sc/test/synctest/TransRecordTest.java new file mode 100644 index 0000000..01f5858 --- /dev/null +++ b/src/test/java/org/bdware/sc/test/synctest/TransRecordTest.java @@ -0,0 +1,43 @@ +package org.bdware.sc.test.synctest; + + +import org.bdware.sc.conn.ByteUtil; +import org.bdware.sc.redo.TransRecord; + +import java.io.*; +import java.util.zip.GZIPInputStream; + +public class TransRecordTest { + static TransRecord currentTransRecord = new TransRecord("myFun","myArg"); + + public static void main(String[] args){ +// currentTransRecord.executes.put("k1","v1"); +// currentTransRecord.executes.put("k2","v2"); +// currentTransRecord.executes.put("k3","v3"); +// +// System.out.println("发送一个TransRecord\n" + currentTransRecord.toString()); +// +// String str1 = currentTransRecord.transferToString(); +// +// try { +// byte[] bytes = str1.getBytes("UTF-8"); +// +// try { +// String re = new String(bytes, "UTF-8"); +// TransRecord transRecord = TransRecord.loadFromStr(re); +// +// System.out.println("收到一个TransRecord\n" + transRecord.toString()); +// +// } catch (UnsupportedEncodingException e) { +// e.printStackTrace(); +// } +// +// +// +// +// } catch (Exception e) { +// e.printStackTrace(); +// } + + } +} diff --git a/src/test/java/org/bdware/sc/test/transformerTest.java b/src/test/java/org/bdware/sc/test/transformerTest.java new file mode 100644 index 0000000..2015ea1 --- /dev/null +++ b/src/test/java/org/bdware/sc/test/transformerTest.java @@ -0,0 +1,19 @@ +package org.bdware.sc.test; +import com.alibaba.datax.transport.transformer.MD5Transformer; +import com.alibaba.datax.transport.transformer.maskingMethods.irreversibleInterference.*; +import org.junit.Test; + +public class transformerTest { + @Test + public void testMD5(){ + + MD5EncryptionImpl masker = new MD5EncryptionImpl(); + try{ + String result = masker.execute("aaa"); + System.out.println(result); + } + catch (Exception e){ + System.out.println(e); + } + } +} diff --git a/src/test/java/org/bdware/sc/trace/test/TraceTest.java b/src/test/java/org/bdware/sc/trace/test/TraceTest.java new file mode 100644 index 0000000..f2de80e --- /dev/null +++ b/src/test/java/org/bdware/sc/trace/test/TraceTest.java @@ -0,0 +1,26 @@ +package org.bdware.sc.trace.test; + +import org.bdware.sc.trace.TraceSetIdentifier; + +import java.util.HashMap; +import java.util.Map; + +public class TraceTest { + public static void main(String[] args) { + Map map = new HashMap<>(); + + TraceSetIdentifier id1 = new TraceSetIdentifier(182, "asd"); + TraceSetIdentifier id2 = new TraceSetIdentifier(182, 3.2); + TraceSetIdentifier id3 = new TraceSetIdentifier(182, "asd"); + TraceSetIdentifier id4 = new TraceSetIdentifier(182, 3.2); + + map.put(id1, "id1"); + map.put(id2, "id2"); + map.put(id3, "id3"); + map.put(id4, "id4"); + + for (String v : map.values()) { + System.out.println(v); + } + } +} diff --git a/src/test/resources/elsetest.yjs b/src/test/resources/elsetest.yjs new file mode 100644 index 0000000..91d2074 --- /dev/null +++ b/src/test/resources/elsetest.yjs @@ -0,0 +1,17 @@ +contract AAT{ + export function aa(arg){ + var oldList= []; + var removedList = []; + var newList = []; + for (var i=0;i