zhuxiaojun 1 هفته پیش
کامیت
8085499e77
86فایلهای تغییر یافته به همراه10527 افزوده شده و 0 حذف شده
  1. 14 0
      .gitignore
  2. 661 0
      LICENSE
  3. 77 0
      README.md
  4. 45 0
      app.js
  5. 47 0
      app.json
  6. 10 0
      app.wxss
  7. BIN
      assets/img/contact_us.png
  8. BIN
      assets/img/icon_arrow.png
  9. BIN
      assets/img/icon_index_add.png
  10. BIN
      assets/img/icon_login_password.png
  11. BIN
      assets/img/icon_login_user.png
  12. BIN
      assets/img/icon_main_index_logo.png
  13. BIN
      assets/img/icon_main_index_logo_red.png
  14. BIN
      assets/img/icon_main_my.png
  15. BIN
      assets/img/icon_main_my_red.png
  16. BIN
      assets/img/icon_main_setting.png
  17. BIN
      assets/img/icon_main_setting_red.png
  18. BIN
      assets/img/icon_my_avatar.png
  19. BIN
      assets/img/icon_read.png
  20. BIN
      assets/img/icon_read_completed.png
  21. BIN
      assets/img/icon_task.png
  22. BIN
      assets/img/icon_task_completed.png
  23. BIN
      assets/img/login_logo.png
  24. 1120 0
      components/image-cropper/image-cropper.js
  25. 3 0
      components/image-cropper/image-cropper.json
  26. 24 0
      components/image-cropper/image-cropper.wxml
  27. 123 0
      components/image-cropper/image-cropper.wxss
  28. 0 0
      components/multipart/Multipart.min.js
  29. 10 0
      components/o2-navi/o2-navi.js
  30. 3 0
      components/o2-navi/o2-navi.json
  31. 9 0
      components/o2-navi/o2-navi.wxml
  32. 0 0
      components/o2-navi/o2-navi.wxss
  33. 93 0
      pages/cms/cms-web.js
  34. 5 0
      pages/cms/cms-web.json
  35. 3 0
      pages/cms/cms-web.wxml
  36. 1 0
      pages/cms/cms-web.wxss
  37. 160 0
      pages/file/download.js
  38. 3 0
      pages/file/download.json
  39. 2 0
      pages/file/download.wxml
  40. 1 0
      pages/file/download.wxss
  41. 241 0
      pages/index/index.js
  42. 6 0
      pages/index/index.json
  43. 59 0
      pages/index/index.wxml
  44. 178 0
      pages/index/index.wxss
  45. 229 0
      pages/login/login.js
  46. 4 0
      pages/login/login.json
  47. 22 0
      pages/login/login.wxml
  48. 100 0
      pages/login/login.wxss
  49. 159 0
      pages/login/register.js
  50. 4 0
      pages/login/register.json
  51. 18 0
      pages/login/register.wxml
  52. 71 0
      pages/login/register.wxss
  53. 15 0
      pages/logs/logs.js
  54. 4 0
      pages/logs/logs.json
  55. 6 0
      pages/logs/logs.wxml
  56. 8 0
      pages/logs/logs.wxss
  57. 143 0
      pages/me/cropper-avatar.js
  58. 7 0
      pages/me/cropper-avatar.json
  59. 10 0
      pages/me/cropper-avatar.wxml
  60. 15 0
      pages/me/cropper-avatar.wxss
  61. 184 0
      pages/me/me.js
  62. 6 0
      pages/me/me.json
  63. 86 0
      pages/me/me.wxml
  64. 83 0
      pages/me/me.wxss
  65. 220 0
      pages/progress/start-work.js
  66. 6 0
      pages/progress/start-work.json
  67. 34 0
      pages/progress/start-work.wxml
  68. 43 0
      pages/progress/start-work.wxss
  69. 171 0
      pages/progress/work-list.js
  70. 6 0
      pages/progress/work-list.json
  71. 10 0
      pages/progress/work-list.wxml
  72. 40 0
      pages/progress/work-list.wxss
  73. 125 0
      pages/progress/work-web.js
  74. 5 0
      pages/progress/work-web.json
  75. 3 0
      pages/progress/work-web.wxml
  76. 1 0
      pages/progress/work-web.wxss
  77. 67 0
      project.config.json
  78. 9 0
      project.private.config.json
  79. BIN
      res/20201123103220.png
  80. BIN
      res/20201123103825.png
  81. BIN
      res/pic_xiaochengxu_o2oa@1.5x.png
  82. 7 0
      sitemap.json
  83. 5370 0
      utils/jsencrypt.js
  84. 142 0
      utils/o2Api.js
  85. 158 0
      utils/o2Request.js
  86. 38 0
      utils/util.js

+ 14 - 0
.gitignore

@@ -0,0 +1,14 @@
+# Windows
+[Dd]esktop.ini
+Thumbs.db
+$RECYCLE.BIN/
+
+# macOS
+.DS_Store
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+
+# Node.js
+node_modules/

+ 661 - 0
LICENSE

@@ -0,0 +1,661 @@
+                    GNU AFFERO GENERAL PUBLIC LICENSE
+                       Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+  A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate.  Many developers of free software are heartened and
+encouraged by the resulting cooperation.  However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+  The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community.  It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server.  Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+  An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals.  This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU Affero General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Remote Network Interaction; Use with the GNU General Public License.
+
+  Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software.  This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time.  Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    小程序
+    Copyright (C) 2020  o2oa
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Affero General Public License as published
+    by the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Affero General Public License for more details.
+
+    You should have received a copy of the GNU Affero General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source.  For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code.  There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+<http://www.gnu.org/licenses/>.

+ 77 - 0
README.md

@@ -0,0 +1,77 @@
+# O2OA 微信小程序
+
+O2OA微信小程序是**O2OA**企业信息化系统的微信小程序端实现。
+
+目前这个小程序连接的是我们O2OA的样例服务器,可以直接扫码体验:
+
+![o2oa小程序](./res/pic_xiaochengxu_o2oa@1.5x.png)
+
+## 小程序源码使用
+1. 首先需要自行申请一个微信小程序,同时这个微信小程序需要通过微信认证,个人小程序无法使用小程序的高级API,很多功能无法使用。
+
+2. 其次微信小程序需要配置后台服务器访问地址,目前小程序只支持https的请求,所以需要将O2OA服务器开启https功能。小程序后台配置如下图:
+
+![](./res/20201123103220.png)
+
+3. 小程序源码中修改O2OA服务器地址:
+
+![app.js](./res/20201123103825.png)
+
+# O2OA : Java企业信息化系统
+
+O2OA是基于J2EE架构,集成移动办公、智能办公,支持私有化部署,自适应负载能力的,能够很大程度上节约企业软件开发成本的基于AGPL协议开放源代码的企业信息化系统需求定制开发解决方案,对外提供专业的开发运维等技术服务。
+
+![o2oa](https://static.oschina.net/uploads/space/2018/0918/200301_N9TG_3931542.png)
+
+O2OA平台拥有流程管理、门户管理、信息管理、数据管理和服务管理五大核心能力。用户可以直接使用平台已有功能进行信息信息化建设,平台提供了完整的用户管理,权限管理,流程和信息管理体系,并且提供了大量的开发组件和开箱即用的应用,可以大幅度减化企业信息化建设成本和业务应用开发难度。
+
+
+## 其主要能力如下:
+
+流程管理:全功能流程引擎。基于任务驱动,开放式服务驱动,高灵活性、扩展性,事件定义丰富。包含人工、自动、拆分、合并、并行、定时、服务调用、子流程等功能。应用场景丰富,可轻松实现公文、合同、项目管理等复杂工作流应用。
+
+信息管理:具有权限控制能力的内容管理平台。支持自定义栏目、分类,表格,表单,多级权限系统,能轻松实现知识管理、通知公司、规章制度、文件管理等内容发布系统。
+
+门户管理:具体可视化表单编辑的,支持HTML直接导入的,支持各类数据源,外部应用集成能力的,所见即所得的门户管理平台。适用于实现企业信息化门户系统,可以轻松结合O2OA提供的认证设置与其他系统进行单点认证集成。
+
+服务管理:可以在前端脚本的形式,开发和自定义web服务,实现与后端服务数据交互的能力。
+
+数据中心:可以通过配置轻松实现数据透视图展示,数据统计、数据可视化图表开发等等功能。
+
+智能办公:拥有语音办公、人脸识别、指纹认证、智能文档纠错、智能填表推荐等智能办公特色
+
+移动办公:支持安卓\IOS手机APP办公,支持与企业微信和钉钉集成,支持企业私有化微信部署
+
+开箱即用:O2OA还提供如考勤管理、日程管理、会议管理、脑图管理、便签、云文件、企业社区、执行力管理等开箱即用的应用供企业选择
+
+
+## 产品特点:
+
+1. 代码全部开源,开发者可以下载源码进行任意,编译成自己的信息化平台。
+
+2. 平台全功能免费,无任何功能和人数限制。
+
+3. 支持私有化部署,下载软件安装包后可以安装在自己的服务器上,数据更安全。
+
+4. 随时随地办公,平台支持兼容HTML5的浏览器,并且提供了原生的IOS/Android应用,并且支持钉钉和企业微信集成。
+
+5. 高可扩展性,用户通过简单的学习后,可以自定义配置门户、流程应用、内容管理应用
+
+更多的产品介绍、使用说明、下载、在线体验、API及讨论请移步至[http://www.o2oa.net/](http://www.o2oa.net/)
+
+
+## 官方网站:
+
+开源主页 : https://www.oschina.net/p/o2oa
+
+官方网站 : http://www.o2oa.net
+
+Gitee : https://gitee.com/o2oa/O2OA
+
+Github : https://github.com/o2oa/o2oa
+
+语雀文档 : https://www.yuque.com/o2oa/course
+
+脚本API:http://www.o2oa.net/x_desktop/portal.html?id=dcd8e168-2da0-4496-83ee-137dc976c7f6
+
+

+ 45 - 0
app.js

@@ -0,0 +1,45 @@
+//app.js
+App({
+  onLaunch: function () {
+    // 展示本地存储能力
+    var logs = wx.getStorageSync('logs') || []
+    logs.unshift(Date.now())
+    wx.setStorageSync('logs', logs)
+    this.getNaviInfo()
+     
+  },
+  // 获取菜单按钮(右上角胶囊按钮)的布局位置信息
+  getNaviInfo: function() {
+    let menuRect = wx.getMenuButtonBoundingClientRect();
+    wx.getSystemInfo({
+      success: (res) => {
+        let naviInfo = this.globalData.naviInfo;
+        naviInfo.naviHeight = res.statusBarHeight + menuRect.height + (menuRect.top - res.statusBarHeight) * 2;
+        naviInfo.naviWidth = res.windowWidth;
+        naviInfo.menuTop = menuRect.top;
+        naviInfo.menuHeight = menuRect.height;
+        naviInfo.menuWidth = menuRect.width;
+        naviInfo.menuRight = res.width - menuRect.width - menuRect.left;
+        naviInfo.statusBarHeight = res.statusBarHeight;
+      },
+    })
+  },
+  globalData: {
+    userInfo: null,
+    o2oa: {
+      centerHost: "43.154.125.245",
+      centerContext: "/x_program_center",
+      centerPort: 8089,
+      httpProtocol: "http"
+    },
+    naviInfo: {
+      naviHeight: 0,
+      naviWidth: 0,
+      menuTop: 0,
+      menuHeight: 0,
+      menuWidth: 0,
+      menuRight: 0,
+      statusBarHeight: 0,
+    }
+  }
+})

+ 47 - 0
app.json

@@ -0,0 +1,47 @@
+{
+  "pages": [
+    "pages/login/login",
+    "pages/index/index",
+    "pages/me/me",
+    "pages/logs/logs",
+    "pages/cms/cms-web",
+    "pages/progress/work-web",
+    "pages/file/download",
+    "pages/progress/work-list",
+    "pages/me/cropper-avatar",
+    "pages/login/register",
+    "pages/progress/start-work"
+  ],
+  "tabBar": {
+    "color": "#666666",
+    "selectedColor": "#fb4747",
+    "backgroundColor": "#ffffff",
+    "borderStyle": "black",
+    "list": [
+      {
+        "pagePath": "pages/index/index",
+        "iconPath": "assets/img/icon_main_index_logo.png",
+        "selectedIconPath": "assets/img/icon_main_index_logo_red.png",
+        "text": "首页"
+      },
+      {
+        "pagePath": "pages/me/me",
+        "iconPath": "assets/img/icon_main_my.png",
+        "selectedIconPath": "assets/img/icon_main_my_red.png",
+        "text": "我的"
+      }
+    ]
+  },
+  "window": {
+    "backgroundTextStyle": "light",
+    "navigationBarBackgroundColor": "#fff",
+    "navigationBarTitleText": "Weixin",
+    "navigationBarTextStyle": "black"
+  },
+  "style": "v2",
+  "sitemapLocation": "sitemap.json",
+  "useExtendedLib": {
+    "weui": true
+  },
+  "lazyCodeLoading": "requiredComponents" 
+}

+ 10 - 0
app.wxss

@@ -0,0 +1,10 @@
+/**app.wxss**/
+.container {
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: space-between;
+  padding: 200rpx 0;
+  box-sizing: border-box;
+}

BIN
assets/img/contact_us.png


BIN
assets/img/icon_arrow.png


BIN
assets/img/icon_index_add.png


BIN
assets/img/icon_login_password.png


BIN
assets/img/icon_login_user.png


BIN
assets/img/icon_main_index_logo.png


BIN
assets/img/icon_main_index_logo_red.png


BIN
assets/img/icon_main_my.png


BIN
assets/img/icon_main_my_red.png


BIN
assets/img/icon_main_setting.png


BIN
assets/img/icon_main_setting_red.png


BIN
assets/img/icon_my_avatar.png


BIN
assets/img/icon_read.png


BIN
assets/img/icon_read_completed.png


BIN
assets/img/icon_task.png


BIN
assets/img/icon_task_completed.png


BIN
assets/img/login_logo.png


+ 1120 - 0
components/image-cropper/image-cropper.js

@@ -0,0 +1,1120 @@
+Component({
+  properties: {
+    /**     
+     * 图片路径
+     */
+    'imgSrc': {
+      type: String
+    },
+    /**
+     * 裁剪框高度
+     */
+    'height': {
+      type: Number,
+      value: 200
+    },
+    /**
+     * 裁剪框宽度
+     */
+    'width': {
+      type: Number,
+      value: 200
+    },
+    /**
+     * 裁剪框最小尺寸
+     */
+    'min_width': {
+      type: Number,
+      value: 100
+    },
+    'min_height': {
+      type: Number,
+      value: 100
+    },
+    /**
+     * 裁剪框最大尺寸
+     */
+    'max_width': {
+      type: Number,
+      value: 300
+    },
+    'max_height': {
+      type: Number,
+      value: 300
+    },
+    /**
+     * 裁剪框禁止拖动
+     */
+    'disable_width': {
+      type: Boolean,
+      value: false
+    },
+    'disable_height': {
+      type: Boolean,
+      value: false
+    },
+    /**
+     * 锁定裁剪框比例
+     */
+    'disable_ratio':{
+      type: Boolean,
+      value: false
+    },
+    /**
+     * 生成的图片尺寸相对剪裁框的比例
+     */
+    'export_scale': {
+      type: Number,
+      value: 3
+    },
+    /**
+     * 生成的图片质量0-1
+     */
+    'quality': {
+      type: Number,
+      value: 1
+    },
+    'cut_top': {
+      type: Number,
+      value: null
+    },
+    'cut_left': {
+      type: Number,
+      value: null
+    },
+    /**
+     * canvas上边距(不设置默认不显示)
+     */
+    'canvas_top': {
+      type: Number,
+      value: null
+    },
+    /**
+     * canvas左边距(不设置默认不显示)
+     */
+    'canvas_left': {
+      type: Number,
+      value: null
+    },
+    /**
+     * 图片宽度
+     */
+    'img_width': {
+      type: null,
+      value: null
+    },
+    /**
+     * 图片高度
+     */
+    'img_height': {
+      type: null,
+      value: null
+    },
+    /**
+     * 图片缩放比
+     */
+    'scale': {
+      type: Number,
+      value: 1
+    },
+    /**
+     * 图片旋转角度
+     */
+    'angle': {
+      type: Number,
+      value: 0
+    },
+    /**
+     * 最小缩放比
+     */
+    'min_scale': {
+      type: Number,
+      value: 0.5
+    },
+    /**
+     * 最大缩放比
+     */
+    'max_scale': {
+      type: Number,
+      value: 2
+    },
+    /**
+     * 是否禁用旋转
+     */
+    'disable_rotate': {
+      type: Boolean,
+      value: false
+    },
+    /**
+     * 是否限制移动范围(剪裁框只能在图片内)
+     */
+    'limit_move':{
+      type: Boolean,
+      value: false
+    }
+  },
+  data: {
+    el: 'image-cropper', //暂时无用
+    info: wx.getSystemInfoSync(),
+    MOVE_THROTTLE:null,//触摸移动节流settimeout
+    MOVE_THROTTLE_FLAG: true,//节流标识
+    INIT_IMGWIDTH: 0, //图片设置尺寸,此值不变(记录最初设定的尺寸)
+    INIT_IMGHEIGHT: 0, //图片设置尺寸,此值不变(记录最初设定的尺寸)
+    TIME_BG: null,//背景变暗延时函数
+    TIME_CUT_CENTER:null,
+    _touch_img_relative: [{
+      x: 0,
+      y: 0
+    }], //鼠标和图片中心的相对位置
+    _flag_cut_touch:false,//是否是拖动裁剪框
+    _hypotenuse_length: 0, //双指触摸时斜边长度
+    _flag_img_endtouch: false, //是否结束触摸
+    _flag_bright: true, //背景是否亮
+    _canvas_overflow:true,//canvas缩略图是否在屏幕外面
+    _canvas_width:200,
+    _canvas_height:200,
+    origin_x: 0.5, //图片旋转中心
+    origin_y: 0.5, //图片旋转中心
+    _cut_animation: false,//是否开启图片和裁剪框过渡
+    _img_top: wx.getSystemInfoSync().windowHeight / 2, //图片上边距
+    _img_left: wx.getSystemInfoSync().windowWidth / 2, //图片左边距
+    watch: {
+      //监听截取框宽高变化
+      width(value, that) {
+        if (value < that.data.min_width){
+          that.setData({
+            width: that.data.min_width
+          });
+        }
+        that._computeCutSize();
+      },
+      height(value, that) {
+        if (value < that.data.min_height) {
+          that.setData({
+            height: that.data.min_height
+          });
+        }
+        that._computeCutSize();
+      },
+      angle(value, that){
+        //停止居中裁剪框,继续修改图片位置
+        that._moveStop();
+        if(that.data.limit_move){
+          if (that.data.angle % 90) {
+            that.setData({
+              angle: Math.round(that.data.angle / 90) * 90
+            });
+            return;
+          }
+        }
+      },
+      _cut_animation(value, that){
+        //开启过渡300毫秒之后自动关闭
+        clearTimeout(that.data._cut_animation_time);
+        if (value){
+          that.data._cut_animation_time = setTimeout(()=>{
+            that.setData({
+              _cut_animation:false
+            });
+          },300)
+        }
+      },
+      limit_move(value, that){
+        if (value) {
+          if (that.data.angle%90){
+            that.setData({
+              angle: Math.round(that.data.angle / 90)*90
+            });
+          }
+          that._imgMarginDetectionScale();
+          !that.data._canvas_overflow && that._draw();
+        }
+      },
+      canvas_top(value, that){
+        that._canvasDetectionPosition();
+      },
+      canvas_left(value, that){
+        that._canvasDetectionPosition();
+      },
+      imgSrc(value, that){
+        that.pushImg();
+      },
+      cut_top(value, that) {
+        that._cutDetectionPosition();
+        if (that.data.limit_move) {
+          !that.data._canvas_overflow && that._draw();
+        }
+      },
+      cut_left(value, that) {
+        that._cutDetectionPosition();
+        if (that.data.limit_move) {
+          !that.data._canvas_overflow && that._draw();
+        }
+      }
+    }
+  },
+  attached() {
+    this.data.info = wx.getSystemInfoSync();
+    //启用数据监听
+    this._watcher();
+    this.data.INIT_IMGWIDTH = this.data.img_width;
+    this.data.INIT_IMGHEIGHT = this.data.img_height;
+    this.setData({
+      _canvas_height: this.data.height,
+      _canvas_width: this.data.width,
+    });
+    this._initCanvas();
+    this.data.imgSrc && (this.data.imgSrc = this.data.imgSrc);
+    //根据开发者设置的图片目标尺寸计算实际尺寸
+    this._initImageSize();
+    //设置裁剪框大小>设置图片尺寸>绘制canvas
+    this._computeCutSize();
+    //检查裁剪框是否在范围内
+    this._cutDetectionPosition();
+    //检查canvas是否在范围内
+    this._canvasDetectionPosition();
+    //初始化完成
+    this.triggerEvent('load', {
+      cropper: this
+    });
+  },
+  methods: {
+    /**
+     * 上传图片
+     */
+    upload() {
+      let that = this;
+      wx.chooseImage({
+        count: 1,
+        sizeType: ['original', 'compressed'],
+        sourceType: ['album', 'camera'],
+        success(res) {
+          const tempFilePaths = res.tempFilePaths[0];
+          that.pushImg(tempFilePaths);
+          wx.showLoading({
+            title: '加载中...'
+          })
+        }
+      })
+    },
+    /**
+     * 返回图片信息
+     */
+    getImg(getCallback) {
+      this._draw(()=>{
+        wx.canvasToTempFilePath({
+          width: this.data.width * this.data.export_scale,
+          height: Math.round(this.data.height * this.data.export_scale),
+          destWidth: this.data.width * this.data.export_scale,
+          destHeight: Math.round(this.data.height) * this.data.export_scale,
+          fileType: 'png',
+          quality: this.data.quality,
+          canvasId: this.data.el,
+          success: (res) => {
+            getCallback({
+              url: res.tempFilePath,
+              width: this.data.width * this.data.export_scale,
+              height: this.data.height * this.data.export_scale
+            });
+          }
+        }, this)
+      });
+    },
+    /**
+     * 设置图片动画
+     * {
+     *    x:10,//图片在原有基础上向下移动10px
+     *    y:10,//图片在原有基础上向右移动10px
+     *    angle:10,//图片在原有基础上旋转10deg
+     *    scale:0.5,//图片在原有基础上增加0.5倍
+     * }
+     */
+    setTransform(transform) {
+      if (!transform) return;
+      if (!this.data.disable_rotate){
+        this.setData({
+          angle: transform.angle ? this.data.angle + transform.angle : this.data.angle
+        });
+      }
+      var scale = this.data.scale;
+      if (transform.scale) {
+        scale = this.data.scale + transform.scale;
+        scale = scale <= this.data.min_scale ? this.data.min_scale : scale;
+        scale = scale >= this.data.max_scale ? this.data.max_scale : scale;
+      }
+      this.data.scale = scale;
+      let cutX = this.data.cut_left;
+      let cutY = this.data.cut_top;
+      if (transform.cutX){
+        this.setData({
+          cut_left: cutX + transform.cutX
+        });
+        this.data.watch.cut_left(null, this);
+      }
+      if (transform.cutY){
+        this.setData({
+          cut_top: cutY + transform.cutY
+        });
+        this.data.watch.cut_top(null, this);
+      }
+      this.data._img_top = transform.y ? this.data._img_top + transform.y : this.data._img_top;
+      this.data._img_left = transform.x ? this.data._img_left + transform.x : this.data._img_left;
+      //图像边缘检测,防止截取到空白
+      this._imgMarginDetectionScale();
+      //停止居中裁剪框,继续修改图片位置
+      this._moveDuring();
+      this.setData({
+        scale: this.data.scale,
+        _img_top: this.data._img_top,
+        _img_left: this.data._img_left
+      });
+      !this.data._canvas_overflow && this._draw();
+      //可以居中裁剪框了
+      this._moveStop();//结束操作
+    },
+    /**
+     * 设置剪裁框位置
+     */
+    setCutXY(x,y){
+      this.setData({
+        cut_top: y,
+        cut_left:x
+      });
+    },
+    /**
+     * 设置剪裁框尺寸
+     */
+    setCutSize(w,h){
+      this.setData({
+        width: w,
+        height:h
+      });
+      this._computeCutSize();
+    },
+    /**
+     * 设置剪裁框和图片居中
+     */
+    setCutCenter() {
+      let cut_top = (this.data.info.windowHeight - this.data.height) * 0.5;
+      let cut_left = (this.data.info.windowWidth - this.data.width) * 0.5;
+      //顺序不能变
+      this.setData({
+        _img_top: this.data._img_top - this.data.cut_top + cut_top,
+        cut_top: cut_top, //截取的框上边距
+        _img_left: this.data._img_left - this.data.cut_left + cut_left,
+        cut_left: cut_left, //截取的框左边距
+      });
+    },
+    _setCutCenter(){
+      let cut_top = (this.data.info.windowHeight - this.data.height) * 0.5;
+      let cut_left = (this.data.info.windowWidth - this.data.width) * 0.5;
+      this.setData({
+        cut_top: cut_top, //截取的框上边距
+        cut_left: cut_left, //截取的框左边距
+      });
+    },
+    /**
+     * 设置剪裁框宽度-即将废弃
+     */
+    setWidth(width) {
+      this.setData({
+        width: width
+      });
+      this._computeCutSize();
+    },
+    /**
+     * 设置剪裁框高度-即将废弃
+     */
+    setHeight(height) {
+      this.setData({
+        height: height
+      });
+      this._computeCutSize();
+    },
+    /**
+     * 是否锁定旋转
+     */
+    setDisableRotate(value){
+      this.data.disable_rotate = value;
+    },
+    /**
+     * 是否限制移动
+     */
+    setLimitMove(value){
+      this.setData({
+        _cut_animation: true,
+        limit_move: !!value
+      });
+    },
+    /**
+     * 初始化图片,包括位置、大小、旋转角度
+     */
+    imgReset() {
+      this.setData({
+        scale: 1,
+        angle: 0,
+        _img_top: wx.getSystemInfoSync().windowHeight / 2,
+        _img_left: wx.getSystemInfoSync().windowWidth / 2,
+      })
+    },
+    /**
+     * 加载(更换)图片
+     */
+    pushImg(src) {
+      if (src) {
+        this.setData({
+          imgSrc: src
+        });
+        //发现是手动赋值直接返回,交给watch处理
+        return;
+      }
+      
+      // getImageInfo接口传入 src: '' 会导致内存泄漏
+      
+      if (!this.data.imgSrc) return;
+      wx.getImageInfo({
+        src: this.data.imgSrc,
+        success: (res) => {
+          this.data.imageObject = res;
+          //图片非本地路径需要换成本地路径
+          if (this.data.imgSrc.search(/tmp/) == -1){
+            this.setData({
+              imgSrc: res.path
+            });
+          }
+          //计算最后图片尺寸
+          this._imgComputeSize();
+          if (this.data.limit_move) {
+            //限制移动,不留空白处理
+            this._imgMarginDetectionScale();
+          }
+          this._draw();
+        },
+        fail: (err) => {
+          this.setData({
+            imgSrc: ''
+          });
+        }
+      });
+    },
+    imageLoad(e){
+      setTimeout(()=>{
+      this.triggerEvent('imageload', this.data.imageObject);
+
+      },1000)
+    },
+    /**
+     * 设置图片放大缩小
+     */
+    setScale(scale) {
+      if (!scale) return;
+      this.setData({
+        scale: scale
+      });
+      !this.data._canvas_overflow && this._draw();
+    },
+    /**
+     * 设置图片旋转角度
+     */
+    setAngle(angle) {
+      if (!angle) return;
+      this.setData({
+        _cut_animation: true,
+        angle: angle
+      });
+      this._imgMarginDetectionScale();
+      !this.data._canvas_overflow && this._draw();
+    },
+    _initCanvas() {
+      //初始化canvas
+      if (!this.data.ctx){
+        this.data.ctx = wx.createCanvasContext("image-cropper", this);
+      }
+    },
+    /**
+     * 根据开发者设置的图片目标尺寸计算实际尺寸
+     */
+    _initImageSize(){
+      //处理宽高特殊单位 %>px
+      if (this.data.INIT_IMGWIDTH && typeof this.data.INIT_IMGWIDTH == "string" && this.data.INIT_IMGWIDTH.indexOf("%") != -1) {
+        let width = this.data.INIT_IMGWIDTH.replace("%", "");
+        this.data.INIT_IMGWIDTH = this.data.img_width = this.data.info.windowWidth / 100 * width;
+      }
+      if (this.data.INIT_IMGHEIGHT && typeof this.data.INIT_IMGHEIGHT == "string" && this.data.INIT_IMGHEIGHT.indexOf("%") != -1) {
+        let height = this.data.img_height.replace("%", "");
+        this.data.INIT_IMGHEIGHT = this.data.img_height = this.data.info.windowHeight / 100 * height;
+      }
+    },
+    /**
+     * 检测剪裁框位置是否在允许的范围内(屏幕内)
+     */
+    _cutDetectionPosition(){
+      let _cutDetectionPositionTop = () => {
+        //检测上边距是否在范围内
+        if (this.data.cut_top < 0) {
+          this.setData({
+            cut_top: 0
+          });
+        }
+        if (this.data.cut_top > this.data.info.windowHeight - this.data.height) {
+          this.setData({
+            cut_top: this.data.info.windowHeight - this.data.height
+          });
+        }
+      }, _cutDetectionPositionLeft = () => {
+        //检测左边距是否在范围内
+        if (this.data.cut_left < 0) {
+          this.setData({
+            cut_left: 0
+          });
+        }
+        if (this.data.cut_left > this.data.info.windowWidth - this.data.width) {
+          this.setData({
+            cut_left: this.data.info.windowWidth - this.data.width
+          });
+        }
+      };
+      //裁剪框坐标处理(如果只写一个参数则另一个默认为0,都不写默认居中)
+      if (this.data.cut_top == null && this.data.cut_left == null) {
+        this._setCutCenter();
+      } else if (this.data.cut_top != null && this.data.cut_left != null){
+        _cutDetectionPositionTop();
+        _cutDetectionPositionLeft();
+      } else if (this.data.cut_top != null && this.data.cut_left == null) {
+        _cutDetectionPositionTop();
+        this.setData({
+          cut_left: (this.data.info.windowWidth - this.data.width) / 2
+        });
+      } else if (this.data.cut_top == null && this.data.cut_left != null) {
+        _cutDetectionPositionLeft();
+        this.setData({
+          cut_top: (this.data.info.windowHeight - this.data.height) / 2
+        });
+      }
+    },
+    /**
+     * 检测canvas位置是否在允许的范围内(屏幕内)如果在屏幕外则不开启实时渲染
+     * 如果只写一个参数则另一个默认为0,都不写默认超出屏幕外
+     */
+    _canvasDetectionPosition(){
+      if(this.data.canvas_top == null && this.data.canvas_left == null) {
+        this.data._canvas_overflow = false;
+        this.setData({
+          canvas_top: -5000,
+          canvas_left: -5000
+        });
+      }else if(this.data.canvas_top != null && this.data.canvas_left != null) {
+        if (this.data.canvas_top < - this.data.height || this.data.canvas_top > this.data.info.windowHeight) {
+          this.data._canvas_overflow = true;
+        } else {
+          this.data._canvas_overflow = false;
+        }
+      }else if(this.data.canvas_top != null && this.data.canvas_left == null) {
+        this.setData({
+          canvas_left: 0
+        });
+      } else if (this.data.canvas_top == null && this.data.canvas_left != null) {
+        this.setData({
+          canvas_top: 0
+        });
+        if (this.data.canvas_left < -this.data.width || this.data.canvas_left > this.data.info.windowWidth) {
+          this.data._canvas_overflow = true;
+        } else {
+          this.data._canvas_overflow = false;
+        }
+      }
+    },
+    /**
+     * 图片边缘检测-位置
+     */
+    _imgMarginDetectionPosition(scale) {
+      if (!this.data.limit_move) return;
+      let left = this.data._img_left;
+      let top = this.data._img_top;
+      var scale = scale || this.data.scale;
+      let img_width = this.data.img_width;
+      let img_height = this.data.img_height;
+      if (this.data.angle / 90 % 2) {
+        img_width = this.data.img_height;
+        img_height = this.data.img_width;
+      }
+      left = this.data.cut_left + img_width * scale / 2 >= left ? left : this.data.cut_left + img_width * scale / 2;
+      left = this.data.cut_left + this.data.width - img_width * scale / 2 <= left ? left : this.data.cut_left + this.data.width - img_width * scale / 2;
+      top = this.data.cut_top + img_height * scale / 2 >= top ? top : this.data.cut_top + img_height * scale / 2;
+      top = this.data.cut_top + this.data.height - img_height * scale / 2 <= top ? top : this.data.cut_top + this.data.height - img_height * scale / 2;
+      this.setData({
+        _img_left: left,
+        _img_top: top,
+        scale: scale
+      })
+    },
+    /**
+     * 图片边缘检测-缩放
+     */
+    _imgMarginDetectionScale(){
+      if (!this.data.limit_move)return;
+      let scale = this.data.scale;
+      let img_width = this.data.img_width;
+      let img_height = this.data.img_height;
+      if (this.data.angle / 90 % 2) {
+        img_width = this.data.img_height;
+        img_height = this.data.img_width;
+      }
+      if (img_width * scale < this.data.width){
+        scale = this.data.width / img_width;
+      }
+      if (img_height * scale < this.data.height) {
+        scale = Math.max(scale,this.data.height / img_height);
+      }
+      this._imgMarginDetectionPosition(scale);
+    },
+    _setData(obj) {
+      let data = {};
+      for (var key in obj) {
+        if (this.data[key] != obj[key]){
+          data[key] = obj[key];
+        }
+      }
+      this.setData(data);
+      return data;
+    },
+    /**
+     * 计算图片尺寸
+     */
+    _imgComputeSize() {
+      let img_width = this.data.img_width,
+          img_height = this.data.img_height;
+      if (!this.data.INIT_IMGHEIGHT && !this.data.INIT_IMGWIDTH) {
+        //默认按图片最小边 = 对应裁剪框尺寸
+        img_width = this.data.imageObject.width;
+        img_height = this.data.imageObject.height;
+        if (img_width / img_height > this.data.width / this.data.height){
+          img_height = this.data.height;
+          img_width = this.data.imageObject.width / this.data.imageObject.height * img_height;
+        }else{
+          img_width = this.data.width;
+          img_height = this.data.imageObject.height / this.data.imageObject.width * img_width;
+        }
+      } else if (this.data.INIT_IMGHEIGHT && !this.data.INIT_IMGWIDTH) {
+        img_width = this.data.imageObject.width / this.data.imageObject.height * this.data.INIT_IMGHEIGHT;
+      } else if (!this.data.INIT_IMGHEIGHT && this.data.INIT_IMGWIDTH) {
+        img_height = this.data.imageObject.height / this.data.imageObject.width * this.data.INIT_IMGWIDTH;
+      }
+      this.setData({
+        img_width: img_width,
+        img_height: img_height
+      });
+    },
+    //改变截取框大小
+    _computeCutSize() {
+      if (this.data.width > this.data.info.windowWidth) {
+        this.setData({
+          width: this.data.info.windowWidth,
+        });
+      } else if (this.data.width + this.data.cut_left > this.data.info.windowWidth){
+        this.setData({
+          cut_left: this.data.info.windowWidth - this.data.cut_left,
+        });
+      };
+      if (this.data.height > this.data.info.windowHeight) {
+        this.setData({
+          height: this.data.info.windowHeight,
+        });
+      } else if (this.data.height + this.data.cut_top > this.data.info.windowHeight){
+        this.setData({
+          cut_top: this.data.info.windowHeight - this.data.cut_top,
+        });
+      }
+      !this.data._canvas_overflow && this._draw();
+    },
+    //开始触摸
+    _start(event) {
+      this.data._flag_img_endtouch = false;
+      if (event.touches.length == 1) {
+        //单指拖动
+        this.data._touch_img_relative[0] = {
+          x: (event.touches[0].clientX - this.data._img_left),
+          y: (event.touches[0].clientY - this.data._img_top)
+        }
+      } else {
+        //双指放大
+        let width = Math.abs(event.touches[0].clientX - event.touches[1].clientX);
+        let height = Math.abs(event.touches[0].clientY - event.touches[1].clientY);
+        this.data._touch_img_relative = [{
+          x: (event.touches[0].clientX - this.data._img_left),
+          y: (event.touches[0].clientY - this.data._img_top)
+        }, {
+          x: (event.touches[1].clientX - this.data._img_left),
+          y: (event.touches[1].clientY - this.data._img_top)
+        }];
+        this.data._hypotenuse_length = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2));
+      }
+      !this.data._canvas_overflow && this._draw();
+    },
+    _move_throttle(){
+      //安卓需要节流
+      if (this.data.info.platform =='android'){
+        clearTimeout(this.data.MOVE_THROTTLE);
+        this.data.MOVE_THROTTLE = setTimeout(() => {
+          this.data.MOVE_THROTTLE_FLAG = true;
+        }, 1000 / 40)
+        return this.data.MOVE_THROTTLE_FLAG;
+      }else{
+        this.data.MOVE_THROTTLE_FLAG = true;
+      }
+    },
+    _move(event) {
+      if (this.data._flag_img_endtouch || !this.data.MOVE_THROTTLE_FLAG) return;
+      this.data.MOVE_THROTTLE_FLAG = false;
+      this._move_throttle();
+      this._moveDuring();
+      if (event.touches.length == 1) {
+        //单指拖动
+        let left = (event.touches[0].clientX - this.data._touch_img_relative[0].x),
+            top = (event.touches[0].clientY - this.data._touch_img_relative[0].y);
+        //图像边缘检测,防止截取到空白
+        this.data._img_left = left;
+        this.data._img_top = top;
+        this._imgMarginDetectionPosition();
+        this.setData({
+          _img_left: this.data._img_left,
+          _img_top: this.data._img_top
+        });
+      } else {
+        //双指放大
+        let width = (Math.abs(event.touches[0].clientX - event.touches[1].clientX)),
+            height = (Math.abs(event.touches[0].clientY - event.touches[1].clientY)),
+            hypotenuse = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2)),
+            scale = this.data.scale * (hypotenuse / this.data._hypotenuse_length),
+            current_deg = 0;
+        scale = scale <= this.data.min_scale ? this.data.min_scale : scale;
+        scale = scale >= this.data.max_scale ? this.data.max_scale : scale;
+        //图像边缘检测,防止截取到空白
+        this.data.scale = scale;
+        this._imgMarginDetectionScale();
+        //双指旋转(如果没禁用旋转)
+        let _touch_img_relative = [{
+          x: (event.touches[0].clientX - this.data._img_left),
+          y: (event.touches[0].clientY - this.data._img_top)
+        }, {
+          x: (event.touches[1].clientX - this.data._img_left),
+          y: (event.touches[1].clientY - this.data._img_top)
+        }];
+        if (!this.data.disable_rotate){
+          let first_atan = 180 / Math.PI * Math.atan2(_touch_img_relative[0].y, _touch_img_relative[0].x);
+          let first_atan_old = 180 / Math.PI * Math.atan2(this.data._touch_img_relative[0].y, this.data._touch_img_relative[0].x);
+          let second_atan = 180 / Math.PI * Math.atan2(_touch_img_relative[1].y, _touch_img_relative[1].x);
+          let second_atan_old = 180 / Math.PI * Math.atan2(this.data._touch_img_relative[1].y, this.data._touch_img_relative[1].x);
+          //当前旋转的角度
+          let first_deg = first_atan - first_atan_old,
+              second_deg = second_atan - second_atan_old;
+          if (first_deg != 0) {
+            current_deg = first_deg;
+          } else if (second_deg != 0) {
+            current_deg = second_deg;
+          }
+        }
+        this.data._touch_img_relative = _touch_img_relative;
+        this.data._hypotenuse_length = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2));
+        //更新视图
+        this.setData({
+          angle: this.data.angle + current_deg,
+          scale: this.data.scale
+        });
+      }
+      !this.data._canvas_overflow && this._draw();
+    },
+    //结束操作
+    _end(event) {
+      this.data._flag_img_endtouch = true;
+      this._moveStop();
+    },
+    //点击中间剪裁框处理
+    _click(event) {
+      if (!this.data.imgSrc) {
+        //调起上传
+        this.upload();
+        return;
+      }
+      this._draw(()=>{
+        let x = event.detail ? event.detail.x : event.touches[0].clientX;
+        let y = event.detail ? event.detail.y : event.touches[0].clientY;
+        if ((x >= this.data.cut_left && x <= (this.data.cut_left + this.data.width)) && (y >= this.data.cut_top && y <= (this.data.cut_top + this.data.height))) {
+          //生成图片并回调
+          wx.canvasToTempFilePath({
+            width: this.data.width * this.data.export_scale,
+            height: Math.round(this.data.height * this.data.export_scale),
+            destWidth: this.data.width * this.data.export_scale,
+            destHeight: Math.round(this.data.height) * this.data.export_scale,
+            fileType: 'png',
+            quality: this.data.quality,
+            canvasId: this.data.el,
+            success: (res) => {
+              this.triggerEvent('tapcut', {
+                url: res.tempFilePath,
+                width: this.data.width * this.data.export_scale,
+                height: this.data.height * this.data.export_scale
+              });
+            }
+          }, this)
+        }
+      });
+    },
+    //渲染
+    _draw(callback) {
+      if (!this.data.imgSrc) return;
+      let draw = () => {
+        //图片实际大小
+        let img_width = this.data.img_width * this.data.scale * this.data.export_scale;
+        let img_height = this.data.img_height * this.data.scale * this.data.export_scale;
+        //canvas和图片的相对距离
+        var xpos = this.data._img_left - this.data.cut_left;
+        var ypos = this.data._img_top - this.data.cut_top;
+        //旋转画布
+        this.data.ctx.translate(xpos * this.data.export_scale, ypos * this.data.export_scale);
+        this.data.ctx.rotate(this.data.angle * Math.PI / 180);
+        this.data.ctx.drawImage(this.data.imgSrc, -img_width / 2, -img_height / 2, img_width, img_height);
+        this.data.ctx.draw(false, () => {
+            callback && callback();
+        });
+      }
+      if (this.data.ctx.width != this.data.width || this.data.ctx.height != this.data.height){
+        //优化拖动裁剪框,所以必须把宽高设置放在离用户触发渲染最近的地方
+        this.setData({
+          _canvas_height: this.data.height,
+          _canvas_width: this.data.width,
+        },()=>{
+          //延迟40毫秒防止点击过快出现拉伸或裁剪过多
+          setTimeout(() => {
+            draw();
+          }, 40);
+        });
+      }else{
+        draw();
+      }
+    },
+    //裁剪框处理
+    _cutTouchMove(e) {
+      if (this.data._flag_cut_touch && this.data.MOVE_THROTTLE_FLAG) {
+        if (this.data.disable_ratio && (this.data.disable_width || this.data.disable_height)) return;
+        //节流
+        this.data.MOVE_THROTTLE_FLAG = false;
+        this._move_throttle();
+        let width = this.data.width,
+          height = this.data.height,
+          cut_top = this.data.cut_top,
+          cut_left = this.data.cut_left,
+          size_correct = () => {
+            width = width <= this.data.max_width ? width >= this.data.min_width ? width : this.data.min_width : this.data.max_width;
+            height = height <= this.data.max_height ? height >= this.data.min_height ? height : this.data.min_height : this.data.max_height;
+          },
+          size_inspect = () => {
+            if ((width > this.data.max_width || width < this.data.min_width || height > this.data.max_height || height < this.data.min_height) && this.data.disable_ratio) {
+              size_correct();
+              return false;
+            } else {
+              size_correct();
+              return true;
+            }
+          };
+        height = this.data.CUT_START.height + ((this.data.CUT_START.corner > 1 && this.data.CUT_START.corner < 4 ? 1 : -1) * (this.data.CUT_START.y - e.touches[0].clientY));
+        switch (this.data.CUT_START.corner) {
+          case 1:
+            width = this.data.CUT_START.width + this.data.CUT_START.x - e.touches[0].clientX;
+            if (this.data.disable_ratio) {
+              height = width / (this.data.width / this.data.height)
+            }
+            if (!size_inspect()) return;
+            cut_left = this.data.CUT_START.cut_left - (width - this.data.CUT_START.width);
+            break
+          case 2:
+            width = this.data.CUT_START.width + this.data.CUT_START.x - e.touches[0].clientX;
+            if (this.data.disable_ratio) {
+              height = width / (this.data.width / this.data.height)
+            }
+            if (!size_inspect()) return;
+            cut_top = this.data.CUT_START.cut_top - (height - this.data.CUT_START.height)
+            cut_left = this.data.CUT_START.cut_left - (width - this.data.CUT_START.width)
+            break
+          case 3:
+            width = this.data.CUT_START.width - this.data.CUT_START.x + e.touches[0].clientX;
+            if (this.data.disable_ratio) {
+              height = width / (this.data.width / this.data.height)
+            }
+            if (!size_inspect()) return;
+            cut_top = this.data.CUT_START.cut_top - (height - this.data.CUT_START.height);
+            break
+          case 4:
+            width = this.data.CUT_START.width - this.data.CUT_START.x + e.touches[0].clientX;
+            if (this.data.disable_ratio) {
+              height = width / (this.data.width / this.data.height)
+            }
+            if (!size_inspect()) return;
+            break
+        }
+        if (!this.data.disable_width && !this.data.disable_height) {
+          this.setData({
+            width: width,
+            cut_left: cut_left,
+            height: height,
+            cut_top: cut_top,
+          })
+        } else if (!this.data.disable_width) {
+          this.setData({
+            width: width,
+            cut_left: cut_left
+          })
+        } else if (!this.data.disable_height) {
+          this.setData({
+            height: height,
+            cut_top: cut_top
+          })
+        }
+        this._imgMarginDetectionScale();
+      }
+    },
+    _cutTouchStart(e) {
+      let currentX = e.touches[0].clientX;
+      let currentY = e.touches[0].clientY;
+      let cutbox_top4 = this.data.cut_top + this.data.height - 30;
+      let cutbox_bottom4 = this.data.cut_top + this.data.height + 20;
+      let cutbox_left4 = this.data.cut_left + this.data.width - 30;
+      let cutbox_right4 = this.data.cut_left + this.data.width + 30;
+
+      let cutbox_top3 = this.data.cut_top - 30;
+      let cutbox_bottom3 = this.data.cut_top + 30;
+      let cutbox_left3 = this.data.cut_left + this.data.width - 30;
+      let cutbox_right3 = this.data.cut_left + this.data.width + 30;
+
+      let cutbox_top2 = this.data.cut_top - 30;
+      let cutbox_bottom2 = this.data.cut_top + 30;
+      let cutbox_left2 = this.data.cut_left - 30;
+      let cutbox_right2 = this.data.cut_left + 30;
+
+      let cutbox_top1 = this.data.cut_top + this.data.height - 30;
+      let cutbox_bottom1 = this.data.cut_top + this.data.height + 30;
+      let cutbox_left1 = this.data.cut_left - 30;
+      let cutbox_right1 = this.data.cut_left + 30;
+      if (currentX > cutbox_left4 && currentX < cutbox_right4 && currentY > cutbox_top4 && currentY < cutbox_bottom4) {
+        this._moveDuring();
+        this.data._flag_cut_touch = true;
+        this.data._flag_img_endtouch = true;
+        this.data.CUT_START = {
+          width: this.data.width,
+          height: this.data.height,
+          x: currentX,
+          y: currentY,
+          corner: 4
+        }
+      } else if (currentX > cutbox_left3 && currentX < cutbox_right3 && currentY > cutbox_top3 && currentY < cutbox_bottom3) {
+        this._moveDuring();
+        this.data._flag_cut_touch = true;
+        this.data._flag_img_endtouch = true;
+        this.data.CUT_START = {
+          width: this.data.width,
+          height: this.data.height,
+          x: currentX,
+          y: currentY,
+          cut_top: this.data.cut_top,
+          cut_left: this.data.cut_left,
+          corner: 3
+        }
+      } else if (currentX > cutbox_left2 && currentX < cutbox_right2 && currentY > cutbox_top2 && currentY < cutbox_bottom2) {
+        this._moveDuring();
+        this.data._flag_cut_touch = true;
+        this.data._flag_img_endtouch = true;
+        this.data.CUT_START = {
+          width: this.data.width,
+          height: this.data.height,
+          cut_top: this.data.cut_top,
+          cut_left: this.data.cut_left,
+          x: currentX,
+          y: currentY,
+          corner: 2
+        }
+      } else if (currentX > cutbox_left1 && currentX < cutbox_right1 && currentY > cutbox_top1 && currentY < cutbox_bottom1) {
+        this._moveDuring();
+        this.data._flag_cut_touch = true;
+        this.data._flag_img_endtouch = true;
+        this.data.CUT_START = {
+          width: this.data.width,
+          height: this.data.height,
+          cut_top: this.data.cut_top,
+          cut_left: this.data.cut_left,
+          x: currentX,
+          y: currentY,
+          corner: 1
+        }
+      }
+    },
+    _cutTouchEnd(e) {
+      this._moveStop();
+      this.data._flag_cut_touch = false;
+    },
+    //停止移动时需要做的操作
+    _moveStop() {
+      //清空之前的自动居中延迟函数并添加最新的
+      clearTimeout(this.data.TIME_CUT_CENTER);
+      this.data.TIME_CUT_CENTER = setTimeout(() => {
+        //动画启动
+        if (!this.data._cut_animation) {
+          this.setData({
+            _cut_animation: true
+          });
+        }
+        this.setCutCenter();
+      }, 1000)
+      //清空之前的背景变化延迟函数并添加最新的
+      clearTimeout(this.data.TIME_BG);
+      this.data.TIME_BG = setTimeout(() => {
+        if (this.data._flag_bright) {
+          this.setData({
+            _flag_bright: false
+          });
+        }
+      }, 2000)
+    },
+    //移动中
+    _moveDuring() {
+      //清空之前的自动居中延迟函数
+      clearTimeout(this.data.TIME_CUT_CENTER);
+      //清空之前的背景变化延迟函数
+      clearTimeout(this.data.TIME_BG);
+      //高亮背景
+      if (!this.data._flag_bright) {
+        this.setData({
+          _flag_bright: true
+        });
+      }
+    },
+    //监听器
+    _watcher() {
+      Object.keys(this.data).forEach(v => {
+        this._observe(this.data, v, this.data.watch[v]);
+      })
+    },
+    _observe(obj, key, watchFun) {
+      var val = obj[key];
+      Object.defineProperty(obj, key, {
+        configurable: true,
+        enumerable: true,
+        set:(value) => {
+          val = value;
+          watchFun && watchFun(val, this);
+        },
+        get() {
+          if (val && '_img_top|img_left||width|height|min_width|max_width|min_height|max_height|export_scale|cut_top|cut_left|canvas_top|canvas_left|img_width|img_height|scale|angle|min_scale|max_scale'.indexOf(key)!=-1){
+            let ret = parseFloat(parseFloat(val).toFixed(3));
+            if (typeof val == "string" && val.indexOf("%") != -1){
+              ret+='%';
+            }
+            return ret;
+          }
+          return val;
+        }
+      })
+    },
+    _preventTouchMove() {
+    }
+  }
+})

+ 3 - 0
components/image-cropper/image-cropper.json

@@ -0,0 +1,3 @@
+{
+  "component": true
+}

+ 24 - 0
components/image-cropper/image-cropper.wxml

@@ -0,0 +1,24 @@
+  <view class='image-cropper' catchtouchmove='_preventTouchMove'>
+    <view class='main' bindtouchend="_cutTouchEnd" bindtouchstart="_cutTouchStart" bindtouchmove="_cutTouchMove" bindtap="_click">
+      <view class='content'>
+        <view class='content_top bg_gray {{_flag_bright?"":"bg_black"}}' style="height:{{cut_top}}px;transition-property:{{_cut_animation?'':'background'}}"></view>
+        <view class='content_middle' style="height:{{height}}px;">
+          <view class='content_middle_left bg_gray {{_flag_bright?"":"bg_black"}}' style="width:{{cut_left}}px;transition-property:{{_cut_animation?'':'background'}}"></view>
+          <view class='content_middle_middle' style="width:{{width}}px;height:{{height}}px;transition-duration: .3s;transition-property:{{_cut_animation?'':'background'}};">
+            <view class="border border-top-left"></view>
+            <view class="border border-top-right"></view>
+            <view class="border border-right-top"></view>
+            <view class="border border-right-bottom"></view>
+            <view class="border border-bottom-right"></view>
+            <view class="border border-bottom-left"></view>
+            <view class="border border-left-bottom"></view>
+            <view class="border border-left-top"></view>
+          </view>
+          <view class='content_middle_right bg_gray {{_flag_bright?"":"bg_black"}}' style="transition-property:{{_cut_animation?'':'background'}}"></view>
+        </view>
+        <view class='content_bottom bg_gray {{_flag_bright?"":"bg_black"}}' style="transition-property:{{_cut_animation?'':'background'}}"></view>
+      </view>
+      <image bindload="imageLoad" bindtouchstart="_start" bindtouchmove="_move" bindtouchend="_end" style="width:{{img_width ? img_width + 'px' : 'auto'}};height:{{img_height ? img_height + 'px' : 'auto'}};transform:translate3d({{_img_left-img_width/2}}px,{{_img_top-img_height/2}}px,0) scale({{scale}}) rotate({{angle}}deg);transition-duration:{{_cut_animation?.4:0}}s;" class='img' src='{{imgSrc}}'></image>
+    </view>
+    <canvas canvas-id='image-cropper' disable-scroll="true" style="width:{{_canvas_width * export_scale}}px;height:{{_canvas_height * export_scale}}px;left:{{canvas_left}}px;top:{{canvas_top}}px" class='image-cropper-canvas'></canvas>
+  </view>

+ 123 - 0
components/image-cropper/image-cropper.wxss

@@ -0,0 +1,123 @@
+.image-cropper{
+  background:rgba(14, 13, 13,.8);
+  position: fixed;
+  top:0;
+  left:0;
+  width:100vw;
+  height:100vh;
+  z-index: 1;
+}
+.main{
+  position: absolute;
+  width:100vw;
+  height:100vh;
+  overflow: hidden;
+}
+.content{
+  z-index: 9;
+  position: absolute;
+  width:100vw;
+  height:100vh;
+  display: flex;
+  flex-direction:column;
+  pointer-events:none;
+}
+.bg_black{
+  background: rgba(0, 0, 0, 0.8)!important;
+}
+.bg_gray{
+  background: rgba(0, 0, 0, 0.45);
+  transition-duration: .35s;
+}
+.content>.content_top{
+  pointer-events:none;
+}
+.content>.content_middle{
+  display: flex;
+  height: 200px;
+  width:100%;
+}
+.content_middle_middle{
+  width:200px;
+  box-sizing:border-box;
+  position: relative;
+  transition-duration: .3s;
+}
+.content_middle_right{
+  flex: auto;
+}
+.content>.content_bottom{
+  flex: auto;
+}
+.image-cropper .img{
+  z-index: 2;
+  top:0;
+  left:0;
+  position: absolute;
+  border:none;
+  width:100%;
+  backface-visibility: hidden;
+  transform-origin:center;
+}
+.image-cropper-canvas{
+  position: fixed;
+  background: white;
+  width:150px;
+  height:150px;
+  z-index: 10;
+  top:-200%;
+  pointer-events:none;
+}
+.border{
+  background: white;
+  pointer-events:auto;
+  position:absolute;
+}
+.border-top-left{
+  left:-2.5px;
+  top:-2.5px;
+  height:2.5px;
+  width:33rpx;
+}
+.border-top-right{
+  right:-2.5px;
+  top:-2.5px;
+  height:2.5px;
+  width:33rpx;
+}
+.border-right-top{
+  top:-1px;
+  width:2.5px;
+  height:30rpx;
+  right:-2.5px;
+}
+.border-right-bottom{
+  width:2.5px;
+  height:30rpx;
+  right:-2.5px;
+  bottom:-1px;
+}
+.border-bottom-left{
+  height:2.5px;
+  width:33rpx;
+  bottom:-2.5px;
+  left:-2.5px;
+}
+.border-bottom-right{
+  height:2.5px;
+  width:33rpx;
+  bottom:-2.5px;
+  right:-2.5px;
+}
+.border-left-top{
+  top:-1px;
+  width:2.5px;
+  height:30rpx;
+  left:-2.5px;
+}
+.border-left-bottom{
+  width:2.5px;
+  height:30rpx;
+  left:-2.5px;
+  bottom:-1px;
+}

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
components/multipart/Multipart.min.js


+ 10 - 0
components/o2-navi/o2-navi.js

@@ -0,0 +1,10 @@
+
+Component({
+  properties: {
+    title: {
+      type: String,
+      value: ''
+    }
+  },
+  data: {}
+})

+ 3 - 0
components/o2-navi/o2-navi.json

@@ -0,0 +1,3 @@
+{
+  "component": true
+}

+ 9 - 0
components/o2-navi/o2-navi.wxml

@@ -0,0 +1,9 @@
+<page-meta>
+  <navigation-bar
+    title="{{title}}"
+    front-color="#ffffff"
+    background-color="#fb4747"
+    color-animation-duration="300"
+    color-animation-timing-func="easeIn"
+  />
+</page-meta>

+ 0 - 0
components/o2-navi/o2-navi.wxss


+ 93 - 0
pages/cms/cms-web.js

@@ -0,0 +1,93 @@
+// pages/cms-web.js
+
+const api = require('../../utils/o2Api.js');
+const util = require('../../utils/util.js');
+
+Page({
+
+  /**
+   * Page initial data
+   */
+  data: {
+    workUrl: '',
+    navTitle: ''
+  },
+
+  /**
+   * Lifecycle function--Called when page load
+   */
+  onLoad: function (options) {
+    var id = options.id;
+    var title = decodeURIComponent(options.title);
+    if (id && id != '') {
+      var url = api.cmsWebUrl(id);
+      var who = wx.getStorageSync('who');
+      var tokenName = wx.getStorageSync('tokenName');
+      var token = ''
+      if (who && who.token) {
+        token = who.token;
+        url = url + '&'+tokenName+'=' + token;
+      }
+      url = url + '#wechat_redirect';
+      this.setData({
+        workUrl: url,
+        navTitle: title
+      });
+    }else {
+      util.toast('没有传入信息id!');
+      wx.navigateBack({
+        delta: 1,
+      });
+    } 
+    
+  },
+
+  /**
+   * Lifecycle function--Called when page is initially rendered
+   */
+  onReady: function () {
+    
+  },
+
+  /**
+   * Lifecycle function--Called when page show
+   */
+  onShow: function () {
+
+  },
+
+  /**
+   * Lifecycle function--Called when page hide
+   */
+  onHide: function () {
+
+  },
+
+  /**
+   * Lifecycle function--Called when page unload
+   */
+  onUnload: function () {
+
+  },
+
+  /**
+   * Page event handler function--Called when user drop down
+   */
+  onPullDownRefresh: function () {
+
+  },
+
+  /**
+   * Called when page reach bottom
+   */
+  onReachBottom: function () {
+
+  },
+
+  /**
+   * Called when user click on the top right corner to share
+   */
+  onShareAppMessage: function () {
+
+  }
+})

+ 5 - 0
pages/cms/cms-web.json

@@ -0,0 +1,5 @@
+{
+  "usingComponents": {
+    "o2-navi": "../../components/o2-navi/o2-navi"
+  }
+}

+ 3 - 0
pages/cms/cms-web.wxml

@@ -0,0 +1,3 @@
+<!--pages/cms-web.wxml-->
+<o2-navi title="{{navTitle}}" ></o2-navi>
+<web-view wx:if="{{workUrl != ''}}" src="{{workUrl}}" ></web-view>

+ 1 - 0
pages/cms/cms-web.wxss

@@ -0,0 +1 @@
+/* pages/cms-web.wxss */

+ 160 - 0
pages/file/download.js

@@ -0,0 +1,160 @@
+// pages/file/download.js
+const util = require('../../utils/util.js');
+const api = require('../../utils/o2Api.js');
+
+Page({
+
+  /**
+   * Page initial data
+   */
+  data: {
+
+  },
+
+  /**
+   * Lifecycle function--Called when page load
+   */
+  onLoad: function (options) {
+    util.showLoading();
+    var attId = options.attId; //附件id
+    var type = options.type; // work | cms | bbs
+    console.log('attId:', attId, ' type: ', type);
+    if (!attId || !type) {
+      util.hideLoading();
+      console.log('没有传入参数!');
+      wx.navigateBack({
+        delta: 1,
+      });
+    }else {
+      if (type == 'work') {  // type = work
+        if (options.workCompleted) {
+          var url = api.workCompletedAttachementUrl(attId, options.workCompleted);
+          this.downloadFileAndOpen(url);
+        } else if (options.work) {
+          var url = api.workAttachmentUrl(attId, options.work);
+          this.downloadFileAndOpen(url);
+        }else {
+          util.hideLoading();
+          console.log('没有传入工作id!');
+          wx.navigateBack({
+            delta: 1,
+          });
+        }
+      } else if (type == 'cms') {//type = cms
+        // var documentId = options.documentId;
+        var url = api.cmsAttachementUrl(attId);
+        this.downloadFileAndOpen(url);
+      } else if (type == 'bbs') {//type = bbs
+        // var subjectId = options.subjectId;
+        var url = api.bbsAttachementUrl(attId);
+        this.downloadFileAndOpen(url);
+      }else {
+        util.hideLoading();
+        console.log('参数type不正确!');
+        wx.navigateBack({
+          delta: 1,
+        });
+      }
+    }
+  },
+  //下载文件
+  downloadFileAndOpen: function (url) {
+    var who = wx.getStorageSync('who');
+    var tokenName = wx.getStorageSync('tokenName');
+    var token = '';
+    if (who && who.token) {
+      token = who.token;
+    }
+    let header =  {}
+    header[tokenName] = token
+    console.log("url ", url)
+    console.log(header)
+    wx.downloadFile({
+      url: url,
+      header: header,
+      success(res) {
+        console.log(res)
+        if (res.statusCode === 200) {
+          console.log(res)
+          var filePath = res.tempFilePath
+          wx.navigateBack({
+            delta: 1,
+            success: function() {
+              // 打开这个文件
+              wx.openDocument({
+                filePath: filePath,
+                success: function (res) {
+                  console.log('打开文档成功')
+                }
+              });
+            }
+          });
+        } else {
+          console.log("下载失败。。。。。");
+          util.hideLoading();
+          util.toast('下载失败!');
+          wx.navigateBack({
+            delta: 1,
+          });
+        }
+      },
+      fail(res) {
+        console.log(res);
+        util.hideLoading();
+        util.toast('下载失败!');
+        wx.navigateBack({
+          delta: 1,
+        });
+      }
+    })
+  },
+
+  /**
+   * Lifecycle function--Called when page is initially rendered
+   */
+  onReady: function () {
+
+  },
+
+  /**
+   * Lifecycle function--Called when page show
+   */
+  onShow: function () {
+
+  },
+
+  /**
+   * Lifecycle function--Called when page hide
+   */
+  onHide: function () {
+
+  },
+
+  /**
+   * Lifecycle function--Called when page unload
+   */
+  onUnload: function () {
+
+  },
+
+  /**
+   * Page event handler function--Called when user drop down
+   */
+  onPullDownRefresh: function () {
+
+  },
+
+  /**
+   * Called when page reach bottom
+   */
+  onReachBottom: function () {
+
+  },
+
+  /**
+   * Called when user click on the top right corner to share
+   */
+  onShareAppMessage: function () {
+
+  }
+})

+ 3 - 0
pages/file/download.json

@@ -0,0 +1,3 @@
+{
+  "usingComponents": {}
+}

+ 2 - 0
pages/file/download.wxml

@@ -0,0 +1,2 @@
+<!--pages/file/download.wxml-->
+

+ 1 - 0
pages/file/download.wxss

@@ -0,0 +1 @@
+/* pages/file/download.wxss */

+ 241 - 0
pages/index/index.js

@@ -0,0 +1,241 @@
+//index.js
+//获取应用实例
+
+const api = require('../../utils/o2Api.js');
+
+const firstId = '(0)';
+const defaultPageSize = 15;
+
+Page({
+  data: {
+    bannerList:[],
+    swiperIndex: 0,
+    currentTab: 'news', //当前列表是信息中心还是办公中心: news | tasks
+    page: 1, // 分页查询
+    lastId: firstId,
+    //文章列表,信息中心和办公中心的数据
+    /**
+    {
+        id: '',
+        title: '这里是一个新闻标题',
+        type: '【新闻通知】',
+        date: '2020-09-10',
+        tag: 'news'
+      }
+    **/
+    articleList:[]
+  },
+  
+  onLoad: function () {
+     this.loadHotNews();
+  },
+  onShow: function() {
+    this.loadArticleList(true);
+  },
+  // 滚动图片数据请求
+  loadHotNews: function() {
+    api.hotPicList().then(list => {
+      // url前端拼接
+      let newList = [];
+      for (let i = 0; i < list.length; i++) {
+        let element = list[i];
+        element.newUrl = this.hotPicUrl(element.picId);
+        newList.push(element);
+      }
+      this.setData({
+        bannerList: newList
+      })
+    }).catch(err => {
+      api.o2Error(err)
+    })
+  },
+  // 滚动图片url拼接
+  hotPicUrl: function(picId) {
+    return api.hotPicUrl(picId)
+  },
+  loadArticleList: function(isRefresh) {
+    if (this.data.currentTab == 'news') {
+      this.loadNews(isRefresh);
+    }else if (this.data.currentTab == 'tasks') {
+      this.loadTasks(isRefresh);
+    }
+  },
+  //查询办公中心数据
+  loadTasks: function(isRefresh) {
+    var lastId = this.data.lastId;
+    if (isRefresh) {
+      this.data.lastId = firstId;
+      lastId = firstId;
+    }
+    api.taskList(lastId, defaultPageSize).then(list => {
+      if (isRefresh) {
+        this.data.articleList = [];
+      }
+      if (list && list.length > 0) {
+        var taskList = [];
+        list.forEach(function(v) {
+          var obj = {
+            id: v.work, //work id 
+            title: v.title == '' ? '无标题' : v.title,
+            type: '【'+v.processName+'】',
+            date: v.startTime.length > 9 ? v.startTime.substring(0, 10) : v.startTime,
+            tag: 'tasks'
+          };
+          taskList.push(obj);
+        });
+        this.data.articleList.push(...taskList);
+        var lastId = list[list.length-1].id;
+        this.setData({
+          articleList: this.data.articleList,
+          lastId: lastId
+        });
+      }else {
+        this.setData({
+          articleList: this.data.articleList
+        });
+      }
+      wx.stopPullDownRefresh();
+    }).catch(err => {
+      api.o2Error(err);
+      wx.stopPullDownRefresh();
+    })
+  },
+  //查询信息中心数据
+  loadNews: function(isRefresh) {
+    let param = {
+      orderField: '',
+      statusList: ['published'],
+      justData: true,
+    };
+    if (isRefresh) {
+      this.data.page = 1;
+    } else {
+      this.data.page++;
+    }
+    api.cmsDocumentFilterListNew(this.data.page, defaultPageSize, param).then(list => {
+      if (isRefresh) {
+        this.data.articleList = [];
+      }
+      if (list && list.length > 0) {
+        var newList = [];
+        list.forEach(function(v) {
+          var obj = {
+            id: v.id,
+            title: v.title == '' ? '无标题' : v.title,
+            type: '【'+v.categoryName+'】',
+            date: v.publishTime.length > 9 ? v.publishTime.substring(0, 10) : v.publishTime,
+            tag: 'news'
+          };
+          newList.push(obj);
+        });
+        this.data.articleList.push(...newList);
+        this.setData({
+          articleList: this.data.articleList,
+        });
+      }else {
+        this.setData({
+          articleList: this.data.articleList
+        });
+      }
+      wx.stopPullDownRefresh();
+    }).catch(err => {
+      api.o2Error(err);
+      wx.stopPullDownRefresh();
+    })
+  },
+  swiperChange: function(event) {
+    this.setData({
+      swiperIndex: event.detail.current
+    })
+  },
+
+  /**
+   * 新建工作
+   * @param event 
+   */
+  bindTapAddProcess: function(event) {
+    wx.navigateTo({
+      url: '../progress/start-work'
+    });
+  },
+
+  //点击滚动图片
+  bindTapHotNews: function(event) {
+    let index = event.currentTarget.dataset.index;
+    let data = this.data.bannerList[index];
+    if (data.application == 'BBS') { //论坛
+
+    }else if (data.application == 'CMS') { //cms
+      wx.navigateTo({
+        url: '../cms/cms-web?id=' + data.infoId + '&title=' + encodeURIComponent(data.title)
+      });
+    }
+  },
+  //点击新闻或者任务
+  bindTapArticle: function(event) {
+    let index = event.currentTarget.dataset.index;
+    let data = this.data.articleList[index];
+    if (data.tag == 'news') { //cms
+      wx.navigateTo({
+        url: '../cms/cms-web?id=' + data.id + '&title=' + encodeURIComponent(data.title)
+      });
+    }else if (data.tag == 'tasks') { //待办
+      wx.navigateTo({
+        url: '../progress/work-web?work='  + data.id + '&title=' + encodeURIComponent(data.title)
+      });
+    }
+  },
+  //点击信息中心Tab
+  bindTapInfoCenter: function(event) {
+    if (this.data.currentTab == 'tasks') {
+      this.setData({
+        currentTab: 'news'
+      });
+      this.loadArticleList(true);
+    }
+  },
+  //点击办公中心Tab
+  bindTapTaskInfoCenter: function(event) {
+    if (this.data.currentTab == 'news') {
+      this.setData({
+        currentTab: 'tasks'
+      });
+      this.loadArticleList(true);
+    }
+  },
+  bindTapTaskList: function() {
+    wx.navigateTo({
+      url: '../progress/work-list?type=task',
+    });
+  },
+  bindTapTaskCompletedList: function() {
+    wx.navigateTo({
+      url: '../progress/work-list?type=taskCompleted',
+    });
+  },
+  bindTapReadList: function() {
+    wx.navigateTo({
+      url: '../progress/work-list?type=read',
+    });
+  },
+  bindTapReadCompletedList: function() {
+    wx.navigateTo({
+      url: '../progress/work-list?type=readCompleted',
+    });
+  },
+   /**
+   * 页面相关事件处理函数--监听用户下拉动作
+   */
+  onPullDownRefresh: function() {
+    // wx.showNavigationBarLoading()
+    this.loadHotNews();
+    this.loadArticleList(true);
+  },
+
+  /**
+   * 页面上拉触底事件的处理函数
+   */
+  onReachBottom: function() {
+    this.loadArticleList(false);
+  },
+})

+ 6 - 0
pages/index/index.json

@@ -0,0 +1,6 @@
+{
+  "usingComponents": {
+    "o2-navi": "../../components/o2-navi/o2-navi"
+  },
+  "enablePullDownRefresh": true
+}

+ 59 - 0
pages/index/index.wxml

@@ -0,0 +1,59 @@
+<!--index.wxml-->
+<o2-navi title="首页" ></o2-navi>
+<!-- 新建工作按钮 -->
+<view class="process-add" bindtap="bindTapAddProcess">
+  <image src="../../assets/img/icon_index_add.png" mode="scaleToFill" class="process-add-img" />
+</view>
+<!--热点图片新闻-->
+<view class="top"  wx:if="{{bannerList.length > 0}}">
+  <swiper class="banner" autoplay="true" interval="3000" duration="500" bindchange="swiperChange">
+    <swiper-item wx:for="{{bannerList}}" wx:key="index">
+      <view class="banner" bindtap="bindTapHotNews" data-index="{{index}}" data-info="{{item.infoId}}" data-application="{{item.application}}">
+        <image mode="scaleToFill" src="{{item.newUrl}}"></image>
+        <view class="title">{{item.title}}</view>
+      </view>
+    </swiper-item>
+  </swiper>
+  <text class="indicator">{{swiperIndex+1}}/{{bannerList.length}}</text>
+</view>
+<!--应用列表-->
+<view class="app-list" >
+  <view class="item" bindtap="bindTapTaskList">
+    <image src="../../assets/img/icon_task.png" ></image>
+    <text>待办</text>
+  </view>
+  <view class="item" bindtap="bindTapTaskCompletedList">
+    <image src="../../assets/img/icon_task_completed.png" ></image>
+    <text>已办</text>
+  </view>
+  <view class="item" bindtap="bindTapReadList">
+    <image src="../../assets/img/icon_read.png" ></image>
+    <text>待阅</text>
+  </view>
+  <view class="item" bindtap="bindTapReadCompletedList">
+    <image src="../../assets/img/icon_read_completed.png" ></image>
+    <text>已阅</text>
+  </view>
+</view>
+<!--分割-->
+<view class="divider" ></view>
+
+<view class="tab-category">
+  <view class="news {{currentTab == 'news' ? 'active' : ''}}" bindtap="bindTapInfoCenter">
+    <text>信息中心</text>
+  </view>
+  <view class="tasks {{currentTab == 'tasks' ? 'active' : ''}}" bindtap="bindTapTaskInfoCenter">
+    <text>办公中心</text>
+  </view>
+</view>
+<!--任务列表 新闻列表-->
+<block>
+  <view class="article" wx:for="{{articleList}}" wx:key="index" bindtap="bindTapArticle" data-id="{{item.id}}" data-index="{{index}}" data-tag="{{item.tag}}" hover-class="item-hover" hover-start-time="0" hover-stay-time="200">
+    <text class="type">{{item.type}}</text>
+    <text class="date">{{item.date}}</text>
+    <text class="title">{{item.title}}</text>
+  </view>
+</block>
+
+<!-- <view class="zixun" ><contact-button type="default-dark" size="100" class="kf"></contact-button></view>
+<view class="zixun_text">联系我们</view> -->

+ 178 - 0
pages/index/index.wxss

@@ -0,0 +1,178 @@
+/**index.wxss**/
+.process-add {
+  width: 84rpx;
+  height: 84rpx;
+  position: fixed;
+  top: 24rpx;
+  right: 24rpx;
+  z-index: 999;
+}
+.process-add-img {
+  width: 84rpx;
+  height: 84rpx;
+}
+.top {
+  position: relative;
+}
+.banner-default-img {
+  height: 50vw;
+  width: 100vw;
+}
+.banner {
+  height: 50vw;
+}
+
+.banner image {
+  width: 100%;
+  height: 100%;
+}
+
+.banner .title {
+  height: 60rpx;
+  width: 100%;
+  line-height: 60rpx;
+  padding-left: 20rpx;
+  background: rgba(0, 0, 0, 0.4);
+  position: absolute;
+  bottom: 0;
+  color: white;
+  font-size: 28rpx;
+}
+
+.indicator {
+  height: 60rpx;
+  line-height: 60rpx;
+  color: white;
+  font-size: 24rpx;
+  position: absolute;
+  bottom: 0;
+  right: 20rpx;
+}
+
+.app-list {
+  display: flex;
+  flex-direction:row;
+  margin: 10rpx 24rpx;
+  justify-content:space-between;
+}
+.app-list .item {
+  text-align:center;
+  margin:5px 10px; 
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+}
+.app-list .item image {
+  width: 84rpx;
+  height: 84rpx;
+  margin-bottom: 20rpx;
+}
+.app-list .item text {
+  font-size: 24rpx;
+  color: #2c2c2c;
+}
+.divider {
+  background-color:#f1efef;
+  height: 20rpx;
+  width: 100%;
+}
+
+.tab-category {
+  height: 80rpx;
+  margin-left: 120rpx;
+  margin-right: 120rpx;
+  display: flex;
+  flex-direction:row;
+  justify-content:space-between;
+  color: #333333;
+  border: 0;
+}
+.tab-category .active {
+  border-bottom:1rpx solid #fb4747;
+  color: #fb4747;
+}
+.news {
+  height: 80rpx;
+  width: 100%;
+  text-align: center;
+}
+.tasks {
+  height: 80rpx;
+  width: 100%;
+  text-align: center;
+} 
+.news text, .tasks text {
+  font-size: 28rpx;
+  line-height: 80rpx;
+}
+
+.article {
+  margin: 0rpx 24rpx;
+  padding: 20rpx;
+  height: 150rpx;
+  box-sizing: border-box;
+  position: relative;
+  border-bottom: 1px #efefef solid;
+}
+
+.article .title {
+  font-size: 28rpx;
+  color: #696969;
+  word-wrap: break-word;
+  white-space: normal !important;
+  display: -webkit-box;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  -webkit-line-clamp: 2;
+  -webkit-box-orient: vertical;
+  position: absolute;
+  bottom: 20rpx;
+  margin-left: 10rpx;
+}
+.article .date {
+  font-size: 24rpx;
+  color: #bfbfbf;
+  position: absolute;
+  top: 20rpx;
+  right: 20rpx;
+}
+.article .type {
+  font-size: 24rpx;
+  font-weight: bold;
+  color: #2c2c2c;
+  padding: 2rpx 5rpx;
+  margin-left: 10rpx;
+}
+
+
+.zixun{
+  width: 55px;
+  height: 55px;
+  position: fixed;
+  bottom: 35px;
+  right: 35px;
+  border-radius: 50%;
+  box-shadow: 0 0 5px #ddd;
+  text-align: center;
+  font-size: 14px;
+  color: #333;
+  background: url(https://sample.o2oa.net/contact_us.png) center center no-repeat;
+}
+
+.zixun .kf{
+  position: relative;
+  top: 0px;
+  left: 0px;
+  margin:15px auto;
+  opacity: 0;
+}
+
+.zixun_text {
+  width: 85px;
+  height: 25px;
+  position: fixed;
+  bottom: 10px;
+  right: 20px;
+  font-size: 13px;
+  text-align: center;
+}

+ 229 - 0
pages/login/login.js

@@ -0,0 +1,229 @@
+let util = require('../../utils/util.js')
+const api = require('../../utils/o2Api.js');
+const encrypt = require('../../utils/jsencrypt.js');
+
+Page({
+  data: {
+    isShowLogin: false,
+    name: '',
+    password: '',
+    nameFocus: true,
+    passwordFocus: false,
+    registerEnable: false,
+    rsa : {
+      rsaEnable: false,
+      publicKey: ''
+    }
+  },
+  onLoad: function () {
+    this.connectCenterServer();
+  },
+  //连接中心服务器获取应用连接地址
+  connectCenterServer: function() {
+    api.centerServer().then(data => {
+      api.setDistribute(data);
+      this.checkIsLogin();
+      this.loadLoginRSAInfo();
+    }).catch( err => {
+      console.error('连接中心服务器失败', err);
+      util.toast('连不上O2OA服务器,请检查网络!');
+    });
+  },
+  //检查登录
+  checkIsLogin: function() {
+    var who = wx.getStorageSync('who');
+    if (who && who.token) {
+      //检查是否过期
+      api.who().then(data => {
+        if(data.token && data.token != "") {
+          wx.setStorageSync('who', data);
+          //跳转到首页
+          wx.switchTab({
+            url: '../index/index'
+          })
+        }else {
+          wx.removeStorageSync('who');
+          //过期
+          this.setData({
+            isShowLogin: true
+           });
+        }
+      }).catch(err => {
+        //已经过期?
+        wx.removeStorageSync('who');
+        this.setData({
+          isShowLogin: true
+         });
+      });
+    }else {
+      this.setData({
+        isShowLogin: true
+       });
+    }
+  },
+  // 获取 RSA 加密公开密钥
+  loadLoginRSAInfo: function() {
+    api.rsaPublishKey().then(data => {
+      console.debug(data);
+      if (data.rsaEnable && data.rsaEnable === true) {
+        let rsa = {
+          rsaEnable: true,
+          publicKey: data.publicKey
+        };
+        this.setData({
+          rsa: rsa
+         });
+      }
+    }).catch(err => {
+      console.error(err);
+    });
+  },
+  checkRegisterMode: function() {
+    api.registerMode().then(res => {
+      if (res.value == 'code' ) {
+        this.setData({
+          registerEnable: true
+        })
+      }
+    })
+  },
+  inputName: function(event) {
+    this.data.name = event.detail.value;
+  },
+
+  inputPassword: function(event) {
+    this.data.password = event.detail.value;
+  },
+  nameBindfocus: function() {
+    this.setData({
+      nameFocus: true,
+      passwordFocus: false
+    })
+  },
+
+  passwordBindfocus: function() {
+    this.setData({
+      nameFocus: false,
+      passwordFocus: true
+    })
+  },
+  login: function() {
+    if (this.data.name.length == 0) {
+      util.toast("请输入用户名!");
+      return;
+    }
+    if (this.data.password.length == 0) {
+      util.toast("请输入密码!");
+      return;
+    }
+    let param = {
+      credential: this.data.name,
+      password: this.data.password
+    }
+    if (this.data.rsa.rsaEnable === true) {
+      var et = new encrypt.JSEncrypt();
+      et.setPublicKey("-----BEGIN PUBLIC KEY-----"+this.data.rsa.publicKey+"-----END PUBLIC KEY-----");
+      param.password = et.encrypt(param.password);
+      param.isEncrypted = "y";
+    } else {
+      param.isEncrypted = 'n';
+    }
+    api.login(param)
+      .then(data => {
+        wx.setStorageSync('who', data);
+        util.toast('登录成功~');
+        //跳转到首页
+        wx.switchTab({
+          url: '../index/index'
+        })
+      }).catch(err => {
+        console.log('登录失败', err);
+        api.o2Error(err, '登录失败');
+      });
+  },
+  toRegister: function() {
+    wx.navigateTo({
+      url: './register',
+    })
+  },
+  // 长按扫码
+  openMPWxImage: function() {
+    wx.previewImage({
+      current: 'https://www.o2oa.net/imagex/experience/zoneland_mpweixin.jpg',
+      urls: ['https://www.o2oa.net/imagex/experience/zoneland_mpweixin.jpg'],
+    })
+  },
+  // 获取体验账号
+  getDemoAccounts: function() {
+    wx.hideKeyboard();
+    api.wwwGetSampleServerAccounts('sample')
+    .then(data => {
+      console.log(data);
+      if (data.value) {
+        var list = [];
+        if (data.value.password) {
+          this.data.samplePassword = data.value.password;
+        }
+        if (data.value.accountList) {
+          this.data.accountList = data.value.accountList;
+          for (let index = 0; index < this.data.accountList.length; index++) {
+            const element = this.data.accountList[index];
+            list.push(element.name+': '+element.account);
+          }
+        }
+        if (list.length > 0) {
+          wx.showActionSheet({
+            itemList: list,
+            success: (res)=> {
+              console.log(res.tapIndex)
+              let account = this.data.accountList[res.tapIndex];
+              console.log(account);
+              this.setData({
+                name: account.account,
+                password: this.data.samplePassword
+              });
+            },
+            fail: (res)=> {
+              console.log(res.errMsg)
+            }
+          }); 
+        } else {
+          util.toast('连不上O2OA服务器,请检查网络!');
+        }
+      } else {
+        util.toast('连不上O2OA服务器,请检查网络!');
+      }
+    }).catch(err => {
+      console.error(err);
+      api.o2Error(err, '获取账号失败,请到O2OA官网查询!');
+    });
+  },
+  // 体验账号登录
+  demoLogin: function(event) {
+    let no = event.currentTarget.dataset.no;
+    const param = {
+      password: 'o2'
+    };
+    if (no == '1') {
+     param['credential'] = '开发部经理'
+    } else if (no == '2') {
+      param['credential'] = '开发部员工1'
+    } else if (no == '3') {
+      param['credential'] = '公司领导1'
+    } else if (no == '4') {
+      param['credential'] = '办公室主任'
+    }
+    api.login(param)
+      .then(data => {
+        wx.setStorageSync('who', data);
+        util.toast('登录成功~');
+        //跳转到首页
+        wx.switchTab({
+          url: '../index/index'
+        })
+      }).catch(err => {
+        console.log('登录失败', err);
+        api.o2Error(err, '登录失败');
+      });
+  }
+})

+ 4 - 0
pages/login/login.json

@@ -0,0 +1,4 @@
+{
+  "usingComponents": {},
+  "navigationBarTitleText": "O2OA 登录"
+}

+ 22 - 0
pages/login/login.wxml

@@ -0,0 +1,22 @@
+<!--login.wxml-->
+<view class="login-page" wx:if="{{isShowLogin}}">
+  <image src="/assets/img/login_logo.png" mode="aspectFit" class="head-img"/>
+  <input class="{{nameFocus?'input-active':''}}" placeholder="用户名" maxlength="20" value="{{name}}" bindfocus="nameBindfocus" bindinput="inputName"></input>
+  <input class="{{passwordFocus?'input-active':''}}" placeholder="密码" password="true" maxlength="20" value="{{password}}" bindfocus="passwordBindfocus" bindinput="inputPassword"></input>
+  <view class="login" bindtap="login" hover-class="hover" hover-start-time="0" hover-stay-time="100">登录</view>
+
+  <view class="weui-btn-area" wx:if="{{registerEnable}}">
+      <text class="register-btn" bindtap="toRegister">注册</text>
+  </view>
+  <!-- <view class="experience-area">
+      <text >各位亲爱的小伙伴,获取试用的登陆账号和密码,请先关注官方微信公众号,即可推送。点击下图后,长按即可扫码关注!</text>
+      <image class="mpwx-img" src="https://www.o2oa.net/imagex/experience/zoneland_mpweixin.jpg" bindtap="openMPWxImage" bindlongpress="openMPWxImage"/>
+
+  </view> -->
+  <!-- <view class="experience-area" bindtap="getDemoAccounts">
+      <text style="margin: 20rpx;">点击获取体验账号</text>
+  </view> -->
+</view>
+
+<!-- <view class="zixun" ><contact-button type="default-dark" size="100" class="kf"></contact-button></view>
+<view class="zixun_text">联系我们</view> -->

+ 100 - 0
pages/login/login.wxss

@@ -0,0 +1,100 @@
+
+.head-img{
+	border-radius: 50%;
+	width: 156rpx;
+  height: 156rpx;
+  margin: 20rpx auto;
+}
+
+
+
+.input-active {
+  border-bottom: 1rpx #fb4747 solid;
+}
+
+.login-page {
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  padding: 130rpx 100rpx 0;
+  box-sizing: border-box;
+}
+
+input {
+  width: 100%;
+  height: 50rpx;
+  margin-top: 60rpx;
+  border-bottom: 1rpx #2c2c2c solid;
+  padding-bottom: 10rpx;
+  font-size: 32rpx;
+}
+
+.login {
+  width: 100%;
+  height: 80rpx;
+  line-height: 80rpx;
+  background-color: #fb4747;
+  color: white;
+  font-size: 32rpx;
+  border-radius: 20rpx;
+  margin-top: 100rpx;
+  text-align: center;
+}
+
+.register-btn {
+  font-size: 32rpx;
+  color: #8a8a8a;
+  text-decoration: underline;
+}
+.demo-people-link {
+  color: #00c0fa;
+  text-decoration: underline;
+  margin-top: 10rpx;
+  display: block;
+}
+.hover{
+   background-color: #fb4747;
+}
+.experience-area {
+  margin-top: 20rpx;
+  font-size: 14px;
+  display: flex;
+  flex-direction: column;
+}
+.mpwx-img{
+	width: 300rpx;
+  height: 300rpx;
+  margin: 20rpx auto;
+}
+.zixun{
+  width: 55px;
+  height: 55px;
+  position: fixed;
+  top: 15px;
+  right: 35px;
+  border-radius: 50%;
+  box-shadow: 0 0 5px #ddd;
+  text-align: center;
+  font-size: 14px;
+  color: #333;
+  background: url(https://sample.o2oa.net/contact_us.png) center center no-repeat;
+}
+
+.zixun .kf{
+  position: relative;
+  top: 0px;
+  left: 0px;
+  margin:15px auto;
+  opacity: 0;
+}
+
+.zixun_text {
+  width: 85px;
+  height: 25px;
+  position: fixed;
+  top: 70px;
+  right: 20px;
+  font-size: 13px;
+  text-align: center;
+}

+ 159 - 0
pages/login/register.js

@@ -0,0 +1,159 @@
+// pages/login/register.js
+let util = require('../../utils/util.js')
+const api = require('../../utils/o2Api.js');
+
+Page({
+
+  /**
+   * Page initial data
+   */
+  data: {
+    name: '',
+    password: '',
+    confirmPassword: '',
+    mobile: '',
+    codeAnswer: '',
+    genderType: 'm',
+    focusLabel: '',
+    sending: false //是否正在发送验证码
+  },
+
+  /**
+   * Lifecycle function--Called when page load
+   */
+  onLoad: function (options) {
+
+  },
+  bindfocusFun: function(event) {
+    var label = event.currentTarget.dataset.label;
+    if (label) {
+      this.setData({
+        focusLabel: label
+      });
+    }
+  },
+  bindInputFun: function(event) {
+    var label = event.currentTarget.dataset.label;
+    if (label == 'name') {
+      this.data.name = event.detail.value;
+    }else if (label == 'password') {
+      this.data.password = event.detail.value;
+    }else if (label == 'confirmPassword') {
+      this.data.confirmPassword = event.detail.value;
+    }else if (label == 'mobile') {
+      this.data.mobile = event.detail.value;
+    }else if (label == 'codeAnswer') {
+      this.data.codeAnswer = event.detail.value;
+    }
+    
+  },
+  bindSendCode: function(event) {
+    if (!this.data.mobile || this.data.mobile == '') {
+      util.toast('请先输入手机号码!');
+    }else {
+      api.sendSms(this.data.mobile).then(res => {
+        console.log('发送验证码', res);
+        if (res.value) {
+          util.toast('发送成功!');
+        }else {
+          util.toast('发送失败!');
+        }
+      }).catch( err => {
+        api.o2Error(err);
+      })
+    }
+  },
+  bindTapRegister: function() {
+    if (this.data.name.length == 0) {
+      util.toast("请输入用户名!");
+      return;
+    }
+    if (this.data.password.length == 0) {
+      util.toast("请输入密码!");
+      return;
+    }
+    if (this.data.confirmPassword.length == 0) {
+      util.toast("请输入确认密码!");
+      return;
+    }
+    if (this.data.confirmPassword != this.data.password) {
+      util.toast("两次密码输入不一致!");
+      return;
+    }
+    if (this.data.mobile.length == 0) {
+      util.toast("请输入手机号码!");
+      return;
+    }
+    if (this.data.codeAnswer.length == 0) {
+      util.toast("请输入手机验证码!");
+      return;
+    }
+    api.register(this.data).then(res => {
+      console.log(res);
+      if (res.value) {
+        util.toast('注册成功!')
+        wx.navigateBack({
+          delta: 1,
+        });
+      }else {
+        util.toast('注册失败!')
+      }
+    }).catch(err =>  {
+      api.o2Error(err, '注册失败!');
+    })
+  },
+  toLogin: function() {
+    wx.navigateBack({
+      delta: 1,
+    });
+  },
+
+  /**
+   * Lifecycle function--Called when page is initially rendered
+   */
+  onReady: function () {
+
+  },
+
+  /**
+   * Lifecycle function--Called when page show
+   */
+  onShow: function () {
+
+  },
+
+  /**
+   * Lifecycle function--Called when page hide
+   */
+  onHide: function () {
+
+  },
+
+  /**
+   * Lifecycle function--Called when page unload
+   */
+  onUnload: function () {
+
+  },
+
+  /**
+   * Page event handler function--Called when user drop down
+   */
+  onPullDownRefresh: function () {
+
+  },
+
+  /**
+   * Called when page reach bottom
+   */
+  onReachBottom: function () {
+
+  },
+
+  /**
+   * Called when user click on the top right corner to share
+   */
+  onShareAppMessage: function () {
+
+  }
+})

+ 4 - 0
pages/login/register.json

@@ -0,0 +1,4 @@
+{
+  "usingComponents": {},
+  "navigationBarTitleText": "O2OA 注册"
+}

+ 18 - 0
pages/login/register.wxml

@@ -0,0 +1,18 @@
+<!--pages/login/register.wxml-->
+<view class="login-page" >
+  <image src="/assets/img/login_logo.png" mode="aspectFit" class="head-img"/>
+  <input class="{{focusLabel == 'name'?'input-active':''}}" placeholder="用户名"  focus="true" data-label="name" bindfocus="bindfocusFun" bindinput="bindInputFun"></input>
+  <input class="{{focusLabel == 'password'?'input-active':''}}" placeholder="密码" password="true" data-label="password" bindfocus="bindfocusFun" bindinput="bindInputFun"></input>
+  <input class="{{focusLabel == 'confirmPassword'?'input-active':''}}" placeholder="确认密码" password="true"  data-label="confirmPassword" bindfocus="bindfocusFun" bindinput="bindInputFun"></input>
+  <input class="{{focusLabel == 'mobile'?'input-active':''}}" placeholder="手机号码"  data-label="mobile"  bindfocus="bindfocusFun" bindinput="bindInputFun"></input>
+  <view>
+    <input class="code-input {{focusLabel == 'codeAnswer'?'input-active':''}}" placeholder="验证码" maxlength="20" data-label="codeAnswer" bindfocus="bindfocusFun" bindinput="bindInputFun"></input>
+    <button class="weui-btn weui-btn_mini weui-btn_primary" style="background-color: #fb4747;width: 50%;float: left;margin-top: 60rpx;margin-left: 20rpx;"   bindtap="bindSendCode" disabled='{{sending}}'>发送验证码</button>
+  </view>
+  <view class="login" bindtap="bindTapRegister" hover-class="hover" hover-start-time="0" hover-stay-time="100">注册</view>
+
+  <view class="weui-btn-area">
+      <text class="register-btn" bindtap="toLogin">去登录</text>
+  </view>
+  
+</view>

+ 71 - 0
pages/login/register.wxss

@@ -0,0 +1,71 @@
+/* pages/login/register.wxss */
+
+.head-img{
+	border-radius: 50%;
+	width: 156rpx;
+  height: 156rpx;
+  margin: 20rpx auto;
+}
+
+.input-active {
+  border-bottom: 1rpx #fb4747 solid;
+}
+
+.login-page {
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  padding: 100rpx 100rpx 0;
+  box-sizing: border-box;
+}
+
+input {
+  width: 100%;
+  height: 50rpx;
+  margin-top: 60rpx;
+  border-bottom: 1rpx #2c2c2c solid;
+  padding-bottom: 10rpx;
+  font-size: 32rpx;
+}
+.code-input  {
+  width: 40%;
+  height: 50rpx;
+  margin-top: 60rpx;
+  border-bottom: 1rpx #2c2c2c solid;
+  padding-bottom: 10rpx;
+  font-size: 32rpx;
+  float: left;
+}
+.code-button {
+  background-color: #fb4747;
+  width: 50%;
+  float: left;
+  margin-top: 60rpx;
+  margin-left: 20rpx;
+}
+
+.login {
+  width: 100%;
+  height: 80rpx;
+  line-height: 80rpx;
+  background-color: #fb4747;
+  color: white;
+  font-size: 32rpx;
+  border-radius: 20rpx;
+  margin-top: 100rpx;
+  text-align: center;
+}
+
+.register-btn {
+  font-size: 32rpx;
+  color: #8a8a8a;
+  text-decoration: underline;
+}
+.demo-people-link {
+  color: #00c0fa;
+  text-decoration: underline;
+}
+.hover{
+   background-color: #fb4747;
+}

+ 15 - 0
pages/logs/logs.js

@@ -0,0 +1,15 @@
+//logs.js
+const util = require('../../utils/util.js')
+
+Page({
+  data: {
+    logs: []
+  },
+  onLoad: function () {
+    this.setData({
+      logs: (wx.getStorageSync('logs') || []).map(log => {
+        return util.formatTime(new Date(log))
+      })
+    })
+  }
+})

+ 4 - 0
pages/logs/logs.json

@@ -0,0 +1,4 @@
+{
+  "navigationBarTitleText": "查看启动日志",
+  "usingComponents": {}
+}

+ 6 - 0
pages/logs/logs.wxml

@@ -0,0 +1,6 @@
+<!--logs.wxml-->
+<view class="container log-list">
+  <block wx:for="{{logs}}" wx:for-item="log">
+    <text class="log-item">{{index + 1}}. {{log}}</text>
+  </block>
+</view>

+ 8 - 0
pages/logs/logs.wxss

@@ -0,0 +1,8 @@
+.log-list {
+  display: flex;
+  flex-direction: column;
+  padding: 40rpx;
+}
+.log-item {
+  margin: 10rpx;
+}

+ 143 - 0
pages/me/cropper-avatar.js

@@ -0,0 +1,143 @@
+// pages/me/cropper-avatar.js
+
+const util = require("../../utils/util");
+const api = require('../../utils/o2Api.js');
+const Multipart = require('../../components/multipart/Multipart.min.js');
+
+Page({
+
+  /**
+   * Page initial data
+   */
+  data: {
+    src:'',
+    width: 250,//宽度
+    height: 250,//高度
+    max_width: 400,
+    max_height: 400
+  },
+
+  /**
+   * Lifecycle function--Called when page load
+   */
+  onLoad: function (options) {
+    //打开当前页面 直接 本地图片选择
+    this.cropper = this.selectComponent("#image-cropper");
+    this.cropper.upload();//选择图片
+  },
+  cropperload(e) {
+    console.log('cropper加载完成');
+  },
+  //重制图片加载
+  loadimage(e){
+    wx.hideLoading();
+    this.cropper.imgReset();
+  },
+  //选择本地图片进行裁剪
+  chooseImage(){
+    let that = this;
+    wx.chooseImage({
+      count: 1,
+      sizeType: ['original', 'compressed'],
+      sourceType: ['album', 'camera'],
+      success(res) {
+        wx.showLoading({
+          title: '加载中',
+        })
+        const tempFilePaths = res.tempFilePaths[0];
+        //重置图片角度、缩放、位置
+        that.cropper.imgReset();
+        that.setData({
+          src: tempFilePaths
+        });
+      }
+    })
+  },
+  // 提交图片
+  submit(){
+    this.cropper.getImg((obj)=>{      
+      const tempFilePath = obj.url;
+      console.log('裁剪完成,,', tempFilePath);
+      var who = wx.getStorageSync('who');
+      var tokenName = wx.getStorageSync('tokenName');
+      var token = '';
+      if (who && who.token) {
+        token = who.token;
+      }
+      let m=new Multipart({files:[], fields:[]})
+      m.file({
+        filePath: tempFilePath,
+        name: 'file'
+      })
+      m.submit(api.uploadMyAvatarUrl(), 
+      {
+        method: 'PUT', 
+        header: {
+          tokenName: token
+      }}).then(res => {
+        const data = res.data
+        console.log('上传头像完成', data);
+        if (data.type == 'error') {
+          util.toast('上传失败!');
+        }
+        wx.navigateBack({
+          delta: -1
+        })
+      }).catch(err => {
+        console.log('上传头像失败', err);
+        util.toast('上传失败!');
+        wx.navigateBack({
+          delta: -1
+        })
+      })
+    });
+  },
+  /**
+   * Lifecycle function--Called when page is initially rendered
+   */
+  onReady: function () {
+
+  },
+
+  /**
+   * Lifecycle function--Called when page show
+   */
+  onShow: function () {
+
+  },
+
+  /**
+   * Lifecycle function--Called when page hide
+   */
+  onHide: function () {
+
+  },
+
+  /**
+   * Lifecycle function--Called when page unload
+   */
+  onUnload: function () {
+
+  },
+
+  /**
+   * Page event handler function--Called when user drop down
+   */
+  onPullDownRefresh: function () {
+
+  },
+
+  /**
+   * Called when page reach bottom
+   */
+  onReachBottom: function () {
+
+  },
+
+  /**
+   * Called when user click on the top right corner to share
+   */
+  onShareAppMessage: function () {
+
+  }
+})

+ 7 - 0
pages/me/cropper-avatar.json

@@ -0,0 +1,7 @@
+{
+  "disableScroll": true,
+  "usingComponents": {
+    "o2-navi": "../../components/o2-navi/o2-navi",
+    "image-cropper": "../../components/image-cropper/image-cropper"
+  }
+}

+ 10 - 0
pages/me/cropper-avatar.wxml

@@ -0,0 +1,10 @@
+<!--pages/me/cropper-avatar.wxml-->
+<o2-navi title="修改头像" ></o2-navi>
+<image-cropper id="image-cropper" bindload="cropperload" bindimageload="loadimage"  limit_move="true" disable_rotate="true" width="{{width}}" height="{{height}}" imgSrc="{{src}}"  max_width="{{max_width}}" max_height="{{max_height}}"  disable_ratio="false">
+</image-cropper>
+
+<view class="bottom">
+  <button class="weui-btn weui-btn_mini weui-btn_default" catchtap='chooseImage' >选择图片</button>
+
+  <button class="weui-btn weui-btn_mini weui-btn_primary" bindtap='submit'>确定</button>
+</view>

+ 15 - 0
pages/me/cropper-avatar.wxss

@@ -0,0 +1,15 @@
+/* pages/me/cropper-avatar.wxss */
+.bottom{
+  position: absolute;
+  width:100%;
+  bottom:50rpx;
+  display: flex;
+  z-index: 10;
+  justify-content: center;
+  align-items: center;
+  flex-wrap:wrap;
+  height: 210rpx;
+}
+.bottom button {
+  margin: 15px auto;
+}

+ 184 - 0
pages/me/me.js

@@ -0,0 +1,184 @@
+
+let util = require('../../utils/util.js')
+const api = require('../../utils/o2Api.js');
+const o2Api = require('../../utils/o2Api.js');
+
+Page({
+  data: {
+    showDialog: false,
+    showLogoutDialog: false,
+    dialogLabel: '',
+    dialogValue: '',
+    dialogPlaceholder: '',
+    dialogParam: '',
+    avatarUrl: '',
+    person: {}
+  },
+  onLoad: function () {
+    this.loadPersonInfo();
+  },
+  onShow: function() {
+    this.avatar();  
+  },
+  loadPersonInfo: function() {
+    //获取用户信息
+    api.me().then(info => {
+      this.setData({
+        person: info
+      });
+    }).catch(err => {
+      api.o2Error(err);
+    });
+  },
+  //获取头像文件
+  avatar: function() {
+    var who = wx.getStorageSync('who');
+    var tokenName = wx.getStorageSync('tokenName');
+    var token = '';
+    if (who && who.token) {
+      token = who.token;
+    }
+    var url = api.myAvatarUrl();
+    var _self = this;
+    wx.downloadFile({
+      url: url,
+      header: {
+        tokenName: token
+      },
+      success(res) {
+        if (res.statusCode === 200) {
+          console.log(res)
+          var filePath = res.tempFilePath
+          _self.setData({
+            avatarUrl: filePath
+          });
+        } else {
+          _self.setData({
+            avatarUrl: '../../assets/img/icon_my_avatar.png'
+          });
+        }
+      },
+      fail(res) {
+        _self.setData({
+          avatarUrl: '../../assets/img/icon_my_avatar.png'
+        });
+      }
+    })
+  },
+  handleContact: function(e) {
+    //点击客服消息可以传送路径和query参数过来
+    console.log(e.detail.path)
+    console.log(e.detail.query)
+  },
+  bindTapLogout: function(event) {
+    this.setData({
+      showLogoutDialog: true
+    });
+  },
+  bindTapAvatar: function(event) {
+    wx.navigateTo({
+      url: './cropper-avatar',
+    });
+  },
+  bindTapLine: function(event) {
+    console.log(event);
+    let param = event.currentTarget.dataset.param;
+    let value = '';
+    let placeholder = '';
+    let label = '';
+    if (!param) {
+      return;
+    } else if (param == 'mail') {
+      value = this.data.person.mail;
+      label = '邮件地址';
+      placeholder = '请输入邮件地址';
+    } else if (param == 'mobile') {
+       value = this.data.person.mobile;
+       label = '手机号码';
+       placeholder = '请输入手机号码';
+    } else if (param == 'officePhone') {
+       value = this.data.person.officePhone;
+       label = '办公电话';
+      placeholder = '请输入办公电话';
+    } else if (param == 'signature') {
+       value = this.data.person.signature;
+       label = '个人签名';
+      placeholder = '请输入个人签名';
+    }
+    this.setData({
+      showDialog: true,
+      dialogLabel: label,
+      dialogPlaceholder: placeholder,
+      dialogValue: value,
+      dialogParam:  param
+    });
+  },
+  getDialogInputValue: function(event) {
+    this.data.dialogValue = event.detail.value;
+  },
+  tapDialogButton: function(event) {
+    console.log(event);
+    var value = this.data.dialogValue;
+    var param = this.data.dialogParam;
+    console.log('value:', value, ',param:', param);
+    this.setData({
+      showDialog: false,
+      dialogLabel: '',
+      dialogValue: '',
+      dialogParam:  ''
+    });
+    if (event.detail.index == 1) {
+      const person =  JSON.parse(JSON.stringify(this.data.person));//Object.clone(this.data.person);
+      if (!value ) {
+        var value = ''
+      }
+      if (param == 'mail') {
+        person.mail = value;
+        this.putPerson(person);
+      }else if (param == 'mobile') {
+        person.mobile = value;
+        this.putPerson(person);
+      }else if (param == 'officePhone') {
+        person.officePhone = value;
+        this.putPerson(person);
+      }else if (param == 'signature') {
+        person.signature = value;
+        this.putPerson(person);
+      }
+    }
+  },
+  putPerson: function(person) {
+    api.putMyInfo(person).then(id => {
+      this.setData({
+        person: person
+      });
+      util.toast('更新成功!');
+    }).catch(err => {
+      o2Api.o2Error(err);
+      //this.loadPersonInfo();
+    })
+  },
+  tapDialogLogoutButton: function(event) {
+    this.setData({
+      showLogoutDialog: false
+    })
+    if (event.detail.index == 1) {
+      api.logout().then(res => {
+        console.log('登出', res);
+        wx.removeStorageSync('who');
+        wx.removeStorageSync('cookie');
+        wx.redirectTo({
+          url: '../login/login'
+        });
+      }).catch(err => {
+        console.log('登出错误', err);
+        wx.removeStorageSync('who');
+        wx.removeStorageSync('cookie');
+        wx.redirectTo({
+          url: '../login/login'
+        });
+      })
+    }
+   
+  }
+})

+ 6 - 0
pages/me/me.json

@@ -0,0 +1,6 @@
+{
+  "usingComponents": {
+    "o2-navi": "../../components/o2-navi/o2-navi",
+    "mp-dialog": "/miniprogram_npm/weui-miniprogram/dialog/dialog"
+  }
+}

+ 86 - 0
pages/me/me.wxml

@@ -0,0 +1,86 @@
+<!--login.wxml-->
+<o2-navi title="我的" ></o2-navi>
+<view class="me">
+ 
+  <image class="avatar" src="{{avatarUrl}}" bindtap="bindTapAvatar"></image>
+<!-- 
+<view style="position: absolute;top: 30rpx;right: 0rpx;width: 128rpx;height: 64rpx;background-color:#ffffff;border-radius:">
+  <view>联系我们</view>
+  <button open-type="contact" bindcontact="handleContact" style="display: inline-block;position: absolute;width: 100%;background: salmon;opacity: 0;"></button>
+</view>
+   -->
+  
+
+  <view class="line">
+    <text class="label">姓名</text>
+    <view class="right">
+      <text>{{person.name}}</text>
+    </view>
+  </view>
+
+  <view class="line">
+    <text class="label">工号</text>
+    <view class="right">
+      <text>{{person.employee}}</text>
+    </view>
+  </view>
+
+  <view class="line" bindtap="bindTapLine" data-param="mail">
+    <text class="label">邮件地址</text>
+    <view class="right">
+      <image src="../../assets/img/icon_arrow.png"></image>
+      <text>{{person.mail}}</text>
+    </view>
+  </view>
+
+  <view class="line" bindtap="bindTapLine" data-param="mobile">
+    <text class="label">手机号码</text>
+    <view class="right">
+      <image src="../../assets/img/icon_arrow.png"></image>
+      <text>{{person.mobile}}</text>
+    </view>
+  </view>
+
+  <view class="line" bindtap="bindTapLine" data-param="officePhone">
+    <text class="label">办公电话</text>
+    <view class="right">
+      <image src="../../assets/img/icon_arrow.png"></image>
+      <text>{{person.officePhone}}</text>
+    </view>
+  </view>
+
+  <view class="line" bindtap="bindTapLine" data-param="signature">
+    <text class="label">个人签名</text>
+    <view class="right">
+      <image src="../../assets/img/icon_arrow.png"></image>
+      <text>{{person.signature}}</text>
+    </view>
+  </view>
+
+  <view class="weui-btn-area">
+      <button class="weui-btn" style="background-color: #fb4747;"  type="primary" bindtap="bindTapLogout">退出登录</button>
+  </view>
+</view>
+
+<mp-dialog title="修改{{dialogLabel}}" show="{{showDialog}}" bindbuttontap="tapDialogButton" buttons="{{[{text: '取消'}, {text: '确认'}]}}">
+    <!-- <view>
+      <mp-cell prop="qq" title="{{dialogLabel}}" ext-class="">
+          <input data-field="qq" class="weui-input" value="{{dialogValue}}" />
+      </mp-cell> -->
+      <view class="page-section">
+        <!-- <view class="weui-cells__title">{{dialogLabel}}</view> -->
+        <view class="weui-cells weui-cells_after-title">
+          <view class="weui-cell weui-cell_input">
+            <input class="weui-input" name="dialogInput" placeholder="{{dialogPlaceholder}}" value="{{dialogValue}}" bindinput="getDialogInputValue"  />
+          </view>
+        </view>
+      </view>
+    <!-- </view> -->
+</mp-dialog>
+
+<mp-dialog title="提示" show="{{showLogoutDialog}}" bindbuttontap="tapDialogLogoutButton" buttons="{{[{text: '取消'}, {text: '确认'}]}}">
+  <view>确定要退出登录吗?</view>
+</mp-dialog>
+
+<!-- <view class="zixun" ><contact-button type="default-dark" size="100" class="kf"></contact-button></view>
+<view class="zixun_text">联系我们</view> -->

+ 83 - 0
pages/me/me.wxss

@@ -0,0 +1,83 @@
+page {
+  height: 100%;
+  transition: all 0.3s linear 0s;
+    margin-top: 0px;
+    background-color: #f7f7f7;
+}
+.me {
+  height: 100%;
+  background-color: #f7f7f7;
+  position: relative;
+}
+
+.avatar {
+  margin:60rpx auto;
+  display: block;
+  width: 128rpx;
+  height: 128rpx;
+  border-radius: 64rpx;
+}
+
+.line {
+  height: 84rpx;
+  background-color:#ffffff;
+  border-bottom: 1px solid #efefef;
+}
+.line .label {
+  display: inline;
+  line-height: 84rpx;
+  color:#333333;
+  margin-left: 24rpx;
+}
+.line .right {
+  float: right;
+  height: 80rpx;
+  margin-right: 24rpx;
+  vertical-align: middle;
+}
+.right text {
+  float: right;
+  vertical-align: middle;
+  margin-right: 16rpx;
+  height: 84rpx;
+  line-height: 84rpx;
+  font-size: smaller;
+}
+.right image {
+  width: 42rpx;
+  height: 42rpx;
+  float: right;
+  margin-top: 21rpx;
+}
+
+.zixun{
+  width: 55px;
+  height: 55px;
+  position: fixed;
+  bottom: 35px;
+  right: 35px;
+  border-radius: 50%;
+  box-shadow: 0 0 5px #ddd;
+  text-align: center;
+  font-size: 14px;
+  color: #333;
+  background: url(https://sample.o2oa.net/contact_us.png) center center no-repeat;
+}
+
+.zixun .kf{
+  position: relative;
+  top: 0px;
+  left: 0px;
+  margin:15px auto;
+  opacity: 0;
+}
+
+.zixun_text {
+  width: 85px;
+  height: 25px;
+  position: fixed;
+  bottom: 10px;
+  right: 20px;
+  font-size: 13px;
+  text-align: center;
+}

+ 220 - 0
pages/progress/start-work.js

@@ -0,0 +1,220 @@
+// pages/progress/start-work.js
+
+const api = require('../../utils/o2Api.js');
+const util = require('../../utils/util.js');
+
+Page({
+
+  /**
+   * Page initial data
+   */
+  data: {
+    navTitle: '创建工作',
+    currentAppId: '',
+    applicationList: [],
+    processList: [],
+    currentProcess: null,
+    showChooseIdentityDialog: false,
+    identityList: [],
+    selectedIdentity: ''
+  },
+
+  /**
+   * Lifecycle function--Called when page load
+   */
+  onLoad: function (options) {
+
+  },
+
+  /**
+   * Lifecycle function--Called when page is initially rendered
+   */
+  onReady: function () {
+
+  },
+
+  /**
+   * Lifecycle function--Called when page show
+   */
+  onShow: function () {
+    this.loadApplication()
+  },
+
+  /**
+   * Lifecycle function--Called when page hide
+   */
+  onHide: function () {
+
+  },
+
+  /**
+   * Lifecycle function--Called when page unload
+   */
+  onUnload: function () {
+
+  },
+
+  /**
+   * Page event handler function--Called when user drop down
+   */
+  onPullDownRefresh: function () {
+
+  },
+
+  /**
+   * Called when page reach bottom
+   */
+  onReachBottom: function () {
+
+  },
+
+  /**
+   * Called when user click on the top right corner to share
+   */
+  onShareAppMessage: function () {
+
+  },
+
+  /**
+   * 获取流程应用列表
+   */
+  loadApplication: function () {
+    util.showLoading()
+    api.applicationList().then(list => {
+      var pList = []
+      var cid = ''
+      if (list && list.length > 0) {
+        pList = list[0].processList
+        cid = list[0].id
+      }
+      this.setData({
+        applicationList: list,
+        processList: pList,
+        currentAppId: cid
+      });
+      util.hideLoading()
+    }).catch(err => {
+      util.hideLoading()
+      api.o2Error(err);
+    })
+  },
+
+  /**
+   * 选择身份
+   */
+  showChooseIdentityDialog: function(identityList){
+    this.setData({
+      showChooseIdentityDialog: true,
+      identityList: identityList
+    })
+  },
+
+  /**
+   * 启动流程实例
+   * @param {*} identityDn 
+   */
+  startProcess: function(identityDn) {
+    let body = {"identity": identityDn}
+    api.createWork(this.data.currentProcess.id, body).then(result => {
+      util.hideLoading()
+      let work = result[0].taskList[0].work
+      let activityName = result[0].taskList[0].activityName
+      if (work) {
+        wx.navigateBack({
+          delta: 1,
+          complete: function() {
+            wx.navigateTo({
+              url: '../progress/work-web?work='  +work + '&title=' + encodeURIComponent(activityName)
+            });
+          }
+        })
+      }
+    }).catch(err => {
+      util.hideLoading()
+      api.o2Error(err);
+    })
+  },
+
+  /**
+   * 启动草稿
+   * @param {*} identityDn 
+   */
+  startDraft: function(identityDn) {
+    let body = {"identity": identityDn}
+    api.createDraft(this.data.currentProcess.id, body).then(result => {
+      console.log(result)
+      console.log(result.work)
+      util.hideLoading()
+      if (result.work) {
+        let draft = JSON.stringify(result.work)
+        wx.navigateBack({
+          delta: 1,
+          complete: function() {
+            wx.navigateTo({
+              url: '../progress/work-web?draft=' + encodeURIComponent(draft)
+            });
+          }
+        })
+      }
+    }).catch(err => {
+      util.hideLoading()
+      api.o2Error(err);
+    })
+  },
+
+  /**
+   * 启动
+   * @param {*} identityDn 
+   */
+  start: function(identityDn) {
+    util.showLoading()
+    if(this.data.currentProcess && this.data.currentProcess.defaultStartMode && this.data.currentProcess.defaultStartMode === 'draft') {
+      this.startDraft(identityDn)
+    }else {
+      this.startProcess(identityDn)
+    }
+  },
+
+  bindTapApplication: function(e) {
+    let index = e.currentTarget.dataset.index
+    let app = this.data.applicationList[index]
+    this.setData({
+      processList: app.processList,
+      currentAppId: app.id
+    })
+  },
+
+  bindTapProcess: function(e) {
+    let index = e.currentTarget.dataset.index
+    let process = this.data.processList[index]
+    this.data.currentProcess = process
+    util.showLoading()
+    api.listAvailableIdentityWithProcess(process.id).then(list => {
+      if (list && list.length > 0) {
+        if (list.length > 1) {
+          this.showChooseIdentityDialog(list)
+        }else {
+          this.start(list[0].distinguishedName)
+        }
+      } else {
+        util.toast('没有获取到当前用户的身份,无法启动流程!')
+      }
+    }).catch(err => {
+      util.hideLoading()
+      api.o2Error(err);
+    })
+  },
+
+  tapDialogButton: function(e) {
+    this.setData({
+      showChooseIdentityDialog: false
+    });
+    if (e.detail.index == 1) {
+      this.start(this.data.selectedIdentity)
+    }
+  },
+
+  identityRadioChange: function(e) {
+    this.data.selectedIdentity = e.detail.value
+  }
+})

+ 6 - 0
pages/progress/start-work.json

@@ -0,0 +1,6 @@
+{
+  "usingComponents": {
+    "o2-navi": "../../components/o2-navi/o2-navi",
+    "mp-dialog": "/miniprogram_npm/weui-miniprogram/dialog/dialog"
+  }
+}

+ 34 - 0
pages/progress/start-work.wxml

@@ -0,0 +1,34 @@
+<!--pages/progress/start-work.wxml-->
+<o2-navi title="{{navTitle}}" ></o2-navi>
+
+<block>
+  <view class="application-list">
+    <view class="application-item {{currentAppId == item.id ? 'application-item-active': ''}}" wx:for="{{applicationList}}" wx:key="index" bindtap="bindTapApplication" data-index="{{index}}"  >
+      <image class="application-icon" src="{{item.icon ? 'data:image/png;base64,'+item.icon : '../../assets/img/icon_main_index_logo.png'}}" mode="scaleToFill"  />
+      <text class="application-name">{{item.name}}</text>
+    </view>
+  </view>
+  <view class="process-list">
+    <view class="process-item" wx:for="{{processList}}" wx:key="index" bindtap="bindTapProcess" data-index="{{index}}"  >
+      <text class="process-name">{{item.name}}</text>
+    </view>
+  </view>
+  
+</block>
+
+<mp-dialog title="请选择启动流程的身份" show="{{showChooseIdentityDialog}}" bindbuttontap="tapDialogButton" buttons="{{[{text: '取消'}, {text: '确认'}]}}">
+      <view class="page-section">
+        <view class="weui-cells weui-cells_after-title">
+          <view class="weui-cell weui-cell_input">
+            <radio-group bindchange="identityRadioChange">
+              <label class="weui-cell weui-check__label" wx:for="{{identityList}}" wx:key="{{item.id}}">
+                <view class="weui-cell__hd">
+                  <radio value="{{item.distinguishedName}}"/>
+                </view>
+                <view class="weui-cell__bd">{{item.name}}({{item.unitName}})</view>
+              </label>
+            </radio-group>
+          </view>
+        </view>
+      </view>
+</mp-dialog>

+ 43 - 0
pages/progress/start-work.wxss

@@ -0,0 +1,43 @@
+/* pages/progress/start-work.wxss */
+
+.application-list {
+  width: 50%;
+  height: 100vh;
+  overflow: scroll;
+  float: left;
+  background-color: #fbfbfb;
+}
+.application-item {
+  height: 84rpx;
+  padding-left: 24rpx;
+  border-bottom: 1px solid #ffffff;
+}
+.application-item-active {
+  background-color: #ffffff;
+}
+.application-icon {
+  width: 64rpx;
+  height: 64rpx;
+  margin-top: 10rpx;
+  float: left;
+}
+.application-name {
+  line-height: 84rpx;
+  font-size: 24rpx;
+  margin-left: 12rpx;
+}
+.process-list {
+  width: 50%;
+  height: 100vh;
+  overflow: scroll;
+  float: left;
+  background-color: white;
+}
+.process-item {
+  height: 84rpx;
+  margin-left: 24rpx;
+}
+.process-name {
+  line-height: 84rpx;
+  font-size: 20rpx;
+}

+ 171 - 0
pages/progress/work-list.js

@@ -0,0 +1,171 @@
+// pages/progress/work-list.js
+
+const api = require('../../utils/o2Api.js');
+const util = require('../../utils/util.js');
+const firstId = '(0)';
+const defaultPageSize = 15;
+
+Page({
+  /**
+   * Page initial data
+   */
+  data: {
+    navTitle: '',
+    type: 'task', //task | taskCompleted | read | readCompleted
+    articleList: [],
+    lastId: firstId,
+  },
+
+  /**
+   * Lifecycle function--Called when page load
+   */
+  onLoad: function (options) {
+    if(!options.type) {
+      util.toast('参数不正确!');
+      wx.navigateBack({
+        delta: 1,
+      });
+    }else {
+      if (options.type == 'task') {
+        this.setData({
+          navTitle: '待办列表',
+          type:'task'
+        });
+        this.loadData(true);
+      } else if (options.type == 'taskCompleted') {
+        this.setData({
+          navTitle: '已办列表',
+          type:'taskCompleted'
+        });
+        this.loadData(true);
+      } else if (options.type == 'read') {
+        this.setData({
+          navTitle: '待阅列表',
+          type:'read'
+        });
+        this.loadData(true);
+      } else if (options.type == 'readCompleted') {
+        this.setData({
+          navTitle: '已阅列表',
+          type:'readCompleted'
+        });
+        this.loadData(true);
+      } else {
+        util.toast('参数不正确!');
+        wx.navigateBack({
+          delta: 1,
+        });
+      }
+    }
+  },
+  loadData: function(isRefresh) {
+    var lastId = this.data.lastId;
+    if (isRefresh) {
+      this.data.lastId = firstId;
+      lastId = firstId;
+    }
+    if (this.data.type == 'task') {
+      var future = api.taskList(lastId, defaultPageSize);
+    } else if (this.data.type == 'taskCompleted') { 
+      var future = api.taskCompletedList(lastId, defaultPageSize);
+    } else if (this.data.type == 'read') { 
+      var future = api.readList(lastId, defaultPageSize);
+    } else if (this.data.type == 'readCompleted') { 
+      var future = api.readCompletedList(lastId, defaultPageSize);
+    }
+    future.then(list => {
+      if (isRefresh) {
+        this.data.articleList = [];
+      }
+      if (list && list.length > 0) {
+        var taskList = [];
+        list.forEach(function(v) {
+          var obj = {
+            work: v.work,
+            workCompleted: v.workCompleted,
+            title: v.title == '' ? '无标题' : v.title,
+            type: '【'+v.processName+'】',
+            date: v.startTime.length > 9 ? v.startTime.substring(0, 10) : v.startTime
+          };
+          taskList.push(obj);
+        });
+        this.data.articleList.push(...taskList);
+        var lastId = list[list.length-1].id;
+        this.setData({
+          articleList: this.data.articleList,
+          lastId: lastId
+        });
+      }else {
+        this.setData({
+          articleList: this.data.articleList
+        });
+      }
+      wx.stopPullDownRefresh();
+    }).catch(err => {
+      api.o2Error(err);
+      wx.stopPullDownRefresh();
+    })
+  },
+
+  bindTapArticle: function(event) {
+    let index = event.currentTarget.dataset.index;
+    let data = this.data.articleList[index];
+    if (!data.workCompleted) {
+      wx.navigateTo({
+        url: '../progress/work-web?work='  + data.work + '&title=' + encodeURIComponent(data.title)
+      });
+    }else {
+      wx.navigateTo({
+        url: '../progress/work-web?workCompleted='  + data.workCompleted + '&title=' + encodeURIComponent(data.title)
+      });
+    }
+  },
+  /**
+   * Lifecycle function--Called when page is initially rendered
+   */
+  onReady: function () {
+
+  },
+
+  /**
+   * Lifecycle function--Called when page show
+   */
+  onShow: function () {
+
+  },
+
+  /**
+   * Lifecycle function--Called when page hide
+   */
+  onHide: function () {
+
+  },
+
+  /**
+   * Lifecycle function--Called when page unload
+   */
+  onUnload: function () {
+
+  },
+
+  /**
+   * Page event handler function--Called when user drop down
+   */
+  onPullDownRefresh: function () {
+    this.loadData(true);
+  },
+
+  /**
+   * Called when page reach bottom
+   */
+  onReachBottom: function () {
+    this.loadData(false);
+  },
+
+  /**
+   * Called when user click on the top right corner to share
+   */
+  onShareAppMessage: function () {
+    
+  }
+})

+ 6 - 0
pages/progress/work-list.json

@@ -0,0 +1,6 @@
+{
+  "usingComponents": {
+    "o2-navi": "../../components/o2-navi/o2-navi"
+  },
+  "enablePullDownRefresh": true
+}

+ 10 - 0
pages/progress/work-list.wxml

@@ -0,0 +1,10 @@
+<!--pages/progress/work-list.wxml-->
+<o2-navi title="{{navTitle}}" ></o2-navi>
+<!--待办、已办、待阅、已阅 列表-->
+<block>
+  <view class="article" wx:for="{{articleList}}" wx:key="index" bindtap="bindTapArticle" data-index="{{index}}" hover-class="item-hover" hover-start-time="0" hover-stay-time="200">
+    <text class="type">{{item.type}}</text>
+    <text class="date">{{item.date}}</text>
+    <text class="title">{{item.title}}</text>
+  </view>
+</block>

+ 40 - 0
pages/progress/work-list.wxss

@@ -0,0 +1,40 @@
+/* pages/progress/work-list.wxss */
+
+
+.article {
+  margin: 0rpx 24rpx;
+  padding: 20rpx;
+  height: 150rpx;
+  box-sizing: border-box;
+  position: relative;
+  border-bottom: 1px #efefef solid;
+}
+
+.article .title {
+  font-size: 28rpx;
+  color: #696969;
+  word-wrap: break-word;
+  white-space: normal !important;
+  display: -webkit-box;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  -webkit-line-clamp: 2;
+  -webkit-box-orient: vertical;
+  position: absolute;
+  bottom: 20rpx;
+  margin-left: 10rpx;
+}
+.article .date {
+  font-size: 24rpx;
+  color: #bfbfbf;
+  position: absolute;
+  top: 20rpx;
+  right: 20rpx;
+}
+.article .type {
+  font-size: 24rpx;
+  font-weight: bold;
+  color: #2c2c2c;
+  padding: 2rpx 5rpx;
+  margin-left: 10rpx;
+}

+ 125 - 0
pages/progress/work-web.js

@@ -0,0 +1,125 @@
+// pages/progress/work-web.js
+
+const api = require('../../utils/o2Api.js');
+const util = require('../../utils/util.js');
+
+
+
+Page({
+
+  /**
+   * Page initial data
+   */
+  data: {
+    workUrl:'',
+    navTitle: ''
+  },
+
+  /**
+   * Lifecycle function--Called when page load
+   */
+  onLoad: function (options) {
+    var title = decodeURIComponent(options.title);
+    if(!options.workCompleted && !options.work && !options.draft) {
+      util.toast('参数错误!');
+      wx.navigateBack({
+        delta: 1,
+      });
+    } else if(options.workCompleted) {
+      this.openWorkCompletedUrl(options.workCompleted, title);
+    } else if(options.work) {
+      this.openWorkUrl(options.work, title);
+    } else if(options.draft) {
+      this.openDraft(options.draft, title);
+    }
+  },
+
+  // 生成url
+  _urlWithToken: function(url) {
+    let newUrl = url;
+    const who = wx.getStorageSync('who');
+    const tokenName = wx.getStorageSync('tokenName');
+    let token = ''
+    if (who && who.token) {
+      token = who.token;
+      newUrl = newUrl + '&'+tokenName+'=' + token;
+    }
+    return newUrl + '#wechat_redirect';
+  },
+  // 打开工作表单 草稿
+  openDraft: function(draft, title = '') {
+    let url = api.workDraftUrl(draft);
+    url = this._urlWithToken(url);
+    this.setData({
+      workUrl: url,
+      navTitle: title
+    });
+  },
+  // 打开工作表单 未完成的工作
+  openWorkUrl: function(work, title = '') {
+    let url = api.workWebUrl(work);
+    url = this._urlWithToken(url);
+    this.setData({
+      workUrl: url,
+      navTitle: title
+    });
+  },
+  // 打开工作表单 已结束的工作
+  openWorkCompletedUrl: function(workcompletedid, title = '') {
+    let url = api.workCompletedWebUrl(workcompletedid);
+    url = this._urlWithToken(url);
+    this.setData({
+      workUrl: url,
+      navTitle: title
+    });
+  },
+
+  /**
+   * Lifecycle function--Called when page is initially rendered
+   */
+  onReady: function () {
+
+  },
+
+  /**
+   * Lifecycle function--Called when page show
+   */
+  onShow: function () {
+
+  },
+
+  /**
+   * Lifecycle function--Called when page hide
+   */
+  onHide: function () {
+
+  },
+
+  /**
+   * Lifecycle function--Called when page unload
+   */
+  onUnload: function () {
+
+  },
+
+  /**
+   * Page event handler function--Called when user drop down
+   */
+  onPullDownRefresh: function () {
+
+  },
+
+  /**
+   * Called when page reach bottom
+   */
+  onReachBottom: function () {
+
+  },
+
+  /**
+   * Called when user click on the top right corner to share
+   */
+  onShareAppMessage: function () {
+
+  }
+})

+ 5 - 0
pages/progress/work-web.json

@@ -0,0 +1,5 @@
+{
+  "usingComponents": {
+    "o2-navi": "../../components/o2-navi/o2-navi"
+  }
+}

+ 3 - 0
pages/progress/work-web.wxml

@@ -0,0 +1,3 @@
+<!--pages/progress/work-web.wxml-->
+<o2-navi title="{{navTitle}}" ></o2-navi>
+<web-view wx:if="{{workUrl != ''}}" src="{{workUrl}}" ></web-view>

+ 1 - 0
pages/progress/work-web.wxss

@@ -0,0 +1 @@
+/* pages/progress/work-web.wxss */

+ 67 - 0
project.config.json

@@ -0,0 +1,67 @@
+{
+  "description": "项目配置文件,详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
+  "setting": {
+    "urlCheck": true,
+    "es6": false,
+    "enhance": true,
+    "postcss": true,
+    "preloadBackgroundData": false,
+    "minified": true,
+    "newFeature": false,
+    "coverView": true,
+    "nodeModules": false,
+    "autoAudits": false,
+    "showShadowRootInWxmlPanel": true,
+    "scopeDataCheck": false,
+    "uglifyFileName": false,
+    "checkInvalidKey": true,
+    "checkSiteMap": true,
+    "uploadWithSourceMap": true,
+    "compileHotReLoad": false,
+    "useMultiFrameRuntime": true,
+    "babelSetting": {
+      "ignore": [],
+      "disablePlugins": [],
+      "outputPath": ""
+    },
+    "bundle": false,
+    "useIsolateContext": true,
+    "useCompilerModule": true,
+    "userConfirmedUseCompilerModuleSwitch": false,
+    "userConfirmedBundleSwitch": false,
+    "packNpmManually": false,
+    "packNpmRelationList": [],
+    "minifyWXSS": true,
+    "showES6CompileOption": false,
+    "minifyWXML": true,
+    "disableUseStrict": false,
+    "useStaticServer": true,
+    "useCompilerPlugins": false,
+    "lazyloadPlaceholderEnable": false,
+    "ignoreUploadUnusedFiles": true
+  },
+  "compileType": "miniprogram",
+  "appid": "wxcf479da3a4fac50a",
+  "projectname": "O2OA-Mini",
+  "simulatorType": "wechat",
+  "simulatorPluginLibVersion": {},
+  "condition": {},
+  "editorSetting": {
+    "tabIndent": "insertSpaces",
+    "tabSize": 2
+  },
+  "libVersion": "2.24.5",
+  "packOptions": {
+    "ignore": [
+      {
+        "value": "res",
+        "type": "folder"
+      },
+      {
+        "value": "README.md",
+        "type": "file"
+      }
+    ],
+    "include": []
+  }
+}

+ 9 - 0
project.private.config.json

@@ -0,0 +1,9 @@
+{
+  "setting": {
+    "urlCheck": false,
+    "compileHotReLoad": true
+  },
+  "description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
+  "libVersion": "2.24.5",
+  "projectname": "O2OA-Mini"
+}

BIN
res/20201123103220.png


BIN
res/20201123103825.png


BIN
res/pic_xiaochengxu_o2oa@1.5x.png


+ 7 - 0
sitemap.json

@@ -0,0 +1,7 @@
+{
+  "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
+  "rules": [{
+  "action": "allow",
+  "page": "*"
+  }]
+}

+ 5370 - 0
utils/jsencrypt.js

@@ -0,0 +1,5370 @@
+(function (global, factory) {
+	typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
+	typeof define === 'function' && define.amd ? define(['exports'], factory) :
+	(factory((global.JSEncrypt = {})));
+}(this, (function (exports) { 'use strict';
+
+var BI_RM = "0123456789abcdefghijklmnopqrstuvwxyz";
+function int2char(n) {
+    return BI_RM.charAt(n);
+}
+//#region BIT_OPERATIONS
+// (public) this & a
+function op_and(x, y) {
+    return x & y;
+}
+// (public) this | a
+function op_or(x, y) {
+    return x | y;
+}
+// (public) this ^ a
+function op_xor(x, y) {
+    return x ^ y;
+}
+// (public) this & ~a
+function op_andnot(x, y) {
+    return x & ~y;
+}
+// return index of lowest 1-bit in x, x < 2^31
+function lbit(x) {
+    if (x == 0) {
+        return -1;
+    }
+    var r = 0;
+    if ((x & 0xffff) == 0) {
+        x >>= 16;
+        r += 16;
+    }
+    if ((x & 0xff) == 0) {
+        x >>= 8;
+        r += 8;
+    }
+    if ((x & 0xf) == 0) {
+        x >>= 4;
+        r += 4;
+    }
+    if ((x & 3) == 0) {
+        x >>= 2;
+        r += 2;
+    }
+    if ((x & 1) == 0) {
+        ++r;
+    }
+    return r;
+}
+// return number of 1 bits in x
+function cbit(x) {
+    var r = 0;
+    while (x != 0) {
+        x &= x - 1;
+        ++r;
+    }
+    return r;
+}
+//#endregion BIT_OPERATIONS
+
+var b64map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+var b64pad = "=";
+function hex2b64(h) {
+    var i;
+    var c;
+    var ret = "";
+    for (i = 0; i + 3 <= h.length; i += 3) {
+        c = parseInt(h.substring(i, i + 3), 16);
+        ret += b64map.charAt(c >> 6) + b64map.charAt(c & 63);
+    }
+    if (i + 1 == h.length) {
+        c = parseInt(h.substring(i, i + 1), 16);
+        ret += b64map.charAt(c << 2);
+    }
+    else if (i + 2 == h.length) {
+        c = parseInt(h.substring(i, i + 2), 16);
+        ret += b64map.charAt(c >> 2) + b64map.charAt((c & 3) << 4);
+    }
+    while ((ret.length & 3) > 0) {
+        ret += b64pad;
+    }
+    return ret;
+}
+// convert a base64 string to hex
+function b64tohex(s) {
+    var ret = "";
+    var i;
+    var k = 0; // b64 state, 0-3
+    var slop = 0;
+    for (i = 0; i < s.length; ++i) {
+        if (s.charAt(i) == b64pad) {
+            break;
+        }
+        var v = b64map.indexOf(s.charAt(i));
+        if (v < 0) {
+            continue;
+        }
+        if (k == 0) {
+            ret += int2char(v >> 2);
+            slop = v & 3;
+            k = 1;
+        }
+        else if (k == 1) {
+            ret += int2char((slop << 2) | (v >> 4));
+            slop = v & 0xf;
+            k = 2;
+        }
+        else if (k == 2) {
+            ret += int2char(slop);
+            ret += int2char(v >> 2);
+            slop = v & 3;
+            k = 3;
+        }
+        else {
+            ret += int2char((slop << 2) | (v >> 4));
+            ret += int2char(v & 0xf);
+            k = 0;
+        }
+    }
+    if (k == 1) {
+        ret += int2char(slop << 2);
+    }
+    return ret;
+}
+
+/*! *****************************************************************************
+Copyright (c) Microsoft Corporation. All rights reserved.
+Licensed under the Apache License, Version 2.0 (the "License"); you may not use
+this file except in compliance with the License. You may obtain a copy of the
+License at http://www.apache.org/licenses/LICENSE-2.0
+
+THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
+WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
+MERCHANTABLITY OR NON-INFRINGEMENT.
+
+See the Apache Version 2.0 License for specific language governing permissions
+and limitations under the License.
+***************************************************************************** */
+/* global Reflect, Promise */
+
+var extendStatics = function(d, b) {
+    extendStatics = Object.setPrototypeOf ||
+        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+    return extendStatics(d, b);
+};
+
+function __extends(d, b) {
+    extendStatics(d, b);
+    function __() { this.constructor = d; }
+    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+}
+
+// Hex JavaScript decoder
+// Copyright (c) 2008-2013 Lapo Luchini <lapo@lapo.it>
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+/*jshint browser: true, strict: true, immed: true, latedef: true, undef: true, regexdash: false */
+var decoder;
+var Hex = {
+    decode: function (a) {
+        var i;
+        if (decoder === undefined) {
+            var hex = "0123456789ABCDEF";
+            var ignore = " \f\n\r\t\u00A0\u2028\u2029";
+            decoder = {};
+            for (i = 0; i < 16; ++i) {
+                decoder[hex.charAt(i)] = i;
+            }
+            hex = hex.toLowerCase();
+            for (i = 10; i < 16; ++i) {
+                decoder[hex.charAt(i)] = i;
+            }
+            for (i = 0; i < ignore.length; ++i) {
+                decoder[ignore.charAt(i)] = -1;
+            }
+        }
+        var out = [];
+        var bits = 0;
+        var char_count = 0;
+        for (i = 0; i < a.length; ++i) {
+            var c = a.charAt(i);
+            if (c == "=") {
+                break;
+            }
+            c = decoder[c];
+            if (c == -1) {
+                continue;
+            }
+            if (c === undefined) {
+                throw new Error("Illegal character at offset " + i);
+            }
+            bits |= c;
+            if (++char_count >= 2) {
+                out[out.length] = bits;
+                bits = 0;
+                char_count = 0;
+            }
+            else {
+                bits <<= 4;
+            }
+        }
+        if (char_count) {
+            throw new Error("Hex encoding incomplete: 4 bits missing");
+        }
+        return out;
+    }
+};
+
+// Base64 JavaScript decoder
+// Copyright (c) 2008-2013 Lapo Luchini <lapo@lapo.it>
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+/*jshint browser: true, strict: true, immed: true, latedef: true, undef: true, regexdash: false */
+var decoder$1;
+var Base64 = {
+    decode: function (a) {
+        var i;
+        if (decoder$1 === undefined) {
+            var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+            var ignore = "= \f\n\r\t\u00A0\u2028\u2029";
+            decoder$1 = Object.create(null);
+            for (i = 0; i < 64; ++i) {
+                decoder$1[b64.charAt(i)] = i;
+            }
+            for (i = 0; i < ignore.length; ++i) {
+                decoder$1[ignore.charAt(i)] = -1;
+            }
+        }
+        var out = [];
+        var bits = 0;
+        var char_count = 0;
+        for (i = 0; i < a.length; ++i) {
+            var c = a.charAt(i);
+            if (c == "=") {
+                break;
+            }
+            c = decoder$1[c];
+            if (c == -1) {
+                continue;
+            }
+            if (c === undefined) {
+                throw new Error("Illegal character at offset " + i);
+            }
+            bits |= c;
+            if (++char_count >= 4) {
+                out[out.length] = (bits >> 16);
+                out[out.length] = (bits >> 8) & 0xFF;
+                out[out.length] = bits & 0xFF;
+                bits = 0;
+                char_count = 0;
+            }
+            else {
+                bits <<= 6;
+            }
+        }
+        switch (char_count) {
+            case 1:
+                throw new Error("Base64 encoding incomplete: at least 2 bits missing");
+            case 2:
+                out[out.length] = (bits >> 10);
+                break;
+            case 3:
+                out[out.length] = (bits >> 16);
+                out[out.length] = (bits >> 8) & 0xFF;
+                break;
+        }
+        return out;
+    },
+    re: /-----BEGIN [^-]+-----([A-Za-z0-9+\/=\s]+)-----END [^-]+-----|begin-base64[^\n]+\n([A-Za-z0-9+\/=\s]+)====/,
+    unarmor: function (a) {
+        var m = Base64.re.exec(a);
+        if (m) {
+            if (m[1]) {
+                a = m[1];
+            }
+            else if (m[2]) {
+                a = m[2];
+            }
+            else {
+                throw new Error("RegExp out of sync");
+            }
+        }
+        return Base64.decode(a);
+    }
+};
+
+// Big integer base-10 printing library
+// Copyright (c) 2014 Lapo Luchini <lapo@lapo.it>
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+/*jshint browser: true, strict: true, immed: true, latedef: true, undef: true, regexdash: false */
+var max = 10000000000000; // biggest integer that can still fit 2^53 when multiplied by 256
+var Int10 = /** @class */ (function () {
+    function Int10(value) {
+        this.buf = [+value || 0];
+    }
+    Int10.prototype.mulAdd = function (m, c) {
+        // assert(m <= 256)
+        var b = this.buf;
+        var l = b.length;
+        var i;
+        var t;
+        for (i = 0; i < l; ++i) {
+            t = b[i] * m + c;
+            if (t < max) {
+                c = 0;
+            }
+            else {
+                c = 0 | (t / max);
+                t -= c * max;
+            }
+            b[i] = t;
+        }
+        if (c > 0) {
+            b[i] = c;
+        }
+    };
+    Int10.prototype.sub = function (c) {
+        // assert(m <= 256)
+        var b = this.buf;
+        var l = b.length;
+        var i;
+        var t;
+        for (i = 0; i < l; ++i) {
+            t = b[i] - c;
+            if (t < 0) {
+                t += max;
+                c = 1;
+            }
+            else {
+                c = 0;
+            }
+            b[i] = t;
+        }
+        while (b[b.length - 1] === 0) {
+            b.pop();
+        }
+    };
+    Int10.prototype.toString = function (base) {
+        if ((base || 10) != 10) {
+            throw new Error("only base 10 is supported");
+        }
+        var b = this.buf;
+        var s = b[b.length - 1].toString();
+        for (var i = b.length - 2; i >= 0; --i) {
+            s += (max + b[i]).toString().substring(1);
+        }
+        return s;
+    };
+    Int10.prototype.valueOf = function () {
+        var b = this.buf;
+        var v = 0;
+        for (var i = b.length - 1; i >= 0; --i) {
+            v = v * max + b[i];
+        }
+        return v;
+    };
+    Int10.prototype.simplify = function () {
+        var b = this.buf;
+        return (b.length == 1) ? b[0] : this;
+    };
+    return Int10;
+}());
+
+// ASN.1 JavaScript decoder
+var ellipsis = "\u2026";
+var reTimeS = /^(\d\d)(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])([01]\d|2[0-3])(?:([0-5]\d)(?:([0-5]\d)(?:[.,](\d{1,3}))?)?)?(Z|[-+](?:[0]\d|1[0-2])([0-5]\d)?)?$/;
+var reTimeL = /^(\d\d\d\d)(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])([01]\d|2[0-3])(?:([0-5]\d)(?:([0-5]\d)(?:[.,](\d{1,3}))?)?)?(Z|[-+](?:[0]\d|1[0-2])([0-5]\d)?)?$/;
+function stringCut(str, len) {
+    if (str.length > len) {
+        str = str.substring(0, len) + ellipsis;
+    }
+    return str;
+}
+var Stream = /** @class */ (function () {
+    function Stream(enc, pos) {
+        this.hexDigits = "0123456789ABCDEF";
+        if (enc instanceof Stream) {
+            this.enc = enc.enc;
+            this.pos = enc.pos;
+        }
+        else {
+            // enc should be an array or a binary string
+            this.enc = enc;
+            this.pos = pos;
+        }
+    }
+    Stream.prototype.get = function (pos) {
+        if (pos === undefined) {
+            pos = this.pos++;
+        }
+        if (pos >= this.enc.length) {
+            throw new Error("Requesting byte offset " + pos + " on a stream of length " + this.enc.length);
+        }
+        return ("string" === typeof this.enc) ? this.enc.charCodeAt(pos) : this.enc[pos];
+    };
+    Stream.prototype.hexByte = function (b) {
+        return this.hexDigits.charAt((b >> 4) & 0xF) + this.hexDigits.charAt(b & 0xF);
+    };
+    Stream.prototype.hexDump = function (start, end, raw) {
+        var s = "";
+        for (var i = start; i < end; ++i) {
+            s += this.hexByte(this.get(i));
+            if (raw !== true) {
+                switch (i & 0xF) {
+                    case 0x7:
+                        s += "  ";
+                        break;
+                    case 0xF:
+                        s += "\n";
+                        break;
+                    default:
+                        s += " ";
+                }
+            }
+        }
+        return s;
+    };
+    Stream.prototype.isASCII = function (start, end) {
+        for (var i = start; i < end; ++i) {
+            var c = this.get(i);
+            if (c < 32 || c > 176) {
+                return false;
+            }
+        }
+        return true;
+    };
+    Stream.prototype.parseStringISO = function (start, end) {
+        var s = "";
+        for (var i = start; i < end; ++i) {
+            s += String.fromCharCode(this.get(i));
+        }
+        return s;
+    };
+    Stream.prototype.parseStringUTF = function (start, end) {
+        var s = "";
+        for (var i = start; i < end;) {
+            var c = this.get(i++);
+            if (c < 128) {
+                s += String.fromCharCode(c);
+            }
+            else if ((c > 191) && (c < 224)) {
+                s += String.fromCharCode(((c & 0x1F) << 6) | (this.get(i++) & 0x3F));
+            }
+            else {
+                s += String.fromCharCode(((c & 0x0F) << 12) | ((this.get(i++) & 0x3F) << 6) | (this.get(i++) & 0x3F));
+            }
+        }
+        return s;
+    };
+    Stream.prototype.parseStringBMP = function (start, end) {
+        var str = "";
+        var hi;
+        var lo;
+        for (var i = start; i < end;) {
+            hi = this.get(i++);
+            lo = this.get(i++);
+            str += String.fromCharCode((hi << 8) | lo);
+        }
+        return str;
+    };
+    Stream.prototype.parseTime = function (start, end, shortYear) {
+        var s = this.parseStringISO(start, end);
+        var m = (shortYear ? reTimeS : reTimeL).exec(s);
+        if (!m) {
+            return "Unrecognized time: " + s;
+        }
+        if (shortYear) {
+            // to avoid querying the timer, use the fixed range [1970, 2069]
+            // it will conform with ITU X.400 [-10, +40] sliding window until 2030
+            m[1] = +m[1];
+            m[1] += (+m[1] < 70) ? 2000 : 1900;
+        }
+        s = m[1] + "-" + m[2] + "-" + m[3] + " " + m[4];
+        if (m[5]) {
+            s += ":" + m[5];
+            if (m[6]) {
+                s += ":" + m[6];
+                if (m[7]) {
+                    s += "." + m[7];
+                }
+            }
+        }
+        if (m[8]) {
+            s += " UTC";
+            if (m[8] != "Z") {
+                s += m[8];
+                if (m[9]) {
+                    s += ":" + m[9];
+                }
+            }
+        }
+        return s;
+    };
+    Stream.prototype.parseInteger = function (start, end) {
+        var v = this.get(start);
+        var neg = (v > 127);
+        var pad = neg ? 255 : 0;
+        var len;
+        var s = "";
+        // skip unuseful bits (not allowed in DER)
+        while (v == pad && ++start < end) {
+            v = this.get(start);
+        }
+        len = end - start;
+        if (len === 0) {
+            return neg ? -1 : 0;
+        }
+        // show bit length of huge integers
+        if (len > 4) {
+            s = v;
+            len <<= 3;
+            while (((+s ^ pad) & 0x80) == 0) {
+                s = +s << 1;
+                --len;
+            }
+            s = "(" + len + " bit)\n";
+        }
+        // decode the integer
+        if (neg) {
+            v = v - 256;
+        }
+        var n = new Int10(v);
+        for (var i = start + 1; i < end; ++i) {
+            n.mulAdd(256, this.get(i));
+        }
+        return s + n.toString();
+    };
+    Stream.prototype.parseBitString = function (start, end, maxLength) {
+        var unusedBit = this.get(start);
+        var lenBit = ((end - start - 1) << 3) - unusedBit;
+        var intro = "(" + lenBit + " bit)\n";
+        var s = "";
+        for (var i = start + 1; i < end; ++i) {
+            var b = this.get(i);
+            var skip = (i == end - 1) ? unusedBit : 0;
+            for (var j = 7; j >= skip; --j) {
+                s += (b >> j) & 1 ? "1" : "0";
+            }
+            if (s.length > maxLength) {
+                return intro + stringCut(s, maxLength);
+            }
+        }
+        return intro + s;
+    };
+    Stream.prototype.parseOctetString = function (start, end, maxLength) {
+        if (this.isASCII(start, end)) {
+            return stringCut(this.parseStringISO(start, end), maxLength);
+        }
+        var len = end - start;
+        var s = "(" + len + " byte)\n";
+        maxLength /= 2; // we work in bytes
+        if (len > maxLength) {
+            end = start + maxLength;
+        }
+        for (var i = start; i < end; ++i) {
+            s += this.hexByte(this.get(i));
+        }
+        if (len > maxLength) {
+            s += ellipsis;
+        }
+        return s;
+    };
+    Stream.prototype.parseOID = function (start, end, maxLength) {
+        var s = "";
+        var n = new Int10();
+        var bits = 0;
+        for (var i = start; i < end; ++i) {
+            var v = this.get(i);
+            n.mulAdd(128, v & 0x7F);
+            bits += 7;
+            if (!(v & 0x80)) { // finished
+                if (s === "") {
+                    n = n.simplify();
+                    if (n instanceof Int10) {
+                        n.sub(80);
+                        s = "2." + n.toString();
+                    }
+                    else {
+                        var m = n < 80 ? n < 40 ? 0 : 1 : 2;
+                        s = m + "." + (n - m * 40);
+                    }
+                }
+                else {
+                    s += "." + n.toString();
+                }
+                if (s.length > maxLength) {
+                    return stringCut(s, maxLength);
+                }
+                n = new Int10();
+                bits = 0;
+            }
+        }
+        if (bits > 0) {
+            s += ".incomplete";
+        }
+        return s;
+    };
+    return Stream;
+}());
+var ASN1 = /** @class */ (function () {
+    function ASN1(stream, header, length, tag, sub) {
+        if (!(tag instanceof ASN1Tag)) {
+            throw new Error("Invalid tag value.");
+        }
+        this.stream = stream;
+        this.header = header;
+        this.length = length;
+        this.tag = tag;
+        this.sub = sub;
+    }
+    ASN1.prototype.typeName = function () {
+        switch (this.tag.tagClass) {
+            case 0: // universal
+                switch (this.tag.tagNumber) {
+                    case 0x00:
+                        return "EOC";
+                    case 0x01:
+                        return "BOOLEAN";
+                    case 0x02:
+                        return "INTEGER";
+                    case 0x03:
+                        return "BIT_STRING";
+                    case 0x04:
+                        return "OCTET_STRING";
+                    case 0x05:
+                        return "NULL";
+                    case 0x06:
+                        return "OBJECT_IDENTIFIER";
+                    case 0x07:
+                        return "ObjectDescriptor";
+                    case 0x08:
+                        return "EXTERNAL";
+                    case 0x09:
+                        return "REAL";
+                    case 0x0A:
+                        return "ENUMERATED";
+                    case 0x0B:
+                        return "EMBEDDED_PDV";
+                    case 0x0C:
+                        return "UTF8String";
+                    case 0x10:
+                        return "SEQUENCE";
+                    case 0x11:
+                        return "SET";
+                    case 0x12:
+                        return "NumericString";
+                    case 0x13:
+                        return "PrintableString"; // ASCII subset
+                    case 0x14:
+                        return "TeletexString"; // aka T61String
+                    case 0x15:
+                        return "VideotexString";
+                    case 0x16:
+                        return "IA5String"; // ASCII
+                    case 0x17:
+                        return "UTCTime";
+                    case 0x18:
+                        return "GeneralizedTime";
+                    case 0x19:
+                        return "GraphicString";
+                    case 0x1A:
+                        return "VisibleString"; // ASCII subset
+                    case 0x1B:
+                        return "GeneralString";
+                    case 0x1C:
+                        return "UniversalString";
+                    case 0x1E:
+                        return "BMPString";
+                }
+                return "Universal_" + this.tag.tagNumber.toString();
+            case 1:
+                return "Application_" + this.tag.tagNumber.toString();
+            case 2:
+                return "[" + this.tag.tagNumber.toString() + "]"; // Context
+            case 3:
+                return "Private_" + this.tag.tagNumber.toString();
+        }
+    };
+    ASN1.prototype.content = function (maxLength) {
+        if (this.tag === undefined) {
+            return null;
+        }
+        if (maxLength === undefined) {
+            maxLength = Infinity;
+        }
+        var content = this.posContent();
+        var len = Math.abs(this.length);
+        if (!this.tag.isUniversal()) {
+            if (this.sub !== null) {
+                return "(" + this.sub.length + " elem)";
+            }
+            return this.stream.parseOctetString(content, content + len, maxLength);
+        }
+        switch (this.tag.tagNumber) {
+            case 0x01: // BOOLEAN
+                return (this.stream.get(content) === 0) ? "false" : "true";
+            case 0x02: // INTEGER
+                return this.stream.parseInteger(content, content + len);
+            case 0x03: // BIT_STRING
+                return this.sub ? "(" + this.sub.length + " elem)" :
+                    this.stream.parseBitString(content, content + len, maxLength);
+            case 0x04: // OCTET_STRING
+                return this.sub ? "(" + this.sub.length + " elem)" :
+                    this.stream.parseOctetString(content, content + len, maxLength);
+            // case 0x05: // NULL
+            case 0x06: // OBJECT_IDENTIFIER
+                return this.stream.parseOID(content, content + len, maxLength);
+            // case 0x07: // ObjectDescriptor
+            // case 0x08: // EXTERNAL
+            // case 0x09: // REAL
+            // case 0x0A: // ENUMERATED
+            // case 0x0B: // EMBEDDED_PDV
+            case 0x10: // SEQUENCE
+            case 0x11: // SET
+                if (this.sub !== null) {
+                    return "(" + this.sub.length + " elem)";
+                }
+                else {
+                    return "(no elem)";
+                }
+            case 0x0C: // UTF8String
+                return stringCut(this.stream.parseStringUTF(content, content + len), maxLength);
+            case 0x12: // NumericString
+            case 0x13: // PrintableString
+            case 0x14: // TeletexString
+            case 0x15: // VideotexString
+            case 0x16: // IA5String
+            // case 0x19: // GraphicString
+            case 0x1A: // VisibleString
+                // case 0x1B: // GeneralString
+                // case 0x1C: // UniversalString
+                return stringCut(this.stream.parseStringISO(content, content + len), maxLength);
+            case 0x1E: // BMPString
+                return stringCut(this.stream.parseStringBMP(content, content + len), maxLength);
+            case 0x17: // UTCTime
+            case 0x18: // GeneralizedTime
+                return this.stream.parseTime(content, content + len, (this.tag.tagNumber == 0x17));
+        }
+        return null;
+    };
+    ASN1.prototype.toString = function () {
+        return this.typeName() + "@" + this.stream.pos + "[header:" + this.header + ",length:" + this.length + ",sub:" + ((this.sub === null) ? "null" : this.sub.length) + "]";
+    };
+    ASN1.prototype.toPrettyString = function (indent) {
+        if (indent === undefined) {
+            indent = "";
+        }
+        var s = indent + this.typeName() + " @" + this.stream.pos;
+        if (this.length >= 0) {
+            s += "+";
+        }
+        s += this.length;
+        if (this.tag.tagConstructed) {
+            s += " (constructed)";
+        }
+        else if ((this.tag.isUniversal() && ((this.tag.tagNumber == 0x03) || (this.tag.tagNumber == 0x04))) && (this.sub !== null)) {
+            s += " (encapsulates)";
+        }
+        s += "\n";
+        if (this.sub !== null) {
+            indent += "  ";
+            for (var i = 0, max = this.sub.length; i < max; ++i) {
+                s += this.sub[i].toPrettyString(indent);
+            }
+        }
+        return s;
+    };
+    ASN1.prototype.posStart = function () {
+        return this.stream.pos;
+    };
+    ASN1.prototype.posContent = function () {
+        return this.stream.pos + this.header;
+    };
+    ASN1.prototype.posEnd = function () {
+        return this.stream.pos + this.header + Math.abs(this.length);
+    };
+    ASN1.prototype.toHexString = function () {
+        return this.stream.hexDump(this.posStart(), this.posEnd(), true);
+    };
+    ASN1.decodeLength = function (stream) {
+        var buf = stream.get();
+        var len = buf & 0x7F;
+        if (len == buf) {
+            return len;
+        }
+        // no reason to use Int10, as it would be a huge buffer anyways
+        if (len > 6) {
+            throw new Error("Length over 48 bits not supported at position " + (stream.pos - 1));
+        }
+        if (len === 0) {
+            return null;
+        } // undefined
+        buf = 0;
+        for (var i = 0; i < len; ++i) {
+            buf = (buf * 256) + stream.get();
+        }
+        return buf;
+    };
+    /**
+     * Retrieve the hexadecimal value (as a string) of the current ASN.1 element
+     * @returns {string}
+     * @public
+     */
+    ASN1.prototype.getHexStringValue = function () {
+        var hexString = this.toHexString();
+        var offset = this.header * 2;
+        var length = this.length * 2;
+        return hexString.substr(offset, length);
+    };
+    ASN1.decode = function (str) {
+        var stream;
+        if (!(str instanceof Stream)) {
+            stream = new Stream(str, 0);
+        }
+        else {
+            stream = str;
+        }
+        var streamStart = new Stream(stream);
+        var tag = new ASN1Tag(stream);
+        var len = ASN1.decodeLength(stream);
+        var start = stream.pos;
+        var header = start - streamStart.pos;
+        var sub = null;
+        var getSub = function () {
+            var ret = [];
+            if (len !== null) {
+                // definite length
+                var end = start + len;
+                while (stream.pos < end) {
+                    ret[ret.length] = ASN1.decode(stream);
+                }
+                if (stream.pos != end) {
+                    throw new Error("Content size is not correct for container starting at offset " + start);
+                }
+            }
+            else {
+                // undefined length
+                try {
+                    for (;;) {
+                        var s = ASN1.decode(stream);
+                        if (s.tag.isEOC()) {
+                            break;
+                        }
+                        ret[ret.length] = s;
+                    }
+                    len = start - stream.pos; // undefined lengths are represented as negative values
+                }
+                catch (e) {
+                    throw new Error("Exception while decoding undefined length content: " + e);
+                }
+            }
+            return ret;
+        };
+        if (tag.tagConstructed) {
+            // must have valid content
+            sub = getSub();
+        }
+        else if (tag.isUniversal() && ((tag.tagNumber == 0x03) || (tag.tagNumber == 0x04))) {
+            // sometimes BitString and OctetString are used to encapsulate ASN.1
+            try {
+                if (tag.tagNumber == 0x03) {
+                    if (stream.get() != 0) {
+                        throw new Error("BIT STRINGs with unused bits cannot encapsulate.");
+                    }
+                }
+                sub = getSub();
+                for (var i = 0; i < sub.length; ++i) {
+                    if (sub[i].tag.isEOC()) {
+                        throw new Error("EOC is not supposed to be actual content.");
+                    }
+                }
+            }
+            catch (e) {
+                // but silently ignore when they don't
+                sub = null;
+            }
+        }
+        if (sub === null) {
+            if (len === null) {
+                throw new Error("We can't skip over an invalid tag with undefined length at offset " + start);
+            }
+            stream.pos = start + Math.abs(len);
+        }
+        return new ASN1(streamStart, header, len, tag, sub);
+    };
+    return ASN1;
+}());
+var ASN1Tag = /** @class */ (function () {
+    function ASN1Tag(stream) {
+        var buf = stream.get();
+        this.tagClass = buf >> 6;
+        this.tagConstructed = ((buf & 0x20) !== 0);
+        this.tagNumber = buf & 0x1F;
+        if (this.tagNumber == 0x1F) { // long tag
+            var n = new Int10();
+            do {
+                buf = stream.get();
+                n.mulAdd(128, buf & 0x7F);
+            } while (buf & 0x80);
+            this.tagNumber = n.simplify();
+        }
+    }
+    ASN1Tag.prototype.isUniversal = function () {
+        return this.tagClass === 0x00;
+    };
+    ASN1Tag.prototype.isEOC = function () {
+        return this.tagClass === 0x00 && this.tagNumber === 0x00;
+    };
+    return ASN1Tag;
+}());
+
+// Copyright (c) 2005  Tom Wu
+// Bits per digit
+var dbits;
+// JavaScript engine analysis
+var canary = 0xdeadbeefcafe;
+var j_lm = ((canary & 0xffffff) == 0xefcafe);
+//#region
+var lowprimes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997];
+var lplim = (1 << 26) / lowprimes[lowprimes.length - 1];
+//#endregion
+// (public) Constructor
+var BigInteger = /** @class */ (function () {
+    function BigInteger(a, b, c) {
+        if (a != null) {
+            if ("number" == typeof a) {
+                this.fromNumber(a, b, c);
+            }
+            else if (b == null && "string" != typeof a) {
+                this.fromString(a, 256);
+            }
+            else {
+                this.fromString(a, b);
+            }
+        }
+    }
+    //#region PUBLIC
+    // BigInteger.prototype.toString = bnToString;
+    // (public) return string representation in given radix
+    BigInteger.prototype.toString = function (b) {
+        if (this.s < 0) {
+            return "-" + this.negate().toString(b);
+        }
+        var k;
+        if (b == 16) {
+            k = 4;
+        }
+        else if (b == 8) {
+            k = 3;
+        }
+        else if (b == 2) {
+            k = 1;
+        }
+        else if (b == 32) {
+            k = 5;
+        }
+        else if (b == 4) {
+            k = 2;
+        }
+        else {
+            return this.toRadix(b);
+        }
+        var km = (1 << k) - 1;
+        var d;
+        var m = false;
+        var r = "";
+        var i = this.t;
+        var p = this.DB - (i * this.DB) % k;
+        if (i-- > 0) {
+            if (p < this.DB && (d = this[i] >> p) > 0) {
+                m = true;
+                r = int2char(d);
+            }
+            while (i >= 0) {
+                if (p < k) {
+                    d = (this[i] & ((1 << p) - 1)) << (k - p);
+                    d |= this[--i] >> (p += this.DB - k);
+                }
+                else {
+                    d = (this[i] >> (p -= k)) & km;
+                    if (p <= 0) {
+                        p += this.DB;
+                        --i;
+                    }
+                }
+                if (d > 0) {
+                    m = true;
+                }
+                if (m) {
+                    r += int2char(d);
+                }
+            }
+        }
+        return m ? r : "0";
+    };
+    // BigInteger.prototype.negate = bnNegate;
+    // (public) -this
+    BigInteger.prototype.negate = function () {
+        var r = nbi();
+        BigInteger.ZERO.subTo(this, r);
+        return r;
+    };
+    // BigInteger.prototype.abs = bnAbs;
+    // (public) |this|
+    BigInteger.prototype.abs = function () {
+        return (this.s < 0) ? this.negate() : this;
+    };
+    // BigInteger.prototype.compareTo = bnCompareTo;
+    // (public) return + if this > a, - if this < a, 0 if equal
+    BigInteger.prototype.compareTo = function (a) {
+        var r = this.s - a.s;
+        if (r != 0) {
+            return r;
+        }
+        var i = this.t;
+        r = i - a.t;
+        if (r != 0) {
+            return (this.s < 0) ? -r : r;
+        }
+        while (--i >= 0) {
+            if ((r = this[i] - a[i]) != 0) {
+                return r;
+            }
+        }
+        return 0;
+    };
+    // BigInteger.prototype.bitLength = bnBitLength;
+    // (public) return the number of bits in "this"
+    BigInteger.prototype.bitLength = function () {
+        if (this.t <= 0) {
+            return 0;
+        }
+        return this.DB * (this.t - 1) + nbits(this[this.t - 1] ^ (this.s & this.DM));
+    };
+    // BigInteger.prototype.mod = bnMod;
+    // (public) this mod a
+    BigInteger.prototype.mod = function (a) {
+        var r = nbi();
+        this.abs().divRemTo(a, null, r);
+        if (this.s < 0 && r.compareTo(BigInteger.ZERO) > 0) {
+            a.subTo(r, r);
+        }
+        return r;
+    };
+    // BigInteger.prototype.modPowInt = bnModPowInt;
+    // (public) this^e % m, 0 <= e < 2^32
+    BigInteger.prototype.modPowInt = function (e, m) {
+        var z;
+        if (e < 256 || m.isEven()) {
+            z = new Classic(m);
+        }
+        else {
+            z = new Montgomery(m);
+        }
+        return this.exp(e, z);
+    };
+    // BigInteger.prototype.clone = bnClone;
+    // (public)
+    BigInteger.prototype.clone = function () {
+        var r = nbi();
+        this.copyTo(r);
+        return r;
+    };
+    // BigInteger.prototype.intValue = bnIntValue;
+    // (public) return value as integer
+    BigInteger.prototype.intValue = function () {
+        if (this.s < 0) {
+            if (this.t == 1) {
+                return this[0] - this.DV;
+            }
+            else if (this.t == 0) {
+                return -1;
+            }
+        }
+        else if (this.t == 1) {
+            return this[0];
+        }
+        else if (this.t == 0) {
+            return 0;
+        }
+        // assumes 16 < DB < 32
+        return ((this[1] & ((1 << (32 - this.DB)) - 1)) << this.DB) | this[0];
+    };
+    // BigInteger.prototype.byteValue = bnByteValue;
+    // (public) return value as byte
+    BigInteger.prototype.byteValue = function () {
+        return (this.t == 0) ? this.s : (this[0] << 24) >> 24;
+    };
+    // BigInteger.prototype.shortValue = bnShortValue;
+    // (public) return value as short (assumes DB>=16)
+    BigInteger.prototype.shortValue = function () {
+        return (this.t == 0) ? this.s : (this[0] << 16) >> 16;
+    };
+    // BigInteger.prototype.signum = bnSigNum;
+    // (public) 0 if this == 0, 1 if this > 0
+    BigInteger.prototype.signum = function () {
+        if (this.s < 0) {
+            return -1;
+        }
+        else if (this.t <= 0 || (this.t == 1 && this[0] <= 0)) {
+            return 0;
+        }
+        else {
+            return 1;
+        }
+    };
+    // BigInteger.prototype.toByteArray = bnToByteArray;
+    // (public) convert to bigendian byte array
+    BigInteger.prototype.toByteArray = function () {
+        var i = this.t;
+        var r = [];
+        r[0] = this.s;
+        var p = this.DB - (i * this.DB) % 8;
+        var d;
+        var k = 0;
+        if (i-- > 0) {
+            if (p < this.DB && (d = this[i] >> p) != (this.s & this.DM) >> p) {
+                r[k++] = d | (this.s << (this.DB - p));
+            }
+            while (i >= 0) {
+                if (p < 8) {
+                    d = (this[i] & ((1 << p) - 1)) << (8 - p);
+                    d |= this[--i] >> (p += this.DB - 8);
+                }
+                else {
+                    d = (this[i] >> (p -= 8)) & 0xff;
+                    if (p <= 0) {
+                        p += this.DB;
+                        --i;
+                    }
+                }
+                if ((d & 0x80) != 0) {
+                    d |= -256;
+                }
+                if (k == 0 && (this.s & 0x80) != (d & 0x80)) {
+                    ++k;
+                }
+                if (k > 0 || d != this.s) {
+                    r[k++] = d;
+                }
+            }
+        }
+        return r;
+    };
+    // BigInteger.prototype.equals = bnEquals;
+    BigInteger.prototype.equals = function (a) {
+        return (this.compareTo(a) == 0);
+    };
+    // BigInteger.prototype.min = bnMin;
+    BigInteger.prototype.min = function (a) {
+        return (this.compareTo(a) < 0) ? this : a;
+    };
+    // BigInteger.prototype.max = bnMax;
+    BigInteger.prototype.max = function (a) {
+        return (this.compareTo(a) > 0) ? this : a;
+    };
+    // BigInteger.prototype.and = bnAnd;
+    BigInteger.prototype.and = function (a) {
+        var r = nbi();
+        this.bitwiseTo(a, op_and, r);
+        return r;
+    };
+    // BigInteger.prototype.or = bnOr;
+    BigInteger.prototype.or = function (a) {
+        var r = nbi();
+        this.bitwiseTo(a, op_or, r);
+        return r;
+    };
+    // BigInteger.prototype.xor = bnXor;
+    BigInteger.prototype.xor = function (a) {
+        var r = nbi();
+        this.bitwiseTo(a, op_xor, r);
+        return r;
+    };
+    // BigInteger.prototype.andNot = bnAndNot;
+    BigInteger.prototype.andNot = function (a) {
+        var r = nbi();
+        this.bitwiseTo(a, op_andnot, r);
+        return r;
+    };
+    // BigInteger.prototype.not = bnNot;
+    // (public) ~this
+    BigInteger.prototype.not = function () {
+        var r = nbi();
+        for (var i = 0; i < this.t; ++i) {
+            r[i] = this.DM & ~this[i];
+        }
+        r.t = this.t;
+        r.s = ~this.s;
+        return r;
+    };
+    // BigInteger.prototype.shiftLeft = bnShiftLeft;
+    // (public) this << n
+    BigInteger.prototype.shiftLeft = function (n) {
+        var r = nbi();
+        if (n < 0) {
+            this.rShiftTo(-n, r);
+        }
+        else {
+            this.lShiftTo(n, r);
+        }
+        return r;
+    };
+    // BigInteger.prototype.shiftRight = bnShiftRight;
+    // (public) this >> n
+    BigInteger.prototype.shiftRight = function (n) {
+        var r = nbi();
+        if (n < 0) {
+            this.lShiftTo(-n, r);
+        }
+        else {
+            this.rShiftTo(n, r);
+        }
+        return r;
+    };
+    // BigInteger.prototype.getLowestSetBit = bnGetLowestSetBit;
+    // (public) returns index of lowest 1-bit (or -1 if none)
+    BigInteger.prototype.getLowestSetBit = function () {
+        for (var i = 0; i < this.t; ++i) {
+            if (this[i] != 0) {
+                return i * this.DB + lbit(this[i]);
+            }
+        }
+        if (this.s < 0) {
+            return this.t * this.DB;
+        }
+        return -1;
+    };
+    // BigInteger.prototype.bitCount = bnBitCount;
+    // (public) return number of set bits
+    BigInteger.prototype.bitCount = function () {
+        var r = 0;
+        var x = this.s & this.DM;
+        for (var i = 0; i < this.t; ++i) {
+            r += cbit(this[i] ^ x);
+        }
+        return r;
+    };
+    // BigInteger.prototype.testBit = bnTestBit;
+    // (public) true iff nth bit is set
+    BigInteger.prototype.testBit = function (n) {
+        var j = Math.floor(n / this.DB);
+        if (j >= this.t) {
+            return (this.s != 0);
+        }
+        return ((this[j] & (1 << (n % this.DB))) != 0);
+    };
+    // BigInteger.prototype.setBit = bnSetBit;
+    // (public) this | (1<<n)
+    BigInteger.prototype.setBit = function (n) {
+        return this.changeBit(n, op_or);
+    };
+    // BigInteger.prototype.clearBit = bnClearBit;
+    // (public) this & ~(1<<n)
+    BigInteger.prototype.clearBit = function (n) {
+        return this.changeBit(n, op_andnot);
+    };
+    // BigInteger.prototype.flipBit = bnFlipBit;
+    // (public) this ^ (1<<n)
+    BigInteger.prototype.flipBit = function (n) {
+        return this.changeBit(n, op_xor);
+    };
+    // BigInteger.prototype.add = bnAdd;
+    // (public) this + a
+    BigInteger.prototype.add = function (a) {
+        var r = nbi();
+        this.addTo(a, r);
+        return r;
+    };
+    // BigInteger.prototype.subtract = bnSubtract;
+    // (public) this - a
+    BigInteger.prototype.subtract = function (a) {
+        var r = nbi();
+        this.subTo(a, r);
+        return r;
+    };
+    // BigInteger.prototype.multiply = bnMultiply;
+    // (public) this * a
+    BigInteger.prototype.multiply = function (a) {
+        var r = nbi();
+        this.multiplyTo(a, r);
+        return r;
+    };
+    // BigInteger.prototype.divide = bnDivide;
+    // (public) this / a
+    BigInteger.prototype.divide = function (a) {
+        var r = nbi();
+        this.divRemTo(a, r, null);
+        return r;
+    };
+    // BigInteger.prototype.remainder = bnRemainder;
+    // (public) this % a
+    BigInteger.prototype.remainder = function (a) {
+        var r = nbi();
+        this.divRemTo(a, null, r);
+        return r;
+    };
+    // BigInteger.prototype.divideAndRemainder = bnDivideAndRemainder;
+    // (public) [this/a,this%a]
+    BigInteger.prototype.divideAndRemainder = function (a) {
+        var q = nbi();
+        var r = nbi();
+        this.divRemTo(a, q, r);
+        return [q, r];
+    };
+    // BigInteger.prototype.modPow = bnModPow;
+    // (public) this^e % m (HAC 14.85)
+    BigInteger.prototype.modPow = function (e, m) {
+        var i = e.bitLength();
+        var k;
+        var r = nbv(1);
+        var z;
+        if (i <= 0) {
+            return r;
+        }
+        else if (i < 18) {
+            k = 1;
+        }
+        else if (i < 48) {
+            k = 3;
+        }
+        else if (i < 144) {
+            k = 4;
+        }
+        else if (i < 768) {
+            k = 5;
+        }
+        else {
+            k = 6;
+        }
+        if (i < 8) {
+            z = new Classic(m);
+        }
+        else if (m.isEven()) {
+            z = new Barrett(m);
+        }
+        else {
+            z = new Montgomery(m);
+        }
+        // precomputation
+        var g = [];
+        var n = 3;
+        var k1 = k - 1;
+        var km = (1 << k) - 1;
+        g[1] = z.convert(this);
+        if (k > 1) {
+            var g2 = nbi();
+            z.sqrTo(g[1], g2);
+            while (n <= km) {
+                g[n] = nbi();
+                z.mulTo(g2, g[n - 2], g[n]);
+                n += 2;
+            }
+        }
+        var j = e.t - 1;
+        var w;
+        var is1 = true;
+        var r2 = nbi();
+        var t;
+        i = nbits(e[j]) - 1;
+        while (j >= 0) {
+            if (i >= k1) {
+                w = (e[j] >> (i - k1)) & km;
+            }
+            else {
+                w = (e[j] & ((1 << (i + 1)) - 1)) << (k1 - i);
+                if (j > 0) {
+                    w |= e[j - 1] >> (this.DB + i - k1);
+                }
+            }
+            n = k;
+            while ((w & 1) == 0) {
+                w >>= 1;
+                --n;
+            }
+            if ((i -= n) < 0) {
+                i += this.DB;
+                --j;
+            }
+            if (is1) { // ret == 1, don't bother squaring or multiplying it
+                g[w].copyTo(r);
+                is1 = false;
+            }
+            else {
+                while (n > 1) {
+                    z.sqrTo(r, r2);
+                    z.sqrTo(r2, r);
+                    n -= 2;
+                }
+                if (n > 0) {
+                    z.sqrTo(r, r2);
+                }
+                else {
+                    t = r;
+                    r = r2;
+                    r2 = t;
+                }
+                z.mulTo(r2, g[w], r);
+            }
+            while (j >= 0 && (e[j] & (1 << i)) == 0) {
+                z.sqrTo(r, r2);
+                t = r;
+                r = r2;
+                r2 = t;
+                if (--i < 0) {
+                    i = this.DB - 1;
+                    --j;
+                }
+            }
+        }
+        return z.revert(r);
+    };
+    // BigInteger.prototype.modInverse = bnModInverse;
+    // (public) 1/this % m (HAC 14.61)
+    BigInteger.prototype.modInverse = function (m) {
+        var ac = m.isEven();
+        if ((this.isEven() && ac) || m.signum() == 0) {
+            return BigInteger.ZERO;
+        }
+        var u = m.clone();
+        var v = this.clone();
+        var a = nbv(1);
+        var b = nbv(0);
+        var c = nbv(0);
+        var d = nbv(1);
+        while (u.signum() != 0) {
+            while (u.isEven()) {
+                u.rShiftTo(1, u);
+                if (ac) {
+                    if (!a.isEven() || !b.isEven()) {
+                        a.addTo(this, a);
+                        b.subTo(m, b);
+                    }
+                    a.rShiftTo(1, a);
+                }
+                else if (!b.isEven()) {
+                    b.subTo(m, b);
+                }
+                b.rShiftTo(1, b);
+            }
+            while (v.isEven()) {
+                v.rShiftTo(1, v);
+                if (ac) {
+                    if (!c.isEven() || !d.isEven()) {
+                        c.addTo(this, c);
+                        d.subTo(m, d);
+                    }
+                    c.rShiftTo(1, c);
+                }
+                else if (!d.isEven()) {
+                    d.subTo(m, d);
+                }
+                d.rShiftTo(1, d);
+            }
+            if (u.compareTo(v) >= 0) {
+                u.subTo(v, u);
+                if (ac) {
+                    a.subTo(c, a);
+                }
+                b.subTo(d, b);
+            }
+            else {
+                v.subTo(u, v);
+                if (ac) {
+                    c.subTo(a, c);
+                }
+                d.subTo(b, d);
+            }
+        }
+        if (v.compareTo(BigInteger.ONE) != 0) {
+            return BigInteger.ZERO;
+        }
+        if (d.compareTo(m) >= 0) {
+            return d.subtract(m);
+        }
+        if (d.signum() < 0) {
+            d.addTo(m, d);
+        }
+        else {
+            return d;
+        }
+        if (d.signum() < 0) {
+            return d.add(m);
+        }
+        else {
+            return d;
+        }
+    };
+    // BigInteger.prototype.pow = bnPow;
+    // (public) this^e
+    BigInteger.prototype.pow = function (e) {
+        return this.exp(e, new NullExp());
+    };
+    // BigInteger.prototype.gcd = bnGCD;
+    // (public) gcd(this,a) (HAC 14.54)
+    BigInteger.prototype.gcd = function (a) {
+        var x = (this.s < 0) ? this.negate() : this.clone();
+        var y = (a.s < 0) ? a.negate() : a.clone();
+        if (x.compareTo(y) < 0) {
+            var t = x;
+            x = y;
+            y = t;
+        }
+        var i = x.getLowestSetBit();
+        var g = y.getLowestSetBit();
+        if (g < 0) {
+            return x;
+        }
+        if (i < g) {
+            g = i;
+        }
+        if (g > 0) {
+            x.rShiftTo(g, x);
+            y.rShiftTo(g, y);
+        }
+        while (x.signum() > 0) {
+            if ((i = x.getLowestSetBit()) > 0) {
+                x.rShiftTo(i, x);
+            }
+            if ((i = y.getLowestSetBit()) > 0) {
+                y.rShiftTo(i, y);
+            }
+            if (x.compareTo(y) >= 0) {
+                x.subTo(y, x);
+                x.rShiftTo(1, x);
+            }
+            else {
+                y.subTo(x, y);
+                y.rShiftTo(1, y);
+            }
+        }
+        if (g > 0) {
+            y.lShiftTo(g, y);
+        }
+        return y;
+    };
+    // BigInteger.prototype.isProbablePrime = bnIsProbablePrime;
+    // (public) test primality with certainty >= 1-.5^t
+    BigInteger.prototype.isProbablePrime = function (t) {
+        var i;
+        var x = this.abs();
+        if (x.t == 1 && x[0] <= lowprimes[lowprimes.length - 1]) {
+            for (i = 0; i < lowprimes.length; ++i) {
+                if (x[0] == lowprimes[i]) {
+                    return true;
+                }
+            }
+            return false;
+        }
+        if (x.isEven()) {
+            return false;
+        }
+        i = 1;
+        while (i < lowprimes.length) {
+            var m = lowprimes[i];
+            var j = i + 1;
+            while (j < lowprimes.length && m < lplim) {
+                m *= lowprimes[j++];
+            }
+            m = x.modInt(m);
+            while (i < j) {
+                if (m % lowprimes[i++] == 0) {
+                    return false;
+                }
+            }
+        }
+        return x.millerRabin(t);
+    };
+    //#endregion PUBLIC
+    //#region PROTECTED
+    // BigInteger.prototype.copyTo = bnpCopyTo;
+    // (protected) copy this to r
+    BigInteger.prototype.copyTo = function (r) {
+        for (var i = this.t - 1; i >= 0; --i) {
+            r[i] = this[i];
+        }
+        r.t = this.t;
+        r.s = this.s;
+    };
+    // BigInteger.prototype.fromInt = bnpFromInt;
+    // (protected) set from integer value x, -DV <= x < DV
+    BigInteger.prototype.fromInt = function (x) {
+        this.t = 1;
+        this.s = (x < 0) ? -1 : 0;
+        if (x > 0) {
+            this[0] = x;
+        }
+        else if (x < -1) {
+            this[0] = x + this.DV;
+        }
+        else {
+            this.t = 0;
+        }
+    };
+    // BigInteger.prototype.fromString = bnpFromString;
+    // (protected) set from string and radix
+    BigInteger.prototype.fromString = function (s, b) {
+        var k;
+        if (b == 16) {
+            k = 4;
+        }
+        else if (b == 8) {
+            k = 3;
+        }
+        else if (b == 256) {
+            k = 8;
+            /* byte array */
+        }
+        else if (b == 2) {
+            k = 1;
+        }
+        else if (b == 32) {
+            k = 5;
+        }
+        else if (b == 4) {
+            k = 2;
+        }
+        else {
+            this.fromRadix(s, b);
+            return;
+        }
+        this.t = 0;
+        this.s = 0;
+        var i = s.length;
+        var mi = false;
+        var sh = 0;
+        while (--i >= 0) {
+            var x = (k == 8) ? (+s[i]) & 0xff : intAt(s, i);
+            if (x < 0) {
+                if (s.charAt(i) == "-") {
+                    mi = true;
+                }
+                continue;
+            }
+            mi = false;
+            if (sh == 0) {
+                this[this.t++] = x;
+            }
+            else if (sh + k > this.DB) {
+                this[this.t - 1] |= (x & ((1 << (this.DB - sh)) - 1)) << sh;
+                this[this.t++] = (x >> (this.DB - sh));
+            }
+            else {
+                this[this.t - 1] |= x << sh;
+            }
+            sh += k;
+            if (sh >= this.DB) {
+                sh -= this.DB;
+            }
+        }
+        if (k == 8 && ((+s[0]) & 0x80) != 0) {
+            this.s = -1;
+            if (sh > 0) {
+                this[this.t - 1] |= ((1 << (this.DB - sh)) - 1) << sh;
+            }
+        }
+        this.clamp();
+        if (mi) {
+            BigInteger.ZERO.subTo(this, this);
+        }
+    };
+    // BigInteger.prototype.clamp = bnpClamp;
+    // (protected) clamp off excess high words
+    BigInteger.prototype.clamp = function () {
+        var c = this.s & this.DM;
+        while (this.t > 0 && this[this.t - 1] == c) {
+            --this.t;
+        }
+    };
+    // BigInteger.prototype.dlShiftTo = bnpDLShiftTo;
+    // (protected) r = this << n*DB
+    BigInteger.prototype.dlShiftTo = function (n, r) {
+        var i;
+        for (i = this.t - 1; i >= 0; --i) {
+            r[i + n] = this[i];
+        }
+        for (i = n - 1; i >= 0; --i) {
+            r[i] = 0;
+        }
+        r.t = this.t + n;
+        r.s = this.s;
+    };
+    // BigInteger.prototype.drShiftTo = bnpDRShiftTo;
+    // (protected) r = this >> n*DB
+    BigInteger.prototype.drShiftTo = function (n, r) {
+        for (var i = n; i < this.t; ++i) {
+            r[i - n] = this[i];
+        }
+        r.t = Math.max(this.t - n, 0);
+        r.s = this.s;
+    };
+    // BigInteger.prototype.lShiftTo = bnpLShiftTo;
+    // (protected) r = this << n
+    BigInteger.prototype.lShiftTo = function (n, r) {
+        var bs = n % this.DB;
+        var cbs = this.DB - bs;
+        var bm = (1 << cbs) - 1;
+        var ds = Math.floor(n / this.DB);
+        var c = (this.s << bs) & this.DM;
+        for (var i = this.t - 1; i >= 0; --i) {
+            r[i + ds + 1] = (this[i] >> cbs) | c;
+            c = (this[i] & bm) << bs;
+        }
+        for (var i = ds - 1; i >= 0; --i) {
+            r[i] = 0;
+        }
+        r[ds] = c;
+        r.t = this.t + ds + 1;
+        r.s = this.s;
+        r.clamp();
+    };
+    // BigInteger.prototype.rShiftTo = bnpRShiftTo;
+    // (protected) r = this >> n
+    BigInteger.prototype.rShiftTo = function (n, r) {
+        r.s = this.s;
+        var ds = Math.floor(n / this.DB);
+        if (ds >= this.t) {
+            r.t = 0;
+            return;
+        }
+        var bs = n % this.DB;
+        var cbs = this.DB - bs;
+        var bm = (1 << bs) - 1;
+        r[0] = this[ds] >> bs;
+        for (var i = ds + 1; i < this.t; ++i) {
+            r[i - ds - 1] |= (this[i] & bm) << cbs;
+            r[i - ds] = this[i] >> bs;
+        }
+        if (bs > 0) {
+            r[this.t - ds - 1] |= (this.s & bm) << cbs;
+        }
+        r.t = this.t - ds;
+        r.clamp();
+    };
+    // BigInteger.prototype.subTo = bnpSubTo;
+    // (protected) r = this - a
+    BigInteger.prototype.subTo = function (a, r) {
+        var i = 0;
+        var c = 0;
+        var m = Math.min(a.t, this.t);
+        while (i < m) {
+            c += this[i] - a[i];
+            r[i++] = c & this.DM;
+            c >>= this.DB;
+        }
+        if (a.t < this.t) {
+            c -= a.s;
+            while (i < this.t) {
+                c += this[i];
+                r[i++] = c & this.DM;
+                c >>= this.DB;
+            }
+            c += this.s;
+        }
+        else {
+            c += this.s;
+            while (i < a.t) {
+                c -= a[i];
+                r[i++] = c & this.DM;
+                c >>= this.DB;
+            }
+            c -= a.s;
+        }
+        r.s = (c < 0) ? -1 : 0;
+        if (c < -1) {
+            r[i++] = this.DV + c;
+        }
+        else if (c > 0) {
+            r[i++] = c;
+        }
+        r.t = i;
+        r.clamp();
+    };
+    // BigInteger.prototype.multiplyTo = bnpMultiplyTo;
+    // (protected) r = this * a, r != this,a (HAC 14.12)
+    // "this" should be the larger one if appropriate.
+    BigInteger.prototype.multiplyTo = function (a, r) {
+        var x = this.abs();
+        var y = a.abs();
+        var i = x.t;
+        r.t = i + y.t;
+        while (--i >= 0) {
+            r[i] = 0;
+        }
+        for (i = 0; i < y.t; ++i) {
+            r[i + x.t] = x.am(0, y[i], r, i, 0, x.t);
+        }
+        r.s = 0;
+        r.clamp();
+        if (this.s != a.s) {
+            BigInteger.ZERO.subTo(r, r);
+        }
+    };
+    // BigInteger.prototype.squareTo = bnpSquareTo;
+    // (protected) r = this^2, r != this (HAC 14.16)
+    BigInteger.prototype.squareTo = function (r) {
+        var x = this.abs();
+        var i = r.t = 2 * x.t;
+        while (--i >= 0) {
+            r[i] = 0;
+        }
+        for (i = 0; i < x.t - 1; ++i) {
+            var c = x.am(i, x[i], r, 2 * i, 0, 1);
+            if ((r[i + x.t] += x.am(i + 1, 2 * x[i], r, 2 * i + 1, c, x.t - i - 1)) >= x.DV) {
+                r[i + x.t] -= x.DV;
+                r[i + x.t + 1] = 1;
+            }
+        }
+        if (r.t > 0) {
+            r[r.t - 1] += x.am(i, x[i], r, 2 * i, 0, 1);
+        }
+        r.s = 0;
+        r.clamp();
+    };
+    // BigInteger.prototype.divRemTo = bnpDivRemTo;
+    // (protected) divide this by m, quotient and remainder to q, r (HAC 14.20)
+    // r != q, this != m.  q or r may be null.
+    BigInteger.prototype.divRemTo = function (m, q, r) {
+        var pm = m.abs();
+        if (pm.t <= 0) {
+            return;
+        }
+        var pt = this.abs();
+        if (pt.t < pm.t) {
+            if (q != null) {
+                q.fromInt(0);
+            }
+            if (r != null) {
+                this.copyTo(r);
+            }
+            return;
+        }
+        if (r == null) {
+            r = nbi();
+        }
+        var y = nbi();
+        var ts = this.s;
+        var ms = m.s;
+        var nsh = this.DB - nbits(pm[pm.t - 1]); // normalize modulus
+        if (nsh > 0) {
+            pm.lShiftTo(nsh, y);
+            pt.lShiftTo(nsh, r);
+        }
+        else {
+            pm.copyTo(y);
+            pt.copyTo(r);
+        }
+        var ys = y.t;
+        var y0 = y[ys - 1];
+        if (y0 == 0) {
+            return;
+        }
+        var yt = y0 * (1 << this.F1) + ((ys > 1) ? y[ys - 2] >> this.F2 : 0);
+        var d1 = this.FV / yt;
+        var d2 = (1 << this.F1) / yt;
+        var e = 1 << this.F2;
+        var i = r.t;
+        var j = i - ys;
+        var t = (q == null) ? nbi() : q;
+        y.dlShiftTo(j, t);
+        if (r.compareTo(t) >= 0) {
+            r[r.t++] = 1;
+            r.subTo(t, r);
+        }
+        BigInteger.ONE.dlShiftTo(ys, t);
+        t.subTo(y, y); // "negative" y so we can replace sub with am later
+        while (y.t < ys) {
+            y[y.t++] = 0;
+        }
+        while (--j >= 0) {
+            // Estimate quotient digit
+            var qd = (r[--i] == y0) ? this.DM : Math.floor(r[i] * d1 + (r[i - 1] + e) * d2);
+            if ((r[i] += y.am(0, qd, r, j, 0, ys)) < qd) { // Try it out
+                y.dlShiftTo(j, t);
+                r.subTo(t, r);
+                while (r[i] < --qd) {
+                    r.subTo(t, r);
+                }
+            }
+        }
+        if (q != null) {
+            r.drShiftTo(ys, q);
+            if (ts != ms) {
+                BigInteger.ZERO.subTo(q, q);
+            }
+        }
+        r.t = ys;
+        r.clamp();
+        if (nsh > 0) {
+            r.rShiftTo(nsh, r);
+        } // Denormalize remainder
+        if (ts < 0) {
+            BigInteger.ZERO.subTo(r, r);
+        }
+    };
+    // BigInteger.prototype.invDigit = bnpInvDigit;
+    // (protected) return "-1/this % 2^DB"; useful for Mont. reduction
+    // justification:
+    //         xy == 1 (mod m)
+    //         xy =  1+km
+    //   xy(2-xy) = (1+km)(1-km)
+    // x[y(2-xy)] = 1-k^2m^2
+    // x[y(2-xy)] == 1 (mod m^2)
+    // if y is 1/x mod m, then y(2-xy) is 1/x mod m^2
+    // should reduce x and y(2-xy) by m^2 at each step to keep size bounded.
+    // JS multiply "overflows" differently from C/C++, so care is needed here.
+    BigInteger.prototype.invDigit = function () {
+        if (this.t < 1) {
+            return 0;
+        }
+        var x = this[0];
+        if ((x & 1) == 0) {
+            return 0;
+        }
+        var y = x & 3; // y == 1/x mod 2^2
+        y = (y * (2 - (x & 0xf) * y)) & 0xf; // y == 1/x mod 2^4
+        y = (y * (2 - (x & 0xff) * y)) & 0xff; // y == 1/x mod 2^8
+        y = (y * (2 - (((x & 0xffff) * y) & 0xffff))) & 0xffff; // y == 1/x mod 2^16
+        // last step - calculate inverse mod DV directly;
+        // assumes 16 < DB <= 32 and assumes ability to handle 48-bit ints
+        y = (y * (2 - x * y % this.DV)) % this.DV; // y == 1/x mod 2^dbits
+        // we really want the negative inverse, and -DV < y < DV
+        return (y > 0) ? this.DV - y : -y;
+    };
+    // BigInteger.prototype.isEven = bnpIsEven;
+    // (protected) true iff this is even
+    BigInteger.prototype.isEven = function () {
+        return ((this.t > 0) ? (this[0] & 1) : this.s) == 0;
+    };
+    // BigInteger.prototype.exp = bnpExp;
+    // (protected) this^e, e < 2^32, doing sqr and mul with "r" (HAC 14.79)
+    BigInteger.prototype.exp = function (e, z) {
+        if (e > 0xffffffff || e < 1) {
+            return BigInteger.ONE;
+        }
+        var r = nbi();
+        var r2 = nbi();
+        var g = z.convert(this);
+        var i = nbits(e) - 1;
+        g.copyTo(r);
+        while (--i >= 0) {
+            z.sqrTo(r, r2);
+            if ((e & (1 << i)) > 0) {
+                z.mulTo(r2, g, r);
+            }
+            else {
+                var t = r;
+                r = r2;
+                r2 = t;
+            }
+        }
+        return z.revert(r);
+    };
+    // BigInteger.prototype.chunkSize = bnpChunkSize;
+    // (protected) return x s.t. r^x < DV
+    BigInteger.prototype.chunkSize = function (r) {
+        return Math.floor(Math.LN2 * this.DB / Math.log(r));
+    };
+    // BigInteger.prototype.toRadix = bnpToRadix;
+    // (protected) convert to radix string
+    BigInteger.prototype.toRadix = function (b) {
+        if (b == null) {
+            b = 10;
+        }
+        if (this.signum() == 0 || b < 2 || b > 36) {
+            return "0";
+        }
+        var cs = this.chunkSize(b);
+        var a = Math.pow(b, cs);
+        var d = nbv(a);
+        var y = nbi();
+        var z = nbi();
+        var r = "";
+        this.divRemTo(d, y, z);
+        while (y.signum() > 0) {
+            r = (a + z.intValue()).toString(b).substr(1) + r;
+            y.divRemTo(d, y, z);
+        }
+        return z.intValue().toString(b) + r;
+    };
+    // BigInteger.prototype.fromRadix = bnpFromRadix;
+    // (protected) convert from radix string
+    BigInteger.prototype.fromRadix = function (s, b) {
+        this.fromInt(0);
+        if (b == null) {
+            b = 10;
+        }
+        var cs = this.chunkSize(b);
+        var d = Math.pow(b, cs);
+        var mi = false;
+        var j = 0;
+        var w = 0;
+        for (var i = 0; i < s.length; ++i) {
+            var x = intAt(s, i);
+            if (x < 0) {
+                if (s.charAt(i) == "-" && this.signum() == 0) {
+                    mi = true;
+                }
+                continue;
+            }
+            w = b * w + x;
+            if (++j >= cs) {
+                this.dMultiply(d);
+                this.dAddOffset(w, 0);
+                j = 0;
+                w = 0;
+            }
+        }
+        if (j > 0) {
+            this.dMultiply(Math.pow(b, j));
+            this.dAddOffset(w, 0);
+        }
+        if (mi) {
+            BigInteger.ZERO.subTo(this, this);
+        }
+    };
+    // BigInteger.prototype.fromNumber = bnpFromNumber;
+    // (protected) alternate constructor
+    BigInteger.prototype.fromNumber = function (a, b, c) {
+        if ("number" == typeof b) {
+            // new BigInteger(int,int,RNG)
+            if (a < 2) {
+                this.fromInt(1);
+            }
+            else {
+                this.fromNumber(a, c);
+                if (!this.testBit(a - 1)) {
+                    // force MSB set
+                    this.bitwiseTo(BigInteger.ONE.shiftLeft(a - 1), op_or, this);
+                }
+                if (this.isEven()) {
+                    this.dAddOffset(1, 0);
+                } // force odd
+                while (!this.isProbablePrime(b)) {
+                    this.dAddOffset(2, 0);
+                    if (this.bitLength() > a) {
+                        this.subTo(BigInteger.ONE.shiftLeft(a - 1), this);
+                    }
+                }
+            }
+        }
+        else {
+            // new BigInteger(int,RNG)
+            var x = [];
+            var t = a & 7;
+            x.length = (a >> 3) + 1;
+            b.nextBytes(x);
+            if (t > 0) {
+                x[0] &= ((1 << t) - 1);
+            }
+            else {
+                x[0] = 0;
+            }
+            this.fromString(x, 256);
+        }
+    };
+    // BigInteger.prototype.bitwiseTo = bnpBitwiseTo;
+    // (protected) r = this op a (bitwise)
+    BigInteger.prototype.bitwiseTo = function (a, op, r) {
+        var i;
+        var f;
+        var m = Math.min(a.t, this.t);
+        for (i = 0; i < m; ++i) {
+            r[i] = op(this[i], a[i]);
+        }
+        if (a.t < this.t) {
+            f = a.s & this.DM;
+            for (i = m; i < this.t; ++i) {
+                r[i] = op(this[i], f);
+            }
+            r.t = this.t;
+        }
+        else {
+            f = this.s & this.DM;
+            for (i = m; i < a.t; ++i) {
+                r[i] = op(f, a[i]);
+            }
+            r.t = a.t;
+        }
+        r.s = op(this.s, a.s);
+        r.clamp();
+    };
+    // BigInteger.prototype.changeBit = bnpChangeBit;
+    // (protected) this op (1<<n)
+    BigInteger.prototype.changeBit = function (n, op) {
+        var r = BigInteger.ONE.shiftLeft(n);
+        this.bitwiseTo(r, op, r);
+        return r;
+    };
+    // BigInteger.prototype.addTo = bnpAddTo;
+    // (protected) r = this + a
+    BigInteger.prototype.addTo = function (a, r) {
+        var i = 0;
+        var c = 0;
+        var m = Math.min(a.t, this.t);
+        while (i < m) {
+            c += this[i] + a[i];
+            r[i++] = c & this.DM;
+            c >>= this.DB;
+        }
+        if (a.t < this.t) {
+            c += a.s;
+            while (i < this.t) {
+                c += this[i];
+                r[i++] = c & this.DM;
+                c >>= this.DB;
+            }
+            c += this.s;
+        }
+        else {
+            c += this.s;
+            while (i < a.t) {
+                c += a[i];
+                r[i++] = c & this.DM;
+                c >>= this.DB;
+            }
+            c += a.s;
+        }
+        r.s = (c < 0) ? -1 : 0;
+        if (c > 0) {
+            r[i++] = c;
+        }
+        else if (c < -1) {
+            r[i++] = this.DV + c;
+        }
+        r.t = i;
+        r.clamp();
+    };
+    // BigInteger.prototype.dMultiply = bnpDMultiply;
+    // (protected) this *= n, this >= 0, 1 < n < DV
+    BigInteger.prototype.dMultiply = function (n) {
+        this[this.t] = this.am(0, n - 1, this, 0, 0, this.t);
+        ++this.t;
+        this.clamp();
+    };
+    // BigInteger.prototype.dAddOffset = bnpDAddOffset;
+    // (protected) this += n << w words, this >= 0
+    BigInteger.prototype.dAddOffset = function (n, w) {
+        if (n == 0) {
+            return;
+        }
+        while (this.t <= w) {
+            this[this.t++] = 0;
+        }
+        this[w] += n;
+        while (this[w] >= this.DV) {
+            this[w] -= this.DV;
+            if (++w >= this.t) {
+                this[this.t++] = 0;
+            }
+            ++this[w];
+        }
+    };
+    // BigInteger.prototype.multiplyLowerTo = bnpMultiplyLowerTo;
+    // (protected) r = lower n words of "this * a", a.t <= n
+    // "this" should be the larger one if appropriate.
+    BigInteger.prototype.multiplyLowerTo = function (a, n, r) {
+        var i = Math.min(this.t + a.t, n);
+        r.s = 0; // assumes a,this >= 0
+        r.t = i;
+        while (i > 0) {
+            r[--i] = 0;
+        }
+        for (var j = r.t - this.t; i < j; ++i) {
+            r[i + this.t] = this.am(0, a[i], r, i, 0, this.t);
+        }
+        for (var j = Math.min(a.t, n); i < j; ++i) {
+            this.am(0, a[i], r, i, 0, n - i);
+        }
+        r.clamp();
+    };
+    // BigInteger.prototype.multiplyUpperTo = bnpMultiplyUpperTo;
+    // (protected) r = "this * a" without lower n words, n > 0
+    // "this" should be the larger one if appropriate.
+    BigInteger.prototype.multiplyUpperTo = function (a, n, r) {
+        --n;
+        var i = r.t = this.t + a.t - n;
+        r.s = 0; // assumes a,this >= 0
+        while (--i >= 0) {
+            r[i] = 0;
+        }
+        for (i = Math.max(n - this.t, 0); i < a.t; ++i) {
+            r[this.t + i - n] = this.am(n - i, a[i], r, 0, 0, this.t + i - n);
+        }
+        r.clamp();
+        r.drShiftTo(1, r);
+    };
+    // BigInteger.prototype.modInt = bnpModInt;
+    // (protected) this % n, n < 2^26
+    BigInteger.prototype.modInt = function (n) {
+        if (n <= 0) {
+            return 0;
+        }
+        var d = this.DV % n;
+        var r = (this.s < 0) ? n - 1 : 0;
+        if (this.t > 0) {
+            if (d == 0) {
+                r = this[0] % n;
+            }
+            else {
+                for (var i = this.t - 1; i >= 0; --i) {
+                    r = (d * r + this[i]) % n;
+                }
+            }
+        }
+        return r;
+    };
+    // BigInteger.prototype.millerRabin = bnpMillerRabin;
+    // (protected) true if probably prime (HAC 4.24, Miller-Rabin)
+    BigInteger.prototype.millerRabin = function (t) {
+        var n1 = this.subtract(BigInteger.ONE);
+        var k = n1.getLowestSetBit();
+        if (k <= 0) {
+            return false;
+        }
+        var r = n1.shiftRight(k);
+        t = (t + 1) >> 1;
+        if (t > lowprimes.length) {
+            t = lowprimes.length;
+        }
+        var a = nbi();
+        for (var i = 0; i < t; ++i) {
+            // Pick bases at random, instead of starting at 2
+            a.fromInt(lowprimes[Math.floor(Math.random() * lowprimes.length)]);
+            var y = a.modPow(r, this);
+            if (y.compareTo(BigInteger.ONE) != 0 && y.compareTo(n1) != 0) {
+                var j = 1;
+                while (j++ < k && y.compareTo(n1) != 0) {
+                    y = y.modPowInt(2, this);
+                    if (y.compareTo(BigInteger.ONE) == 0) {
+                        return false;
+                    }
+                }
+                if (y.compareTo(n1) != 0) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    };
+    // BigInteger.prototype.square = bnSquare;
+    // (public) this^2
+    BigInteger.prototype.square = function () {
+        var r = nbi();
+        this.squareTo(r);
+        return r;
+    };
+    //#region ASYNC
+    // Public API method
+    BigInteger.prototype.gcda = function (a, callback) {
+        var x = (this.s < 0) ? this.negate() : this.clone();
+        var y = (a.s < 0) ? a.negate() : a.clone();
+        if (x.compareTo(y) < 0) {
+            var t = x;
+            x = y;
+            y = t;
+        }
+        var i = x.getLowestSetBit();
+        var g = y.getLowestSetBit();
+        if (g < 0) {
+            callback(x);
+            return;
+        }
+        if (i < g) {
+            g = i;
+        }
+        if (g > 0) {
+            x.rShiftTo(g, x);
+            y.rShiftTo(g, y);
+        }
+        // Workhorse of the algorithm, gets called 200 - 800 times per 512 bit keygen.
+        var gcda1 = function () {
+            if ((i = x.getLowestSetBit()) > 0) {
+                x.rShiftTo(i, x);
+            }
+            if ((i = y.getLowestSetBit()) > 0) {
+                y.rShiftTo(i, y);
+            }
+            if (x.compareTo(y) >= 0) {
+                x.subTo(y, x);
+                x.rShiftTo(1, x);
+            }
+            else {
+                y.subTo(x, y);
+                y.rShiftTo(1, y);
+            }
+            if (!(x.signum() > 0)) {
+                if (g > 0) {
+                    y.lShiftTo(g, y);
+                }
+                setTimeout(function () { callback(y); }, 0); // escape
+            }
+            else {
+                setTimeout(gcda1, 0);
+            }
+        };
+        setTimeout(gcda1, 10);
+    };
+    // (protected) alternate constructor
+    BigInteger.prototype.fromNumberAsync = function (a, b, c, callback) {
+        if ("number" == typeof b) {
+            if (a < 2) {
+                this.fromInt(1);
+            }
+            else {
+                this.fromNumber(a, c);
+                if (!this.testBit(a - 1)) {
+                    this.bitwiseTo(BigInteger.ONE.shiftLeft(a - 1), op_or, this);
+                }
+                if (this.isEven()) {
+                    this.dAddOffset(1, 0);
+                }
+                var bnp_1 = this;
+                var bnpfn1_1 = function () {
+                    bnp_1.dAddOffset(2, 0);
+                    if (bnp_1.bitLength() > a) {
+                        bnp_1.subTo(BigInteger.ONE.shiftLeft(a - 1), bnp_1);
+                    }
+                    if (bnp_1.isProbablePrime(b)) {
+                        setTimeout(function () { callback(); }, 0); // escape
+                    }
+                    else {
+                        setTimeout(bnpfn1_1, 0);
+                    }
+                };
+                setTimeout(bnpfn1_1, 0);
+            }
+        }
+        else {
+            var x = [];
+            var t = a & 7;
+            x.length = (a >> 3) + 1;
+            b.nextBytes(x);
+            if (t > 0) {
+                x[0] &= ((1 << t) - 1);
+            }
+            else {
+                x[0] = 0;
+            }
+            this.fromString(x, 256);
+        }
+    };
+    return BigInteger;
+}());
+//#region REDUCERS
+//#region NullExp
+var NullExp = /** @class */ (function () {
+    function NullExp() {
+    }
+    // NullExp.prototype.convert = nNop;
+    NullExp.prototype.convert = function (x) {
+        return x;
+    };
+    // NullExp.prototype.revert = nNop;
+    NullExp.prototype.revert = function (x) {
+        return x;
+    };
+    // NullExp.prototype.mulTo = nMulTo;
+    NullExp.prototype.mulTo = function (x, y, r) {
+        x.multiplyTo(y, r);
+    };
+    // NullExp.prototype.sqrTo = nSqrTo;
+    NullExp.prototype.sqrTo = function (x, r) {
+        x.squareTo(r);
+    };
+    return NullExp;
+}());
+// Modular reduction using "classic" algorithm
+var Classic = /** @class */ (function () {
+    function Classic(m) {
+        this.m = m;
+    }
+    // Classic.prototype.convert = cConvert;
+    Classic.prototype.convert = function (x) {
+        if (x.s < 0 || x.compareTo(this.m) >= 0) {
+            return x.mod(this.m);
+        }
+        else {
+            return x;
+        }
+    };
+    // Classic.prototype.revert = cRevert;
+    Classic.prototype.revert = function (x) {
+        return x;
+    };
+    // Classic.prototype.reduce = cReduce;
+    Classic.prototype.reduce = function (x) {
+        x.divRemTo(this.m, null, x);
+    };
+    // Classic.prototype.mulTo = cMulTo;
+    Classic.prototype.mulTo = function (x, y, r) {
+        x.multiplyTo(y, r);
+        this.reduce(r);
+    };
+    // Classic.prototype.sqrTo = cSqrTo;
+    Classic.prototype.sqrTo = function (x, r) {
+        x.squareTo(r);
+        this.reduce(r);
+    };
+    return Classic;
+}());
+//#endregion
+//#region Montgomery
+// Montgomery reduction
+var Montgomery = /** @class */ (function () {
+    function Montgomery(m) {
+        this.m = m;
+        this.mp = m.invDigit();
+        this.mpl = this.mp & 0x7fff;
+        this.mph = this.mp >> 15;
+        this.um = (1 << (m.DB - 15)) - 1;
+        this.mt2 = 2 * m.t;
+    }
+    // Montgomery.prototype.convert = montConvert;
+    // xR mod m
+    Montgomery.prototype.convert = function (x) {
+        var r = nbi();
+        x.abs().dlShiftTo(this.m.t, r);
+        r.divRemTo(this.m, null, r);
+        if (x.s < 0 && r.compareTo(BigInteger.ZERO) > 0) {
+            this.m.subTo(r, r);
+        }
+        return r;
+    };
+    // Montgomery.prototype.revert = montRevert;
+    // x/R mod m
+    Montgomery.prototype.revert = function (x) {
+        var r = nbi();
+        x.copyTo(r);
+        this.reduce(r);
+        return r;
+    };
+    // Montgomery.prototype.reduce = montReduce;
+    // x = x/R mod m (HAC 14.32)
+    Montgomery.prototype.reduce = function (x) {
+        while (x.t <= this.mt2) {
+            // pad x so am has enough room later
+            x[x.t++] = 0;
+        }
+        for (var i = 0; i < this.m.t; ++i) {
+            // faster way of calculating u0 = x[i]*mp mod DV
+            var j = x[i] & 0x7fff;
+            var u0 = (j * this.mpl + (((j * this.mph + (x[i] >> 15) * this.mpl) & this.um) << 15)) & x.DM;
+            // use am to combine the multiply-shift-add into one call
+            j = i + this.m.t;
+            x[j] += this.m.am(0, u0, x, i, 0, this.m.t);
+            // propagate carry
+            while (x[j] >= x.DV) {
+                x[j] -= x.DV;
+                x[++j]++;
+            }
+        }
+        x.clamp();
+        x.drShiftTo(this.m.t, x);
+        if (x.compareTo(this.m) >= 0) {
+            x.subTo(this.m, x);
+        }
+    };
+    // Montgomery.prototype.mulTo = montMulTo;
+    // r = "xy/R mod m"; x,y != r
+    Montgomery.prototype.mulTo = function (x, y, r) {
+        x.multiplyTo(y, r);
+        this.reduce(r);
+    };
+    // Montgomery.prototype.sqrTo = montSqrTo;
+    // r = "x^2/R mod m"; x != r
+    Montgomery.prototype.sqrTo = function (x, r) {
+        x.squareTo(r);
+        this.reduce(r);
+    };
+    return Montgomery;
+}());
+//#endregion Montgomery
+//#region Barrett
+// Barrett modular reduction
+var Barrett = /** @class */ (function () {
+    function Barrett(m) {
+        this.m = m;
+        // setup Barrett
+        this.r2 = nbi();
+        this.q3 = nbi();
+        BigInteger.ONE.dlShiftTo(2 * m.t, this.r2);
+        this.mu = this.r2.divide(m);
+    }
+    // Barrett.prototype.convert = barrettConvert;
+    Barrett.prototype.convert = function (x) {
+        if (x.s < 0 || x.t > 2 * this.m.t) {
+            return x.mod(this.m);
+        }
+        else if (x.compareTo(this.m) < 0) {
+            return x;
+        }
+        else {
+            var r = nbi();
+            x.copyTo(r);
+            this.reduce(r);
+            return r;
+        }
+    };
+    // Barrett.prototype.revert = barrettRevert;
+    Barrett.prototype.revert = function (x) {
+        return x;
+    };
+    // Barrett.prototype.reduce = barrettReduce;
+    // x = x mod m (HAC 14.42)
+    Barrett.prototype.reduce = function (x) {
+        x.drShiftTo(this.m.t - 1, this.r2);
+        if (x.t > this.m.t + 1) {
+            x.t = this.m.t + 1;
+            x.clamp();
+        }
+        this.mu.multiplyUpperTo(this.r2, this.m.t + 1, this.q3);
+        this.m.multiplyLowerTo(this.q3, this.m.t + 1, this.r2);
+        while (x.compareTo(this.r2) < 0) {
+            x.dAddOffset(1, this.m.t + 1);
+        }
+        x.subTo(this.r2, x);
+        while (x.compareTo(this.m) >= 0) {
+            x.subTo(this.m, x);
+        }
+    };
+    // Barrett.prototype.mulTo = barrettMulTo;
+    // r = x*y mod m; x,y != r
+    Barrett.prototype.mulTo = function (x, y, r) {
+        x.multiplyTo(y, r);
+        this.reduce(r);
+    };
+    // Barrett.prototype.sqrTo = barrettSqrTo;
+    // r = x^2 mod m; x != r
+    Barrett.prototype.sqrTo = function (x, r) {
+        x.squareTo(r);
+        this.reduce(r);
+    };
+    return Barrett;
+}());
+//#endregion
+//#endregion REDUCERS
+// return new, unset BigInteger
+function nbi() { return new BigInteger(null); }
+function parseBigInt(str, r) {
+    return new BigInteger(str, r);
+}
+// am: Compute w_j += (x*this_i), propagate carries,
+// c is initial carry, returns final carry.
+// c < 3*dvalue, x < 2*dvalue, this_i < dvalue
+// We need to select the fastest one that works in this environment.
+// am1: use a single mult and divide to get the high bits,
+// max digit bits should be 26 because
+// max internal value = 2*dvalue^2-2*dvalue (< 2^53)
+function am1(i, x, w, j, c, n) {
+    while (--n >= 0) {
+        var v = x * this[i++] + w[j] + c;
+        c = Math.floor(v / 0x4000000);
+        w[j++] = v & 0x3ffffff;
+    }
+    return c;
+}
+// am2 avoids a big mult-and-extract completely.
+// Max digit bits should be <= 30 because we do bitwise ops
+// on values up to 2*hdvalue^2-hdvalue-1 (< 2^31)
+function am2(i, x, w, j, c, n) {
+    var xl = x & 0x7fff;
+    var xh = x >> 15;
+    while (--n >= 0) {
+        var l = this[i] & 0x7fff;
+        var h = this[i++] >> 15;
+        var m = xh * l + h * xl;
+        l = xl * l + ((m & 0x7fff) << 15) + w[j] + (c & 0x3fffffff);
+        c = (l >>> 30) + (m >>> 15) + xh * h + (c >>> 30);
+        w[j++] = l & 0x3fffffff;
+    }
+    return c;
+}
+// Alternately, set max digit bits to 28 since some
+// browsers slow down when dealing with 32-bit numbers.
+function am3(i, x, w, j, c, n) {
+    var xl = x & 0x3fff;
+    var xh = x >> 14;
+    while (--n >= 0) {
+        var l = this[i] & 0x3fff;
+        var h = this[i++] >> 14;
+        var m = xh * l + h * xl;
+        l = xl * l + ((m & 0x3fff) << 14) + w[j] + c;
+        c = (l >> 28) + (m >> 14) + xh * h;
+        w[j++] = l & 0xfffffff;
+    }
+    return c;
+}
+if (j_lm && navigator && (navigator.appName == "Microsoft Internet Explorer")) {
+    BigInteger.prototype.am = am2;
+    dbits = 30;
+}
+else if (j_lm && navigator && (navigator.appName != "Netscape")) {
+    BigInteger.prototype.am = am1;
+    dbits = 26;
+}
+else { // Mozilla/Netscape seems to prefer am3
+    BigInteger.prototype.am = am3;
+    dbits = 28;
+}
+BigInteger.prototype.DB = dbits;
+BigInteger.prototype.DM = ((1 << dbits) - 1);
+BigInteger.prototype.DV = (1 << dbits);
+var BI_FP = 52;
+BigInteger.prototype.FV = Math.pow(2, BI_FP);
+BigInteger.prototype.F1 = BI_FP - dbits;
+BigInteger.prototype.F2 = 2 * dbits - BI_FP;
+// Digit conversions
+var BI_RC = [];
+var rr;
+var vv;
+rr = "0".charCodeAt(0);
+for (vv = 0; vv <= 9; ++vv) {
+    BI_RC[rr++] = vv;
+}
+rr = "a".charCodeAt(0);
+for (vv = 10; vv < 36; ++vv) {
+    BI_RC[rr++] = vv;
+}
+rr = "A".charCodeAt(0);
+for (vv = 10; vv < 36; ++vv) {
+    BI_RC[rr++] = vv;
+}
+function intAt(s, i) {
+    var c = BI_RC[s.charCodeAt(i)];
+    return (c == null) ? -1 : c;
+}
+// return bigint initialized to value
+function nbv(i) {
+    var r = nbi();
+    r.fromInt(i);
+    return r;
+}
+// returns bit length of the integer x
+function nbits(x) {
+    var r = 1;
+    var t;
+    if ((t = x >>> 16) != 0) {
+        x = t;
+        r += 16;
+    }
+    if ((t = x >> 8) != 0) {
+        x = t;
+        r += 8;
+    }
+    if ((t = x >> 4) != 0) {
+        x = t;
+        r += 4;
+    }
+    if ((t = x >> 2) != 0) {
+        x = t;
+        r += 2;
+    }
+    if ((t = x >> 1) != 0) {
+        x = t;
+        r += 1;
+    }
+    return r;
+}
+// "constants"
+BigInteger.ZERO = nbv(0);
+BigInteger.ONE = nbv(1);
+
+// prng4.js - uses Arcfour as a PRNG
+var Arcfour = /** @class */ (function () {
+    function Arcfour() {
+        this.i = 0;
+        this.j = 0;
+        this.S = [];
+    }
+    // Arcfour.prototype.init = ARC4init;
+    // Initialize arcfour context from key, an array of ints, each from [0..255]
+    Arcfour.prototype.init = function (key) {
+        var i;
+        var j;
+        var t;
+        for (i = 0; i < 256; ++i) {
+            this.S[i] = i;
+        }
+        j = 0;
+        for (i = 0; i < 256; ++i) {
+            j = (j + this.S[i] + key[i % key.length]) & 255;
+            t = this.S[i];
+            this.S[i] = this.S[j];
+            this.S[j] = t;
+        }
+        this.i = 0;
+        this.j = 0;
+    };
+    // Arcfour.prototype.next = ARC4next;
+    Arcfour.prototype.next = function () {
+        var t;
+        this.i = (this.i + 1) & 255;
+        this.j = (this.j + this.S[this.i]) & 255;
+        t = this.S[this.i];
+        this.S[this.i] = this.S[this.j];
+        this.S[this.j] = t;
+        return this.S[(t + this.S[this.i]) & 255];
+    };
+    return Arcfour;
+}());
+// Plug in your RNG constructor here
+function prng_newstate() {
+    return new Arcfour();
+}
+// Pool size must be a multiple of 4 and greater than 32.
+// An array of bytes the size of the pool will be passed to init()
+var rng_psize = 256;
+
+// Random number generator - requires a PRNG backend, e.g. prng4.js
+var rng_state;
+var rng_pool = null;
+var rng_pptr;
+// Initialize the pool with junk if needed.
+if (rng_pool == null) {
+    rng_pool = [];
+    rng_pptr = 0;
+    var t = void 0;
+    if (window && window.crypto && window.crypto.getRandomValues) {
+        // Extract entropy (2048 bits) from RNG if available
+        var z = new Uint32Array(256);
+        window.crypto.getRandomValues(z);
+        for (t = 0; t < z.length; ++t) {
+            rng_pool[rng_pptr++] = z[t] & 255;
+        }
+    }
+    // Use mouse events for entropy, if we do not have enough entropy by the time
+    // we need it, entropy will be generated by Math.random.
+    var onMouseMoveListener_1 = function (ev) {
+        this.count = this.count || 0;
+        if (this.count >= 256 || rng_pptr >= rng_psize) {
+            if (window.removeEventListener) {
+                window.removeEventListener("mousemove", onMouseMoveListener_1, false);
+            }
+            else if (window.detachEvent) {
+                window.detachEvent("onmousemove", onMouseMoveListener_1);
+            }
+            return;
+        }
+        try {
+            var mouseCoordinates = ev.x + ev.y;
+            rng_pool[rng_pptr++] = mouseCoordinates & 255;
+            this.count += 1;
+        }
+        catch (e) {
+            // Sometimes Firefox will deny permission to access event properties for some reason. Ignore.
+        }
+    };
+    if (window && window.addEventListener) {
+        window.addEventListener("mousemove", onMouseMoveListener_1, false);
+    }
+    else if (window && window.attachEvent) {
+        window.attachEvent("onmousemove", onMouseMoveListener_1);
+    }
+}
+function rng_get_byte() {
+    if (rng_state == null) {
+        rng_state = prng_newstate();
+        // At this point, we may not have collected enough entropy.  If not, fall back to Math.random
+        while (rng_pptr < rng_psize) {
+            var random = Math.floor(65536 * Math.random());
+            rng_pool[rng_pptr++] = random & 255;
+        }
+        rng_state.init(rng_pool);
+        for (rng_pptr = 0; rng_pptr < rng_pool.length; ++rng_pptr) {
+            rng_pool[rng_pptr] = 0;
+        }
+        rng_pptr = 0;
+    }
+    // TODO: allow reseeding after first request
+    return rng_state.next();
+}
+var SecureRandom = /** @class */ (function () {
+    function SecureRandom() {
+    }
+    SecureRandom.prototype.nextBytes = function (ba) {
+        for (var i = 0; i < ba.length; ++i) {
+            ba[i] = rng_get_byte();
+        }
+    };
+    return SecureRandom;
+}());
+
+// Depends on jsbn.js and rng.js
+// function linebrk(s,n) {
+//   var ret = "";
+//   var i = 0;
+//   while(i + n < s.length) {
+//     ret += s.substring(i,i+n) + "\n";
+//     i += n;
+//   }
+//   return ret + s.substring(i,s.length);
+// }
+// function byte2Hex(b) {
+//   if(b < 0x10)
+//     return "0" + b.toString(16);
+//   else
+//     return b.toString(16);
+// }
+function pkcs1pad1(s, n) {
+    if (n < s.length + 22) {
+        console.error("Message too long for RSA");
+        return null;
+    }
+    var len = n - s.length - 6;
+    var filler = "";
+    for (var f = 0; f < len; f += 2) {
+        filler += "ff";
+    }
+    var m = "0001" + filler + "00" + s;
+    return parseBigInt(m, 16);
+}
+// PKCS#1 (type 2, random) pad input string s to n bytes, and return a bigint
+function pkcs1pad2(s, n) {
+    if (n < s.length + 11) { // TODO: fix for utf-8
+        console.error("Message too long for RSA");
+        return null;
+    }
+    var ba = [];
+    var i = s.length - 1;
+    while (i >= 0 && n > 0) {
+        var c = s.charCodeAt(i--);
+        if (c < 128) { // encode using utf-8
+            ba[--n] = c;
+        }
+        else if ((c > 127) && (c < 2048)) {
+            ba[--n] = (c & 63) | 128;
+            ba[--n] = (c >> 6) | 192;
+        }
+        else {
+            ba[--n] = (c & 63) | 128;
+            ba[--n] = ((c >> 6) & 63) | 128;
+            ba[--n] = (c >> 12) | 224;
+        }
+    }
+    ba[--n] = 0;
+    var rng = new SecureRandom();
+    var x = [];
+    while (n > 2) { // random non-zero pad
+        x[0] = 0;
+        while (x[0] == 0) {
+            rng.nextBytes(x);
+        }
+        ba[--n] = x[0];
+    }
+    ba[--n] = 2;
+    ba[--n] = 0;
+    return new BigInteger(ba);
+}
+// "empty" RSA key constructor
+var RSAKey = /** @class */ (function () {
+    function RSAKey() {
+        this.n = null;
+        this.e = 0;
+        this.d = null;
+        this.p = null;
+        this.q = null;
+        this.dmp1 = null;
+        this.dmq1 = null;
+        this.coeff = null;
+    }
+    //#region PROTECTED
+    // protected
+    // RSAKey.prototype.doPublic = RSADoPublic;
+    // Perform raw public operation on "x": return x^e (mod n)
+    RSAKey.prototype.doPublic = function (x) {
+        return x.modPowInt(this.e, this.n);
+    };
+    // RSAKey.prototype.doPrivate = RSADoPrivate;
+    // Perform raw private operation on "x": return x^d (mod n)
+    RSAKey.prototype.doPrivate = function (x) {
+        if (this.p == null || this.q == null) {
+            return x.modPow(this.d, this.n);
+        }
+        // TODO: re-calculate any missing CRT params
+        var xp = x.mod(this.p).modPow(this.dmp1, this.p);
+        var xq = x.mod(this.q).modPow(this.dmq1, this.q);
+        while (xp.compareTo(xq) < 0) {
+            xp = xp.add(this.p);
+        }
+        return xp.subtract(xq).multiply(this.coeff).mod(this.p).multiply(this.q).add(xq);
+    };
+    //#endregion PROTECTED
+    //#region PUBLIC
+    // RSAKey.prototype.setPublic = RSASetPublic;
+    // Set the public key fields N and e from hex strings
+    RSAKey.prototype.setPublic = function (N, E) {
+        if (N != null && E != null && N.length > 0 && E.length > 0) {
+            this.n = parseBigInt(N, 16);
+            this.e = parseInt(E, 16);
+        }
+        else {
+            console.error("Invalid RSA public key");
+        }
+    };
+    // RSAKey.prototype.encrypt = RSAEncrypt;
+    // Return the PKCS#1 RSA encryption of "text" as an even-length hex string
+    RSAKey.prototype.encrypt = function (text) {
+        var m = pkcs1pad2(text, (this.n.bitLength() + 7) >> 3);
+        if (m == null) {
+            return null;
+        }
+        var c = this.doPublic(m);
+        if (c == null) {
+            return null;
+        }
+        var h = c.toString(16);
+        if ((h.length & 1) == 0) {
+            return h;
+        }
+        else {
+            return "0" + h;
+        }
+    };
+    // RSAKey.prototype.setPrivate = RSASetPrivate;
+    // Set the private key fields N, e, and d from hex strings
+    RSAKey.prototype.setPrivate = function (N, E, D) {
+        if (N != null && E != null && N.length > 0 && E.length > 0) {
+            this.n = parseBigInt(N, 16);
+            this.e = parseInt(E, 16);
+            this.d = parseBigInt(D, 16);
+        }
+        else {
+            console.error("Invalid RSA private key");
+        }
+    };
+    // RSAKey.prototype.setPrivateEx = RSASetPrivateEx;
+    // Set the private key fields N, e, d and CRT params from hex strings
+    RSAKey.prototype.setPrivateEx = function (N, E, D, P, Q, DP, DQ, C) {
+        if (N != null && E != null && N.length > 0 && E.length > 0) {
+            this.n = parseBigInt(N, 16);
+            this.e = parseInt(E, 16);
+            this.d = parseBigInt(D, 16);
+            this.p = parseBigInt(P, 16);
+            this.q = parseBigInt(Q, 16);
+            this.dmp1 = parseBigInt(DP, 16);
+            this.dmq1 = parseBigInt(DQ, 16);
+            this.coeff = parseBigInt(C, 16);
+        }
+        else {
+            console.error("Invalid RSA private key");
+        }
+    };
+    // RSAKey.prototype.generate = RSAGenerate;
+    // Generate a new random private key B bits long, using public expt E
+    RSAKey.prototype.generate = function (B, E) {
+        var rng = new SecureRandom();
+        var qs = B >> 1;
+        this.e = parseInt(E, 16);
+        var ee = new BigInteger(E, 16);
+        for (;;) {
+            for (;;) {
+                this.p = new BigInteger(B - qs, 1, rng);
+                if (this.p.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.p.isProbablePrime(10)) {
+                    break;
+                }
+            }
+            for (;;) {
+                this.q = new BigInteger(qs, 1, rng);
+                if (this.q.subtract(BigInteger.ONE).gcd(ee).compareTo(BigInteger.ONE) == 0 && this.q.isProbablePrime(10)) {
+                    break;
+                }
+            }
+            if (this.p.compareTo(this.q) <= 0) {
+                var t = this.p;
+                this.p = this.q;
+                this.q = t;
+            }
+            var p1 = this.p.subtract(BigInteger.ONE);
+            var q1 = this.q.subtract(BigInteger.ONE);
+            var phi = p1.multiply(q1);
+            if (phi.gcd(ee).compareTo(BigInteger.ONE) == 0) {
+                this.n = this.p.multiply(this.q);
+                this.d = ee.modInverse(phi);
+                this.dmp1 = this.d.mod(p1);
+                this.dmq1 = this.d.mod(q1);
+                this.coeff = this.q.modInverse(this.p);
+                break;
+            }
+        }
+    };
+    // RSAKey.prototype.decrypt = RSADecrypt;
+    // Return the PKCS#1 RSA decryption of "ctext".
+    // "ctext" is an even-length hex string and the output is a plain string.
+    RSAKey.prototype.decrypt = function (ctext) {
+        var c = parseBigInt(ctext, 16);
+        var m = this.doPrivate(c);
+        if (m == null) {
+            return null;
+        }
+        return pkcs1unpad2(m, (this.n.bitLength() + 7) >> 3);
+    };
+    // Generate a new random private key B bits long, using public expt E
+    RSAKey.prototype.generateAsync = function (B, E, callback) {
+        var rng = new SecureRandom();
+        var qs = B >> 1;
+        this.e = parseInt(E, 16);
+        var ee = new BigInteger(E, 16);
+        var rsa = this;
+        // These functions have non-descript names because they were originally for(;;) loops.
+        // I don't know about cryptography to give them better names than loop1-4.
+        var loop1 = function () {
+            var loop4 = function () {
+                if (rsa.p.compareTo(rsa.q) <= 0) {
+                    var t = rsa.p;
+                    rsa.p = rsa.q;
+                    rsa.q = t;
+                }
+                var p1 = rsa.p.subtract(BigInteger.ONE);
+                var q1 = rsa.q.subtract(BigInteger.ONE);
+                var phi = p1.multiply(q1);
+                if (phi.gcd(ee).compareTo(BigInteger.ONE) == 0) {
+                    rsa.n = rsa.p.multiply(rsa.q);
+                    rsa.d = ee.modInverse(phi);
+                    rsa.dmp1 = rsa.d.mod(p1);
+                    rsa.dmq1 = rsa.d.mod(q1);
+                    rsa.coeff = rsa.q.modInverse(rsa.p);
+                    setTimeout(function () { callback(); }, 0); // escape
+                }
+                else {
+                    setTimeout(loop1, 0);
+                }
+            };
+            var loop3 = function () {
+                rsa.q = nbi();
+                rsa.q.fromNumberAsync(qs, 1, rng, function () {
+                    rsa.q.subtract(BigInteger.ONE).gcda(ee, function (r) {
+                        if (r.compareTo(BigInteger.ONE) == 0 && rsa.q.isProbablePrime(10)) {
+                            setTimeout(loop4, 0);
+                        }
+                        else {
+                            setTimeout(loop3, 0);
+                        }
+                    });
+                });
+            };
+            var loop2 = function () {
+                rsa.p = nbi();
+                rsa.p.fromNumberAsync(B - qs, 1, rng, function () {
+                    rsa.p.subtract(BigInteger.ONE).gcda(ee, function (r) {
+                        if (r.compareTo(BigInteger.ONE) == 0 && rsa.p.isProbablePrime(10)) {
+                            setTimeout(loop3, 0);
+                        }
+                        else {
+                            setTimeout(loop2, 0);
+                        }
+                    });
+                });
+            };
+            setTimeout(loop2, 0);
+        };
+        setTimeout(loop1, 0);
+    };
+    RSAKey.prototype.sign = function (text, digestMethod, digestName) {
+        var header = getDigestHeader(digestName);
+        var digest = header + digestMethod(text).toString();
+        var m = pkcs1pad1(digest, this.n.bitLength() / 4);
+        if (m == null) {
+            return null;
+        }
+        var c = this.doPrivate(m);
+        if (c == null) {
+            return null;
+        }
+        var h = c.toString(16);
+        if ((h.length & 1) == 0) {
+            return h;
+        }
+        else {
+            return "0" + h;
+        }
+    };
+    RSAKey.prototype.verify = function (text, signature, digestMethod) {
+        var c = parseBigInt(signature, 16);
+        var m = this.doPublic(c);
+        if (m == null) {
+            return null;
+        }
+        var unpadded = m.toString(16).replace(/^1f+00/, "");
+        var digest = removeDigestHeader(unpadded);
+        return digest == digestMethod(text).toString();
+    };
+    return RSAKey;
+}());
+// Undo PKCS#1 (type 2, random) padding and, if valid, return the plaintext
+function pkcs1unpad2(d, n) {
+    var b = d.toByteArray();
+    var i = 0;
+    while (i < b.length && b[i] == 0) {
+        ++i;
+    }
+    if (b.length - i != n - 1 || b[i] != 2) {
+        return null;
+    }
+    ++i;
+    while (b[i] != 0) {
+        if (++i >= b.length) {
+            return null;
+        }
+    }
+    var ret = "";
+    while (++i < b.length) {
+        var c = b[i] & 255;
+        if (c < 128) { // utf-8 decode
+            ret += String.fromCharCode(c);
+        }
+        else if ((c > 191) && (c < 224)) {
+            ret += String.fromCharCode(((c & 31) << 6) | (b[i + 1] & 63));
+            ++i;
+        }
+        else {
+            ret += String.fromCharCode(((c & 15) << 12) | ((b[i + 1] & 63) << 6) | (b[i + 2] & 63));
+            i += 2;
+        }
+    }
+    return ret;
+}
+// https://tools.ietf.org/html/rfc3447#page-43
+var DIGEST_HEADERS = {
+    md2: "3020300c06082a864886f70d020205000410",
+    md5: "3020300c06082a864886f70d020505000410",
+    sha1: "3021300906052b0e03021a05000414",
+    sha224: "302d300d06096086480165030402040500041c",
+    sha256: "3031300d060960864801650304020105000420",
+    sha384: "3041300d060960864801650304020205000430",
+    sha512: "3051300d060960864801650304020305000440",
+    ripemd160: "3021300906052b2403020105000414",
+};
+function getDigestHeader(name) {
+    return DIGEST_HEADERS[name] || "";
+}
+function removeDigestHeader(str) {
+    for (var name_1 in DIGEST_HEADERS) {
+        if (DIGEST_HEADERS.hasOwnProperty(name_1)) {
+            var header = DIGEST_HEADERS[name_1];
+            var len = header.length;
+            if (str.substr(0, len) == header) {
+                return str.substr(len);
+            }
+        }
+    }
+    return str;
+}
+// Return the PKCS#1 RSA encryption of "text" as a Base64-encoded string
+// function RSAEncryptB64(text) {
+//  var h = this.encrypt(text);
+//  if(h) return hex2b64(h); else return null;
+// }
+// public
+// RSAKey.prototype.encrypt_b64 = RSAEncryptB64;
+
+/*!
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+var YAHOO = {};
+YAHOO.lang = {
+    /**
+     * Utility to set up the prototype, constructor and superclass properties to
+     * support an inheritance strategy that can chain constructors and methods.
+     * Static members will not be inherited.
+     *
+     * @method extend
+     * @static
+     * @param {Function} subc   the object to modify
+     * @param {Function} superc the object to inherit
+     * @param {Object} overrides  additional properties/methods to add to the
+     *                              subclass prototype.  These will override the
+     *                              matching items obtained from the superclass
+     *                              if present.
+     */
+    extend: function(subc, superc, overrides) {
+        if (! superc || ! subc) {
+            throw new Error("YAHOO.lang.extend failed, please check that " +
+                "all dependencies are included.");
+        }
+
+        var F = function() {};
+        F.prototype = superc.prototype;
+        subc.prototype = new F();
+        subc.prototype.constructor = subc;
+        subc.superclass = superc.prototype;
+
+        if (superc.prototype.constructor == Object.prototype.constructor) {
+            superc.prototype.constructor = superc;
+        }
+
+        if (overrides) {
+            var i;
+            for (i in overrides) {
+                subc.prototype[i] = overrides[i];
+            }
+
+            /*
+             * IE will not enumerate native functions in a derived object even if the
+             * function was overridden.  This is a workaround for specific functions
+             * we care about on the Object prototype.
+             * @property _IEEnumFix
+             * @param {Function} r  the object to receive the augmentation
+             * @param {Function} s  the object that supplies the properties to augment
+             * @static
+             * @private
+             */
+            var _IEEnumFix = function() {},
+                ADD = ["toString", "valueOf"];
+            try {
+                if (/MSIE/.test(navigator.userAgent)) {
+                    _IEEnumFix = function(r, s) {
+                        for (i = 0; i < ADD.length; i = i + 1) {
+                            var fname = ADD[i], f = s[fname];
+                            if (typeof f === 'function' && f != Object.prototype[fname]) {
+                                r[fname] = f;
+                            }
+                        }
+                    };
+                }
+            } catch (ex) {}            _IEEnumFix(subc.prototype, overrides);
+        }
+    }
+};
+
+/* asn1-1.0.13.js (c) 2013-2017 Kenji Urushima | kjur.github.com/jsrsasign/license
+ */
+
+/**
+ * @fileOverview
+ * @name asn1-1.0.js
+ * @author Kenji Urushima kenji.urushima@gmail.com
+ * @version asn1 1.0.13 (2017-Jun-02)
+ * @since jsrsasign 2.1
+ * @license <a href="https://kjur.github.io/jsrsasign/license/">MIT License</a>
+ */
+
+/**
+ * kjur's class library name space
+ * <p>
+ * This name space provides following name spaces:
+ * <ul>
+ * <li>{@link KJUR.asn1} - ASN.1 primitive hexadecimal encoder</li>
+ * <li>{@link KJUR.asn1.x509} - ASN.1 structure for X.509 certificate and CRL</li>
+ * <li>{@link KJUR.crypto} - Java Cryptographic Extension(JCE) style MessageDigest/Signature
+ * class and utilities</li>
+ * </ul>
+ * </p>
+ * NOTE: Please ignore method summary and document of this namespace. This caused by a bug of jsdoc2.
+ * @name KJUR
+ * @namespace kjur's class library name space
+ */
+var KJUR = {};
+
+/**
+ * kjur's ASN.1 class library name space
+ * <p>
+ * This is ITU-T X.690 ASN.1 DER encoder class library and
+ * class structure and methods is very similar to
+ * org.bouncycastle.asn1 package of
+ * well known BouncyCaslte Cryptography Library.
+ * <h4>PROVIDING ASN.1 PRIMITIVES</h4>
+ * Here are ASN.1 DER primitive classes.
+ * <ul>
+ * <li>0x01 {@link KJUR.asn1.DERBoolean}</li>
+ * <li>0x02 {@link KJUR.asn1.DERInteger}</li>
+ * <li>0x03 {@link KJUR.asn1.DERBitString}</li>
+ * <li>0x04 {@link KJUR.asn1.DEROctetString}</li>
+ * <li>0x05 {@link KJUR.asn1.DERNull}</li>
+ * <li>0x06 {@link KJUR.asn1.DERObjectIdentifier}</li>
+ * <li>0x0a {@link KJUR.asn1.DEREnumerated}</li>
+ * <li>0x0c {@link KJUR.asn1.DERUTF8String}</li>
+ * <li>0x12 {@link KJUR.asn1.DERNumericString}</li>
+ * <li>0x13 {@link KJUR.asn1.DERPrintableString}</li>
+ * <li>0x14 {@link KJUR.asn1.DERTeletexString}</li>
+ * <li>0x16 {@link KJUR.asn1.DERIA5String}</li>
+ * <li>0x17 {@link KJUR.asn1.DERUTCTime}</li>
+ * <li>0x18 {@link KJUR.asn1.DERGeneralizedTime}</li>
+ * <li>0x30 {@link KJUR.asn1.DERSequence}</li>
+ * <li>0x31 {@link KJUR.asn1.DERSet}</li>
+ * </ul>
+ * <h4>OTHER ASN.1 CLASSES</h4>
+ * <ul>
+ * <li>{@link KJUR.asn1.ASN1Object}</li>
+ * <li>{@link KJUR.asn1.DERAbstractString}</li>
+ * <li>{@link KJUR.asn1.DERAbstractTime}</li>
+ * <li>{@link KJUR.asn1.DERAbstractStructured}</li>
+ * <li>{@link KJUR.asn1.DERTaggedObject}</li>
+ * </ul>
+ * <h4>SUB NAME SPACES</h4>
+ * <ul>
+ * <li>{@link KJUR.asn1.cades} - CAdES long term signature format</li>
+ * <li>{@link KJUR.asn1.cms} - Cryptographic Message Syntax</li>
+ * <li>{@link KJUR.asn1.csr} - Certificate Signing Request (CSR/PKCS#10)</li>
+ * <li>{@link KJUR.asn1.tsp} - RFC 3161 Timestamping Protocol Format</li>
+ * <li>{@link KJUR.asn1.x509} - RFC 5280 X.509 certificate and CRL</li>
+ * </ul>
+ * </p>
+ * NOTE: Please ignore method summary and document of this namespace.
+ * This caused by a bug of jsdoc2.
+ * @name KJUR.asn1
+ * @namespace
+ */
+if (typeof KJUR.asn1 == "undefined" || !KJUR.asn1) KJUR.asn1 = {};
+
+/**
+ * ASN1 utilities class
+ * @name KJUR.asn1.ASN1Util
+ * @class ASN1 utilities class
+ * @since asn1 1.0.2
+ */
+KJUR.asn1.ASN1Util = new function() {
+    this.integerToByteHex = function(i) {
+        var h = i.toString(16);
+        if ((h.length % 2) == 1) h = '0' + h;
+        return h;
+    };
+    this.bigIntToMinTwosComplementsHex = function(bigIntegerValue) {
+        var h = bigIntegerValue.toString(16);
+        if (h.substr(0, 1) != '-') {
+            if (h.length % 2 == 1) {
+                h = '0' + h;
+            } else {
+                if (! h.match(/^[0-7]/)) {
+                    h = '00' + h;
+                }
+            }
+        } else {
+            var hPos = h.substr(1);
+            var xorLen = hPos.length;
+            if (xorLen % 2 == 1) {
+                xorLen += 1;
+            } else {
+                if (! h.match(/^[0-7]/)) {
+                    xorLen += 2;
+                }
+            }
+            var hMask = '';
+            for (var i = 0; i < xorLen; i++) {
+                hMask += 'f';
+            }
+            var biMask = new BigInteger(hMask, 16);
+            var biNeg = biMask.xor(bigIntegerValue).add(BigInteger.ONE);
+            h = biNeg.toString(16).replace(/^-/, '');
+        }
+        return h;
+    };
+    /**
+     * get PEM string from hexadecimal data and header string
+     * @name getPEMStringFromHex
+     * @memberOf KJUR.asn1.ASN1Util
+     * @function
+     * @param {String} dataHex hexadecimal string of PEM body
+     * @param {String} pemHeader PEM header string (ex. 'RSA PRIVATE KEY')
+     * @return {String} PEM formatted string of input data
+     * @description
+     * This method converts a hexadecimal string to a PEM string with
+     * a specified header. Its line break will be CRLF("\r\n").
+     * @example
+     * var pem  = KJUR.asn1.ASN1Util.getPEMStringFromHex('616161', 'RSA PRIVATE KEY');
+     * // value of pem will be:
+     * -----BEGIN PRIVATE KEY-----
+     * YWFh
+     * -----END PRIVATE KEY-----
+     */
+    this.getPEMStringFromHex = function(dataHex, pemHeader) {
+        return hextopem(dataHex, pemHeader);
+    };
+
+    /**
+     * generate ASN1Object specifed by JSON parameters
+     * @name newObject
+     * @memberOf KJUR.asn1.ASN1Util
+     * @function
+     * @param {Array} param JSON parameter to generate ASN1Object
+     * @return {KJUR.asn1.ASN1Object} generated object
+     * @since asn1 1.0.3
+     * @description
+     * generate any ASN1Object specified by JSON param
+     * including ASN.1 primitive or structured.
+     * Generally 'param' can be described as follows:
+     * <blockquote>
+     * {TYPE-OF-ASNOBJ: ASN1OBJ-PARAMETER}
+     * </blockquote>
+     * 'TYPE-OF-ASN1OBJ' can be one of following symbols:
+     * <ul>
+     * <li>'bool' - DERBoolean</li>
+     * <li>'int' - DERInteger</li>
+     * <li>'bitstr' - DERBitString</li>
+     * <li>'octstr' - DEROctetString</li>
+     * <li>'null' - DERNull</li>
+     * <li>'oid' - DERObjectIdentifier</li>
+     * <li>'enum' - DEREnumerated</li>
+     * <li>'utf8str' - DERUTF8String</li>
+     * <li>'numstr' - DERNumericString</li>
+     * <li>'prnstr' - DERPrintableString</li>
+     * <li>'telstr' - DERTeletexString</li>
+     * <li>'ia5str' - DERIA5String</li>
+     * <li>'utctime' - DERUTCTime</li>
+     * <li>'gentime' - DERGeneralizedTime</li>
+     * <li>'seq' - DERSequence</li>
+     * <li>'set' - DERSet</li>
+     * <li>'tag' - DERTaggedObject</li>
+     * </ul>
+     * @example
+     * newObject({'prnstr': 'aaa'});
+     * newObject({'seq': [{'int': 3}, {'prnstr': 'aaa'}]})
+     * // ASN.1 Tagged Object
+     * newObject({'tag': {'tag': 'a1',
+     *                    'explicit': true,
+     *                    'obj': {'seq': [{'int': 3}, {'prnstr': 'aaa'}]}}});
+     * // more simple representation of ASN.1 Tagged Object
+     * newObject({'tag': ['a1',
+     *                    true,
+     *                    {'seq': [
+     *                      {'int': 3},
+     *                      {'prnstr': 'aaa'}]}
+     *                   ]});
+     */
+    this.newObject = function(param) {
+        var _KJUR = KJUR,
+            _KJUR_asn1 = _KJUR.asn1,
+            _DERBoolean = _KJUR_asn1.DERBoolean,
+            _DERInteger = _KJUR_asn1.DERInteger,
+            _DERBitString = _KJUR_asn1.DERBitString,
+            _DEROctetString = _KJUR_asn1.DEROctetString,
+            _DERNull = _KJUR_asn1.DERNull,
+            _DERObjectIdentifier = _KJUR_asn1.DERObjectIdentifier,
+            _DEREnumerated = _KJUR_asn1.DEREnumerated,
+            _DERUTF8String = _KJUR_asn1.DERUTF8String,
+            _DERNumericString = _KJUR_asn1.DERNumericString,
+            _DERPrintableString = _KJUR_asn1.DERPrintableString,
+            _DERTeletexString = _KJUR_asn1.DERTeletexString,
+            _DERIA5String = _KJUR_asn1.DERIA5String,
+            _DERUTCTime = _KJUR_asn1.DERUTCTime,
+            _DERGeneralizedTime = _KJUR_asn1.DERGeneralizedTime,
+            _DERSequence = _KJUR_asn1.DERSequence,
+            _DERSet = _KJUR_asn1.DERSet,
+            _DERTaggedObject = _KJUR_asn1.DERTaggedObject,
+            _newObject = _KJUR_asn1.ASN1Util.newObject;
+
+        var keys = Object.keys(param);
+        if (keys.length != 1)
+            throw "key of param shall be only one.";
+        var key = keys[0];
+
+        if (":bool:int:bitstr:octstr:null:oid:enum:utf8str:numstr:prnstr:telstr:ia5str:utctime:gentime:seq:set:tag:".indexOf(":" + key + ":") == -1)
+            throw "undefined key: " + key;
+
+        if (key == "bool")    return new _DERBoolean(param[key]);
+        if (key == "int")     return new _DERInteger(param[key]);
+        if (key == "bitstr")  return new _DERBitString(param[key]);
+        if (key == "octstr")  return new _DEROctetString(param[key]);
+        if (key == "null")    return new _DERNull(param[key]);
+        if (key == "oid")     return new _DERObjectIdentifier(param[key]);
+        if (key == "enum")    return new _DEREnumerated(param[key]);
+        if (key == "utf8str") return new _DERUTF8String(param[key]);
+        if (key == "numstr")  return new _DERNumericString(param[key]);
+        if (key == "prnstr")  return new _DERPrintableString(param[key]);
+        if (key == "telstr")  return new _DERTeletexString(param[key]);
+        if (key == "ia5str")  return new _DERIA5String(param[key]);
+        if (key == "utctime") return new _DERUTCTime(param[key]);
+        if (key == "gentime") return new _DERGeneralizedTime(param[key]);
+
+        if (key == "seq") {
+            var paramList = param[key];
+            var a = [];
+            for (var i = 0; i < paramList.length; i++) {
+                var asn1Obj = _newObject(paramList[i]);
+                a.push(asn1Obj);
+            }
+            return new _DERSequence({'array': a});
+        }
+
+        if (key == "set") {
+            var paramList = param[key];
+            var a = [];
+            for (var i = 0; i < paramList.length; i++) {
+                var asn1Obj = _newObject(paramList[i]);
+                a.push(asn1Obj);
+            }
+            return new _DERSet({'array': a});
+        }
+
+        if (key == "tag") {
+            var tagParam = param[key];
+            if (Object.prototype.toString.call(tagParam) === '[object Array]' &&
+                tagParam.length == 3) {
+                var obj = _newObject(tagParam[2]);
+                return new _DERTaggedObject({tag: tagParam[0],
+                    explicit: tagParam[1],
+                    obj: obj});
+            } else {
+                var newParam = {};
+                if (tagParam.explicit !== undefined)
+                    newParam.explicit = tagParam.explicit;
+                if (tagParam.tag !== undefined)
+                    newParam.tag = tagParam.tag;
+                if (tagParam.obj === undefined)
+                    throw "obj shall be specified for 'tag'.";
+                newParam.obj = _newObject(tagParam.obj);
+                return new _DERTaggedObject(newParam);
+            }
+        }
+    };
+
+    /**
+     * get encoded hexadecimal string of ASN1Object specifed by JSON parameters
+     * @name jsonToASN1HEX
+     * @memberOf KJUR.asn1.ASN1Util
+     * @function
+     * @param {Array} param JSON parameter to generate ASN1Object
+     * @return hexadecimal string of ASN1Object
+     * @since asn1 1.0.4
+     * @description
+     * As for ASN.1 object representation of JSON object,
+     * please see {@link newObject}.
+     * @example
+     * jsonToASN1HEX({'prnstr': 'aaa'});
+     */
+    this.jsonToASN1HEX = function(param) {
+        var asn1Obj = this.newObject(param);
+        return asn1Obj.getEncodedHex();
+    };
+};
+
+/**
+ * get dot noted oid number string from hexadecimal value of OID
+ * @name oidHexToInt
+ * @memberOf KJUR.asn1.ASN1Util
+ * @function
+ * @param {String} hex hexadecimal value of object identifier
+ * @return {String} dot noted string of object identifier
+ * @since jsrsasign 4.8.3 asn1 1.0.7
+ * @description
+ * This static method converts from hexadecimal string representation of
+ * ASN.1 value of object identifier to oid number string.
+ * @example
+ * KJUR.asn1.ASN1Util.oidHexToInt('550406') &rarr; "2.5.4.6"
+ */
+KJUR.asn1.ASN1Util.oidHexToInt = function(hex) {
+    var s = "";
+    var i01 = parseInt(hex.substr(0, 2), 16);
+    var i0 = Math.floor(i01 / 40);
+    var i1 = i01 % 40;
+    var s = i0 + "." + i1;
+
+    var binbuf = "";
+    for (var i = 2; i < hex.length; i += 2) {
+        var value = parseInt(hex.substr(i, 2), 16);
+        var bin = ("00000000" + value.toString(2)).slice(- 8);
+        binbuf = binbuf + bin.substr(1, 7);
+        if (bin.substr(0, 1) == "0") {
+            var bi = new BigInteger(binbuf, 2);
+            s = s + "." + bi.toString(10);
+            binbuf = "";
+        }
+    }
+    return s;
+};
+
+/**
+ * get hexadecimal value of object identifier from dot noted oid value
+ * @name oidIntToHex
+ * @memberOf KJUR.asn1.ASN1Util
+ * @function
+ * @param {String} oidString dot noted string of object identifier
+ * @return {String} hexadecimal value of object identifier
+ * @since jsrsasign 4.8.3 asn1 1.0.7
+ * @description
+ * This static method converts from object identifier value string.
+ * to hexadecimal string representation of it.
+ * @example
+ * KJUR.asn1.ASN1Util.oidIntToHex("2.5.4.6") &rarr; "550406"
+ */
+KJUR.asn1.ASN1Util.oidIntToHex = function(oidString) {
+    var itox = function(i) {
+        var h = i.toString(16);
+        if (h.length == 1) h = '0' + h;
+        return h;
+    };
+
+    var roidtox = function(roid) {
+        var h = '';
+        var bi = new BigInteger(roid, 10);
+        var b = bi.toString(2);
+        var padLen = 7 - b.length % 7;
+        if (padLen == 7) padLen = 0;
+        var bPad = '';
+        for (var i = 0; i < padLen; i++) bPad += '0';
+        b = bPad + b;
+        for (var i = 0; i < b.length - 1; i += 7) {
+            var b8 = b.substr(i, 7);
+            if (i != b.length - 7) b8 = '1' + b8;
+            h += itox(parseInt(b8, 2));
+        }
+        return h;
+    };
+
+    if (! oidString.match(/^[0-9.]+$/)) {
+        throw "malformed oid string: " + oidString;
+    }
+    var h = '';
+    var a = oidString.split('.');
+    var i0 = parseInt(a[0]) * 40 + parseInt(a[1]);
+    h += itox(i0);
+    a.splice(0, 2);
+    for (var i = 0; i < a.length; i++) {
+        h += roidtox(a[i]);
+    }
+    return h;
+};
+
+
+// ********************************************************************
+//  Abstract ASN.1 Classes
+// ********************************************************************
+
+// ********************************************************************
+
+/**
+ * base class for ASN.1 DER encoder object
+ * @name KJUR.asn1.ASN1Object
+ * @class base class for ASN.1 DER encoder object
+ * @property {Boolean} isModified flag whether internal data was changed
+ * @property {String} hTLV hexadecimal string of ASN.1 TLV
+ * @property {String} hT hexadecimal string of ASN.1 TLV tag(T)
+ * @property {String} hL hexadecimal string of ASN.1 TLV length(L)
+ * @property {String} hV hexadecimal string of ASN.1 TLV value(V)
+ * @description
+ */
+KJUR.asn1.ASN1Object = function() {
+    var hV = '';
+
+    /**
+     * get hexadecimal ASN.1 TLV length(L) bytes from TLV value(V)
+     * @name getLengthHexFromValue
+     * @memberOf KJUR.asn1.ASN1Object#
+     * @function
+     * @return {String} hexadecimal string of ASN.1 TLV length(L)
+     */
+    this.getLengthHexFromValue = function() {
+        if (typeof this.hV == "undefined" || this.hV == null) {
+            throw "this.hV is null or undefined.";
+        }
+        if (this.hV.length % 2 == 1) {
+            throw "value hex must be even length: n=" + hV.length + ",v=" + this.hV;
+        }
+        var n = this.hV.length / 2;
+        var hN = n.toString(16);
+        if (hN.length % 2 == 1) {
+            hN = "0" + hN;
+        }
+        if (n < 128) {
+            return hN;
+        } else {
+            var hNlen = hN.length / 2;
+            if (hNlen > 15) {
+                throw "ASN.1 length too long to represent by 8x: n = " + n.toString(16);
+            }
+            var head = 128 + hNlen;
+            return head.toString(16) + hN;
+        }
+    };
+
+    /**
+     * get hexadecimal string of ASN.1 TLV bytes
+     * @name getEncodedHex
+     * @memberOf KJUR.asn1.ASN1Object#
+     * @function
+     * @return {String} hexadecimal string of ASN.1 TLV
+     */
+    this.getEncodedHex = function() {
+        if (this.hTLV == null || this.isModified) {
+            this.hV = this.getFreshValueHex();
+            this.hL = this.getLengthHexFromValue();
+            this.hTLV = this.hT + this.hL + this.hV;
+            this.isModified = false;
+            //alert("first time: " + this.hTLV);
+        }
+        return this.hTLV;
+    };
+
+    /**
+     * get hexadecimal string of ASN.1 TLV value(V) bytes
+     * @name getValueHex
+     * @memberOf KJUR.asn1.ASN1Object#
+     * @function
+     * @return {String} hexadecimal string of ASN.1 TLV value(V) bytes
+     */
+    this.getValueHex = function() {
+        this.getEncodedHex();
+        return this.hV;
+    };
+
+    this.getFreshValueHex = function() {
+        return '';
+    };
+};
+
+// == BEGIN DERAbstractString ================================================
+/**
+ * base class for ASN.1 DER string classes
+ * @name KJUR.asn1.DERAbstractString
+ * @class base class for ASN.1 DER string classes
+ * @param {Array} params associative array of parameters (ex. {'str': 'aaa'})
+ * @property {String} s internal string of value
+ * @extends KJUR.asn1.ASN1Object
+ * @description
+ * <br/>
+ * As for argument 'params' for constructor, you can specify one of
+ * following properties:
+ * <ul>
+ * <li>str - specify initial ASN.1 value(V) by a string</li>
+ * <li>hex - specify initial ASN.1 value(V) by a hexadecimal string</li>
+ * </ul>
+ * NOTE: 'params' can be omitted.
+ */
+KJUR.asn1.DERAbstractString = function(params) {
+    KJUR.asn1.DERAbstractString.superclass.constructor.call(this);
+
+    /**
+     * get string value of this string object
+     * @name getString
+     * @memberOf KJUR.asn1.DERAbstractString#
+     * @function
+     * @return {String} string value of this string object
+     */
+    this.getString = function() {
+        return this.s;
+    };
+
+    /**
+     * set value by a string
+     * @name setString
+     * @memberOf KJUR.asn1.DERAbstractString#
+     * @function
+     * @param {String} newS value by a string to set
+     */
+    this.setString = function(newS) {
+        this.hTLV = null;
+        this.isModified = true;
+        this.s = newS;
+        this.hV = stohex(this.s);
+    };
+
+    /**
+     * set value by a hexadecimal string
+     * @name setStringHex
+     * @memberOf KJUR.asn1.DERAbstractString#
+     * @function
+     * @param {String} newHexString value by a hexadecimal string to set
+     */
+    this.setStringHex = function(newHexString) {
+        this.hTLV = null;
+        this.isModified = true;
+        this.s = null;
+        this.hV = newHexString;
+    };
+
+    this.getFreshValueHex = function() {
+        return this.hV;
+    };
+
+    if (typeof params != "undefined") {
+        if (typeof params == "string") {
+            this.setString(params);
+        } else if (typeof params['str'] != "undefined") {
+            this.setString(params['str']);
+        } else if (typeof params['hex'] != "undefined") {
+            this.setStringHex(params['hex']);
+        }
+    }
+};
+YAHOO.lang.extend(KJUR.asn1.DERAbstractString, KJUR.asn1.ASN1Object);
+// == END   DERAbstractString ================================================
+
+// == BEGIN DERAbstractTime ==================================================
+/**
+ * base class for ASN.1 DER Generalized/UTCTime class
+ * @name KJUR.asn1.DERAbstractTime
+ * @class base class for ASN.1 DER Generalized/UTCTime class
+ * @param {Array} params associative array of parameters (ex. {'str': '130430235959Z'})
+ * @extends KJUR.asn1.ASN1Object
+ * @description
+ * @see KJUR.asn1.ASN1Object - superclass
+ */
+KJUR.asn1.DERAbstractTime = function(params) {
+    KJUR.asn1.DERAbstractTime.superclass.constructor.call(this);
+
+    // --- PRIVATE METHODS --------------------
+    this.localDateToUTC = function(d) {
+        utc = d.getTime() + (d.getTimezoneOffset() * 60000);
+        var utcDate = new Date(utc);
+        return utcDate;
+    };
+
+    /*
+     * format date string by Data object
+     * @name formatDate
+     * @memberOf KJUR.asn1.AbstractTime;
+     * @param {Date} dateObject
+     * @param {string} type 'utc' or 'gen'
+     * @param {boolean} withMillis flag for with millisections or not
+     * @description
+     * 'withMillis' flag is supported from asn1 1.0.6.
+     */
+    this.formatDate = function(dateObject, type, withMillis) {
+        var pad = this.zeroPadding;
+        var d = this.localDateToUTC(dateObject);
+        var year = String(d.getFullYear());
+        if (type == 'utc') year = year.substr(2, 2);
+        var month = pad(String(d.getMonth() + 1), 2);
+        var day = pad(String(d.getDate()), 2);
+        var hour = pad(String(d.getHours()), 2);
+        var min = pad(String(d.getMinutes()), 2);
+        var sec = pad(String(d.getSeconds()), 2);
+        var s = year + month + day + hour + min + sec;
+        if (withMillis === true) {
+            var millis = d.getMilliseconds();
+            if (millis != 0) {
+                var sMillis = pad(String(millis), 3);
+                sMillis = sMillis.replace(/[0]+$/, "");
+                s = s + "." + sMillis;
+            }
+        }
+        return s + "Z";
+    };
+
+    this.zeroPadding = function(s, len) {
+        if (s.length >= len) return s;
+        return new Array(len - s.length + 1).join('0') + s;
+    };
+
+    // --- PUBLIC METHODS --------------------
+    /**
+     * get string value of this string object
+     * @name getString
+     * @memberOf KJUR.asn1.DERAbstractTime#
+     * @function
+     * @return {String} string value of this time object
+     */
+    this.getString = function() {
+        return this.s;
+    };
+
+    /**
+     * set value by a string
+     * @name setString
+     * @memberOf KJUR.asn1.DERAbstractTime#
+     * @function
+     * @param {String} newS value by a string to set such like "130430235959Z"
+     */
+    this.setString = function(newS) {
+        this.hTLV = null;
+        this.isModified = true;
+        this.s = newS;
+        this.hV = stohex(newS);
+    };
+
+    /**
+     * set value by a Date object
+     * @name setByDateValue
+     * @memberOf KJUR.asn1.DERAbstractTime#
+     * @function
+     * @param {Integer} year year of date (ex. 2013)
+     * @param {Integer} month month of date between 1 and 12 (ex. 12)
+     * @param {Integer} day day of month
+     * @param {Integer} hour hours of date
+     * @param {Integer} min minutes of date
+     * @param {Integer} sec seconds of date
+     */
+    this.setByDateValue = function(year, month, day, hour, min, sec) {
+        var dateObject = new Date(Date.UTC(year, month - 1, day, hour, min, sec, 0));
+        this.setByDate(dateObject);
+    };
+
+    this.getFreshValueHex = function() {
+        return this.hV;
+    };
+};
+YAHOO.lang.extend(KJUR.asn1.DERAbstractTime, KJUR.asn1.ASN1Object);
+// == END   DERAbstractTime ==================================================
+
+// == BEGIN DERAbstractStructured ============================================
+/**
+ * base class for ASN.1 DER structured class
+ * @name KJUR.asn1.DERAbstractStructured
+ * @class base class for ASN.1 DER structured class
+ * @property {Array} asn1Array internal array of ASN1Object
+ * @extends KJUR.asn1.ASN1Object
+ * @description
+ * @see KJUR.asn1.ASN1Object - superclass
+ */
+KJUR.asn1.DERAbstractStructured = function(params) {
+    KJUR.asn1.DERAbstractString.superclass.constructor.call(this);
+
+    /**
+     * set value by array of ASN1Object
+     * @name setByASN1ObjectArray
+     * @memberOf KJUR.asn1.DERAbstractStructured#
+     * @function
+     * @param {array} asn1ObjectArray array of ASN1Object to set
+     */
+    this.setByASN1ObjectArray = function(asn1ObjectArray) {
+        this.hTLV = null;
+        this.isModified = true;
+        this.asn1Array = asn1ObjectArray;
+    };
+
+    /**
+     * append an ASN1Object to internal array
+     * @name appendASN1Object
+     * @memberOf KJUR.asn1.DERAbstractStructured#
+     * @function
+     * @param {ASN1Object} asn1Object to add
+     */
+    this.appendASN1Object = function(asn1Object) {
+        this.hTLV = null;
+        this.isModified = true;
+        this.asn1Array.push(asn1Object);
+    };
+
+    this.asn1Array = new Array();
+    if (typeof params != "undefined") {
+        if (typeof params['array'] != "undefined") {
+            this.asn1Array = params['array'];
+        }
+    }
+};
+YAHOO.lang.extend(KJUR.asn1.DERAbstractStructured, KJUR.asn1.ASN1Object);
+
+
+// ********************************************************************
+//  ASN.1 Object Classes
+// ********************************************************************
+
+// ********************************************************************
+/**
+ * class for ASN.1 DER Boolean
+ * @name KJUR.asn1.DERBoolean
+ * @class class for ASN.1 DER Boolean
+ * @extends KJUR.asn1.ASN1Object
+ * @description
+ * @see KJUR.asn1.ASN1Object - superclass
+ */
+KJUR.asn1.DERBoolean = function() {
+    KJUR.asn1.DERBoolean.superclass.constructor.call(this);
+    this.hT = "01";
+    this.hTLV = "0101ff";
+};
+YAHOO.lang.extend(KJUR.asn1.DERBoolean, KJUR.asn1.ASN1Object);
+
+// ********************************************************************
+/**
+ * class for ASN.1 DER Integer
+ * @name KJUR.asn1.DERInteger
+ * @class class for ASN.1 DER Integer
+ * @extends KJUR.asn1.ASN1Object
+ * @description
+ * <br/>
+ * As for argument 'params' for constructor, you can specify one of
+ * following properties:
+ * <ul>
+ * <li>int - specify initial ASN.1 value(V) by integer value</li>
+ * <li>bigint - specify initial ASN.1 value(V) by BigInteger object</li>
+ * <li>hex - specify initial ASN.1 value(V) by a hexadecimal string</li>
+ * </ul>
+ * NOTE: 'params' can be omitted.
+ */
+KJUR.asn1.DERInteger = function(params) {
+    KJUR.asn1.DERInteger.superclass.constructor.call(this);
+    this.hT = "02";
+
+    /**
+     * set value by Tom Wu's BigInteger object
+     * @name setByBigInteger
+     * @memberOf KJUR.asn1.DERInteger#
+     * @function
+     * @param {BigInteger} bigIntegerValue to set
+     */
+    this.setByBigInteger = function(bigIntegerValue) {
+        this.hTLV = null;
+        this.isModified = true;
+        this.hV = KJUR.asn1.ASN1Util.bigIntToMinTwosComplementsHex(bigIntegerValue);
+    };
+
+    /**
+     * set value by integer value
+     * @name setByInteger
+     * @memberOf KJUR.asn1.DERInteger
+     * @function
+     * @param {Integer} integer value to set
+     */
+    this.setByInteger = function(intValue) {
+        var bi = new BigInteger(String(intValue), 10);
+        this.setByBigInteger(bi);
+    };
+
+    /**
+     * set value by integer value
+     * @name setValueHex
+     * @memberOf KJUR.asn1.DERInteger#
+     * @function
+     * @param {String} hexadecimal string of integer value
+     * @description
+     * <br/>
+     * NOTE: Value shall be represented by minimum octet length of
+     * two's complement representation.
+     * @example
+     * new KJUR.asn1.DERInteger(123);
+     * new KJUR.asn1.DERInteger({'int': 123});
+     * new KJUR.asn1.DERInteger({'hex': '1fad'});
+     */
+    this.setValueHex = function(newHexString) {
+        this.hV = newHexString;
+    };
+
+    this.getFreshValueHex = function() {
+        return this.hV;
+    };
+
+    if (typeof params != "undefined") {
+        if (typeof params['bigint'] != "undefined") {
+            this.setByBigInteger(params['bigint']);
+        } else if (typeof params['int'] != "undefined") {
+            this.setByInteger(params['int']);
+        } else if (typeof params == "number") {
+            this.setByInteger(params);
+        } else if (typeof params['hex'] != "undefined") {
+            this.setValueHex(params['hex']);
+        }
+    }
+};
+YAHOO.lang.extend(KJUR.asn1.DERInteger, KJUR.asn1.ASN1Object);
+
+// ********************************************************************
+/**
+ * class for ASN.1 DER encoded BitString primitive
+ * @name KJUR.asn1.DERBitString
+ * @class class for ASN.1 DER encoded BitString primitive
+ * @extends KJUR.asn1.ASN1Object
+ * @description
+ * <br/>
+ * As for argument 'params' for constructor, you can specify one of
+ * following properties:
+ * <ul>
+ * <li>bin - specify binary string (ex. '10111')</li>
+ * <li>array - specify array of boolean (ex. [true,false,true,true])</li>
+ * <li>hex - specify hexadecimal string of ASN.1 value(V) including unused bits</li>
+ * <li>obj - specify {@link KJUR.asn1.ASN1Util.newObject}
+ * argument for "BitString encapsulates" structure.</li>
+ * </ul>
+ * NOTE1: 'params' can be omitted.<br/>
+ * NOTE2: 'obj' parameter have been supported since
+ * asn1 1.0.11, jsrsasign 6.1.1 (2016-Sep-25).<br/>
+ * @example
+ * // default constructor
+ * o = new KJUR.asn1.DERBitString();
+ * // initialize with binary string
+ * o = new KJUR.asn1.DERBitString({bin: "1011"});
+ * // initialize with boolean array
+ * o = new KJUR.asn1.DERBitString({array: [true,false,true,true]});
+ * // initialize with hexadecimal string (04 is unused bits)
+ * o = new KJUR.asn1.DEROctetString({hex: "04bac0"});
+ * // initialize with ASN1Util.newObject argument for encapsulated
+ * o = new KJUR.asn1.DERBitString({obj: {seq: [{int: 3}, {prnstr: 'aaa'}]}});
+ * // above generates a ASN.1 data like this:
+ * // BIT STRING, encapsulates {
+ * //   SEQUENCE {
+ * //     INTEGER 3
+ * //     PrintableString 'aaa'
+ * //     }
+ * //   }
+ */
+KJUR.asn1.DERBitString = function(params) {
+    if (params !== undefined && typeof params.obj !== "undefined") {
+        var o = KJUR.asn1.ASN1Util.newObject(params.obj);
+        params.hex = "00" + o.getEncodedHex();
+    }
+    KJUR.asn1.DERBitString.superclass.constructor.call(this);
+    this.hT = "03";
+
+    /**
+     * set ASN.1 value(V) by a hexadecimal string including unused bits
+     * @name setHexValueIncludingUnusedBits
+     * @memberOf KJUR.asn1.DERBitString#
+     * @function
+     * @param {String} newHexStringIncludingUnusedBits
+     */
+    this.setHexValueIncludingUnusedBits = function(newHexStringIncludingUnusedBits) {
+        this.hTLV = null;
+        this.isModified = true;
+        this.hV = newHexStringIncludingUnusedBits;
+    };
+
+    /**
+     * set ASN.1 value(V) by unused bit and hexadecimal string of value
+     * @name setUnusedBitsAndHexValue
+     * @memberOf KJUR.asn1.DERBitString#
+     * @function
+     * @param {Integer} unusedBits
+     * @param {String} hValue
+     */
+    this.setUnusedBitsAndHexValue = function(unusedBits, hValue) {
+        if (unusedBits < 0 || 7 < unusedBits) {
+            throw "unused bits shall be from 0 to 7: u = " + unusedBits;
+        }
+        var hUnusedBits = "0" + unusedBits;
+        this.hTLV = null;
+        this.isModified = true;
+        this.hV = hUnusedBits + hValue;
+    };
+
+    /**
+     * set ASN.1 DER BitString by binary string<br/>
+     * @name setByBinaryString
+     * @memberOf KJUR.asn1.DERBitString#
+     * @function
+     * @param {String} binaryString binary value string (i.e. '10111')
+     * @description
+     * Its unused bits will be calculated automatically by length of
+     * 'binaryValue'. <br/>
+     * NOTE: Trailing zeros '0' will be ignored.
+     * @example
+     * o = new KJUR.asn1.DERBitString();
+     * o.setByBooleanArray("01011");
+     */
+    this.setByBinaryString = function(binaryString) {
+        binaryString = binaryString.replace(/0+$/, '');
+        var unusedBits = 8 - binaryString.length % 8;
+        if (unusedBits == 8) unusedBits = 0;
+        for (var i = 0; i <= unusedBits; i++) {
+            binaryString += '0';
+        }
+        var h = '';
+        for (var i = 0; i < binaryString.length - 1; i += 8) {
+            var b = binaryString.substr(i, 8);
+            var x = parseInt(b, 2).toString(16);
+            if (x.length == 1) x = '0' + x;
+            h += x;
+        }
+        this.hTLV = null;
+        this.isModified = true;
+        this.hV = '0' + unusedBits + h;
+    };
+
+    /**
+     * set ASN.1 TLV value(V) by an array of boolean<br/>
+     * @name setByBooleanArray
+     * @memberOf KJUR.asn1.DERBitString#
+     * @function
+     * @param {array} booleanArray array of boolean (ex. [true, false, true])
+     * @description
+     * NOTE: Trailing falses will be ignored in the ASN.1 DER Object.
+     * @example
+     * o = new KJUR.asn1.DERBitString();
+     * o.setByBooleanArray([false, true, false, true, true]);
+     */
+    this.setByBooleanArray = function(booleanArray) {
+        var s = '';
+        for (var i = 0; i < booleanArray.length; i++) {
+            if (booleanArray[i] == true) {
+                s += '1';
+            } else {
+                s += '0';
+            }
+        }
+        this.setByBinaryString(s);
+    };
+
+    /**
+     * generate an array of falses with specified length<br/>
+     * @name newFalseArray
+     * @memberOf KJUR.asn1.DERBitString
+     * @function
+     * @param {Integer} nLength length of array to generate
+     * @return {array} array of boolean falses
+     * @description
+     * This static method may be useful to initialize boolean array.
+     * @example
+     * o = new KJUR.asn1.DERBitString();
+     * o.newFalseArray(3) &rarr; [false, false, false]
+     */
+    this.newFalseArray = function(nLength) {
+        var a = new Array(nLength);
+        for (var i = 0; i < nLength; i++) {
+            a[i] = false;
+        }
+        return a;
+    };
+
+    this.getFreshValueHex = function() {
+        return this.hV;
+    };
+
+    if (typeof params != "undefined") {
+        if (typeof params == "string" && params.toLowerCase().match(/^[0-9a-f]+$/)) {
+            this.setHexValueIncludingUnusedBits(params);
+        } else if (typeof params['hex'] != "undefined") {
+            this.setHexValueIncludingUnusedBits(params['hex']);
+        } else if (typeof params['bin'] != "undefined") {
+            this.setByBinaryString(params['bin']);
+        } else if (typeof params['array'] != "undefined") {
+            this.setByBooleanArray(params['array']);
+        }
+    }
+};
+YAHOO.lang.extend(KJUR.asn1.DERBitString, KJUR.asn1.ASN1Object);
+
+// ********************************************************************
+/**
+ * class for ASN.1 DER OctetString<br/>
+ * @name KJUR.asn1.DEROctetString
+ * @class class for ASN.1 DER OctetString
+ * @param {Array} params associative array of parameters (ex. {'str': 'aaa'})
+ * @extends KJUR.asn1.DERAbstractString
+ * @description
+ * This class provides ASN.1 OctetString simple type.<br/>
+ * Supported "params" attributes are:
+ * <ul>
+ * <li>str - to set a string as a value</li>
+ * <li>hex - to set a hexadecimal string as a value</li>
+ * <li>obj - to set a encapsulated ASN.1 value by JSON object
+ * which is defined in {@link KJUR.asn1.ASN1Util.newObject}</li>
+ * </ul>
+ * NOTE: A parameter 'obj' have been supported
+ * for "OCTET STRING, encapsulates" structure.
+ * since asn1 1.0.11, jsrsasign 6.1.1 (2016-Sep-25).
+ * @see KJUR.asn1.DERAbstractString - superclass
+ * @example
+ * // default constructor
+ * o = new KJUR.asn1.DEROctetString();
+ * // initialize with string
+ * o = new KJUR.asn1.DEROctetString({str: "aaa"});
+ * // initialize with hexadecimal string
+ * o = new KJUR.asn1.DEROctetString({hex: "616161"});
+ * // initialize with ASN1Util.newObject argument
+ * o = new KJUR.asn1.DEROctetString({obj: {seq: [{int: 3}, {prnstr: 'aaa'}]}});
+ * // above generates a ASN.1 data like this:
+ * // OCTET STRING, encapsulates {
+ * //   SEQUENCE {
+ * //     INTEGER 3
+ * //     PrintableString 'aaa'
+ * //     }
+ * //   }
+ */
+KJUR.asn1.DEROctetString = function(params) {
+    if (params !== undefined && typeof params.obj !== "undefined") {
+        var o = KJUR.asn1.ASN1Util.newObject(params.obj);
+        params.hex = o.getEncodedHex();
+    }
+    KJUR.asn1.DEROctetString.superclass.constructor.call(this, params);
+    this.hT = "04";
+};
+YAHOO.lang.extend(KJUR.asn1.DEROctetString, KJUR.asn1.DERAbstractString);
+
+// ********************************************************************
+/**
+ * class for ASN.1 DER Null
+ * @name KJUR.asn1.DERNull
+ * @class class for ASN.1 DER Null
+ * @extends KJUR.asn1.ASN1Object
+ * @description
+ * @see KJUR.asn1.ASN1Object - superclass
+ */
+KJUR.asn1.DERNull = function() {
+    KJUR.asn1.DERNull.superclass.constructor.call(this);
+    this.hT = "05";
+    this.hTLV = "0500";
+};
+YAHOO.lang.extend(KJUR.asn1.DERNull, KJUR.asn1.ASN1Object);
+
+// ********************************************************************
+/**
+ * class for ASN.1 DER ObjectIdentifier
+ * @name KJUR.asn1.DERObjectIdentifier
+ * @class class for ASN.1 DER ObjectIdentifier
+ * @param {Array} params associative array of parameters (ex. {'oid': '2.5.4.5'})
+ * @extends KJUR.asn1.ASN1Object
+ * @description
+ * <br/>
+ * As for argument 'params' for constructor, you can specify one of
+ * following properties:
+ * <ul>
+ * <li>oid - specify initial ASN.1 value(V) by a oid string (ex. 2.5.4.13)</li>
+ * <li>hex - specify initial ASN.1 value(V) by a hexadecimal string</li>
+ * </ul>
+ * NOTE: 'params' can be omitted.
+ */
+KJUR.asn1.DERObjectIdentifier = function(params) {
+    var itox = function(i) {
+        var h = i.toString(16);
+        if (h.length == 1) h = '0' + h;
+        return h;
+    };
+    var roidtox = function(roid) {
+        var h = '';
+        var bi = new BigInteger(roid, 10);
+        var b = bi.toString(2);
+        var padLen = 7 - b.length % 7;
+        if (padLen == 7) padLen = 0;
+        var bPad = '';
+        for (var i = 0; i < padLen; i++) bPad += '0';
+        b = bPad + b;
+        for (var i = 0; i < b.length - 1; i += 7) {
+            var b8 = b.substr(i, 7);
+            if (i != b.length - 7) b8 = '1' + b8;
+            h += itox(parseInt(b8, 2));
+        }
+        return h;
+    };
+
+    KJUR.asn1.DERObjectIdentifier.superclass.constructor.call(this);
+    this.hT = "06";
+
+    /**
+     * set value by a hexadecimal string
+     * @name setValueHex
+     * @memberOf KJUR.asn1.DERObjectIdentifier#
+     * @function
+     * @param {String} newHexString hexadecimal value of OID bytes
+     */
+    this.setValueHex = function(newHexString) {
+        this.hTLV = null;
+        this.isModified = true;
+        this.s = null;
+        this.hV = newHexString;
+    };
+
+    /**
+     * set value by a OID string<br/>
+     * @name setValueOidString
+     * @memberOf KJUR.asn1.DERObjectIdentifier#
+     * @function
+     * @param {String} oidString OID string (ex. 2.5.4.13)
+     * @example
+     * o = new KJUR.asn1.DERObjectIdentifier();
+     * o.setValueOidString("2.5.4.13");
+     */
+    this.setValueOidString = function(oidString) {
+        if (! oidString.match(/^[0-9.]+$/)) {
+            throw "malformed oid string: " + oidString;
+        }
+        var h = '';
+        var a = oidString.split('.');
+        var i0 = parseInt(a[0]) * 40 + parseInt(a[1]);
+        h += itox(i0);
+        a.splice(0, 2);
+        for (var i = 0; i < a.length; i++) {
+            h += roidtox(a[i]);
+        }
+        this.hTLV = null;
+        this.isModified = true;
+        this.s = null;
+        this.hV = h;
+    };
+
+    /**
+     * set value by a OID name
+     * @name setValueName
+     * @memberOf KJUR.asn1.DERObjectIdentifier#
+     * @function
+     * @param {String} oidName OID name (ex. 'serverAuth')
+     * @since 1.0.1
+     * @description
+     * OID name shall be defined in 'KJUR.asn1.x509.OID.name2oidList'.
+     * Otherwise raise error.
+     * @example
+     * o = new KJUR.asn1.DERObjectIdentifier();
+     * o.setValueName("serverAuth");
+     */
+    this.setValueName = function(oidName) {
+        var oid = KJUR.asn1.x509.OID.name2oid(oidName);
+        if (oid !== '') {
+            this.setValueOidString(oid);
+        } else {
+            throw "DERObjectIdentifier oidName undefined: " + oidName;
+        }
+    };
+
+    this.getFreshValueHex = function() {
+        return this.hV;
+    };
+
+    if (params !== undefined) {
+        if (typeof params === "string") {
+            if (params.match(/^[0-2].[0-9.]+$/)) {
+                this.setValueOidString(params);
+            } else {
+                this.setValueName(params);
+            }
+        } else if (params.oid !== undefined) {
+            this.setValueOidString(params.oid);
+        } else if (params.hex !== undefined) {
+            this.setValueHex(params.hex);
+        } else if (params.name !== undefined) {
+            this.setValueName(params.name);
+        }
+    }
+};
+YAHOO.lang.extend(KJUR.asn1.DERObjectIdentifier, KJUR.asn1.ASN1Object);
+
+// ********************************************************************
+/**
+ * class for ASN.1 DER Enumerated
+ * @name KJUR.asn1.DEREnumerated
+ * @class class for ASN.1 DER Enumerated
+ * @extends KJUR.asn1.ASN1Object
+ * @description
+ * <br/>
+ * As for argument 'params' for constructor, you can specify one of
+ * following properties:
+ * <ul>
+ * <li>int - specify initial ASN.1 value(V) by integer value</li>
+ * <li>hex - specify initial ASN.1 value(V) by a hexadecimal string</li>
+ * </ul>
+ * NOTE: 'params' can be omitted.
+ * @example
+ * new KJUR.asn1.DEREnumerated(123);
+ * new KJUR.asn1.DEREnumerated({int: 123});
+ * new KJUR.asn1.DEREnumerated({hex: '1fad'});
+ */
+KJUR.asn1.DEREnumerated = function(params) {
+    KJUR.asn1.DEREnumerated.superclass.constructor.call(this);
+    this.hT = "0a";
+
+    /**
+     * set value by Tom Wu's BigInteger object
+     * @name setByBigInteger
+     * @memberOf KJUR.asn1.DEREnumerated#
+     * @function
+     * @param {BigInteger} bigIntegerValue to set
+     */
+    this.setByBigInteger = function(bigIntegerValue) {
+        this.hTLV = null;
+        this.isModified = true;
+        this.hV = KJUR.asn1.ASN1Util.bigIntToMinTwosComplementsHex(bigIntegerValue);
+    };
+
+    /**
+     * set value by integer value
+     * @name setByInteger
+     * @memberOf KJUR.asn1.DEREnumerated#
+     * @function
+     * @param {Integer} integer value to set
+     */
+    this.setByInteger = function(intValue) {
+        var bi = new BigInteger(String(intValue), 10);
+        this.setByBigInteger(bi);
+    };
+
+    /**
+     * set value by integer value
+     * @name setValueHex
+     * @memberOf KJUR.asn1.DEREnumerated#
+     * @function
+     * @param {String} hexadecimal string of integer value
+     * @description
+     * <br/>
+     * NOTE: Value shall be represented by minimum octet length of
+     * two's complement representation.
+     */
+    this.setValueHex = function(newHexString) {
+        this.hV = newHexString;
+    };
+
+    this.getFreshValueHex = function() {
+        return this.hV;
+    };
+
+    if (typeof params != "undefined") {
+        if (typeof params['int'] != "undefined") {
+            this.setByInteger(params['int']);
+        } else if (typeof params == "number") {
+            this.setByInteger(params);
+        } else if (typeof params['hex'] != "undefined") {
+            this.setValueHex(params['hex']);
+        }
+    }
+};
+YAHOO.lang.extend(KJUR.asn1.DEREnumerated, KJUR.asn1.ASN1Object);
+
+// ********************************************************************
+/**
+ * class for ASN.1 DER UTF8String
+ * @name KJUR.asn1.DERUTF8String
+ * @class class for ASN.1 DER UTF8String
+ * @param {Array} params associative array of parameters (ex. {'str': 'aaa'})
+ * @extends KJUR.asn1.DERAbstractString
+ * @description
+ * @see KJUR.asn1.DERAbstractString - superclass
+ */
+KJUR.asn1.DERUTF8String = function(params) {
+    KJUR.asn1.DERUTF8String.superclass.constructor.call(this, params);
+    this.hT = "0c";
+};
+YAHOO.lang.extend(KJUR.asn1.DERUTF8String, KJUR.asn1.DERAbstractString);
+
+// ********************************************************************
+/**
+ * class for ASN.1 DER NumericString
+ * @name KJUR.asn1.DERNumericString
+ * @class class for ASN.1 DER NumericString
+ * @param {Array} params associative array of parameters (ex. {'str': 'aaa'})
+ * @extends KJUR.asn1.DERAbstractString
+ * @description
+ * @see KJUR.asn1.DERAbstractString - superclass
+ */
+KJUR.asn1.DERNumericString = function(params) {
+    KJUR.asn1.DERNumericString.superclass.constructor.call(this, params);
+    this.hT = "12";
+};
+YAHOO.lang.extend(KJUR.asn1.DERNumericString, KJUR.asn1.DERAbstractString);
+
+// ********************************************************************
+/**
+ * class for ASN.1 DER PrintableString
+ * @name KJUR.asn1.DERPrintableString
+ * @class class for ASN.1 DER PrintableString
+ * @param {Array} params associative array of parameters (ex. {'str': 'aaa'})
+ * @extends KJUR.asn1.DERAbstractString
+ * @description
+ * @see KJUR.asn1.DERAbstractString - superclass
+ */
+KJUR.asn1.DERPrintableString = function(params) {
+    KJUR.asn1.DERPrintableString.superclass.constructor.call(this, params);
+    this.hT = "13";
+};
+YAHOO.lang.extend(KJUR.asn1.DERPrintableString, KJUR.asn1.DERAbstractString);
+
+// ********************************************************************
+/**
+ * class for ASN.1 DER TeletexString
+ * @name KJUR.asn1.DERTeletexString
+ * @class class for ASN.1 DER TeletexString
+ * @param {Array} params associative array of parameters (ex. {'str': 'aaa'})
+ * @extends KJUR.asn1.DERAbstractString
+ * @description
+ * @see KJUR.asn1.DERAbstractString - superclass
+ */
+KJUR.asn1.DERTeletexString = function(params) {
+    KJUR.asn1.DERTeletexString.superclass.constructor.call(this, params);
+    this.hT = "14";
+};
+YAHOO.lang.extend(KJUR.asn1.DERTeletexString, KJUR.asn1.DERAbstractString);
+
+// ********************************************************************
+/**
+ * class for ASN.1 DER IA5String
+ * @name KJUR.asn1.DERIA5String
+ * @class class for ASN.1 DER IA5String
+ * @param {Array} params associative array of parameters (ex. {'str': 'aaa'})
+ * @extends KJUR.asn1.DERAbstractString
+ * @description
+ * @see KJUR.asn1.DERAbstractString - superclass
+ */
+KJUR.asn1.DERIA5String = function(params) {
+    KJUR.asn1.DERIA5String.superclass.constructor.call(this, params);
+    this.hT = "16";
+};
+YAHOO.lang.extend(KJUR.asn1.DERIA5String, KJUR.asn1.DERAbstractString);
+
+// ********************************************************************
+/**
+ * class for ASN.1 DER UTCTime
+ * @name KJUR.asn1.DERUTCTime
+ * @class class for ASN.1 DER UTCTime
+ * @param {Array} params associative array of parameters (ex. {'str': '130430235959Z'})
+ * @extends KJUR.asn1.DERAbstractTime
+ * @description
+ * <br/>
+ * As for argument 'params' for constructor, you can specify one of
+ * following properties:
+ * <ul>
+ * <li>str - specify initial ASN.1 value(V) by a string (ex.'130430235959Z')</li>
+ * <li>hex - specify initial ASN.1 value(V) by a hexadecimal string</li>
+ * <li>date - specify Date object.</li>
+ * </ul>
+ * NOTE: 'params' can be omitted.
+ * <h4>EXAMPLES</h4>
+ * @example
+ * d1 = new KJUR.asn1.DERUTCTime();
+ * d1.setString('130430125959Z');
+ *
+ * d2 = new KJUR.asn1.DERUTCTime({'str': '130430125959Z'});
+ * d3 = new KJUR.asn1.DERUTCTime({'date': new Date(Date.UTC(2015, 0, 31, 0, 0, 0, 0))});
+ * d4 = new KJUR.asn1.DERUTCTime('130430125959Z');
+ */
+KJUR.asn1.DERUTCTime = function(params) {
+    KJUR.asn1.DERUTCTime.superclass.constructor.call(this, params);
+    this.hT = "17";
+
+    /**
+     * set value by a Date object<br/>
+     * @name setByDate
+     * @memberOf KJUR.asn1.DERUTCTime#
+     * @function
+     * @param {Date} dateObject Date object to set ASN.1 value(V)
+     * @example
+     * o = new KJUR.asn1.DERUTCTime();
+     * o.setByDate(new Date("2016/12/31"));
+     */
+    this.setByDate = function(dateObject) {
+        this.hTLV = null;
+        this.isModified = true;
+        this.date = dateObject;
+        this.s = this.formatDate(this.date, 'utc');
+        this.hV = stohex(this.s);
+    };
+
+    this.getFreshValueHex = function() {
+        if (typeof this.date == "undefined" && typeof this.s == "undefined") {
+            this.date = new Date();
+            this.s = this.formatDate(this.date, 'utc');
+            this.hV = stohex(this.s);
+        }
+        return this.hV;
+    };
+
+    if (params !== undefined) {
+        if (params.str !== undefined) {
+            this.setString(params.str);
+        } else if (typeof params == "string" && params.match(/^[0-9]{12}Z$/)) {
+            this.setString(params);
+        } else if (params.hex !== undefined) {
+            this.setStringHex(params.hex);
+        } else if (params.date !== undefined) {
+            this.setByDate(params.date);
+        }
+    }
+};
+YAHOO.lang.extend(KJUR.asn1.DERUTCTime, KJUR.asn1.DERAbstractTime);
+
+// ********************************************************************
+/**
+ * class for ASN.1 DER GeneralizedTime
+ * @name KJUR.asn1.DERGeneralizedTime
+ * @class class for ASN.1 DER GeneralizedTime
+ * @param {Array} params associative array of parameters (ex. {'str': '20130430235959Z'})
+ * @property {Boolean} withMillis flag to show milliseconds or not
+ * @extends KJUR.asn1.DERAbstractTime
+ * @description
+ * <br/>
+ * As for argument 'params' for constructor, you can specify one of
+ * following properties:
+ * <ul>
+ * <li>str - specify initial ASN.1 value(V) by a string (ex.'20130430235959Z')</li>
+ * <li>hex - specify initial ASN.1 value(V) by a hexadecimal string</li>
+ * <li>date - specify Date object.</li>
+ * <li>millis - specify flag to show milliseconds (from 1.0.6)</li>
+ * </ul>
+ * NOTE1: 'params' can be omitted.
+ * NOTE2: 'withMillis' property is supported from asn1 1.0.6.
+ */
+KJUR.asn1.DERGeneralizedTime = function(params) {
+    KJUR.asn1.DERGeneralizedTime.superclass.constructor.call(this, params);
+    this.hT = "18";
+    this.withMillis = false;
+
+    /**
+     * set value by a Date object
+     * @name setByDate
+     * @memberOf KJUR.asn1.DERGeneralizedTime#
+     * @function
+     * @param {Date} dateObject Date object to set ASN.1 value(V)
+     * @example
+     * When you specify UTC time, use 'Date.UTC' method like this:<br/>
+     * o1 = new DERUTCTime();
+     * o1.setByDate(date);
+     *
+     * date = new Date(Date.UTC(2015, 0, 31, 23, 59, 59, 0)); #2015JAN31 23:59:59
+     */
+    this.setByDate = function(dateObject) {
+        this.hTLV = null;
+        this.isModified = true;
+        this.date = dateObject;
+        this.s = this.formatDate(this.date, 'gen', this.withMillis);
+        this.hV = stohex(this.s);
+    };
+
+    this.getFreshValueHex = function() {
+        if (this.date === undefined && this.s === undefined) {
+            this.date = new Date();
+            this.s = this.formatDate(this.date, 'gen', this.withMillis);
+            this.hV = stohex(this.s);
+        }
+        return this.hV;
+    };
+
+    if (params !== undefined) {
+        if (params.str !== undefined) {
+            this.setString(params.str);
+        } else if (typeof params == "string" && params.match(/^[0-9]{14}Z$/)) {
+            this.setString(params);
+        } else if (params.hex !== undefined) {
+            this.setStringHex(params.hex);
+        } else if (params.date !== undefined) {
+            this.setByDate(params.date);
+        }
+        if (params.millis === true) {
+            this.withMillis = true;
+        }
+    }
+};
+YAHOO.lang.extend(KJUR.asn1.DERGeneralizedTime, KJUR.asn1.DERAbstractTime);
+
+// ********************************************************************
+/**
+ * class for ASN.1 DER Sequence
+ * @name KJUR.asn1.DERSequence
+ * @class class for ASN.1 DER Sequence
+ * @extends KJUR.asn1.DERAbstractStructured
+ * @description
+ * <br/>
+ * As for argument 'params' for constructor, you can specify one of
+ * following properties:
+ * <ul>
+ * <li>array - specify array of ASN1Object to set elements of content</li>
+ * </ul>
+ * NOTE: 'params' can be omitted.
+ */
+KJUR.asn1.DERSequence = function(params) {
+    KJUR.asn1.DERSequence.superclass.constructor.call(this, params);
+    this.hT = "30";
+    this.getFreshValueHex = function() {
+        var h = '';
+        for (var i = 0; i < this.asn1Array.length; i++) {
+            var asn1Obj = this.asn1Array[i];
+            h += asn1Obj.getEncodedHex();
+        }
+        this.hV = h;
+        return this.hV;
+    };
+};
+YAHOO.lang.extend(KJUR.asn1.DERSequence, KJUR.asn1.DERAbstractStructured);
+
+// ********************************************************************
+/**
+ * class for ASN.1 DER Set
+ * @name KJUR.asn1.DERSet
+ * @class class for ASN.1 DER Set
+ * @extends KJUR.asn1.DERAbstractStructured
+ * @description
+ * <br/>
+ * As for argument 'params' for constructor, you can specify one of
+ * following properties:
+ * <ul>
+ * <li>array - specify array of ASN1Object to set elements of content</li>
+ * <li>sortflag - flag for sort (default: true). ASN.1 BER is not sorted in 'SET OF'.</li>
+ * </ul>
+ * NOTE1: 'params' can be omitted.<br/>
+ * NOTE2: sortflag is supported since 1.0.5.
+ */
+KJUR.asn1.DERSet = function(params) {
+    KJUR.asn1.DERSet.superclass.constructor.call(this, params);
+    this.hT = "31";
+    this.sortFlag = true; // item shall be sorted only in ASN.1 DER
+    this.getFreshValueHex = function() {
+        var a = new Array();
+        for (var i = 0; i < this.asn1Array.length; i++) {
+            var asn1Obj = this.asn1Array[i];
+            a.push(asn1Obj.getEncodedHex());
+        }
+        if (this.sortFlag == true) a.sort();
+        this.hV = a.join('');
+        return this.hV;
+    };
+
+    if (typeof params != "undefined") {
+        if (typeof params.sortflag != "undefined" &&
+            params.sortflag == false)
+            this.sortFlag = false;
+    }
+};
+YAHOO.lang.extend(KJUR.asn1.DERSet, KJUR.asn1.DERAbstractStructured);
+
+// ********************************************************************
+/**
+ * class for ASN.1 DER TaggedObject
+ * @name KJUR.asn1.DERTaggedObject
+ * @class class for ASN.1 DER TaggedObject
+ * @extends KJUR.asn1.ASN1Object
+ * @description
+ * <br/>
+ * Parameter 'tagNoNex' is ASN.1 tag(T) value for this object.
+ * For example, if you find '[1]' tag in a ASN.1 dump,
+ * 'tagNoHex' will be 'a1'.
+ * <br/>
+ * As for optional argument 'params' for constructor, you can specify *ANY* of
+ * following properties:
+ * <ul>
+ * <li>explicit - specify true if this is explicit tag otherwise false
+ *     (default is 'true').</li>
+ * <li>tag - specify tag (default is 'a0' which means [0])</li>
+ * <li>obj - specify ASN1Object which is tagged</li>
+ * </ul>
+ * @example
+ * d1 = new KJUR.asn1.DERUTF8String({'str':'a'});
+ * d2 = new KJUR.asn1.DERTaggedObject({'obj': d1});
+ * hex = d2.getEncodedHex();
+ */
+KJUR.asn1.DERTaggedObject = function(params) {
+    KJUR.asn1.DERTaggedObject.superclass.constructor.call(this);
+    this.hT = "a0";
+    this.hV = '';
+    this.isExplicit = true;
+    this.asn1Object = null;
+
+    /**
+     * set value by an ASN1Object
+     * @name setString
+     * @memberOf KJUR.asn1.DERTaggedObject#
+     * @function
+     * @param {Boolean} isExplicitFlag flag for explicit/implicit tag
+     * @param {Integer} tagNoHex hexadecimal string of ASN.1 tag
+     * @param {ASN1Object} asn1Object ASN.1 to encapsulate
+     */
+    this.setASN1Object = function(isExplicitFlag, tagNoHex, asn1Object) {
+        this.hT = tagNoHex;
+        this.isExplicit = isExplicitFlag;
+        this.asn1Object = asn1Object;
+        if (this.isExplicit) {
+            this.hV = this.asn1Object.getEncodedHex();
+            this.hTLV = null;
+            this.isModified = true;
+        } else {
+            this.hV = null;
+            this.hTLV = asn1Object.getEncodedHex();
+            this.hTLV = this.hTLV.replace(/^../, tagNoHex);
+            this.isModified = false;
+        }
+    };
+
+    this.getFreshValueHex = function() {
+        return this.hV;
+    };
+
+    if (typeof params != "undefined") {
+        if (typeof params['tag'] != "undefined") {
+            this.hT = params['tag'];
+        }
+        if (typeof params['explicit'] != "undefined") {
+            this.isExplicit = params['explicit'];
+        }
+        if (typeof params['obj'] != "undefined") {
+            this.asn1Object = params['obj'];
+            this.setASN1Object(this.isExplicit, this.hT, this.asn1Object);
+        }
+    }
+};
+YAHOO.lang.extend(KJUR.asn1.DERTaggedObject, KJUR.asn1.ASN1Object);
+
+/**
+ * Create a new JSEncryptRSAKey that extends Tom Wu's RSA key object.
+ * This object is just a decorator for parsing the key parameter
+ * @param {string|Object} key - The key in string format, or an object containing
+ * the parameters needed to build a RSAKey object.
+ * @constructor
+ */
+var JSEncryptRSAKey = /** @class */ (function (_super) {
+    __extends(JSEncryptRSAKey, _super);
+    function JSEncryptRSAKey(key) {
+        var _this = _super.call(this) || this;
+        // Call the super constructor.
+        //  RSAKey.call(this);
+        // If a key key was provided.
+        if (key) {
+            // If this is a string...
+            if (typeof key === "string") {
+                _this.parseKey(key);
+            }
+            else if (JSEncryptRSAKey.hasPrivateKeyProperty(key) ||
+                JSEncryptRSAKey.hasPublicKeyProperty(key)) {
+                // Set the values for the key.
+                _this.parsePropertiesFrom(key);
+            }
+        }
+        return _this;
+    }
+    /**
+     * Method to parse a pem encoded string containing both a public or private key.
+     * The method will translate the pem encoded string in a der encoded string and
+     * will parse private key and public key parameters. This method accepts public key
+     * in the rsaencryption pkcs #1 format (oid: 1.2.840.113549.1.1.1).
+     *
+     * @todo Check how many rsa formats use the same format of pkcs #1.
+     *
+     * The format is defined as:
+     * PublicKeyInfo ::= SEQUENCE {
+     *   algorithm       AlgorithmIdentifier,
+     *   PublicKey       BIT STRING
+     * }
+     * Where AlgorithmIdentifier is:
+     * AlgorithmIdentifier ::= SEQUENCE {
+     *   algorithm       OBJECT IDENTIFIER,     the OID of the enc algorithm
+     *   parameters      ANY DEFINED BY algorithm OPTIONAL (NULL for PKCS #1)
+     * }
+     * and PublicKey is a SEQUENCE encapsulated in a BIT STRING
+     * RSAPublicKey ::= SEQUENCE {
+     *   modulus           INTEGER,  -- n
+     *   publicExponent    INTEGER   -- e
+     * }
+     * it's possible to examine the structure of the keys obtained from openssl using
+     * an asn.1 dumper as the one used here to parse the components: http://lapo.it/asn1js/
+     * @argument {string} pem the pem encoded string, can include the BEGIN/END header/footer
+     * @private
+     */
+    JSEncryptRSAKey.prototype.parseKey = function (pem) {
+        try {
+            var modulus = 0;
+            var public_exponent = 0;
+            var reHex = /^\s*(?:[0-9A-Fa-f][0-9A-Fa-f]\s*)+$/;
+            var der = reHex.test(pem) ? Hex.decode(pem) : Base64.unarmor(pem);
+            var asn1 = ASN1.decode(der);
+            // Fixes a bug with OpenSSL 1.0+ private keys
+            if (asn1.sub.length === 3) {
+                asn1 = asn1.sub[2].sub[0];
+            }
+            if (asn1.sub.length === 9) {
+                // Parse the private key.
+                modulus = asn1.sub[1].getHexStringValue(); // bigint
+                this.n = parseBigInt(modulus, 16);
+                public_exponent = asn1.sub[2].getHexStringValue(); // int
+                this.e = parseInt(public_exponent, 16);
+                var private_exponent = asn1.sub[3].getHexStringValue(); // bigint
+                this.d = parseBigInt(private_exponent, 16);
+                var prime1 = asn1.sub[4].getHexStringValue(); // bigint
+                this.p = parseBigInt(prime1, 16);
+                var prime2 = asn1.sub[5].getHexStringValue(); // bigint
+                this.q = parseBigInt(prime2, 16);
+                var exponent1 = asn1.sub[6].getHexStringValue(); // bigint
+                this.dmp1 = parseBigInt(exponent1, 16);
+                var exponent2 = asn1.sub[7].getHexStringValue(); // bigint
+                this.dmq1 = parseBigInt(exponent2, 16);
+                var coefficient = asn1.sub[8].getHexStringValue(); // bigint
+                this.coeff = parseBigInt(coefficient, 16);
+            }
+            else if (asn1.sub.length === 2) {
+                // Parse the public key.
+                var bit_string = asn1.sub[1];
+                var sequence = bit_string.sub[0];
+                modulus = sequence.sub[0].getHexStringValue();
+                this.n = parseBigInt(modulus, 16);
+                public_exponent = sequence.sub[1].getHexStringValue();
+                this.e = parseInt(public_exponent, 16);
+            }
+            else {
+                return false;
+            }
+            return true;
+        }
+        catch (ex) {
+            return false;
+        }
+    };
+    /**
+     * Translate rsa parameters in a hex encoded string representing the rsa key.
+     *
+     * The translation follow the ASN.1 notation :
+     * RSAPrivateKey ::= SEQUENCE {
+     *   version           Version,
+     *   modulus           INTEGER,  -- n
+     *   publicExponent    INTEGER,  -- e
+     *   privateExponent   INTEGER,  -- d
+     *   prime1            INTEGER,  -- p
+     *   prime2            INTEGER,  -- q
+     *   exponent1         INTEGER,  -- d mod (p1)
+     *   exponent2         INTEGER,  -- d mod (q-1)
+     *   coefficient       INTEGER,  -- (inverse of q) mod p
+     * }
+     * @returns {string}  DER Encoded String representing the rsa private key
+     * @private
+     */
+    JSEncryptRSAKey.prototype.getPrivateBaseKey = function () {
+        var options = {
+            array: [
+                new KJUR.asn1.DERInteger({ int: 0 }),
+                new KJUR.asn1.DERInteger({ bigint: this.n }),
+                new KJUR.asn1.DERInteger({ int: this.e }),
+                new KJUR.asn1.DERInteger({ bigint: this.d }),
+                new KJUR.asn1.DERInteger({ bigint: this.p }),
+                new KJUR.asn1.DERInteger({ bigint: this.q }),
+                new KJUR.asn1.DERInteger({ bigint: this.dmp1 }),
+                new KJUR.asn1.DERInteger({ bigint: this.dmq1 }),
+                new KJUR.asn1.DERInteger({ bigint: this.coeff })
+            ]
+        };
+        var seq = new KJUR.asn1.DERSequence(options);
+        return seq.getEncodedHex();
+    };
+    /**
+     * base64 (pem) encoded version of the DER encoded representation
+     * @returns {string} pem encoded representation without header and footer
+     * @public
+     */
+    JSEncryptRSAKey.prototype.getPrivateBaseKeyB64 = function () {
+        return hex2b64(this.getPrivateBaseKey());
+    };
+    /**
+     * Translate rsa parameters in a hex encoded string representing the rsa public key.
+     * The representation follow the ASN.1 notation :
+     * PublicKeyInfo ::= SEQUENCE {
+     *   algorithm       AlgorithmIdentifier,
+     *   PublicKey       BIT STRING
+     * }
+     * Where AlgorithmIdentifier is:
+     * AlgorithmIdentifier ::= SEQUENCE {
+     *   algorithm       OBJECT IDENTIFIER,     the OID of the enc algorithm
+     *   parameters      ANY DEFINED BY algorithm OPTIONAL (NULL for PKCS #1)
+     * }
+     * and PublicKey is a SEQUENCE encapsulated in a BIT STRING
+     * RSAPublicKey ::= SEQUENCE {
+     *   modulus           INTEGER,  -- n
+     *   publicExponent    INTEGER   -- e
+     * }
+     * @returns {string} DER Encoded String representing the rsa public key
+     * @private
+     */
+    JSEncryptRSAKey.prototype.getPublicBaseKey = function () {
+        var first_sequence = new KJUR.asn1.DERSequence({
+            array: [
+                new KJUR.asn1.DERObjectIdentifier({ oid: "1.2.840.113549.1.1.1" }),
+                new KJUR.asn1.DERNull()
+            ]
+        });
+        var second_sequence = new KJUR.asn1.DERSequence({
+            array: [
+                new KJUR.asn1.DERInteger({ bigint: this.n }),
+                new KJUR.asn1.DERInteger({ int: this.e })
+            ]
+        });
+        var bit_string = new KJUR.asn1.DERBitString({
+            hex: "00" + second_sequence.getEncodedHex()
+        });
+        var seq = new KJUR.asn1.DERSequence({
+            array: [
+                first_sequence,
+                bit_string
+            ]
+        });
+        return seq.getEncodedHex();
+    };
+    /**
+     * base64 (pem) encoded version of the DER encoded representation
+     * @returns {string} pem encoded representation without header and footer
+     * @public
+     */
+    JSEncryptRSAKey.prototype.getPublicBaseKeyB64 = function () {
+        return hex2b64(this.getPublicBaseKey());
+    };
+    /**
+     * wrap the string in block of width chars. The default value for rsa keys is 64
+     * characters.
+     * @param {string} str the pem encoded string without header and footer
+     * @param {Number} [width=64] - the length the string has to be wrapped at
+     * @returns {string}
+     * @private
+     */
+    JSEncryptRSAKey.wordwrap = function (str, width) {
+        width = width || 64;
+        if (!str) {
+            return str;
+        }
+        var regex = "(.{1," + width + "})( +|$\n?)|(.{1," + width + "})";
+        return str.match(RegExp(regex, "g")).join("\n");
+    };
+    /**
+     * Retrieve the pem encoded private key
+     * @returns {string} the pem encoded private key with header/footer
+     * @public
+     */
+    JSEncryptRSAKey.prototype.getPrivateKey = function () {
+        var key = "-----BEGIN RSA PRIVATE KEY-----\n";
+        key += JSEncryptRSAKey.wordwrap(this.getPrivateBaseKeyB64()) + "\n";
+        key += "-----END RSA PRIVATE KEY-----";
+        return key;
+    };
+    /**
+     * Retrieve the pem encoded public key
+     * @returns {string} the pem encoded public key with header/footer
+     * @public
+     */
+    JSEncryptRSAKey.prototype.getPublicKey = function () {
+        var key = "-----BEGIN PUBLIC KEY-----\n";
+        key += JSEncryptRSAKey.wordwrap(this.getPublicBaseKeyB64()) + "\n";
+        key += "-----END PUBLIC KEY-----";
+        return key;
+    };
+    /**
+     * Check if the object contains the necessary parameters to populate the rsa modulus
+     * and public exponent parameters.
+     * @param {Object} [obj={}] - An object that may contain the two public key
+     * parameters
+     * @returns {boolean} true if the object contains both the modulus and the public exponent
+     * properties (n and e)
+     * @todo check for types of n and e. N should be a parseable bigInt object, E should
+     * be a parseable integer number
+     * @private
+     */
+    JSEncryptRSAKey.hasPublicKeyProperty = function (obj) {
+        obj = obj || {};
+        return (obj.hasOwnProperty("n") &&
+            obj.hasOwnProperty("e"));
+    };
+    /**
+     * Check if the object contains ALL the parameters of an RSA key.
+     * @param {Object} [obj={}] - An object that may contain nine rsa key
+     * parameters
+     * @returns {boolean} true if the object contains all the parameters needed
+     * @todo check for types of the parameters all the parameters but the public exponent
+     * should be parseable bigint objects, the public exponent should be a parseable integer number
+     * @private
+     */
+    JSEncryptRSAKey.hasPrivateKeyProperty = function (obj) {
+        obj = obj || {};
+        return (obj.hasOwnProperty("n") &&
+            obj.hasOwnProperty("e") &&
+            obj.hasOwnProperty("d") &&
+            obj.hasOwnProperty("p") &&
+            obj.hasOwnProperty("q") &&
+            obj.hasOwnProperty("dmp1") &&
+            obj.hasOwnProperty("dmq1") &&
+            obj.hasOwnProperty("coeff"));
+    };
+    /**
+     * Parse the properties of obj in the current rsa object. Obj should AT LEAST
+     * include the modulus and public exponent (n, e) parameters.
+     * @param {Object} obj - the object containing rsa parameters
+     * @private
+     */
+    JSEncryptRSAKey.prototype.parsePropertiesFrom = function (obj) {
+        this.n = obj.n;
+        this.e = obj.e;
+        if (obj.hasOwnProperty("d")) {
+            this.d = obj.d;
+            this.p = obj.p;
+            this.q = obj.q;
+            this.dmp1 = obj.dmp1;
+            this.dmq1 = obj.dmq1;
+            this.coeff = obj.coeff;
+        }
+    };
+    return JSEncryptRSAKey;
+}(RSAKey));
+
+/**
+ *
+ * @param {Object} [options = {}] - An object to customize JSEncrypt behaviour
+ * possible parameters are:
+ * - default_key_size        {number}  default: 1024 the key size in bit
+ * - default_public_exponent {string}  default: '010001' the hexadecimal representation of the public exponent
+ * - log                     {boolean} default: false whether log warn/error or not
+ * @constructor
+ */
+var JSEncrypt = /** @class */ (function () {
+    function JSEncrypt(options) {
+        options = options || {};
+        this.default_key_size = parseInt(options.default_key_size, 10) || 1024;
+        this.default_public_exponent = options.default_public_exponent || "010001"; // 65537 default openssl public exponent for rsa key type
+        this.log = options.log || false;
+        // The private and public key.
+        this.key = null;
+    }
+    /**
+     * Method to set the rsa key parameter (one method is enough to set both the public
+     * and the private key, since the private key contains the public key paramenters)
+     * Log a warning if logs are enabled
+     * @param {Object|string} key the pem encoded string or an object (with or without header/footer)
+     * @public
+     */
+    JSEncrypt.prototype.setKey = function (key) {
+        if (this.log && this.key) {
+            console.warn("A key was already set, overriding existing.");
+        }
+        this.key = new JSEncryptRSAKey(key);
+    };
+    /**
+     * Proxy method for setKey, for api compatibility
+     * @see setKey
+     * @public
+     */
+    JSEncrypt.prototype.setPrivateKey = function (privkey) {
+        // Create the key.
+        this.setKey(privkey);
+    };
+    /**
+     * Proxy method for setKey, for api compatibility
+     * @see setKey
+     * @public
+     */
+    JSEncrypt.prototype.setPublicKey = function (pubkey) {
+        // Sets the public key.
+        this.setKey(pubkey);
+    };
+    /**
+     * Proxy method for RSAKey object's decrypt, decrypt the string using the private
+     * components of the rsa key object. Note that if the object was not set will be created
+     * on the fly (by the getKey method) using the parameters passed in the JSEncrypt constructor
+     * @param {string} str base64 encoded crypted string to decrypt
+     * @return {string} the decrypted string
+     * @public
+     */
+    JSEncrypt.prototype.decrypt = function (str) {
+        // Return the decrypted string.
+        try {
+            return this.getKey().decrypt(b64tohex(str));
+        }
+        catch (ex) {
+            return false;
+        }
+    };
+    /**
+     * Proxy method for RSAKey object's encrypt, encrypt the string using the public
+     * components of the rsa key object. Note that if the object was not set will be created
+     * on the fly (by the getKey method) using the parameters passed in the JSEncrypt constructor
+     * @param {string} str the string to encrypt
+     * @return {string} the encrypted string encoded in base64
+     * @public
+     */
+    JSEncrypt.prototype.encrypt = function (str) {
+        // Return the encrypted string.
+        try {
+            return hex2b64(this.getKey().encrypt(str));
+        }
+        catch (ex) {
+            return false;
+        }
+    };
+    /**
+     * Proxy method for RSAKey object's sign.
+     * @param {string} str the string to sign
+     * @param {function} digestMethod hash method
+     * @param {string} digestName the name of the hash algorithm
+     * @return {string} the signature encoded in base64
+     * @public
+     */
+    JSEncrypt.prototype.sign = function (str, digestMethod, digestName) {
+        // return the RSA signature of 'str' in 'hex' format.
+        try {
+            return hex2b64(this.getKey().sign(str, digestMethod, digestName));
+        }
+        catch (ex) {
+            return false;
+        }
+    };
+    /**
+     * Proxy method for RSAKey object's verify.
+     * @param {string} str the string to verify
+     * @param {string} signature the signature encoded in base64 to compare the string to
+     * @param {function} digestMethod hash method
+     * @return {boolean} whether the data and signature match
+     * @public
+     */
+    JSEncrypt.prototype.verify = function (str, signature, digestMethod) {
+        // Return the decrypted 'digest' of the signature.
+        try {
+            return this.getKey().verify(str, b64tohex(signature), digestMethod);
+        }
+        catch (ex) {
+            return false;
+        }
+    };
+    /**
+     * Getter for the current JSEncryptRSAKey object. If it doesn't exists a new object
+     * will be created and returned
+     * @param {callback} [cb] the callback to be called if we want the key to be generated
+     * in an async fashion
+     * @returns {JSEncryptRSAKey} the JSEncryptRSAKey object
+     * @public
+     */
+    JSEncrypt.prototype.getKey = function (cb) {
+        // Only create new if it does not exist.
+        if (!this.key) {
+            // Get a new private key.
+            this.key = new JSEncryptRSAKey();
+            if (cb && {}.toString.call(cb) === "[object Function]") {
+                this.key.generateAsync(this.default_key_size, this.default_public_exponent, cb);
+                return;
+            }
+            // Generate the key.
+            this.key.generate(this.default_key_size, this.default_public_exponent);
+        }
+        return this.key;
+    };
+    /**
+     * Returns the pem encoded representation of the private key
+     * If the key doesn't exists a new key will be created
+     * @returns {string} pem encoded representation of the private key WITH header and footer
+     * @public
+     */
+    JSEncrypt.prototype.getPrivateKey = function () {
+        // Return the private representation of this key.
+        return this.getKey().getPrivateKey();
+    };
+    /**
+     * Returns the pem encoded representation of the private key
+     * If the key doesn't exists a new key will be created
+     * @returns {string} pem encoded representation of the private key WITHOUT header and footer
+     * @public
+     */
+    JSEncrypt.prototype.getPrivateKeyB64 = function () {
+        // Return the private representation of this key.
+        return this.getKey().getPrivateBaseKeyB64();
+    };
+    /**
+     * Returns the pem encoded representation of the public key
+     * If the key doesn't exists a new key will be created
+     * @returns {string} pem encoded representation of the public key WITH header and footer
+     * @public
+     */
+    JSEncrypt.prototype.getPublicKey = function () {
+        // Return the private representation of this key.
+        return this.getKey().getPublicKey();
+    };
+    /**
+     * Returns the pem encoded representation of the public key
+     * If the key doesn't exists a new key will be created
+     * @returns {string} pem encoded representation of the public key WITHOUT header and footer
+     * @public
+     */
+    JSEncrypt.prototype.getPublicKeyB64 = function () {
+        // Return the private representation of this key.
+        return this.getKey().getPublicBaseKeyB64();
+    };
+    JSEncrypt.version = "3.0.0-rc.1";
+    return JSEncrypt;
+}());
+
+if (window)window.JSEncrypt = JSEncrypt;
+
+exports.JSEncrypt = JSEncrypt;
+exports.default = JSEncrypt;
+
+Object.defineProperty(exports, '__esModule', { value: true });
+
+})));

+ 142 - 0
utils/o2Api.js

@@ -0,0 +1,142 @@
+const o2Request = require('/o2Request.js');
+const util = require('/util.js');
+
+let setDistribute = (distribute) => o2Request.setDistribute(distribute);
+
+// cms 移动端 html地址
+let cmsWebUrl = (id) => o2Request.getO2WebBaseUrl() + '/x_desktop/cmsdocMobile.html?id=' + id;
+// 未完成的工作表单打开地址
+let workWebUrl = (work) => o2Request.getO2WebBaseUrl() + '/x_desktop/workmobilewithaction.html?workid=' + work;
+// 草稿 工作地址
+let workDraftUrl = (draft) => o2Request.getO2WebBaseUrl() + '/x_desktop/workmobilewithaction.html?draft=' + draft;
+//工作表单打开地址 已结束 
+let workCompletedWebUrl = (workcompletedid) => o2Request.getO2WebBaseUrl() + '/x_desktop/workmobilewithaction.html?workcompletedid=' + workcompletedid;
+//论坛帖子打开地址 subjectId:帖子id page:评论页码
+let bbsWebUrl = (subjectId, page) => o2Request.getO2WebBaseUrl() + '/x_desktop/forumdocMobile.html?id=' + subjectId + '&page=' + page;
+
+// 中心服务器
+let centerServer = () => o2Request.get(o2Request.o2oaCenterUrl());
+
+/////////////////////////////认证中心///////////////////////////////////
+// 认证
+let who = () => o2Request.get(o2Request.o2oaOrganizationAuthenticationBaseUrl() + '/jaxrs/authentication');
+//param: credential=xxxx,password=xxxx
+let login = (param) => o2Request.post(o2Request.o2oaOrganizationAuthenticationBaseUrl() + '/jaxrs/authentication', param);
+//登出
+let logout = () => o2Request.delete(o2Request.o2oaOrganizationAuthenticationBaseUrl() + '/jaxrs/authentication');
+// 获取 rsa publish key
+let rsaPublishKey =()=> o2Request.get(o2Request.o2oaOrganizationAuthenticationBaseUrl() + '/jaxrs/authentication/captchaRSAPublicKey');
+
+
+//////////////////////////cms 信息中心//////////////////////////////
+
+//热点图片列表 默认取前5条
+let hotPicList = () => o2Request.put(o2Request.o2oaHotPicServiceBaseUrl() + '/jaxrs/user/hotpic/filter/list/page/1/count/5', {}, false);
+// 热电图片url地址
+let hotPicUrl = (picId) => o2Request.o2oaFileServiceBaseUrl() + '/jaxrs/file/'+picId+'/download/stream';
+
+//cms 分页获取文档列表
+let cmsDocumentFilterList = (lastId, pageSize, param) => o2Request.put(o2Request.o2oaCmsServiceBaseUrl() + '/jaxrs/document/filter/list/'+lastId+'/next/'+pageSize, param);
+let cmsDocumentFilterListNew = (page, pageSize, body) => o2Request.put(o2Request.o2oaCmsServiceBaseUrl() + '/jaxrs/document/filter/list/'+page+'/size/'+pageSize, body);
+//cms 附件下载地址
+let cmsAttachementUrl = (attId) => o2Request.o2oaCmsServiceBaseUrl() + '/jaxrs/fileinfo/download/document/'+attId;
+
+/////////////////////流程 //////////////////////////////
+
+// 流程应用
+let applicationList = () => o2Request.get(o2Request.o2oaProcessServiceBaseUrl() + '/jaxrs/application/list/complex');
+// 获取当前用户在指定流程中可启动流程的身份.
+let listAvailableIdentityWithProcess = (processId) => o2Request.get(o2Request.o2oaProcessServiceBaseUrl() + '/jaxrs/process/list/available/identity/process/'+processId);
+// 启动草稿
+let createDraft = (processId, body) => o2Request.post(o2Request.o2oaProcessServiceBaseUrl() + '/jaxrs/draft/process/'+processId, body);
+// 启动流程
+let createWork = (processId, body) => o2Request.post(o2Request.o2oaProcessServiceBaseUrl() + '/jaxrs/work/process/'+processId, body);
+
+// 待办列表
+let taskList = (lastId, pageSize) => o2Request.get(o2Request.o2oaProcessServiceBaseUrl() + '/jaxrs/task/list/'+lastId+'/next/'+pageSize);
+//已办列表
+let taskCompletedList = (lastId, pageSize) => o2Request.get(o2Request.o2oaProcessServiceBaseUrl() + '/jaxrs/taskcompleted/list/'+lastId+'/next/'+pageSize);
+//待阅列表
+let readList = (lastId, pageSize) => o2Request.get(o2Request.o2oaProcessServiceBaseUrl() + '/jaxrs/read/list/'+lastId+'/next/'+pageSize);
+//已阅列表
+let readCompletedList = (lastId, pageSize) => o2Request.get(o2Request.o2oaProcessServiceBaseUrl() + '/jaxrs/readcompleted/list/'+lastId+'/next/'+pageSize);
+
+//工作附件下载地址
+let workAttachmentUrl = (attId, workId) => o2Request.o2oaProcessServiceBaseUrl() + '/jaxrs/attachment/download/'+attId+'/work/'+workId;
+//完成工作的附件下载地址
+let workCompletedAttachementUrl = (attId, workcompletedId) => o2Request.o2oaProcessServiceBaseUrl() + '/jaxrs/attachment/download/'+attId+'/workcompleted/'+workcompletedId;
+
+
+/////////////////////////论坛///////////////////////////
+//帖子附件
+let bbsAttachementUrl = (attId) => o2Request.o2oaBBSServiceBaseUrl() + '/jaxrs/attachment/download/' + attId;
+
+////////////////////////人员//////////////////////////
+//个人信息
+let me = () => o2Request.get(o2Request.o2oaPersonalServiceBaseUrl() + '/jaxrs/person');
+//个人用户的头像地址
+let myAvatarUrl = () => o2Request.o2oaPersonalServiceBaseUrl() + '/jaxrs/person/icon';
+//更新个人信息
+let putMyInfo = (person) => o2Request.put(o2Request.o2oaPersonalServiceBaseUrl() + '/jaxrs/person', person);
+// 上传当前用户头像的 上传地址
+let uploadMyAvatarUrl = () => o2Request.o2oaPersonalServiceBaseUrl() + '/jaxrs/person/icon';
+// 发送短信 获取短信验证码
+let sendSms = (mobile) => o2Request.get(o2Request.o2oaPersonalServiceBaseUrl() + '/jaxrs/regist/code/mobile/' + mobile);
+//注册人员
+let register = (form) => o2Request.post(o2Request.o2oaPersonalServiceBaseUrl() + '/jaxrs/regist', form);
+//是否开启注册功能 "data": {"value": "disable"}  disable,captcha,code
+let registerMode = () => o2Request.get(o2Request.o2oaPersonalServiceBaseUrl() + '/jaxrs/regist/mode');
+
+
+// 官网查询账号列表
+let wwwGetSampleServerAccounts = (id) => o2Request.post(o2Request.wwwGetSampleServerAccountsUrl(), {serverId: id});
+
+
+
+// 处理o2请求返回错误
+function o2Error(err, optionsMessage = '请求失败') {
+  if(err && err.message) {
+    util.toast(err.message);
+  }else {
+    util.toast(optionsMessage);
+  }
+}
+
+module.exports = {
+  o2Error: o2Error,
+  centerServer,
+  setDistribute,
+  cmsWebUrl,
+  workWebUrl,
+  workDraftUrl,
+  workCompletedWebUrl,
+  bbsWebUrl,
+  workAttachmentUrl,
+  workCompletedAttachementUrl,
+  cmsAttachementUrl,
+  bbsAttachementUrl,
+  who,
+  login,
+  logout,
+  rsaPublishKey,
+  hotPicList,
+  hotPicUrl,
+  cmsDocumentFilterList,
+  cmsDocumentFilterListNew,
+  taskList,
+  taskCompletedList,
+  readList,
+  readCompletedList,
+  applicationList,
+  listAvailableIdentityWithProcess,
+  createDraft,
+  createWork,
+  me,
+  myAvatarUrl,
+  uploadMyAvatarUrl,
+  putMyInfo,
+  sendSms,
+  register,
+  registerMode,
+  wwwGetSampleServerAccounts
+}

+ 158 - 0
utils/o2Request.js

@@ -0,0 +1,158 @@
+let app = getApp();
+
+function request(method, url, param, isShowLoading) {
+  //返回一个Promise对象
+  return new Promise(function(resolve, reject) {
+    if (isShowLoading) {
+      wx.showLoading({
+        title: '加载中...',
+        mask: true
+      });
+    }
+    wx.request({
+      url: url,
+      method: method,
+      data: param,
+      header: {
+        'content-type': 'application/json',
+        'cookie': wx.getStorageSync('cookie')
+      },
+      success: function(res) {
+        // 保存登录返回的cookie
+        if (res.header['Set-Cookie']) {
+          wx.setStorageSync('cookie', res.header['Set-Cookie']);
+          // wx.setStorage({
+          //   key: 'cookie',
+          //   data: res.header['Set-Cookie'],
+          // })
+        }
+        // console.log('接口:' + url, ' 参数:', param, '\n返回值:', res.data)
+        if (isShowLoading) {
+          wx.hideLoading();
+        }
+        if (res.data.type == 'success') { // 接口正常返回
+          resolve(res.data.data);
+        } else { // 出现异常
+          wx.showToast({
+            title: res.data.message,
+            icon: 'none',
+            duration: 2000
+          });
+          reject(res.data);
+        }
+      },
+      fail: function(res) {
+        wx.hideLoading();
+        console.log('请求异常 接口:' + url, ' 参数:', param, '\n返回值:', res)
+        wx.showToast({
+          title: '请求异常',
+          icon: 'none',
+          duration: 2000
+        });
+        reject(res);
+      }
+    });
+  });
+}
+
+//设置应用地址到存储中
+function setDistribute(distribute) {
+  ['webServer', 'assembles', 'tokenName'].forEach( t => {
+    wx.removeStorageSync(t);
+    if (t === 'tokenName') {
+      wx.setStorageSync(t, distribute[t] || 'x-token');
+    } else {
+      wx.setStorageSync(t, distribute[t] || {});
+    }
+  });
+}
+
+// 获取模块的baseUrl
+function getO2AssembleUrl(contextName) {
+  var assemble = wx.getStorageSync('assembles')[contextName] || {host: app.globalData.o2oa.centerHost, port: app.globalData.o2oa.centerPort, context: "/"+contextName};
+  return  app.globalData.o2oa.httpProtocol + "://" + assemble["host"] + ":" + assemble["port"]+ assemble["context"];
+}
+
+//web服务器根地址 如 https://sample.o2oa.net:443
+function getO2WebBaseUrl() {
+  var webServer = wx.getStorageSync('webServer');
+  return app.globalData.o2oa.httpProtocol + "://" + webServer["host"] + ":" + webServer["port"];
+}
+
+
+// 中心服务器获取
+function o2oaCenterUrl() {
+  return  app.globalData.o2oa.httpProtocol + "://" + app.globalData.o2oa.centerHost + ":" + app.globalData.o2oa.centerPort + app.globalData.o2oa.centerContext + "/jaxrs/distribute/webserver/assemble/source/" + app.globalData.o2oa.centerHost;
+}
+
+// 获取演示服务器账号列表
+function wwwGetSampleServerAccountsUrl() {
+  return "https://www.o2oa.net/oa/x_program_center/jaxrs/invoke/demo_app_get_login_accounts/execute";
+}
+
+//认证模块
+function o2oaOrganizationAuthenticationBaseUrl() {
+    return getO2AssembleUrl('x_organization_assemble_authentication');
+}
+//cms模块
+function o2oaCmsServiceBaseUrl() {
+  return getO2AssembleUrl('x_cms_assemble_control');
+}
+//bbs论坛模块
+function o2oaBBSServiceBaseUrl() {
+  return getO2AssembleUrl('x_bbs_assemble_control');
+}
+//热点图片模块
+function o2oaHotPicServiceBaseUrl() {
+  return getO2AssembleUrl('x_hotpic_assemble_control');
+}
+//文件管理模块
+function o2oaFileServiceBaseUrl() {
+  return getO2AssembleUrl('x_file_assemble_control');
+}
+//流程模块
+function o2oaProcessServiceBaseUrl() {
+  return getO2AssembleUrl('x_processplatform_assemble_surface');
+}
+//人员管理
+function o2oaPersonalServiceBaseUrl() {
+  return getO2AssembleUrl('x_organization_assemble_personal');
+}
+
+// get请求
+function get(path, param = {}, isShowLoading = true) {
+  return request("GET", path, param, isShowLoading);
+}
+
+// post请求
+function post(path, param = {}, isShowLoading = true) {
+  return request("POST", path, param, isShowLoading);
+} 
+
+// PUT 请求
+function put(path, param = {}, isShowLoading = true) {
+  return request("PUT", path, param, isShowLoading);
+}
+
+// DELETE 请求
+function deleteReq(path, param = {}, isShowLoading = true) {
+  return request("DELETE", path, param, isShowLoading);
+}
+
+module.exports = {
+  get: get,
+  post: post,
+  put: put,
+  delete: deleteReq,
+  o2oaOrganizationAuthenticationBaseUrl: o2oaOrganizationAuthenticationBaseUrl,
+  o2oaCenterUrl: o2oaCenterUrl,
+  setDistribute: setDistribute,
+  getO2WebBaseUrl: getO2WebBaseUrl,
+  o2oaCmsServiceBaseUrl: o2oaCmsServiceBaseUrl,
+  o2oaHotPicServiceBaseUrl: o2oaHotPicServiceBaseUrl,
+  o2oaFileServiceBaseUrl: o2oaFileServiceBaseUrl,
+  o2oaProcessServiceBaseUrl: o2oaProcessServiceBaseUrl,
+  o2oaBBSServiceBaseUrl: o2oaBBSServiceBaseUrl,
+  o2oaPersonalServiceBaseUrl: o2oaPersonalServiceBaseUrl,
+  wwwGetSampleServerAccountsUrl: wwwGetSampleServerAccountsUrl
+}

+ 38 - 0
utils/util.js

@@ -0,0 +1,38 @@
+const formatTime = date => {
+  const year = date.getFullYear()
+  const month = date.getMonth() + 1
+  const day = date.getDate()
+  const hour = date.getHours()
+  const minute = date.getMinutes()
+  const second = date.getSeconds()
+
+  return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':')
+}
+
+const formatNumber = n => {
+  n = n.toString()
+  return n[1] ? n : '0' + n
+}
+
+// 显示toast
+const toast = (title, icon = 'none') => {
+  wx.showToast({
+    title: title,
+    icon: icon
+  })
+}
+const showLoading = (message = '加载中...') => {
+  wx.showLoading({
+    title: message,
+  });
+}
+
+const hideLoading = () => wx.hideLoading();
+ 
+
+module.exports = {
+  formatTime: formatTime,
+  toast: toast,
+  showLoading: showLoading,
+  hideLoading: hideLoading
+}

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است