tamarin-prover (empty) → 0.1.0.0
raw patch · 97 files changed
+26286/−0 lines, 97 filesdep +aesondep +arraydep +basesetup-changedbinary-added
Dependencies added: aeson, array, base, binary, blaze-builder, bytestring, cmdargs, containers, data-default, deepseq, derive, directory, fclabels, filepath, hamlet, http-types, monad-control, mtl, old-locale, parallel, parsec, process, safe, syb, tamarin-prover-term, tamarin-prover-utils, template-haskell, text, threads, time, transformers, uniplate, wai, wai-extra, warp, yesod-core, yesod-form, yesod-json, yesod-static
Files
- .ghci +5/−0
- CHANGES +1/−0
- LICENSE +621/−0
- README +127/−0
- Setup.hs +2/−0
- data/AUTHORS +7/−0
- data/LICENSE +621/−0
- data/css/jquery-contextmenu.css +65/−0
- data/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png binary
- data/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png binary
- data/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png binary
- data/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png binary
- data/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png binary
- data/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png binary
- data/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png binary
- data/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png binary
- data/css/smoothness/images/ui-icons_222222_256x240.png binary
- data/css/smoothness/images/ui-icons_2e83ff_256x240.png binary
- data/css/smoothness/images/ui-icons_454545_256x240.png binary
- data/css/smoothness/images/ui-icons_888888_256x240.png binary
- data/css/smoothness/images/ui-icons_cd0a0a_256x240.png binary
- data/css/smoothness/jquery-ui.css +578/−0
- data/css/tamarin-prover-ui.css +506/−0
- data/etc/filetype.vim +4/−0
- data/etc/spthy.vim +204/−0
- data/examples/TLS.spthy +190/−0
- data/examples/UserGuide.spthy +437/−0
- data/examples/csf12/Artificial.spthy +64/−0
- data/examples/csf12/JKL_TS1_2004-KI.spthy +116/−0
- data/examples/csf12/JKL_TS1_2008-KI.spthy +120/−0
- data/examples/csf12/JKL_TS1_2008-KI_wPFS.spthy +139/−0
- data/examples/csf12/JKL_TS2_2004-KI.spthy +117/−0
- data/examples/csf12/JKL_TS2_2004-KI_wPFS.spthy +135/−0
- data/examples/csf12/JKL_TS2_2008-KI.spthy +120/−0
- data/examples/csf12/JKL_TS2_2008-KI_wPFS.spthy +139/−0
- data/examples/csf12/JKL_TS3_2004-KI_wPFS.spthy-nonterm +199/−0
- data/examples/csf12/JKL_TS3_2008-KI_wPFS.spthy-nonterm +188/−0
- data/examples/csf12/KEA_plus_KI_KCI.spthy +159/−0
- data/examples/csf12/KEA_plus_KI_KCI_wPFS.spthy +155/−0
- data/examples/csf12/KEA_plus_eCK.spthy +155/−0
- data/examples/csf12/NAXOS_eCK.spthy +156/−0
- data/examples/csf12/NAXOS_eCK_PFS.spthy +153/−0
- data/examples/csf12/STS-MAC-fix1.spthy +123/−0
- data/examples/csf12/STS-MAC-fix2.spthy +122/−0
- data/examples/csf12/STS-MAC.spthy +122/−0
- data/examples/csf12/SignedDH_PFS.spthy +69/−0
- data/examples/csf12/SignedDH_eCK.spthy +140/−0
- data/examples/csf12/UM_PFS.spthy +112/−0
- data/examples/csf12/UM_eCK.spthy +140/−0
- data/examples/csf12/UM_eCK_noKCI.spthy +140/−0
- data/examples/csf12/UM_wPFS.spthy +131/−0
- data/img/ajax-loader.gif binary
- data/img/autoprove.png binary
- data/img/delete.png binary
- data/img/edit.png binary
- data/img/favicon.ico binary
- data/img/option-off.png binary
- data/img/option-on.png binary
- data/intruder_variants_dh.spthy +272/−0
- data/js/jquery-contextmenu.js +211/−0
- data/js/jquery-cookie.js +91/−0
- data/js/jquery-layout.js +4332/−0
- data/js/jquery-superfish.js +121/−0
- data/js/jquery-ui.js +783/−0
- data/js/jquery.js +16/−0
- data/js/tamarin-prover-ui.js +747/−0
- interactive-only-src/Lexer.x +418/−0
- interactive-only-src/Paths_tamarin_prover.hs +32/−0
- src/Main.hs +715/−0
- src/Theory.hs +765/−0
- src/Theory/Atom.hs +168/−0
- src/Theory/Fact.hs +339/−0
- src/Theory/Formula.hs +317/−0
- src/Theory/IntruderRules.hs +222/−0
- src/Theory/Lexer.hs +621/−0
- src/Theory/Parser.hs +829/−0
- src/Theory/Pretty.hs +109/−0
- src/Theory/Proof.hs +772/−0
- src/Theory/Proof/CaseDistinctions.hs +388/−0
- src/Theory/Proof/EquationStore.hs +438/−0
- src/Theory/Proof/Guarded.hs +562/−0
- src/Theory/Proof/Sequent.hs +1035/−0
- src/Theory/Proof/Sequent/Dot.hs +425/−0
- src/Theory/Proof/SolveGuarded.hs +323/−0
- src/Theory/Proof/Types.hs +828/−0
- src/Theory/Rule.hs +527/−0
- src/Theory/RuleVariants.hs +87/−0
- src/Theory/Signature.hs +196/−0
- src/Theory/Wellformedness.hs +440/−0
- src/Web/Dispatch.hs +147/−0
- src/Web/Hamlet.hs +342/−0
- src/Web/Handler.hs +649/−0
- src/Web/Instances.hs +44/−0
- src/Web/Settings.hs +32/−0
- src/Web/Theory.hs +798/−0
- src/Web/Types.hs +344/−0
- tamarin-prover.cabal +219/−0
@@ -0,0 +1,5 @@+:set -iinteractive-only-src+-- :set -ilib/term/src+-- :set -ilib/utils/src+:set -isrc+:set -Wall
@@ -0,0 +1,1 @@+* 0.1.0 First public release
@@ -0,0 +1,621 @@+ GNU GENERAL PUBLIC LICENSE+ Version 3, 29 June 2007++ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>+ Everyone is permitted to copy and distribute verbatim copies+ of this license document, but changing it is not allowed.++ Preamble++ The GNU General Public License is a free, copyleft license for+software and other kinds of works.++ The licenses for most software and other practical works are designed+to take away your freedom to share and change the works. By contrast,+the GNU General Public License is intended to guarantee your freedom to+share and change all versions of a program--to make sure it remains free+software for all its users. We, the Free Software Foundation, use the+GNU General Public License for most of our software; it applies also to+any other work released this way by its authors. You can apply it to+your programs, too.++ When we speak of free software, we are referring to freedom, not+price. Our General Public Licenses are designed to make sure that you+have the freedom to distribute copies of free software (and charge for+them if you wish), that you receive source code or can get it if you+want it, that you can change the software or use pieces of it in new+free programs, and that you know you can do these things.++ To protect your rights, we need to prevent others from denying you+these rights or asking you to surrender the rights. Therefore, you have+certain responsibilities if you distribute copies of the software, or if+you modify it: responsibilities to respect the freedom of others.++ For example, if you distribute copies of such a program, whether+gratis or for a fee, you must pass on to the recipients the same+freedoms that you received. You must make sure that they, too, receive+or can get the source code. And you must show them these terms so they+know their rights.++ Developers that use the GNU GPL protect your rights with two steps:+(1) assert copyright on the software, and (2) offer you this License+giving you legal permission to copy, distribute and/or modify it.++ For the developers' and authors' protection, the GPL clearly explains+that there is no warranty for this free software. For both users' and+authors' sake, the GPL requires that modified versions be marked as+changed, so that their problems will not be attributed erroneously to+authors of previous versions.++ Some devices are designed to deny users access to install or run+modified versions of the software inside them, although the manufacturer+can do so. This is fundamentally incompatible with the aim of+protecting users' freedom to change the software. The systematic+pattern of such abuse occurs in the area of products for individuals to+use, which is precisely where it is most unacceptable. Therefore, we+have designed this version of the GPL to prohibit the practice for those+products. If such problems arise substantially in other domains, we+stand ready to extend this provision to those domains in future versions+of the GPL, as needed to protect the freedom of users.++ Finally, every program is threatened constantly by software patents.+States should not allow patents to restrict development and use of+software on general-purpose computers, but in those that do, we wish to+avoid the special danger that patents applied to a free program could+make it effectively proprietary. To prevent this, the GPL assures that+patents cannot be used to render the program non-free.++ The precise terms and conditions for copying, distribution and+modification follow.++ TERMS AND CONDITIONS++ 0. Definitions.++ "This License" refers to version 3 of the GNU General Public License.++ "Copyright" also means copyright-like laws that apply to other kinds of+works, such as semiconductor masks.++ "The Program" refers to any copyrightable work licensed under this+License. Each licensee is addressed as "you". "Licensees" and+"recipients" may be individuals or organizations.++ To "modify" a work means to copy from or adapt all or part of the work+in a fashion requiring copyright permission, other than the making of an+exact copy. The resulting work is called a "modified version" of the+earlier work or a work "based on" the earlier work.++ A "covered work" means either the unmodified Program or a work based+on the Program.++ To "propagate" a work means to do anything with it that, without+permission, would make you directly or secondarily liable for+infringement under applicable copyright law, except executing it on a+computer or modifying a private copy. Propagation includes copying,+distribution (with or without modification), making available to the+public, and in some countries other activities as well.++ To "convey" a work means any kind of propagation that enables other+parties to make or receive copies. Mere interaction with a user through+a computer network, with no transfer of a copy, is not conveying.++ An interactive user interface displays "Appropriate Legal Notices"+to the extent that it includes a convenient and prominently visible+feature that (1) displays an appropriate copyright notice, and (2)+tells the user that there is no warranty for the work (except to the+extent that warranties are provided), that licensees may convey the+work under this License, and how to view a copy of this License. If+the interface presents a list of user commands or options, such as a+menu, a prominent item in the list meets this criterion.++ 1. Source Code.++ The "source code" for a work means the preferred form of the work+for making modifications to it. "Object code" means any non-source+form of a work.++ A "Standard Interface" means an interface that either is an official+standard defined by a recognized standards body, or, in the case of+interfaces specified for a particular programming language, one that+is widely used among developers working in that language.++ The "System Libraries" of an executable work include anything, other+than the work as a whole, that (a) is included in the normal form of+packaging a Major Component, but which is not part of that Major+Component, and (b) serves only to enable use of the work with that+Major Component, or to implement a Standard Interface for which an+implementation is available to the public in source code form. A+"Major Component", in this context, means a major essential component+(kernel, window system, and so on) of the specific operating system+(if any) on which the executable work runs, or a compiler used to+produce the work, or an object code interpreter used to run it.++ The "Corresponding Source" for a work in object code form means all+the source code needed to generate, install, and (for an executable+work) run the object code and to modify the work, including scripts to+control those activities. However, it does not include the work's+System Libraries, or general-purpose tools or generally available free+programs which are used unmodified in performing those activities but+which are not part of the work. For example, Corresponding Source+includes interface definition files associated with source files for+the work, and the source code for shared libraries and dynamically+linked subprograms that the work is specifically designed to require,+such as by intimate data communication or control flow between those+subprograms and other parts of the work.++ The Corresponding Source need not include anything that users+can regenerate automatically from other parts of the Corresponding+Source.++ The Corresponding Source for a work in source code form is that+same work.++ 2. Basic Permissions.++ All rights granted under this License are granted for the term of+copyright on the Program, and are irrevocable provided the stated+conditions are met. This License explicitly affirms your unlimited+permission to run the unmodified Program. The output from running a+covered work is covered by this License only if the output, given its+content, constitutes a covered work. This License acknowledges your+rights of fair use or other equivalent, as provided by copyright law.++ You may make, run and propagate covered works that you do not+convey, without conditions so long as your license otherwise remains+in force. You may convey covered works to others for the sole purpose+of having them make modifications exclusively for you, or provide you+with facilities for running those works, provided that you comply with+the terms of this License in conveying all material for which you do+not control copyright. Those thus making or running the covered works+for you must do so exclusively on your behalf, under your direction+and control, on terms that prohibit them from making any copies of+your copyrighted material outside their relationship with you.++ Conveying under any other circumstances is permitted solely under+the conditions stated below. Sublicensing is not allowed; section 10+makes it unnecessary.++ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.++ No covered work shall be deemed part of an effective technological+measure under any applicable law fulfilling obligations under article+11 of the WIPO copyright treaty adopted on 20 December 1996, or+similar laws prohibiting or restricting circumvention of such+measures.++ When you convey a covered work, you waive any legal power to forbid+circumvention of technological measures to the extent such circumvention+is effected by exercising rights under this License with respect to+the covered work, and you disclaim any intention to limit operation or+modification of the work as a means of enforcing, against the work's+users, your or third parties' legal rights to forbid circumvention of+technological measures.++ 4. Conveying Verbatim Copies.++ You may convey verbatim copies of the Program's source code as you+receive it, in any medium, provided that you conspicuously and+appropriately publish on each copy an appropriate copyright notice;+keep intact all notices stating that this License and any+non-permissive terms added in accord with section 7 apply to the code;+keep intact all notices of the absence of any warranty; and give all+recipients a copy of this License along with the Program.++ You may charge any price or no price for each copy that you convey,+and you may offer support or warranty protection for a fee.++ 5. Conveying Modified Source Versions.++ You may convey a work based on the Program, or the modifications to+produce it from the Program, in the form of source code under the+terms of section 4, provided that you also meet all of these conditions:++ a) The work must carry prominent notices stating that you modified+ it, and giving a relevant date.++ b) The work must carry prominent notices stating that it is+ released under this License and any conditions added under section+ 7. This requirement modifies the requirement in section 4 to+ "keep intact all notices".++ c) You must license the entire work, as a whole, under this+ License to anyone who comes into possession of a copy. This+ License will therefore apply, along with any applicable section 7+ additional terms, to the whole of the work, and all its parts,+ regardless of how they are packaged. This License gives no+ permission to license the work in any other way, but it does not+ invalidate such permission if you have separately received it.++ d) If the work has interactive user interfaces, each must display+ Appropriate Legal Notices; however, if the Program has interactive+ interfaces that do not display Appropriate Legal Notices, your+ work need not make them do so.++ A compilation of a covered work with other separate and independent+works, which are not by their nature extensions of the covered work,+and which are not combined with it such as to form a larger program,+in or on a volume of a storage or distribution medium, is called an+"aggregate" if the compilation and its resulting copyright are not+used to limit the access or legal rights of the compilation's users+beyond what the individual works permit. Inclusion of a covered work+in an aggregate does not cause this License to apply to the other+parts of the aggregate.++ 6. Conveying Non-Source Forms.++ You may convey a covered work in object code form under the terms+of sections 4 and 5, provided that you also convey the+machine-readable Corresponding Source under the terms of this License,+in one of these ways:++ a) Convey the object code in, or embodied in, a physical product+ (including a physical distribution medium), accompanied by the+ Corresponding Source fixed on a durable physical medium+ customarily used for software interchange.++ b) Convey the object code in, or embodied in, a physical product+ (including a physical distribution medium), accompanied by a+ written offer, valid for at least three years and valid for as+ long as you offer spare parts or customer support for that product+ model, to give anyone who possesses the object code either (1) a+ copy of the Corresponding Source for all the software in the+ product that is covered by this License, on a durable physical+ medium customarily used for software interchange, for a price no+ more than your reasonable cost of physically performing this+ conveying of source, or (2) access to copy the+ Corresponding Source from a network server at no charge.++ c) Convey individual copies of the object code with a copy of the+ written offer to provide the Corresponding Source. This+ alternative is allowed only occasionally and noncommercially, and+ only if you received the object code with such an offer, in accord+ with subsection 6b.++ d) Convey the object code by offering access from a designated+ place (gratis or for a charge), and offer equivalent access to the+ Corresponding Source in the same way through the same place at no+ further charge. You need not require recipients to copy the+ Corresponding Source along with the object code. If the place to+ copy the object code is a network server, the Corresponding Source+ may be on a different server (operated by you or a third party)+ that supports equivalent copying facilities, provided you maintain+ clear directions next to the object code saying where to find the+ Corresponding Source. Regardless of what server hosts the+ Corresponding Source, you remain obligated to ensure that it is+ available for as long as needed to satisfy these requirements.++ e) Convey the object code using peer-to-peer transmission, provided+ you inform other peers where the object code and Corresponding+ Source of the work are being offered to the general public at no+ charge under subsection 6d.++ A separable portion of the object code, whose source code is excluded+from the Corresponding Source as a System Library, need not be+included in conveying the object code work.++ A "User Product" is either (1) a "consumer product", which means any+tangible personal property which is normally used for personal, family,+or household purposes, or (2) anything designed or sold for incorporation+into a dwelling. In determining whether a product is a consumer product,+doubtful cases shall be resolved in favor of coverage. For a particular+product received by a particular user, "normally used" refers to a+typical or common use of that class of product, regardless of the status+of the particular user or of the way in which the particular user+actually uses, or expects or is expected to use, the product. A product+is a consumer product regardless of whether the product has substantial+commercial, industrial or non-consumer uses, unless such uses represent+the only significant mode of use of the product.++ "Installation Information" for a User Product means any methods,+procedures, authorization keys, or other information required to install+and execute modified versions of a covered work in that User Product from+a modified version of its Corresponding Source. The information must+suffice to ensure that the continued functioning of the modified object+code is in no case prevented or interfered with solely because+modification has been made.++ If you convey an object code work under this section in, or with, or+specifically for use in, a User Product, and the conveying occurs as+part of a transaction in which the right of possession and use of the+User Product is transferred to the recipient in perpetuity or for a+fixed term (regardless of how the transaction is characterized), the+Corresponding Source conveyed under this section must be accompanied+by the Installation Information. But this requirement does not apply+if neither you nor any third party retains the ability to install+modified object code on the User Product (for example, the work has+been installed in ROM).++ The requirement to provide Installation Information does not include a+requirement to continue to provide support service, warranty, or updates+for a work that has been modified or installed by the recipient, or for+the User Product in which it has been modified or installed. Access to a+network may be denied when the modification itself materially and+adversely affects the operation of the network or violates the rules and+protocols for communication across the network.++ Corresponding Source conveyed, and Installation Information provided,+in accord with this section must be in a format that is publicly+documented (and with an implementation available to the public in+source code form), and must require no special password or key for+unpacking, reading or copying.++ 7. Additional Terms.++ "Additional permissions" are terms that supplement the terms of this+License by making exceptions from one or more of its conditions.+Additional permissions that are applicable to the entire Program shall+be treated as though they were included in this License, to the extent+that they are valid under applicable law. If additional permissions+apply only to part of the Program, that part may be used separately+under those permissions, but the entire Program remains governed by+this License without regard to the additional permissions.++ When you convey a copy of a covered work, you may at your option+remove any additional permissions from that copy, or from any part of+it. (Additional permissions may be written to require their own+removal in certain cases when you modify the work.) You may place+additional permissions on material, added by you to a covered work,+for which you have or can give appropriate copyright permission.++ Notwithstanding any other provision of this License, for material you+add to a covered work, you may (if authorized by the copyright holders of+that material) supplement the terms of this License with terms:++ a) Disclaiming warranty or limiting liability differently from the+ terms of sections 15 and 16 of this License; or++ b) Requiring preservation of specified reasonable legal notices or+ author attributions in that material or in the Appropriate Legal+ Notices displayed by works containing it; or++ c) Prohibiting misrepresentation of the origin of that material, or+ requiring that modified versions of such material be marked in+ reasonable ways as different from the original version; or++ d) Limiting the use for publicity purposes of names of licensors or+ authors of the material; or++ e) Declining to grant rights under trademark law for use of some+ trade names, trademarks, or service marks; or++ f) Requiring indemnification of licensors and authors of that+ material by anyone who conveys the material (or modified versions of+ it) with contractual assumptions of liability to the recipient, for+ any liability that these contractual assumptions directly impose on+ those licensors and authors.++ All other non-permissive additional terms are considered "further+restrictions" within the meaning of section 10. If the Program as you+received it, or any part of it, contains a notice stating that it is+governed by this License along with a term that is a further+restriction, you may remove that term. If a license document contains+a further restriction but permits relicensing or conveying under this+License, you may add to a covered work material governed by the terms+of that license document, provided that the further restriction does+not survive such relicensing or conveying.++ If you add terms to a covered work in accord with this section, you+must place, in the relevant source files, a statement of the+additional terms that apply to those files, or a notice indicating+where to find the applicable terms.++ Additional terms, permissive or non-permissive, may be stated in the+form of a separately written license, or stated as exceptions;+the above requirements apply either way.++ 8. Termination.++ You may not propagate or modify a covered work except as expressly+provided under this License. Any attempt otherwise to propagate or+modify it is void, and will automatically terminate your rights under+this License (including any patent licenses granted under the third+paragraph of section 11).++ However, if you cease all violation of this License, then your+license from a particular copyright holder is reinstated (a)+provisionally, unless and until the copyright holder explicitly and+finally terminates your license, and (b) permanently, if the copyright+holder fails to notify you of the violation by some reasonable means+prior to 60 days after the cessation.++ Moreover, your license from a particular copyright holder is+reinstated permanently if the copyright holder notifies you of the+violation by some reasonable means, this is the first time you have+received notice of violation of this License (for any work) from that+copyright holder, and you cure the violation prior to 30 days after+your receipt of the notice.++ Termination of your rights under this section does not terminate the+licenses of parties who have received copies or rights from you under+this License. If your rights have been terminated and not permanently+reinstated, you do not qualify to receive new licenses for the same+material under section 10.++ 9. Acceptance Not Required for Having Copies.++ You are not required to accept this License in order to receive or+run a copy of the Program. Ancillary propagation of a covered work+occurring solely as a consequence of using peer-to-peer transmission+to receive a copy likewise does not require acceptance. However,+nothing other than this License grants you permission to propagate or+modify any covered work. These actions infringe copyright if you do+not accept this License. Therefore, by modifying or propagating a+covered work, you indicate your acceptance of this License to do so.++ 10. Automatic Licensing of Downstream Recipients.++ Each time you convey a covered work, the recipient automatically+receives a license from the original licensors, to run, modify and+propagate that work, subject to this License. You are not responsible+for enforcing compliance by third parties with this License.++ An "entity transaction" is a transaction transferring control of an+organization, or substantially all assets of one, or subdividing an+organization, or merging organizations. If propagation of a covered+work results from an entity transaction, each party to that+transaction who receives a copy of the work also receives whatever+licenses to the work the party's predecessor in interest had or could+give under the previous paragraph, plus a right to possession of the+Corresponding Source of the work from the predecessor in interest, if+the predecessor has it or can get it with reasonable efforts.++ You may not impose any further restrictions on the exercise of the+rights granted or affirmed under this License. For example, you may+not impose a license fee, royalty, or other charge for exercise of+rights granted under this License, and you may not initiate litigation+(including a cross-claim or counterclaim in a lawsuit) alleging that+any patent claim is infringed by making, using, selling, offering for+sale, or importing the Program or any portion of it.++ 11. Patents.++ A "contributor" is a copyright holder who authorizes use under this+License of the Program or a work on which the Program is based. The+work thus licensed is called the contributor's "contributor version".++ A contributor's "essential patent claims" are all patent claims+owned or controlled by the contributor, whether already acquired or+hereafter acquired, that would be infringed by some manner, permitted+by this License, of making, using, or selling its contributor version,+but do not include claims that would be infringed only as a+consequence of further modification of the contributor version. For+purposes of this definition, "control" includes the right to grant+patent sublicenses in a manner consistent with the requirements of+this License.++ Each contributor grants you a non-exclusive, worldwide, royalty-free+patent license under the contributor's essential patent claims, to+make, use, sell, offer for sale, import and otherwise run, modify and+propagate the contents of its contributor version.++ In the following three paragraphs, a "patent license" is any express+agreement or commitment, however denominated, not to enforce a patent+(such as an express permission to practice a patent or covenant not to+sue for patent infringement). To "grant" such a patent license to a+party means to make such an agreement or commitment not to enforce a+patent against the party.++ If you convey a covered work, knowingly relying on a patent license,+and the Corresponding Source of the work is not available for anyone+to copy, free of charge and under the terms of this License, through a+publicly available network server or other readily accessible means,+then you must either (1) cause the Corresponding Source to be so+available, or (2) arrange to deprive yourself of the benefit of the+patent license for this particular work, or (3) arrange, in a manner+consistent with the requirements of this License, to extend the patent+license to downstream recipients. "Knowingly relying" means you have+actual knowledge that, but for the patent license, your conveying the+covered work in a country, or your recipient's use of the covered work+in a country, would infringe one or more identifiable patents in that+country that you have reason to believe are valid.++ If, pursuant to or in connection with a single transaction or+arrangement, you convey, or propagate by procuring conveyance of, a+covered work, and grant a patent license to some of the parties+receiving the covered work authorizing them to use, propagate, modify+or convey a specific copy of the covered work, then the patent license+you grant is automatically extended to all recipients of the covered+work and works based on it.++ A patent license is "discriminatory" if it does not include within+the scope of its coverage, prohibits the exercise of, or is+conditioned on the non-exercise of one or more of the rights that are+specifically granted under this License. You may not convey a covered+work if you are a party to an arrangement with a third party that is+in the business of distributing software, under which you make payment+to the third party based on the extent of your activity of conveying+the work, and under which the third party grants, to any of the+parties who would receive the covered work from you, a discriminatory+patent license (a) in connection with copies of the covered work+conveyed by you (or copies made from those copies), or (b) primarily+for and in connection with specific products or compilations that+contain the covered work, unless you entered into that arrangement,+or that patent license was granted, prior to 28 March 2007.++ Nothing in this License shall be construed as excluding or limiting+any implied license or other defenses to infringement that may+otherwise be available to you under applicable patent law.++ 12. No Surrender of Others' Freedom.++ If conditions are imposed on you (whether by court order, agreement or+otherwise) that contradict the conditions of this License, they do not+excuse you from the conditions of this License. If you cannot convey a+covered work so as to satisfy simultaneously your obligations under this+License and any other pertinent obligations, then as a consequence you may+not convey it at all. For example, if you agree to terms that obligate you+to collect a royalty for further conveying from those to whom you convey+the Program, the only way you could satisfy both those terms and this+License would be to refrain entirely from conveying the Program.++ 13. Use with the GNU Affero General Public License.++ Notwithstanding any other provision of this License, you have+permission to link or combine any covered work with a work licensed+under version 3 of the GNU Affero General Public License into a single+combined work, and to convey the resulting work. The terms of this+License will continue to apply to the part which is the covered work,+but the special requirements of the GNU Affero General Public License,+section 13, concerning interaction through a network will apply to the+combination as such.++ 14. Revised Versions of this License.++ The Free Software Foundation may publish revised and/or new versions of+the GNU General Public License from time to time. Such new versions will+be similar in spirit to the present version, but may differ in detail to+address new problems or concerns.++ Each version is given a distinguishing version number. If the+Program specifies that a certain numbered version of the GNU General+Public License "or any later version" applies to it, you have the+option of following the terms and conditions either of that numbered+version or of any later version published by the Free Software+Foundation. If the Program does not specify a version number of the+GNU General Public License, you may choose any version ever published+by the Free Software Foundation.++ If the Program specifies that a proxy can decide which future+versions of the GNU General Public License can be used, that proxy's+public statement of acceptance of a version permanently authorizes you+to choose that version for the Program.++ Later license versions may give you additional or different+permissions. However, no additional obligations are imposed on any+author or copyright holder as a result of your choosing to follow a+later version.++ 15. Disclaimer of Warranty.++ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.++ 16. Limitation of Liability.++ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF+SUCH DAMAGES.++ 17. Interpretation of Sections 15 and 16.++ If the disclaimer of warranty and limitation of liability provided+above cannot be given local legal effect according to their terms,+reviewing courts shall apply local law that most closely approximates+an absolute waiver of all civil liability in connection with the+Program, unless a warranty or assumption of liability accompanies a+copy of the Program in return for a fee.++ END OF TERMS AND CONDITIONS
@@ -0,0 +1,127 @@+======================================================================+README for the tamarin-prover for security protocol verification+======================================================================++Author: Simon Meier <simon.meier@inf.ethz.ch>++Creation Date: 8/02/2012+++1. Introduction+===============++ The tool is written in Haskell and provides two usage modes as described+ below.+++ NOTE TO REVIEWERS: + to reproduce our results from the paper install the tool and run++ make case-studies++ in the root directory of this source distribution. This will create+ a directory './case-studies' with the analyzed files and their proofs and+ attacks.++++2. Installation instructions+============================++2.1 Requirements+----------------++ The tool was tested on Linux and Mac OsX. It relies on + + - maude version 2.6 for AC unification + + download and install "Full Maude 2.6" from http://maude.cs.uiuc.edu/download/++ - the 'dot' tool from GraphViz for rendering proof states as graphs++ download and install from http://www.graphviz.org/+ (most Linux distributions have a corresponding package)+ + - GHC 7.0.4 and cabal-install++ included in the Haskell Platform 2011.2.0.1+ available from http://hackage.haskell.org/platform/+++2.1 Installing tamarin-prover+----------------------------++ You need a working Haskell environment that provides GHC 7 and the 'cabal+ install' tool. The simplest way to get such an environment is to download and+ install the Haskell Platform package for your OS. + + http://hackage.haskell.org/platform/+ + Then call++ cabal install++ in the root directory of this source code package. This will use the+ Haskell's deployment tool 'cabal-install' to download all missing libraries+ from Hackage, the central Haskell library repository and install the+ 'tamarin-prover' executable in the default installation location of+ cabal-install. The installation location is printed at the end of the build+ process. Note that this may take a long time due to the large number of+ dependencies of the built-in webserver used to serve the interactive mode.+++3. Usage+========++the tamarin-prover can be used in two modes: ++ (1) a batch mode where it just tries to parse the given file (and if called+ with --prove) to prove their specified lemmas.++ (2) an interactive mode, which runs a webserver that allows to construct+ and explore security proofs interactively.+ This mode has to be run with an argument that specifies directory+ containing the protocol models to be investigated. ++See the help message output when calling 'tamarin-prover' without any flags+for more information.++++4. Built-in Equational theories+===============================++There are several built-in equational theories which can be activated+for a given theory file by including:++> builtin: theoryname++The following theories are supported as builtins:++diffie-hellman:+ functions: _ ^ _, inv(_), _*_+ equations: see paper++hashing:+ functions: h(_)+ no equations++signing:+ functions: sign(_,_), verify(_,_,_), pk(_), true+ equations: verify(sign(m,sk), m, pk(sk)) = true++symmetric-encryption:+ functions: senc(_,_), sdec(_,_)+ equations: sdec(senc(m,k),k) = m++asymmetric-encryption:+ functions: aenc(_,_), adec(_,_), pk(_)+ equations: adec(aenc(m, pk(sk)), sk) = m+++***+* Happy Proving :-)+*+* In case of questions do not hesistate to contact the authors+* simon.meier@inf.ethz.ch or benedikt.schmidt@inf.ethz.ch+***
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
@@ -0,0 +1,7 @@+Authors:+ Benedikt Schmidt <benedikt.schmidt@inf.ethz.ch>+ Simon Meier <simon.meier@inf.ethz.ch>++Contributors:+ protocol models: Cas Cremers <cas.cremers@inf.ethz.ch>+ web interface: Cedric Staub <cs@cssx.ch
@@ -0,0 +1,621 @@+ GNU GENERAL PUBLIC LICENSE+ Version 3, 29 June 2007++ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>+ Everyone is permitted to copy and distribute verbatim copies+ of this license document, but changing it is not allowed.++ Preamble++ The GNU General Public License is a free, copyleft license for+software and other kinds of works.++ The licenses for most software and other practical works are designed+to take away your freedom to share and change the works. By contrast,+the GNU General Public License is intended to guarantee your freedom to+share and change all versions of a program--to make sure it remains free+software for all its users. We, the Free Software Foundation, use the+GNU General Public License for most of our software; it applies also to+any other work released this way by its authors. You can apply it to+your programs, too.++ When we speak of free software, we are referring to freedom, not+price. Our General Public Licenses are designed to make sure that you+have the freedom to distribute copies of free software (and charge for+them if you wish), that you receive source code or can get it if you+want it, that you can change the software or use pieces of it in new+free programs, and that you know you can do these things.++ To protect your rights, we need to prevent others from denying you+these rights or asking you to surrender the rights. Therefore, you have+certain responsibilities if you distribute copies of the software, or if+you modify it: responsibilities to respect the freedom of others.++ For example, if you distribute copies of such a program, whether+gratis or for a fee, you must pass on to the recipients the same+freedoms that you received. You must make sure that they, too, receive+or can get the source code. And you must show them these terms so they+know their rights.++ Developers that use the GNU GPL protect your rights with two steps:+(1) assert copyright on the software, and (2) offer you this License+giving you legal permission to copy, distribute and/or modify it.++ For the developers' and authors' protection, the GPL clearly explains+that there is no warranty for this free software. For both users' and+authors' sake, the GPL requires that modified versions be marked as+changed, so that their problems will not be attributed erroneously to+authors of previous versions.++ Some devices are designed to deny users access to install or run+modified versions of the software inside them, although the manufacturer+can do so. This is fundamentally incompatible with the aim of+protecting users' freedom to change the software. The systematic+pattern of such abuse occurs in the area of products for individuals to+use, which is precisely where it is most unacceptable. Therefore, we+have designed this version of the GPL to prohibit the practice for those+products. If such problems arise substantially in other domains, we+stand ready to extend this provision to those domains in future versions+of the GPL, as needed to protect the freedom of users.++ Finally, every program is threatened constantly by software patents.+States should not allow patents to restrict development and use of+software on general-purpose computers, but in those that do, we wish to+avoid the special danger that patents applied to a free program could+make it effectively proprietary. To prevent this, the GPL assures that+patents cannot be used to render the program non-free.++ The precise terms and conditions for copying, distribution and+modification follow.++ TERMS AND CONDITIONS++ 0. Definitions.++ "This License" refers to version 3 of the GNU General Public License.++ "Copyright" also means copyright-like laws that apply to other kinds of+works, such as semiconductor masks.++ "The Program" refers to any copyrightable work licensed under this+License. Each licensee is addressed as "you". "Licensees" and+"recipients" may be individuals or organizations.++ To "modify" a work means to copy from or adapt all or part of the work+in a fashion requiring copyright permission, other than the making of an+exact copy. The resulting work is called a "modified version" of the+earlier work or a work "based on" the earlier work.++ A "covered work" means either the unmodified Program or a work based+on the Program.++ To "propagate" a work means to do anything with it that, without+permission, would make you directly or secondarily liable for+infringement under applicable copyright law, except executing it on a+computer or modifying a private copy. Propagation includes copying,+distribution (with or without modification), making available to the+public, and in some countries other activities as well.++ To "convey" a work means any kind of propagation that enables other+parties to make or receive copies. Mere interaction with a user through+a computer network, with no transfer of a copy, is not conveying.++ An interactive user interface displays "Appropriate Legal Notices"+to the extent that it includes a convenient and prominently visible+feature that (1) displays an appropriate copyright notice, and (2)+tells the user that there is no warranty for the work (except to the+extent that warranties are provided), that licensees may convey the+work under this License, and how to view a copy of this License. If+the interface presents a list of user commands or options, such as a+menu, a prominent item in the list meets this criterion.++ 1. Source Code.++ The "source code" for a work means the preferred form of the work+for making modifications to it. "Object code" means any non-source+form of a work.++ A "Standard Interface" means an interface that either is an official+standard defined by a recognized standards body, or, in the case of+interfaces specified for a particular programming language, one that+is widely used among developers working in that language.++ The "System Libraries" of an executable work include anything, other+than the work as a whole, that (a) is included in the normal form of+packaging a Major Component, but which is not part of that Major+Component, and (b) serves only to enable use of the work with that+Major Component, or to implement a Standard Interface for which an+implementation is available to the public in source code form. A+"Major Component", in this context, means a major essential component+(kernel, window system, and so on) of the specific operating system+(if any) on which the executable work runs, or a compiler used to+produce the work, or an object code interpreter used to run it.++ The "Corresponding Source" for a work in object code form means all+the source code needed to generate, install, and (for an executable+work) run the object code and to modify the work, including scripts to+control those activities. However, it does not include the work's+System Libraries, or general-purpose tools or generally available free+programs which are used unmodified in performing those activities but+which are not part of the work. For example, Corresponding Source+includes interface definition files associated with source files for+the work, and the source code for shared libraries and dynamically+linked subprograms that the work is specifically designed to require,+such as by intimate data communication or control flow between those+subprograms and other parts of the work.++ The Corresponding Source need not include anything that users+can regenerate automatically from other parts of the Corresponding+Source.++ The Corresponding Source for a work in source code form is that+same work.++ 2. Basic Permissions.++ All rights granted under this License are granted for the term of+copyright on the Program, and are irrevocable provided the stated+conditions are met. This License explicitly affirms your unlimited+permission to run the unmodified Program. The output from running a+covered work is covered by this License only if the output, given its+content, constitutes a covered work. This License acknowledges your+rights of fair use or other equivalent, as provided by copyright law.++ You may make, run and propagate covered works that you do not+convey, without conditions so long as your license otherwise remains+in force. You may convey covered works to others for the sole purpose+of having them make modifications exclusively for you, or provide you+with facilities for running those works, provided that you comply with+the terms of this License in conveying all material for which you do+not control copyright. Those thus making or running the covered works+for you must do so exclusively on your behalf, under your direction+and control, on terms that prohibit them from making any copies of+your copyrighted material outside their relationship with you.++ Conveying under any other circumstances is permitted solely under+the conditions stated below. Sublicensing is not allowed; section 10+makes it unnecessary.++ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.++ No covered work shall be deemed part of an effective technological+measure under any applicable law fulfilling obligations under article+11 of the WIPO copyright treaty adopted on 20 December 1996, or+similar laws prohibiting or restricting circumvention of such+measures.++ When you convey a covered work, you waive any legal power to forbid+circumvention of technological measures to the extent such circumvention+is effected by exercising rights under this License with respect to+the covered work, and you disclaim any intention to limit operation or+modification of the work as a means of enforcing, against the work's+users, your or third parties' legal rights to forbid circumvention of+technological measures.++ 4. Conveying Verbatim Copies.++ You may convey verbatim copies of the Program's source code as you+receive it, in any medium, provided that you conspicuously and+appropriately publish on each copy an appropriate copyright notice;+keep intact all notices stating that this License and any+non-permissive terms added in accord with section 7 apply to the code;+keep intact all notices of the absence of any warranty; and give all+recipients a copy of this License along with the Program.++ You may charge any price or no price for each copy that you convey,+and you may offer support or warranty protection for a fee.++ 5. Conveying Modified Source Versions.++ You may convey a work based on the Program, or the modifications to+produce it from the Program, in the form of source code under the+terms of section 4, provided that you also meet all of these conditions:++ a) The work must carry prominent notices stating that you modified+ it, and giving a relevant date.++ b) The work must carry prominent notices stating that it is+ released under this License and any conditions added under section+ 7. This requirement modifies the requirement in section 4 to+ "keep intact all notices".++ c) You must license the entire work, as a whole, under this+ License to anyone who comes into possession of a copy. This+ License will therefore apply, along with any applicable section 7+ additional terms, to the whole of the work, and all its parts,+ regardless of how they are packaged. This License gives no+ permission to license the work in any other way, but it does not+ invalidate such permission if you have separately received it.++ d) If the work has interactive user interfaces, each must display+ Appropriate Legal Notices; however, if the Program has interactive+ interfaces that do not display Appropriate Legal Notices, your+ work need not make them do so.++ A compilation of a covered work with other separate and independent+works, which are not by their nature extensions of the covered work,+and which are not combined with it such as to form a larger program,+in or on a volume of a storage or distribution medium, is called an+"aggregate" if the compilation and its resulting copyright are not+used to limit the access or legal rights of the compilation's users+beyond what the individual works permit. Inclusion of a covered work+in an aggregate does not cause this License to apply to the other+parts of the aggregate.++ 6. Conveying Non-Source Forms.++ You may convey a covered work in object code form under the terms+of sections 4 and 5, provided that you also convey the+machine-readable Corresponding Source under the terms of this License,+in one of these ways:++ a) Convey the object code in, or embodied in, a physical product+ (including a physical distribution medium), accompanied by the+ Corresponding Source fixed on a durable physical medium+ customarily used for software interchange.++ b) Convey the object code in, or embodied in, a physical product+ (including a physical distribution medium), accompanied by a+ written offer, valid for at least three years and valid for as+ long as you offer spare parts or customer support for that product+ model, to give anyone who possesses the object code either (1) a+ copy of the Corresponding Source for all the software in the+ product that is covered by this License, on a durable physical+ medium customarily used for software interchange, for a price no+ more than your reasonable cost of physically performing this+ conveying of source, or (2) access to copy the+ Corresponding Source from a network server at no charge.++ c) Convey individual copies of the object code with a copy of the+ written offer to provide the Corresponding Source. This+ alternative is allowed only occasionally and noncommercially, and+ only if you received the object code with such an offer, in accord+ with subsection 6b.++ d) Convey the object code by offering access from a designated+ place (gratis or for a charge), and offer equivalent access to the+ Corresponding Source in the same way through the same place at no+ further charge. You need not require recipients to copy the+ Corresponding Source along with the object code. If the place to+ copy the object code is a network server, the Corresponding Source+ may be on a different server (operated by you or a third party)+ that supports equivalent copying facilities, provided you maintain+ clear directions next to the object code saying where to find the+ Corresponding Source. Regardless of what server hosts the+ Corresponding Source, you remain obligated to ensure that it is+ available for as long as needed to satisfy these requirements.++ e) Convey the object code using peer-to-peer transmission, provided+ you inform other peers where the object code and Corresponding+ Source of the work are being offered to the general public at no+ charge under subsection 6d.++ A separable portion of the object code, whose source code is excluded+from the Corresponding Source as a System Library, need not be+included in conveying the object code work.++ A "User Product" is either (1) a "consumer product", which means any+tangible personal property which is normally used for personal, family,+or household purposes, or (2) anything designed or sold for incorporation+into a dwelling. In determining whether a product is a consumer product,+doubtful cases shall be resolved in favor of coverage. For a particular+product received by a particular user, "normally used" refers to a+typical or common use of that class of product, regardless of the status+of the particular user or of the way in which the particular user+actually uses, or expects or is expected to use, the product. A product+is a consumer product regardless of whether the product has substantial+commercial, industrial or non-consumer uses, unless such uses represent+the only significant mode of use of the product.++ "Installation Information" for a User Product means any methods,+procedures, authorization keys, or other information required to install+and execute modified versions of a covered work in that User Product from+a modified version of its Corresponding Source. The information must+suffice to ensure that the continued functioning of the modified object+code is in no case prevented or interfered with solely because+modification has been made.++ If you convey an object code work under this section in, or with, or+specifically for use in, a User Product, and the conveying occurs as+part of a transaction in which the right of possession and use of the+User Product is transferred to the recipient in perpetuity or for a+fixed term (regardless of how the transaction is characterized), the+Corresponding Source conveyed under this section must be accompanied+by the Installation Information. But this requirement does not apply+if neither you nor any third party retains the ability to install+modified object code on the User Product (for example, the work has+been installed in ROM).++ The requirement to provide Installation Information does not include a+requirement to continue to provide support service, warranty, or updates+for a work that has been modified or installed by the recipient, or for+the User Product in which it has been modified or installed. Access to a+network may be denied when the modification itself materially and+adversely affects the operation of the network or violates the rules and+protocols for communication across the network.++ Corresponding Source conveyed, and Installation Information provided,+in accord with this section must be in a format that is publicly+documented (and with an implementation available to the public in+source code form), and must require no special password or key for+unpacking, reading or copying.++ 7. Additional Terms.++ "Additional permissions" are terms that supplement the terms of this+License by making exceptions from one or more of its conditions.+Additional permissions that are applicable to the entire Program shall+be treated as though they were included in this License, to the extent+that they are valid under applicable law. If additional permissions+apply only to part of the Program, that part may be used separately+under those permissions, but the entire Program remains governed by+this License without regard to the additional permissions.++ When you convey a copy of a covered work, you may at your option+remove any additional permissions from that copy, or from any part of+it. (Additional permissions may be written to require their own+removal in certain cases when you modify the work.) You may place+additional permissions on material, added by you to a covered work,+for which you have or can give appropriate copyright permission.++ Notwithstanding any other provision of this License, for material you+add to a covered work, you may (if authorized by the copyright holders of+that material) supplement the terms of this License with terms:++ a) Disclaiming warranty or limiting liability differently from the+ terms of sections 15 and 16 of this License; or++ b) Requiring preservation of specified reasonable legal notices or+ author attributions in that material or in the Appropriate Legal+ Notices displayed by works containing it; or++ c) Prohibiting misrepresentation of the origin of that material, or+ requiring that modified versions of such material be marked in+ reasonable ways as different from the original version; or++ d) Limiting the use for publicity purposes of names of licensors or+ authors of the material; or++ e) Declining to grant rights under trademark law for use of some+ trade names, trademarks, or service marks; or++ f) Requiring indemnification of licensors and authors of that+ material by anyone who conveys the material (or modified versions of+ it) with contractual assumptions of liability to the recipient, for+ any liability that these contractual assumptions directly impose on+ those licensors and authors.++ All other non-permissive additional terms are considered "further+restrictions" within the meaning of section 10. If the Program as you+received it, or any part of it, contains a notice stating that it is+governed by this License along with a term that is a further+restriction, you may remove that term. If a license document contains+a further restriction but permits relicensing or conveying under this+License, you may add to a covered work material governed by the terms+of that license document, provided that the further restriction does+not survive such relicensing or conveying.++ If you add terms to a covered work in accord with this section, you+must place, in the relevant source files, a statement of the+additional terms that apply to those files, or a notice indicating+where to find the applicable terms.++ Additional terms, permissive or non-permissive, may be stated in the+form of a separately written license, or stated as exceptions;+the above requirements apply either way.++ 8. Termination.++ You may not propagate or modify a covered work except as expressly+provided under this License. Any attempt otherwise to propagate or+modify it is void, and will automatically terminate your rights under+this License (including any patent licenses granted under the third+paragraph of section 11).++ However, if you cease all violation of this License, then your+license from a particular copyright holder is reinstated (a)+provisionally, unless and until the copyright holder explicitly and+finally terminates your license, and (b) permanently, if the copyright+holder fails to notify you of the violation by some reasonable means+prior to 60 days after the cessation.++ Moreover, your license from a particular copyright holder is+reinstated permanently if the copyright holder notifies you of the+violation by some reasonable means, this is the first time you have+received notice of violation of this License (for any work) from that+copyright holder, and you cure the violation prior to 30 days after+your receipt of the notice.++ Termination of your rights under this section does not terminate the+licenses of parties who have received copies or rights from you under+this License. If your rights have been terminated and not permanently+reinstated, you do not qualify to receive new licenses for the same+material under section 10.++ 9. Acceptance Not Required for Having Copies.++ You are not required to accept this License in order to receive or+run a copy of the Program. Ancillary propagation of a covered work+occurring solely as a consequence of using peer-to-peer transmission+to receive a copy likewise does not require acceptance. However,+nothing other than this License grants you permission to propagate or+modify any covered work. These actions infringe copyright if you do+not accept this License. Therefore, by modifying or propagating a+covered work, you indicate your acceptance of this License to do so.++ 10. Automatic Licensing of Downstream Recipients.++ Each time you convey a covered work, the recipient automatically+receives a license from the original licensors, to run, modify and+propagate that work, subject to this License. You are not responsible+for enforcing compliance by third parties with this License.++ An "entity transaction" is a transaction transferring control of an+organization, or substantially all assets of one, or subdividing an+organization, or merging organizations. If propagation of a covered+work results from an entity transaction, each party to that+transaction who receives a copy of the work also receives whatever+licenses to the work the party's predecessor in interest had or could+give under the previous paragraph, plus a right to possession of the+Corresponding Source of the work from the predecessor in interest, if+the predecessor has it or can get it with reasonable efforts.++ You may not impose any further restrictions on the exercise of the+rights granted or affirmed under this License. For example, you may+not impose a license fee, royalty, or other charge for exercise of+rights granted under this License, and you may not initiate litigation+(including a cross-claim or counterclaim in a lawsuit) alleging that+any patent claim is infringed by making, using, selling, offering for+sale, or importing the Program or any portion of it.++ 11. Patents.++ A "contributor" is a copyright holder who authorizes use under this+License of the Program or a work on which the Program is based. The+work thus licensed is called the contributor's "contributor version".++ A contributor's "essential patent claims" are all patent claims+owned or controlled by the contributor, whether already acquired or+hereafter acquired, that would be infringed by some manner, permitted+by this License, of making, using, or selling its contributor version,+but do not include claims that would be infringed only as a+consequence of further modification of the contributor version. For+purposes of this definition, "control" includes the right to grant+patent sublicenses in a manner consistent with the requirements of+this License.++ Each contributor grants you a non-exclusive, worldwide, royalty-free+patent license under the contributor's essential patent claims, to+make, use, sell, offer for sale, import and otherwise run, modify and+propagate the contents of its contributor version.++ In the following three paragraphs, a "patent license" is any express+agreement or commitment, however denominated, not to enforce a patent+(such as an express permission to practice a patent or covenant not to+sue for patent infringement). To "grant" such a patent license to a+party means to make such an agreement or commitment not to enforce a+patent against the party.++ If you convey a covered work, knowingly relying on a patent license,+and the Corresponding Source of the work is not available for anyone+to copy, free of charge and under the terms of this License, through a+publicly available network server or other readily accessible means,+then you must either (1) cause the Corresponding Source to be so+available, or (2) arrange to deprive yourself of the benefit of the+patent license for this particular work, or (3) arrange, in a manner+consistent with the requirements of this License, to extend the patent+license to downstream recipients. "Knowingly relying" means you have+actual knowledge that, but for the patent license, your conveying the+covered work in a country, or your recipient's use of the covered work+in a country, would infringe one or more identifiable patents in that+country that you have reason to believe are valid.++ If, pursuant to or in connection with a single transaction or+arrangement, you convey, or propagate by procuring conveyance of, a+covered work, and grant a patent license to some of the parties+receiving the covered work authorizing them to use, propagate, modify+or convey a specific copy of the covered work, then the patent license+you grant is automatically extended to all recipients of the covered+work and works based on it.++ A patent license is "discriminatory" if it does not include within+the scope of its coverage, prohibits the exercise of, or is+conditioned on the non-exercise of one or more of the rights that are+specifically granted under this License. You may not convey a covered+work if you are a party to an arrangement with a third party that is+in the business of distributing software, under which you make payment+to the third party based on the extent of your activity of conveying+the work, and under which the third party grants, to any of the+parties who would receive the covered work from you, a discriminatory+patent license (a) in connection with copies of the covered work+conveyed by you (or copies made from those copies), or (b) primarily+for and in connection with specific products or compilations that+contain the covered work, unless you entered into that arrangement,+or that patent license was granted, prior to 28 March 2007.++ Nothing in this License shall be construed as excluding or limiting+any implied license or other defenses to infringement that may+otherwise be available to you under applicable patent law.++ 12. No Surrender of Others' Freedom.++ If conditions are imposed on you (whether by court order, agreement or+otherwise) that contradict the conditions of this License, they do not+excuse you from the conditions of this License. If you cannot convey a+covered work so as to satisfy simultaneously your obligations under this+License and any other pertinent obligations, then as a consequence you may+not convey it at all. For example, if you agree to terms that obligate you+to collect a royalty for further conveying from those to whom you convey+the Program, the only way you could satisfy both those terms and this+License would be to refrain entirely from conveying the Program.++ 13. Use with the GNU Affero General Public License.++ Notwithstanding any other provision of this License, you have+permission to link or combine any covered work with a work licensed+under version 3 of the GNU Affero General Public License into a single+combined work, and to convey the resulting work. The terms of this+License will continue to apply to the part which is the covered work,+but the special requirements of the GNU Affero General Public License,+section 13, concerning interaction through a network will apply to the+combination as such.++ 14. Revised Versions of this License.++ The Free Software Foundation may publish revised and/or new versions of+the GNU General Public License from time to time. Such new versions will+be similar in spirit to the present version, but may differ in detail to+address new problems or concerns.++ Each version is given a distinguishing version number. If the+Program specifies that a certain numbered version of the GNU General+Public License "or any later version" applies to it, you have the+option of following the terms and conditions either of that numbered+version or of any later version published by the Free Software+Foundation. If the Program does not specify a version number of the+GNU General Public License, you may choose any version ever published+by the Free Software Foundation.++ If the Program specifies that a proxy can decide which future+versions of the GNU General Public License can be used, that proxy's+public statement of acceptance of a version permanently authorizes you+to choose that version for the Program.++ Later license versions may give you additional or different+permissions. However, no additional obligations are imposed on any+author or copyright holder as a result of your choosing to follow a+later version.++ 15. Disclaimer of Warranty.++ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.++ 16. Limitation of Liability.++ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF+SUCH DAMAGES.++ 17. Interpretation of Sections 15 and 16.++ If the disclaimer of warranty and limitation of liability provided+above cannot be given local legal effect according to their terms,+reviewing courts shall apply local law that most closely approximates+an absolute waiver of all civil liability in connection with the+Program, unless a warranty or assumption of liability accompanies a+copy of the Program in return for a fee.++ END OF TERMS AND CONDITIONS
@@ -0,0 +1,65 @@+/* Generic context menu styles */ + +ul#contextMenu { + display: none; +} + +.contextMenu { + position: absolute; + width: 10em; + z-index: 99999; + border: solid 1px #CCC; + background: #EEE; + padding: 0; + margin: 0; + display: none; +} + +.contextMenu LI { + list-style: none; + padding: 0; + margin: 0; +} + +.contextMenu A { + color: #333; + text-decoration: none; + display: block; + line-height: 1em; + height: 1em; + outline: none; + padding: 0.3em; + padding-left: 1.4em; +} + +.contextMenu LI.hover A { + color: #FFF; + background-color: #3399FF; +} + +.contextMenu LI.disabled A { + color: #AAA; + cursor: default; +} + +.contextMenu LI.hover.disabled A { + background-color: transparent; +} + +.contextMenu LI.separator { + border-top: solid 1px #CCC; +} + +li.autoprove a { + background-image: url(/static/img/autoprove.png); + background-repeat: no-repeat; + background-position: 0.2em center; + background-size: 1em; +} + +li.delstep a { + background-image: url(/static/img/delete.png); + background-repeat: no-repeat; + background-position: 0.2em center; + background-size: 1em; +}
binary file changed (absent → 180 bytes)
binary file changed (absent → 178 bytes)
binary file changed (absent → 120 bytes)
binary file changed (absent → 105 bytes)
binary file changed (absent → 111 bytes)
binary file changed (absent → 110 bytes)
binary file changed (absent → 119 bytes)
binary file changed (absent → 101 bytes)
binary file changed (absent → 4369 bytes)
binary file changed (absent → 4369 bytes)
binary file changed (absent → 4369 bytes)
binary file changed (absent → 4369 bytes)
binary file changed (absent → 4369 bytes)
@@ -0,0 +1,578 @@+/*+ * jQuery UI CSS Framework 1.8.13+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Theming/API+ */++/* Layout helpers+----------------------------------*/+.ui-helper-hidden { display: none; }+.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }+.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }+.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }+.ui-helper-clearfix { display: inline-block; }+/* required comment for clearfix to work in Opera \*/+* html .ui-helper-clearfix { height:1%; }+.ui-helper-clearfix { display:block; }+/* end clearfix */+.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }+++/* Interaction Cues+----------------------------------*/+.ui-state-disabled { cursor: default !important; }+++/* Icons+----------------------------------*/++/* states and images */+.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }+++/* Misc visuals+----------------------------------*/++/* Overlays */+.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }+++/*+ * jQuery UI CSS Framework 1.8.13+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Theming/API+ *+ * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana,Arial,sans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=03_highlight_soft.png&bgImgOpacityHeader=75&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=ffffff&bgTextureContent=01_flat.png&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=e6e6e6&bgTextureDefault=02_glass.png&bgImgOpacityDefault=75&borderColorDefault=d3d3d3&fcDefault=555555&iconColorDefault=888888&bgColorHover=dadada&bgTextureHover=02_glass.png&bgImgOpacityHover=75&borderColorHover=999999&fcHover=212121&iconColorHover=454545&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=aaaaaa&fcActive=212121&iconColorActive=454545&bgColorHighlight=fbf9ee&bgTextureHighlight=02_glass.png&bgImgOpacityHighlight=55&borderColorHighlight=fcefa1&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=02_glass.png&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px+ */+++/* Component containers+----------------------------------*/+.ui-widget { font-family: Verdana,Arial,sans-serif; font-size: 1.1em; }+.ui-widget .ui-widget { font-size: 1em; }+.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif; font-size: 1em; }+.ui-widget-content { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x; color: #222222; }+.ui-widget-content a { color: #222222; }+.ui-widget-header { border: 1px solid #aaaaaa; background: #cccccc url(images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x; color: #222222; font-weight: bold; }+.ui-widget-header a { color: #222222; }++/* Interaction states+----------------------------------*/+.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3; background: #e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #555555; }+.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555; text-decoration: none; }+.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #999999; background: #dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; }+.ui-state-hover a, .ui-state-hover a:hover { color: #212121; text-decoration: none; }+.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; }+.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121; text-decoration: none; }+.ui-widget :active { outline: none; }++/* Interaction Cues+----------------------------------*/+.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fcefa1; background: #fbf9ee url(images/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x; color: #363636; }+.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; }+.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; color: #cd0a0a; }+.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a; }+.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a; }+.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }+.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }+.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }++/* Icons+----------------------------------*/++/* states and images */+.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); }+.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }+.ui-widget-header .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }+.ui-state-default .ui-icon { background-image: url(images/ui-icons_888888_256x240.png); }+.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); }+.ui-state-active .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); }+.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png); }+.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png); }++/* positioning */+.ui-icon-carat-1-n { background-position: 0 0; }+.ui-icon-carat-1-ne { background-position: -16px 0; }+.ui-icon-carat-1-e { background-position: -32px 0; }+.ui-icon-carat-1-se { background-position: -48px 0; }+.ui-icon-carat-1-s { background-position: -64px 0; }+.ui-icon-carat-1-sw { background-position: -80px 0; }+.ui-icon-carat-1-w { background-position: -96px 0; }+.ui-icon-carat-1-nw { background-position: -112px 0; }+.ui-icon-carat-2-n-s { background-position: -128px 0; }+.ui-icon-carat-2-e-w { background-position: -144px 0; }+.ui-icon-triangle-1-n { background-position: 0 -16px; }+.ui-icon-triangle-1-ne { background-position: -16px -16px; }+.ui-icon-triangle-1-e { background-position: -32px -16px; }+.ui-icon-triangle-1-se { background-position: -48px -16px; }+.ui-icon-triangle-1-s { background-position: -64px -16px; }+.ui-icon-triangle-1-sw { background-position: -80px -16px; }+.ui-icon-triangle-1-w { background-position: -96px -16px; }+.ui-icon-triangle-1-nw { background-position: -112px -16px; }+.ui-icon-triangle-2-n-s { background-position: -128px -16px; }+.ui-icon-triangle-2-e-w { background-position: -144px -16px; }+.ui-icon-arrow-1-n { background-position: 0 -32px; }+.ui-icon-arrow-1-ne { background-position: -16px -32px; }+.ui-icon-arrow-1-e { background-position: -32px -32px; }+.ui-icon-arrow-1-se { background-position: -48px -32px; }+.ui-icon-arrow-1-s { background-position: -64px -32px; }+.ui-icon-arrow-1-sw { background-position: -80px -32px; }+.ui-icon-arrow-1-w { background-position: -96px -32px; }+.ui-icon-arrow-1-nw { background-position: -112px -32px; }+.ui-icon-arrow-2-n-s { background-position: -128px -32px; }+.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }+.ui-icon-arrow-2-e-w { background-position: -160px -32px; }+.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }+.ui-icon-arrowstop-1-n { background-position: -192px -32px; }+.ui-icon-arrowstop-1-e { background-position: -208px -32px; }+.ui-icon-arrowstop-1-s { background-position: -224px -32px; }+.ui-icon-arrowstop-1-w { background-position: -240px -32px; }+.ui-icon-arrowthick-1-n { background-position: 0 -48px; }+.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }+.ui-icon-arrowthick-1-e { background-position: -32px -48px; }+.ui-icon-arrowthick-1-se { background-position: -48px -48px; }+.ui-icon-arrowthick-1-s { background-position: -64px -48px; }+.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }+.ui-icon-arrowthick-1-w { background-position: -96px -48px; }+.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }+.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }+.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }+.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }+.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }+.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }+.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }+.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }+.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }+.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }+.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }+.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }+.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }+.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }+.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }+.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }+.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }+.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }+.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }+.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }+.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }+.ui-icon-arrow-4 { background-position: 0 -80px; }+.ui-icon-arrow-4-diag { background-position: -16px -80px; }+.ui-icon-extlink { background-position: -32px -80px; }+.ui-icon-newwin { background-position: -48px -80px; }+.ui-icon-refresh { background-position: -64px -80px; }+.ui-icon-shuffle { background-position: -80px -80px; }+.ui-icon-transfer-e-w { background-position: -96px -80px; }+.ui-icon-transferthick-e-w { background-position: -112px -80px; }+.ui-icon-folder-collapsed { background-position: 0 -96px; }+.ui-icon-folder-open { background-position: -16px -96px; }+.ui-icon-document { background-position: -32px -96px; }+.ui-icon-document-b { background-position: -48px -96px; }+.ui-icon-note { background-position: -64px -96px; }+.ui-icon-mail-closed { background-position: -80px -96px; }+.ui-icon-mail-open { background-position: -96px -96px; }+.ui-icon-suitcase { background-position: -112px -96px; }+.ui-icon-comment { background-position: -128px -96px; }+.ui-icon-person { background-position: -144px -96px; }+.ui-icon-print { background-position: -160px -96px; }+.ui-icon-trash { background-position: -176px -96px; }+.ui-icon-locked { background-position: -192px -96px; }+.ui-icon-unlocked { background-position: -208px -96px; }+.ui-icon-bookmark { background-position: -224px -96px; }+.ui-icon-tag { background-position: -240px -96px; }+.ui-icon-home { background-position: 0 -112px; }+.ui-icon-flag { background-position: -16px -112px; }+.ui-icon-calendar { background-position: -32px -112px; }+.ui-icon-cart { background-position: -48px -112px; }+.ui-icon-pencil { background-position: -64px -112px; }+.ui-icon-clock { background-position: -80px -112px; }+.ui-icon-disk { background-position: -96px -112px; }+.ui-icon-calculator { background-position: -112px -112px; }+.ui-icon-zoomin { background-position: -128px -112px; }+.ui-icon-zoomout { background-position: -144px -112px; }+.ui-icon-search { background-position: -160px -112px; }+.ui-icon-wrench { background-position: -176px -112px; }+.ui-icon-gear { background-position: -192px -112px; }+.ui-icon-heart { background-position: -208px -112px; }+.ui-icon-star { background-position: -224px -112px; }+.ui-icon-link { background-position: -240px -112px; }+.ui-icon-cancel { background-position: 0 -128px; }+.ui-icon-plus { background-position: -16px -128px; }+.ui-icon-plusthick { background-position: -32px -128px; }+.ui-icon-minus { background-position: -48px -128px; }+.ui-icon-minusthick { background-position: -64px -128px; }+.ui-icon-close { background-position: -80px -128px; }+.ui-icon-closethick { background-position: -96px -128px; }+.ui-icon-key { background-position: -112px -128px; }+.ui-icon-lightbulb { background-position: -128px -128px; }+.ui-icon-scissors { background-position: -144px -128px; }+.ui-icon-clipboard { background-position: -160px -128px; }+.ui-icon-copy { background-position: -176px -128px; }+.ui-icon-contact { background-position: -192px -128px; }+.ui-icon-image { background-position: -208px -128px; }+.ui-icon-video { background-position: -224px -128px; }+.ui-icon-script { background-position: -240px -128px; }+.ui-icon-alert { background-position: 0 -144px; }+.ui-icon-info { background-position: -16px -144px; }+.ui-icon-notice { background-position: -32px -144px; }+.ui-icon-help { background-position: -48px -144px; }+.ui-icon-check { background-position: -64px -144px; }+.ui-icon-bullet { background-position: -80px -144px; }+.ui-icon-radio-off { background-position: -96px -144px; }+.ui-icon-radio-on { background-position: -112px -144px; }+.ui-icon-pin-w { background-position: -128px -144px; }+.ui-icon-pin-s { background-position: -144px -144px; }+.ui-icon-play { background-position: 0 -160px; }+.ui-icon-pause { background-position: -16px -160px; }+.ui-icon-seek-next { background-position: -32px -160px; }+.ui-icon-seek-prev { background-position: -48px -160px; }+.ui-icon-seek-end { background-position: -64px -160px; }+.ui-icon-seek-start { background-position: -80px -160px; }+/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */+.ui-icon-seek-first { background-position: -80px -160px; }+.ui-icon-stop { background-position: -96px -160px; }+.ui-icon-eject { background-position: -112px -160px; }+.ui-icon-volume-off { background-position: -128px -160px; }+.ui-icon-volume-on { background-position: -144px -160px; }+.ui-icon-power { background-position: 0 -176px; }+.ui-icon-signal-diag { background-position: -16px -176px; }+.ui-icon-signal { background-position: -32px -176px; }+.ui-icon-battery-0 { background-position: -48px -176px; }+.ui-icon-battery-1 { background-position: -64px -176px; }+.ui-icon-battery-2 { background-position: -80px -176px; }+.ui-icon-battery-3 { background-position: -96px -176px; }+.ui-icon-circle-plus { background-position: 0 -192px; }+.ui-icon-circle-minus { background-position: -16px -192px; }+.ui-icon-circle-close { background-position: -32px -192px; }+.ui-icon-circle-triangle-e { background-position: -48px -192px; }+.ui-icon-circle-triangle-s { background-position: -64px -192px; }+.ui-icon-circle-triangle-w { background-position: -80px -192px; }+.ui-icon-circle-triangle-n { background-position: -96px -192px; }+.ui-icon-circle-arrow-e { background-position: -112px -192px; }+.ui-icon-circle-arrow-s { background-position: -128px -192px; }+.ui-icon-circle-arrow-w { background-position: -144px -192px; }+.ui-icon-circle-arrow-n { background-position: -160px -192px; }+.ui-icon-circle-zoomin { background-position: -176px -192px; }+.ui-icon-circle-zoomout { background-position: -192px -192px; }+.ui-icon-circle-check { background-position: -208px -192px; }+.ui-icon-circlesmall-plus { background-position: 0 -208px; }+.ui-icon-circlesmall-minus { background-position: -16px -208px; }+.ui-icon-circlesmall-close { background-position: -32px -208px; }+.ui-icon-squaresmall-plus { background-position: -48px -208px; }+.ui-icon-squaresmall-minus { background-position: -64px -208px; }+.ui-icon-squaresmall-close { background-position: -80px -208px; }+.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }+.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }+.ui-icon-grip-solid-vertical { background-position: -32px -224px; }+.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }+.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }+.ui-icon-grip-diagonal-se { background-position: -80px -224px; }+++/* Misc visuals+----------------------------------*/++/* Corner radius */+.ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; }+.ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; }+.ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }+.ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }+.ui-corner-top { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; }+.ui-corner-bottom { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }+.ui-corner-right { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }+.ui-corner-left { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }+.ui-corner-all { -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; }++/* Overlays */+.ui-widget-overlay { background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); }+.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; }/*+ * jQuery UI Resizable 1.8.13+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Resizable#theming+ */+.ui-resizable { position: relative;}+.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;+ /* http://bugs.jqueryui.com/ticket/7233+ - Resizable: resizable handles fail to work in IE if transparent and content overlaps+ */+ background-image:url(data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=);+}+.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }+.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; }+.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; }+.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; }+.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; }+.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }+.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }+.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }+.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/*+ * jQuery UI Selectable 1.8.13+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Selectable#theming+ */+.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; }+/*+ * jQuery UI Accordion 1.8.13+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Accordion#theming+ */+/* IE/Win - Fix animation bug - #4615 */+.ui-accordion { width: 100%; }+.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; }+.ui-accordion .ui-accordion-li-fix { display: inline; }+.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; }+.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; }+.ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; }+.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }+.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; }+.ui-accordion .ui-accordion-content-active { display: block; }+/*+ * jQuery UI Autocomplete 1.8.13+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Autocomplete#theming+ */+.ui-autocomplete { position: absolute; cursor: default; } ++/* workarounds */+* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */++/*+ * jQuery UI Menu 1.8.13+ *+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Menu#theming+ */+.ui-menu {+ list-style:none;+ padding: 2px;+ margin: 0;+ display:block;+ float: left;+}+.ui-menu .ui-menu {+ margin-top: -3px;+}+.ui-menu .ui-menu-item {+ margin:0;+ padding: 0;+ zoom: 1;+ float: left;+ clear: left;+ width: 100%;+}+.ui-menu .ui-menu-item a {+ text-decoration:none;+ display:block;+ padding:.2em .4em;+ line-height:1.5;+ zoom:1;+}+.ui-menu .ui-menu-item a.ui-state-hover,+.ui-menu .ui-menu-item a.ui-state-active {+ font-weight: normal;+ margin: -1px;+}+/*+ * jQuery UI Button 1.8.13+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Button#theming+ */+.ui-button { display: inline-block; position: relative; padding: 0; margin-top: 0em; margin-bottom: 0em; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */+.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */+button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */+.ui-button-icons-only { width: 3.4em; } +button.ui-button-icons-only { width: 3.7em; } ++/*button text element */+.ui-button .ui-button-text { display: block; line-height: 1; font-size: 1em; }+.ui-button-text-only .ui-button-text { padding: .4em 1em; }+.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; }+.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; }+.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; }+.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; }+/* no icon support for input elements, provide padding by default */+input.ui-button { padding: .4em 1em; }++/*button icon element(s) */+.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; }+.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; }+.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; }+.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }+.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }++/*button sets*/+.ui-buttonset { margin-right: 7px; }+.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; }++/* workarounds */+button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */+/*+ * jQuery UI Dialog 1.8.13+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Dialog#theming+ */+.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; }+.ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative; }+.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; } +.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }+.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }+.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }+.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }+.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .0em 0 0 0; padding: .3em 1em .1em .4em; }+.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; }+.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; }+.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }+.ui-draggable .ui-dialog-titlebar { cursor: move; }+/*+ * jQuery UI Slider 1.8.13+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Slider#theming+ */+.ui-slider { position: relative; text-align: left; }+.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }+.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; }++.ui-slider-horizontal { height: .8em; }+.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }+.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }+.ui-slider-horizontal .ui-slider-range-min { left: 0; }+.ui-slider-horizontal .ui-slider-range-max { right: 0; }++.ui-slider-vertical { width: .8em; height: 100px; }+.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }+.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }+.ui-slider-vertical .ui-slider-range-min { bottom: 0; }+.ui-slider-vertical .ui-slider-range-max { top: 0; }/*+ * jQuery UI Tabs 1.8.13+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Tabs#theming+ */+.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */+.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; }+.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; }+.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; }+.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; }+.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; }+.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */+.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; }+.ui-tabs .ui-tabs-hide { display: none !important; }+/*+ * jQuery UI Datepicker 1.8.13+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Datepicker#theming+ */+.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }+.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }+.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }+.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }+.ui-datepicker .ui-datepicker-prev { left:2px; }+.ui-datepicker .ui-datepicker-next { right:2px; }+.ui-datepicker .ui-datepicker-prev-hover { left:1px; }+.ui-datepicker .ui-datepicker-next-hover { right:1px; }+.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; }+.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }+.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }+.ui-datepicker select.ui-datepicker-month-year {width: 100%;}+.ui-datepicker select.ui-datepicker-month, +.ui-datepicker select.ui-datepicker-year { width: 49%;}+.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }+.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; }+.ui-datepicker td { border: 0; padding: 1px; }+.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }+.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }+.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }+.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }++/* with multiple calendars */+.ui-datepicker.ui-datepicker-multi { width:auto; }+.ui-datepicker-multi .ui-datepicker-group { float:left; }+.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }+.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }+.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }+.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }+.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }+.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }+.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }+.ui-datepicker-row-break { clear:both; width:100%; }++/* RTL support */+.ui-datepicker-rtl { direction: rtl; }+.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }+.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }+.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }+.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }+.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }+.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }+.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }+.ui-datepicker-rtl .ui-datepicker-group { float:right; }+.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }+.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }++/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */+.ui-datepicker-cover {+ display: none; /*sorry for IE5*/+ display/**/: block; /*sorry for IE5*/+ position: absolute; /*must have*/+ z-index: -1; /*must have*/+ filter: mask(); /*must have*/+ top: -4px; /*must have*/+ left: -4px; /*must have*/+ width: 200px; /*must have*/+ height: 200px; /*must have*/+}/*+ * jQuery UI Progressbar 1.8.13+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Progressbar#theming+ */+.ui-progressbar { height:2em; text-align: left; }+.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }
@@ -0,0 +1,506 @@+/* Common Style+ **************/++html, body {+ font-family: + 'DejaVu Sans', /* Linux */+ 'Liberation Sans', /* Linux/RedHat */+ 'Geneva', /* Mac OS X */+ 'Arial', /* Windows */+ sans-serif; /* Fallback */+ background: #fff;+ font-size: 0.95em;+}++a {+ color: #203ab7;+ text-decoration: none;+}++a:hover {+ color: #000000;+}++a.active-link {+ background: #ffffb0;+}++.monospace {+ font-size: 0.9em;+ font-family:+ 'DejaVu Sans Mono', /* Linux */+ 'Liberation Mono', /* Linux/RedHat */+ 'Monaco', /* Mac OS X */+ 'Lucida Consola', /* Windows */+ monospace; /* Fallback */+}++p.loading, p.message {+ position: fixed;+ z-index: 999999;+ margin: 0;+ padding: 0.6em 0.5em 0.5em 0.5em;+ right: 0.3em;+ bottom: 0.3em;+ font-size: 1em;+ line-height: 1.2em;+ background: #dddddd;+ border: solid 2px #2067fe;+ font-weight: bold;+ text-align: left;+ border-radius: 0.5em;+}++p.loading {+ display: none;+ padding-left: 1.8em !important;+ background-image: url(/static/img/ajax-loader.gif);+ background-repeat: no-repeat;+ background-position: 0.4em;+ background-size: 1.2em; +}++div.content {+ margin: 0.5em;+}++img.icon {+ padding: 0;+ margin: 0;+ height: 1em;+}++/* Highlighting Styles+ *********************/++.hl_comment {+ color: #808080;+}++.hl_keyword {+ font-weight: bold;+}++.hl_operator {+ color: #a00000;+}++.hl_solved {+ background: #bbeebb;+}++.hl_superfluous {+ background: #eebbbb;+}++.keys {+ font-weight: bold;+ color: #800000;+}++/* Specific Styles+ *****************/++.ui-dialog-content {+ font-size: 0.85em;+}++div#dialog {+ display: none;+}++span#err {+ color: #800000;+ font-weight: bold;+}++span#loading img {+ vertical-align: middle;+}++p.rules {+ margin-top: 0em;+ padding-top: 0em;+}++img.graph {+ border: solid 1px #ccc;+}++/* Forms+ *******/++form {+ width: 100%;+ height: 100%;+}++label {+ display: block;+ font-weight: bold;+ margin-bottom: 1em;+}++div.tooltip {+ display: none;+}++div.required {+ width: 100%;+ height: 90%;+ margin-bottom: 3.5em;+}++textarea {+ display: block;+ width: 100%;+ height: 100%;+}++form.root-form div.required {+ height: auto;+ margin-bottom: 0;+}++form.root-form div.required label {+ display: none;+ font-weight: bold;+}++/* Navigation+ ************/++a.active-option {+ background-image: url(/static/img/option-on.png) !important;+ background-repeat: no-repeat !important;+ background-position: 12.8em center !important;+}++a.inactive-option {+ background-image: url(/static/img/option-off.png) !important;+ background-repeat: no-repeat !important;+ background-position: 12.8em center !important;+}++a.remove-step {+ height: 1em;+ padding: 0 1em 0 1em;+ background-image: url(/static/img/delete.png) !important;+ background-repeat: no-repeat !important;+ background-position: center !important;+ background-size: 1em;+ /* Standard */+ opacity: 0;+ /* Trident */+ filter: alpha(opacity=0);+}++a.edit-link:hover, a.delete-link:hover {+ background: none;+}++span.hl_solved:hover + a.remove-step,+a.proof-step:hover + a.remove-step {+ /* Standard */+ opacity: 0.5;+ /* Trident */+ filter: alpha(opacity=50);+}++a.remove-step:hover {+ /* Standard */+ opacity: 1;+ /* Trident */+ filter: alpha(opacity=100);+}++ul#navigation {+ list-style: none;+ float: right;+ margin: 0em;+ padding: 0em;+ margin-right: 0.3em;+}++ul#navigation li {+ float: left;+ width: 11em;+ display: inline;+ margin-right: 0.8em;+ position: relative;+ z-index: 999;+ padding-left: 0.5em;+}++ul#navigation li a {+ display: block;+ color: #000;+ width: 100%;+ margin-top: 0em;+ border-radius: 0.3em;+ padding: 0.3em;+ border: solid 1px #aeaeae;+ /* Gecko */+ background:+ -moz-linear-gradient(+ top,+ #eeeeee 0%,+ #cccccc 100%);+ /* Presto */+ background:+ -o-linear-gradient(+ top,+ #eeeeee 0%,+ #cccccc 100%);+ /* Webkit */+ background:+ -webkit-linear-gradient(+ top,+ #eeeeee 0%,+ #cccccc 100%);+ /* Trident */+ filter:+ progid:DXImageTransform.Microsoft.gradient(+ startColorstr='#eeeeee',+ endColorstr='#cccccc',+ GradientType=0 );+}++ul#navigation li a:hover {+ background: #ccc;+ /* Standard */+ opacity: 0.8;+ /* Trident */+ filter: alpha(opacity=80);+}++ul#navigation li ul {+ width: 13em;+ display: none;+ list-style: none;+ margin-left: -0.8em;+ padding: 0.3em 0 0 0;+ /* Standard */+ opacity: 0.8;+ /* Trident */+ filter: alpha(opacity=80);+}++ul#navigation li ul li {+ width: 100%;+ margin: 0em;+ padding: 0em;+ background: #000;+ font-size: 0.8em;+ border-bottom: solid 1px #666;+}++ul#navigation li ul li:first-child {+ border-radius: 0.5em 0.5em 0 0;+}++ul#navigation li ul li:last-child {+ border-radius: 0 0 0.5em 0.5em;+ border-bottom: none;+}++ul#navigation li ul li a {+ display: block;+ width: 100%;+ height: 100%;+ color: #fff;+ padding: 0.5em;+ background: none;+ border: none;+}++ul#navigation li ul li a:hover {+ background: none;+}++ul#navigation li ul li:hover {+ background: #666;+}++/* Tables+ ********/++table {+ border-collapse: collapse;+}++table th {+ padding: 0.5em;+ background: #eeeeee;+ border: solid 1px #aeaeae;+ /* Gecko */+ background:+ -moz-linear-gradient(+ top,+ #eeeeee 0%,+ #cccccc 100%);+ /* Presto */+ background:+ -o-linear-gradient(+ top,+ #eeeeee 0%,+ #cccccc 100%);+ /* Webkit */+ background:+ -webkit-linear-gradient(+ top,+ #eeeeee 0%,+ #cccccc 100%);+ /* Trident */+ filter:+ progid:DXImageTransform.Microsoft.gradient(+ startColorstr='#eeeeee',+ endColorstr='#cccccc',+ GradientType=0 );+}++table td {+ background: #fff;+ text-align: left;+ padding: 0.5em;+ border: solid 1px #aeaeae;+}++/* Headings+ **********/++h1.pane-head {+ z-index: inherit;+ font-size: 1.1em;+ font-weight: bold;+ position: relative;+ margin: 0em;+ padding: 0.5em;+ background: #eeeeee;+ border-bottom: solid 1px #aeaeae;+ width: 100%;+ /* Gecko */+ background:+ -moz-linear-gradient(+ top,+ #eeeeee 0%,+ #cccccc 100%);+ /* Presto */+ background:+ -o-linear-gradient(+ top,+ #eeeeee 0%,+ #cccccc 100%);+ /* Webkit */+ background:+ -webkit-linear-gradient(+ top,+ #eeeeee 0%,+ #cccccc 100%);+ /* Trident */+ filter:+ progid:DXImageTransform.Microsoft.gradient(+ startColorstr='#eeeeee',+ endColorstr='#cccccc',+ GradientType=0 );+}++h1 {+ font-size: 1.5em;+ z-index: inherit;+}++h2 {+ margin-top: 0em;+ margin-bottom: 0em;+ font-size: 1.2em;+}++h3 {+ margin-top: 0em;+ margin-bottom: 0em;+ font-size: 1em;+}++h4 {+ margin-top: 0em;+ margin-bottom: 0em;+ font-size: 1em;+}++/* Layout+ ********/++.ui-layout-north {+ z-index: 2 !important;+}++.ui-layout-east, .ui-layout-west, .ui-layout-center {+ z-index: 1;+ padding: 0em;+ margin: 0em;+ border: none;+ overflow: hidden;+}++.scroll-wrapper {+ position: absolute;+ top: 2.4em;+ bottom: 0em;+ left: 0em;+ right: 0em;+ padding: 0em;+ overflow: auto;+}++#ui-main-display, #ui-debug-display, #proof {+ z-index: inherit;+ padding: 0.8em;+ margin: 0em;+ height: 90%;+}++#ui-debug-display {+ font-size: 0.75em;+}++.ui-layout-pane {+ background: #fff;+}++.ui-layout-pane-north {+ font-size: 0.8em;+ background: #eeeeee;+ border-bottom: solid 1px #aeaeae;+}++div#header-info {+ float: left;+ font-weight: bold;+ padding: 0.75em;+ border: solid 1px #eeeeee;+}++div#header-links {+ float: right;+ font-weight: bold;+ padding: 0.5em;+}++div#header-links a.plain-link,+div#header-links a.save-link {+ margin: 0em;+ padding: 1em;+ padding-bottom: 0;+ line-height: 2em;+}++.ui-layout-resizer {+ background-color: #aeaeae;+ z-index: 1 !important;+}++.ui-layout-toggler {+ background-color: #666666;+ border-radius: 1em;+}
@@ -0,0 +1,4 @@+" autocommand to detect .spthy files+augroup filetypedetect+au BufNewFile,BufRead *.spthy setf spthy+augroup END
@@ -0,0 +1,204 @@+" Vim syntax file+" Language: DH-proto-proof Security Protocol Theory Files+" Maintainer: +" Last Change: 2010 12 17+" based on Claudio Fleiner's <claudio@fleiner.com> spthy syntax highlighting+" file.++" Quit when a syntax file was already loaded+if !exists("main_syntax")+ if version < 600+ syntax clear+ elseif exists("b:current_syntax")+ finish+ endif+ " we define it here so that included files can test for it+ let main_syntax='spthy'+ syn region spthyFold start="{" end="}" transparent fold+endif++" don't use standard HiLink, it will not work with included syntax files+if version < 508+ command! -nargs=+ SpthyHiLink hi link <args>+else+ command! -nargs=+ SpthyHiLink hi def link <args>+endif++" some characters that cannot be in a spthy program (outside a string)+" syn match spthyError "[\\@`]"+" syn match spthyError "<<<\|\.\.\|=>\|<>\|||=\|&&=\|[^-]->\|\*\/"+" syn match spthyOK "\.\.\."++syn match spthyLAtom ":>"+syn match spthyLAtom "--|"+syn match spthyLAtom "<:"+syn match spthyLAtom ">+>"+syn match spthyLAtom ">->"+syn match spthyLAtom "="+syn match spthyLAtom "@"+syn match spthyLAtom "<"++syn keyword spthyConstr aenc sdec senc sdec sign verify hashing signing+syn match spthyConstr "\<h("he=e-1+syn match spthyConstr "\<sk("he=e-1+syn match spthyConstr "\<pk("he=e-1+syn match spthyConstr "\<fr("he=e-1+syn match spthyConstr "\<pb("he=e-1+syn match spthyConstr "\<lts("he=e-1+syn match spthyConstr "*"+syn match spthyConstr "\^"+syn match spthyConstr "\<diffie-hellman"+syn match spthyConstr "\<symmetric-encryption"+syn match spthyConstr "\<asymmetric-encryption"++syn keyword spthyDecl lemma assert equations functions builtin protocol property properties let theory begin end subsection section text note+syn match spthyDecl "\<enable"+syn match spthyDecl "\<rule"+syn match spthyDecl "\<assertions"+syn match spthyDecl "\<modulo"+syn match spthyDecl "\<default_rules"+syn match spthyDecl "\<anb-proto"+syn match spthyDecl ":"+syn match spthyDecl "{\*"+syn match spthyDecl "\*}"+syn match spthyDecl "\""+syn match spthyDecl "\d\+\."++syn match spthyTransfer "->"+syn match spthyTransfer "<-"+syn match spthyDecl "-->"+syn match spthyDecl "--\["+syn match spthyDecl "\]->"++syn region spthyLiteral start="'" end="'"++syn match spthyLogicOp "==>"+syn match spthyLogicOp "<=>"+syn keyword spthyLogicOp F T All Ex+syn match spthyLogicOp "|"+syn match spthyLogicOp "&"+syn match spthyLogicOp "\."++" The following cluster contains all spthy groups except the contained ones+syn cluster spthyTop add=spthyLAtom,spthyDecl+++" Comments+syn keyword spthyTodo contained TODO FIXME XXX+syn region spthyComment start="/\*" end="\*/" contains=spthyTodo+syn match spthyLineComment "//.*" contains=spthyTodo++syn cluster spthyTop add=spthyComment,spthyLineComment++" Strings and constants+" syn match spthySpecialError contained "\\."+" syn match spthySpecialCharError contained "[^']"+" syn match spthySpecialChar contained "\\\([4-9]\d\|[0-3]\d\d\|[\"\\'ntbrf]\|u\+\x\{4\}\)"+" syn region spthyString start=+"+ end=+"+ end=+$+ contains=spthySpecialChar,spthySpecialError,@Spell+" " next line disabled, it can cause a crash for a long line+" "syn match spthyStringError +"\([^"\\]\|\\.\)*$++" syn match spthyCharacter "'[^']*'" contains=spthySpecialChar,spthySpecialCharError+" syn match spthyCharacter "'\\''" contains=spthySpecialChar+" syn match spthyCharacter "'[^\\]'"+" syn match spthyNumber "\<\(0[0-7]*\|0[xX]\x\+\|\d\+\)[lL]\=\>"+" syn match spthyNumber "\(\<\d\+\.\d*\|\.\d\+\)\([eE][-+]\=\d\+\)\=[fFdD]\="+" syn match spthyNumber "\<\d\+[eE][-+]\=\d\+[fFdD]\=\>"+" syn match spthyNumber "\<\d\+\([eE][-+]\=\d\+\)\=[fFdD]\>"+" +" " unicode characters+" syn match spthySpecial "\\u\+\d\{4\}"+" +" syn cluster spthyTop add=spthyString,spthyCharacter,spthyNumber,spthySpecial,spthyStringError++" catch errors caused by wrong parenthesis+" syn region spthyParenT transparent matchgroup=spthyParen start="(" end=")" contains=@spthyTop,spthyParenT1+" syn region spthyParenT1 transparent matchgroup=spthyParen1 start="(" end=")" contains=@spthyTop,spthyParenT2 contained+" syn region spthyParenT2 transparent matchgroup=spthyParen2 start="(" end=")" contains=@spthyTop,spthyParenT contained+" syn match spthyParenError ")"+" " catch errors caused by wrong square parenthesis+" syn region spthyParenT transparent matchgroup=spthyParen start="\[" end="\]" contains=@spthyTop,spthyParenT1+" syn region spthyParenT1 transparent matchgroup=spthyParen1 start="\[" end="\]" contains=@spthyTop,spthyParenT2 contained+" syn region spthyParenT2 transparent matchgroup=spthyParen2 start="\[" end="\]" contains=@spthyTop,spthyParenT contained+" syn match spthyParenError "\]"+" +" SpthyHiLink spthyParenError spthyError++if !exists("spthy_minlines")+ let spthy_minlines = 10+endif+exec "syn sync ccomment spthyComment minlines=" . spthy_minlines++" The default highlighting.+if version >= 508 || !exists("did_spthy_syn_inits")+ if version < 508+ let did_spthy_syn_inits = 1+ endif+ SpthyHiLink spthyLAtom Operator+ SpthyHiLink spthyComment Comment+ SpthyHiLink spthyDocComment Comment+ SpthyHiLink spthyLineComment Comment+ SpthyHiLink spthyError Error+ SpthyHiLink spthyDecl Typedef+ SpthyHiLink spthyTransfer Typedef+ SpthyHiLink spthyConstr Function+ SpthyHiLink spthyLiteral String+ SpthyHiLink spthyTODO Todo+ SpthyHiLink spthyLogicOp Boolean+" SpthyHiLink spthyVarArg Function+" SpthyHiLink spthyBraces Function+" SpthyHiLink spthyBranch Conditional+" SpthyHiLink spthyUserLabelRef spthyUserLabel+" SpthyHiLink spthyLabel Label+" SpthyHiLink spthyUserLabel Label+" SpthyHiLink spthyConditional Conditional+" SpthyHiLink spthyRepeat Repeat+" SpthyHiLink spthyExceptions Exception+" SpthyHiLink spthyAssert Statement+" SpthyHiLink spthyStorageClass StorageClass+" SpthyHiLink spthyMethodDecl spthyStorageClass+" SpthyHiLink spthyClassDecl spthyStorageClass+" SpthyHiLink spthyScopeDecl spthyStorageClass+" SpthyHiLink spthyBoolean Boolean+" SpthyHiLink spthySpecial Special+" SpthyHiLink spthySpecialError Error+" SpthyHiLink spthySpecialCharError Error+" SpthyHiLink spthyString String+" SpthyHiLink spthyCharacter Character+" SpthyHiLink spthySpecialChar SpecialChar+" SpthyHiLink spthyNumber Number+" SpthyHiLink spthyStringError Error+" SpthyHiLink spthyStatement Statement+" SpthyHiLink spthyOperator Operator+" SpthyHiLink spthyComment Comment+" SpthyHiLink spthyDocComment Comment+" SpthyHiLink spthyLineComment Comment+" SpthyHiLink spthyConstant Constant+" SpthyHiLink spthyTypedef Typedef+" SpthyHiLink spthyTodo Todo+" SpthyHiLink spthyAnnotation PreProc+"+" SpthyHiLink spthyCommentTitle SpecialComment+" SpthyHiLink spthyDocTags Special+" SpthyHiLink spthyDocParam Function+" SpthyHiLink spthyDocSeeTagParam Function+" SpthyHiLink spthyCommentStar spthyComment+"+" SpthyHiLink spthyType Type+" SpthyHiLink spthyExternal Include+"+" SpthyHiLink htmlComment Special+" SpthyHiLink htmlCommentPart Special+" SpthyHiLink spthySpaceError Error+endif++delcommand SpthyHiLink++let b:current_syntax = "spthy"++if main_syntax == 'spthy'+ unlet main_syntax+endif++let b:spell_options="contained"++" vim: ts=8
@@ -0,0 +1,190 @@+theory TLS +begin++builtin: hashing, symmetric-encryption, asymmetric-encryption, signing++section{* TLS Handshake *}++/*+ * Protocol: TLS Handshake+ * Modeler: Simon Meier+ * Date: January 2012+ * Source: Modeled after Paulson`s TLS model in Isabelle/src/HOL/Auth/TLS.thy.+ *+ * Status: working (25 seconds on an i7 Quad-Core CPU with +RTS -N)+ */++text{*+ Modeled after Paulson`s TLS model in Isabelle/src/HOL/Auth/TLS.thy. Notable+ differences are:++ 1. We use explicit global constants to differentiate between different+ encryptions instead of implicit typing.++ 2. We model session keys directly as hashes of the relevant information.+ Due to our support for composed keys, we do not need any custom+ axiomatization as Paulson does.++*}++// Public key infrastructure+rule Register_pk:+ [ Fr(~ltkA) ] + --> + [ !Ltk($A, ~ltkA), !Pk($A, pk(~ltkA)), Out(pk(~ltkA)) ]++rule Reveal_ltk:+ [ !Ltk(A, ltkA) ] --[ RevLtk(A) ]-> [ Out(ltkA) ]+++/* We formalize the following signature based TLS handshake.++ protocol TLS {+ 1. C -> S: C, nc, sid, pc+ 2. C <- S: ns, sid, ps++ 3. C -> S: { '31', pms }pk(S) ,+ sign{ '32', h('32', ns, S, pms) }pk(C) ,+ { '33', sid, h('PRF', pms, nc, ns),+ nc, pc, C, ns, ps, S+ } + h('clientKey', nc, ns, h('PRF', pms, nc, ns))++ 4. C <- S: { '4', sid, h('PRF', pms, nc, ns),+ nc, pc, C, ns, ps, S+ } + h('serverKey', nc, ns, h('PRF', pms, nc, ns))+ }+*/++rule C_1:+ [ Fr(~nc)+ , Fr(~sid)+ ]+ --[]->+ [ Out(+ <$C, ~nc, ~sid, $pc>+ )+ , St_C_1($C, ~nc, ~sid, $pc)+ ]++rule S_1:+ [ In( + <$C, nc, sid, pc>+ )+ , Fr(~ns)+ ]+ --[]->+ [ Out(+ <$S, ~ns, sid, $ps>+ )+ , St_S_1($S, $C, sid, nc, pc, ~ns, $ps)+ ]++rule C_2:+ [ St_C_1(C, nc, sid, pc)+ , In(+ <S, ns, sid, ps>+ )+ , Fr(~pms)+ , !Pk(S, pkS)+ , !Ltk(C, ltkC)+ ]+ --[]->+ [ Out(+ < aenc{ '31', ~pms }pkS+ , sign{ '32', h('32', ns, S, ~pms) }ltkC+ , senc{ '33', sid, h('PRF', ~pms, nc, ns), nc, pc, C, ns, ps, S}+ h('clientKey', nc, ns, h('PRF', ~pms, nc, ns))+ >+ )+ , St_C_2(S, C, sid, nc, pc, ns, ps, ~pms)+ ]++rule S_2:+ [ St_S_1(S, C, sid, nc, pc, ns, ps)+ , In(+ < aenc{ '31', pms }pk(ltkS)+ , signature+ , senc{ '33', sid, h('PRF', pms, nc, ns), nc, pc, C, ns, ps, S}+ h('clientKey', nc, ns, h('PRF', pms, nc, ns))+ >+ )+ , !Pk(C, pkC)+ , !Ltk(S, ltkS)+ ]+ /* Explicit equality check, enforced as part of the property. */+ --[ Eq(verify(signature, <'32', h('32', ns, S, pms)>, pkC), true )+ , SessionKeys+ ( S, C+ , h('serverKey', nc, ns, h('PRF', pms, nc, ns))+ , h('clientKey', nc, ns, h('PRF', pms, nc, ns))+ )+ ]->+ [ Out(+ senc{ '4', sid, h('PRF', pms, nc, ns), nc, pc, C, ns, ps, S}+ h('serverKey', nc, ns, h('PRF', pms, nc, ns))+ )+ ]++rule C_3:+ [ St_C_2(S, C, sid, nc, pc, ns, ps, pms)+ , In(+ senc{ '4', sid, h('PRF', pms, nc, ns), nc, pc, C, ns, ps, S}+ h('serverKey', nc, ns, h('PRF', pms, nc, ns))+ )+ ]+ --[ SessionKeys+ ( S, C+ , h('serverKey', nc, ns, h('PRF', pms, nc, ns))+ , h('clientKey', nc, ns, h('PRF', pms, nc, ns))+ )+ ]->+ []+++/* TODO: Also model session-key reveals and adapt security properties. */+++/* Session key secrecy from the perspecitive of both the server and the client+ * for both the key of the server and the key of the client. Note that this+ * lemma thus captures four security properties at once. */+lemma session_key_secrecy:+ " /* If all equality checks succeeded */+ (All x y #i. Eq(x,y) @ i ==> x = y)+ ==>+ /* then there is no attack */ + (not( + /* It cannot be that */+ Ex S C keyS keyC #k.+ /* somebody claims to have setup session keys, */+ SessionKeys(S, C, keyS, keyC) @ k + /* but the adversary knows one of them */+ & ( (Ex #i. K(keyS) @ i) + | (Ex #i. K(keyC) @ i)+ )+ /* without having performed a long-term key reveal. */+ & not (Ex #r. RevLtk(S) @ r)+ & not (Ex #r. RevLtk(C) @ r)+ ) )"++/* Consistency check: this lemma must NOT have a proof,+ * as otherwise no session-keys could be setup between honest agents. */+lemma session_key_setup_possible:+ " /* If all equality checks succeeded */+ (All x y #i. Eq(x,y) @ i ==> x = y)+ ==>+ /* then there is no trace */ + (not( + /* It cannot be that */+ Ex S C keyS keyC #k.+ /* somebody claims to have setup session keys, */+ SessionKeys(S, C, keyS, keyC) @ k + /* without having performed a long-term key reveal. */+ & not (Ex #r. RevLtk(S) @ r)+ & not (Ex #r. RevLtk(C) @ r)+ ) )"+++end+
@@ -0,0 +1,437 @@+/*+User guide to the tamarin prover for security protocol analysis+===============================================================++Authors: Simon Meier, Benedikt Schmidt+Date: February 2012+++Introduction+------------++This user guide assumes that you have a copy of our CSF'12 submission on+"Automated Analysis of Diffie-Hellman Protocols and Advanced Security+Properties". Drop us a mail, if you would like to receive a copy.++The input files for the tamarin prover have the extension .spthy, which is+short for 'security protocol theory'. A security protocol theory specifies++ 1. the signature and equational theory to use for the message algebra,+ 2. the set of set of multiset rewriting rules modeling the protocol and+ the adversary capabilities, and+ 3. the guarded trace properties whose validity for this set of multiset+ rewriting rules we want to check.++We explain each of these parts where they occur in the following security+protocol theory. Before we start, a few notes on the syntax.+As you probably noticed, comments are C-style. All identifiers are+case-sensitive. The parser is layout-insensitive, i.e., your are free to use+whitespace as it suits you. For people using the 'vim' text-editor, we provide+syntax highlighting files. We explain how to install them, before we explain+how to model a simple example protocol.+++Installing the vim syntax highlighting files+--------------------------------------------++As you've probably noticed, calling 'tamarin-prover' without any arguments+yields an informative help-message listing all available flags and the paths+to the installed example protocol files. We call the directory above the+example files the DATA_PATH. The examples are found at++ DATA_PATH/examples++and the 'vim' syntax highlighting files are found at++ DATA_PATH/etc/++To install them, copy++ DATA_PATH/etc/filepath.vim++to the ~/.vim directory and copy++ DATA_PATH/etc/spthy.vim++to the ~/.vim/syntax directory. If one of these directories does not exist,+then just create it.++++Modeling a security protocol+----------------------------++Every security protocol theory starts with a header of the following form.+*/++theory UserGuide+begin++/*+Obviously, you can replace 'UserGuide' with any name you like to give your+theory. After 'begin', you can declare function symbols, equations that they+must satisfy, multiset rewriting rules, and lemmas specifying security+properties. Moreover, you can also insert formal comments, to structure your+theory. We give examples of each of these elements while modeling the+a simple protocol. ++In this protocol a client C generates a fresh symmetric key 'k', encrypts it+with the public key of a server 'S' and sends it to 'S'. The server confirms+the receipt of the key by sending back its hash to the client. In+Alice-and-Bob notation the protocol would read as follows.++ C -> S: aenc{k}pk(S)+ S <- C: h(k)++This protocol is artificial and it satisfies only very weak security+guarantees. We can prove that from the perspective of the client, the freshly+generated key is secret provided that the server is uncompromised.++We model this protocol in three steps. First, we declare the function symbols+and the equations defining them. Then, we introduce multiset rewriting rules+modeling a public key infrastructure (PKI) and the protocol. Finally, we state+the expected security properties.+++Function Signature and Equational Theory+----------------------------------------++We model hashing using the unary function 'h'.+We model asymmetric encryption by declaring + a binary function 'aenc' denoting a call to the encryption algorithm,+ a binary function 'adec' denoting a call to the decryption algorithm, and+ a unary function 'pk' denoting a call to the algorithm computing a public+ key from a private key.+*/++functions: h/1, aenc/2, adec/2, pk/1+equations: adec(aenc(m, pk(k)), k) = m++/*+The above equation then models the interaction between calls to these three+algorithms. All these equations must be subterm-convergent rewriting rules,+when read from left to right. This means that the right-hand-side must be a+subterm of the left-hand-side or a nullary function symbol.++Certain equational theories are used very often when modeling cryptographic+messages. We therefore provide builtin definitions for them. The above theory+could also be enabled using the declaration++ builtin: hashing, asymmetric-encryption++We support the following builtin theories:+ + diffie-hellman, signing, asymmetric-encryption, symmetric-encryption,+ hashing++Apart from 'diffie-hellman', all of these theories are subterm-convergent and+can therefore also be declared directly, as above. You can inspect their+definitions by uncommenting the following two line-comments and calling++ tamarin-prover UserGuide.spthy++*/++// builtin: diffie-hellman, signing, asymmetric-encryption, symmetric-encryption,+// hashing++/*+The call 'tamarin-prover UserGuide.spthy' parses the UserGuide.spthy file,+computes the variants of the multiset rewriting rules and checks their+wellformedness (explained below), and pretty-prints the theory. The+declaration of the signature and the equations can be found at the top of the+pretty-printed theory.++Proving all lemmas contained in the theory would be as simple as adding the+flag '--prove' to the call; i.e.,++ tamarin-prover UserGuide.spthy --prove++However, let's not go there yet. We first have to model the PKI and our+protocol.++Modeling the Public Key Infrastructure+--------------------------------------+*/++// Registering a public key+rule Register_pk:+ [ Fr(~ltk) ] + --> + [ !Ltk($A, ~ltk), !Pk($A, pk(~ltk)) ]++/* The above rule models registering a public key. It makes use of the+ following syntax.+ + Facts always start with an upper-case letter. They are declared implicitly.+ If their name is prefixed with an exclamation mark '!', then they are+ persistent. Otherwise, they are linear. Note that you must use every fact+ name consistently; i.e., you must always use it with the same arity, casing,+ and multiplicity. Otherwise, the tamarin prover complains that the theory+ is not wellformed.++ The 'Fr' fact is a builtin fact. It denotes a freshly generated fresh name.+ See the paper for details.++ We denote the sort of variables using prefixes:++ ~x denotes x:fresh+ $x denotes x:pub+ #i denotes i:temp+ i denotes i:msg++ 'c' denotes a public name 'c \in PN'; i.e., a fixed, global constant+ + Thus, the above rule can be read as follows. First, freshly generate a+ fresh name 'ltk', the new private key and nondeterministically choose a+ public name 'A', the agent for which we are generating the key-pair.+ Then, generate the persistent fact !Ltk($A, ~ltk), which denotes the+ association between agent 'A' and its private key 'ltk, and generate the+ persistent fact !Pk($A, pk(~ltk)), which denotes the association between the+ agent 'A' and its public key 'pk(~ltk)'.++ We allow the adversary to retrieve any public key using the following rule.+ Intuitively, it just reads a public-key database entry and sends the public+ key to the network using the builtin fact 'Out' denoting a message sent to+ the network. See our paper for more information.+*/++rule Get_pk:+ [ !Pk(A, pk) ] + --> + [ Out(pk) ]++/*+ We model dynamic compromise of long-term private keys using the following+ rule. Intuitively, it reads a private-key database entry and sends it to+ the adversary. This rule has an observable 'LtkReveal' action stating that+ the long-term key of agent 'A' was compromised. We will use this action in+ the security property below to determine which agents are compromised.+*/++rule Reveal_ltk:+ [ !Ltk(A, ltk) ]+ --[ LtkReveal(A) ]->+ [ Out(ltk) ]+++/*++Modeling the protocol+----------------------++Recall that we want to model the following protocol.++ C -> S: aenc{k}pk(S)+ S <- C: h(k)++We model it use the following three rules.+*/++// Start a new thread executing the client role, choosing the server+// non-deterministically.+rule Client_1:+ [ Fr(~k) // choose fresh key+ , !Pk($S, pkS) // lookup public-key of server+ ]+ -->+ [ Client_1( $S, ~k ) // Store server and key for next step of thread+ , Out( aenc{'1', ~k}pkS ) // Send the encrypted session key to the server+ // We add the tag '1' to the request to allow+ // the server to check whether the decryption+ // was successful.+ ]++rule Init_2:+ [ Client_1(S, k) // Retrieve server and session key from previous step+ , In( h(k) ) // Receive hashed session key from network+ ]+ --[ SessKeyC( S, k ) ]-> // State that the session key 'k'+ [] // was setup with server 'S'++// A server thread answering in one-step to a session-key setup request from+// some client.+rule Serv_1:+ [ !Ltk($S, ~ltkS) // lookup the private-key+ , In( request ) // receive a request+ ]+ --[ Eq(fst(adec(request, ~ltkS)), '1')+ , AnswerRequest($S, snd(adec(request, ~ltkS))) // Explanation below+ ]-> + [ Out( h(snd(adec(request, ~ltkS))) ) ] // Return the hash of the+ // decrypted request.++/* Above, we model all applications of cryptographic algorithms explicitly.+ Call 'tamarin-prover UserGuide.spthy' to inspect the finite variants of the+ Serv_1 rule, which list all possible interactions of the destructors used.+ In our proof search, we will consider all these interactions.++ We also model that the server explicitly checks that the first component of+ the request is equal to '1'. We model this by logging the claimed equality+ and then adapting the security property such that it only considers traces+ where all 'Eq' actions occur with two equal arguments. Note that 'Eq' is NO+ builtin fact. Guarded trace properties are strong enough to formalize this+ requirement without builtin support.++ We log the session-key setup requests received by servers to allow+ formalizing the authentication property for the client.+++Modeling the security properties+--------------------------------++The syntax for specifying security properties uses++ All for universal quantification, temporal variables are prefixed with #+ Ex for existential quantification, temporal variables are prefixed with #+ ==> for implication+ & for conjunction+ | for disjunction+ not for negation+ + f @ i for action constraints, the sort prefix for the temporal variable 'i'+ is optional+ + i < j for temporal ordering, the sort prefix for the temporal variable 'i'+ is optional++ #i = #j for an equality between temporal variables 'i' and 'j'+ x = y for an equality between message variables 'x' and 'y'++Note that apart from public names (delimited using single-quotes), no terms+may occur in guarded trace properties. Moreover, all variables must be+guarded. The error message for an unguarded variable is currently not very+good. ++For universally quantified variables, one has to check that they all occur in+an action constraint right after the quantifier and that the toplevel inside+the quantifier is an implication.+For existentially quantified variables, one has to check that they all occur in+an action constraint right after the quantifier and that the toplevel inside+the quantifier is a conjunction.+Note also that currently the precedence of the logical connectives is not+specified. We therefore recommend to use parentheses, when in doubt.+++The following two properties should be self-explanatory.+*/++lemma Client_session_key_secrecy:+ " /* For all traces, where all equality checks succeed, */+ (All x y #i. Eq(x,y) @ i ==> x = y)+ ==>+ /* it cannot be that a */+ not(+ Ex S k #i #j.+ /* client setup a session key 'k' with a server'S' */+ SessKeyC(S, k) @ #i+ /* and the adversary knows 'k' */+ & K(k) @ #j+ /* without having performed a long-term key reveal on 'S'. */+ & not(Ex #r. LtkReveal(S) @ r) + )+ "+++lemma Client_auth:+ " /* For all traces, where all equality checks succeed, */+ (All x y #i. Eq(x,y) @ i ==> x = y)+ ==>+ /* for all session keys 'k' setup by clients with a server 'S' */+ ( All S k #i. SessKeyC(S, k) @ #i+ ==>+ /* there is a server that answered the request */+ ( (Ex #a. AnswerRequest(S, k) @ a)+ /* or the intruder performed a long-term key reveal on 'S'+ before the key was setup. */+ | (Ex #r. LtkReveal(S) @ r & r < i)+ )+ )+ "++/*+ You can verify them by calling++ tamarin-prover --prove UserGuide.spthy++ This will first output some logging from the constraint solver and then the+ UserGuide security protocol theory with the lemmas and their attached+ (dis)proofs.++ Finding attacks is very useful, to check that a security property is not+ trivial due to too strong preconditions. The following property must not be+ provable, as otherwise there would be no possibility to setup a session key+ with a honest sever.++*/++// Must not be provable!+lemma Client_session_key_honest_setup_possible:+ " (All x y #i. Eq(x,y) @ i ==> x = y)+ ==>+ not(+ Ex S k #i.+ SessKeyC(S, k) @ #i+ & not(Ex #r. LtkReveal(S) @ r) + )+ "++/* As you can see from the output of ++ tamarin-prover --prove UserGuide.spthy++ It finds an "attack" on this property, as expected. To characterize all+ possible attacks use++ tamarin-prover --prove --stop-on-attack=NONE UserGuide.spthy++ You can see from the output that there is exactly one way to setup a session+ key with an honest server.+++Interactive proof visualization and construction+------------------------------------------------++Just call ++ tamarin-prover interactive UserGuide.spthy++This will start a web-server that loads all security protocol theories in the+same directory as UserGuide.spthy. Point your browser to++ http://localhost:3001++and explore the the UserGuide theory interactively by clicking on the+'UserGuide' entry in the table of loaded theories. You can prove a lemma+interactively by clicking on the available proof methods (corresponding to+applications of constraint reduction rules) or by calling the 'autoprover' by+right-clicking on a node in the theory overview.+++Conclusion+----------++The case studies from our CSF'12 submission should now be readable. Recall+that you can find them in the directory listed at the bottom of the help+message, when calling 'tamarin-prover' without any arguments. If you have+further questions, please do not hesitate to contact either++ Benedikt Schmidt benedikt.schmidt@inf.ethz.ch + Simon Meier simon.meier@inf.ethz.ch.++Note that our CSF'12 submission does not explain how we compose multiple+constraint reduction into a precomputed case distinction. It also does not+explain how we delay splitting on the different variants of multiset rewriting+rules. We will report on this in an upcoming technical report. This report+will also explain the support for proving loop invariants by induction, as it+is already supported by this version of 'tamarin'.+++BTW, every security protocol theory must be delimited with 'end'.++ (-: HAPPY PROVING :-)+*/++end++
@@ -0,0 +1,64 @@+theory Artificial+begin++/*+ Protocol: Example+ Modeler: Simon Meier, Benedikt Schmidt+ Date: January 2012+ + Status: working+ + This is the artificial protocol from our CSF'12 paper, which we use to+ illustrate constraint solving and characterization. Note that, for+ characerization, you have to call the tamarin-prover as follows.++ tamarin-prover --prove --stop-on-attack=NONE your_protocol.spthy++ The --stop-on-attack=NONE flag ensures that all solved constraint systems+ are explored by the constraint solver. By default, it stops as soon as the+ first attack is found. Note that depending on the protocol,+ characterization might take a long time, as there are many slightly+ different possible attacks.++ As a more interesting example try characterizing the setup of a session-key+ between two honest agents in the TLS.spthy example, which models a TLS+ handshake using signatures.++ tamarin-prover --prove --stop-on-attack=NONE TLS.spthy +RTS -N++ Note that we add the +RTS -N to tell the Haskell runtime system that it+ should use as many cores as your system provides. For TLS, this speeds-up+ the proof generation/characterization quite a bit. After this call, the+ tool will output the complete set of cases, which it had to explore for+ finding all counter-examples to this property. Exactly, two of the cases+ will be of the form++ SOLVED (trace found)++ They correspond to the _only_ two ways of setting up a session-key between+ honest agents: one for the client and one for the server.++ */++builtin: symmetric-encryption++rule Step1:+ [ Fr(~x), Fr(~k) ] + --> + [ St(~x, ~k), Out(senc{~x}~k), Key(~k) ]++rule Step2:+ [ St(x, k), In(<x,x>) ] + --[ Fin(x, k) ]-> + [ ]++rule Reveal_key:+ [ Key(k) ]+ --[ Rev(k) ]->+ [ Out(k) ]++lemma Characterize_Fin:+ "not( Ex k S #i. Fin(S, k) @ i )+ "++end
@@ -0,0 +1,116 @@+theory JKL_TS1_2004+begin++builtin: hashing, diffie-hellman++section{* Jeong, Katz, Lee : TS1 (2004) *}++/*+ * Protocol: JKL-TS1-2004+ * Modeler: Cas Cremers+ * Date: January 2012+ * Source: "One-Round Protocols for Two-Party Authenticated Key Exchange"+ * Jeong, Katz, Lee, 2004.+ *+ * Status: working+ */++/* Protocol rules */++rule generate_ltk:+ [ Fr(~lk) ] -->+ [ !Ltk( $A, ~lk ), !Pk( $A, 'g'^~lk ), Out( 'g'^~lk ) ]++rule Init_1:+ [ Fr( ~ekI ), !Ltk( $I, ~lkI ) ]+ --[ SidI_1(~ekI,$I,$R, ~ekI ) ]->+ [ Init_1( ~ekI, $I, $R, ~lkI, ~ekI ),+ !Ephk(~ekI),+ Out( ~ekI ) ]++rule Init_2:+ [ Init_1( ~ekI, $I, $R, ~lkI , ~ekI), In( Y ), !Pk( $R,'g'^~lkR ) ]+ --[SidI_2( ~ekI, $I, $R, ~ekI, Y,+ h( < ~ekI, Y, ('g'^~lkR)^~lkI > ) ) ]->+ [ !Sessk( ~ekI, + h( < ~ekI, Y, ('g'^~lkR)^~lkI > ) ) ]++rule Resp_1:+ [ In( X ), Fr( ~ekR ), !Ltk($R, ~lkR), !Pk($I, 'g'^~lkI) ]+ --[ SidR_1( ~ekR, $I, $R, X, ~ekR ,+ h( < X, ~ekR, ('g'^~lkI)^~lkR > ) ) ]->+ [ Out( ~ekR ),+ !Ephk(~ekR),+ !Sessk( ~ekR, + h( < X, ~ekR, ('g'^~lkI)^~lkR > ) ) ]++rule Sessk_reveal: + [ !Sessk(~tid, k) ]+ --[ SesskRev(~tid) ]->+ [ Out(k) ]++rule Ephk_reveal:+ [ !Ephk(~ekI) ]+ --[ EphkRev(~ekI) ]->+ [ Out(~ekI) ]++rule Ltk_reveal:+ [ !Ltk($A, k) ]+ --[ LtkRev($A) ]->+ [ Out(k) ]++/* Security properties */++/*+lemma key_agreement_reachable:+ "not (Ex #i1 #i2 ekI ekR I R k hkI hkR.+ SidI_2(ekI, I, R, hkI, hkR, k) @ i1 & SidR_1(ekR, I, R, hkI, hkR, k) @ i2)"+*/++/* An attack is valid in the security model if the session key of the test session is deduced and+ the test session is clean.+*/+lemma JKL2008_1_initiator_key:+ "not (Ex #i1 #i2 ttest I R k hkI hkR.+ SidI_2(ttest, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* Not ephemeral-key-reveal */+ & (All #i3 t. EphkRev( t ) @ i3 ==> F)++ /* Not longterm-key-reveal */+ & (All #i3 a. LtkRev( a ) @ i3 ==> F)++ /* Not session-key-reveal of test thread. */+ & (All #i3. SesskRev( ttest ) @ i3 ==> F)++ /* Not session-key-reveal of partner thread. */+ & (All #i3 #i4 tpartner kpartner.+ SidR_1( tpartner,I,R,hkI,hkR,kpartner ) @i3+ & SesskRev( tpartner ) @ i4 ==> F)+ )"++/* An attack is valid in the security model if the session key of the test session is deduced and+ the test session is clean.+*/+lemma JKL2008_1_responder_key:+ "not (Ex #i1 #i2 ttest I R k hkI hkR.+ SidR_1(ttest, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* Not ephemeral-key-reveal */+ & (All #i3 t. EphkRev( t ) @ i3 ==> F)++ /* Not longterm-key-reveal */+ & (All #i3 a. LtkRev( a ) @ i3 ==> F)++ /* Not session-key-reveal of test thread. */+ & (All #i3. SesskRev( ttest ) @ i3 ==> F)++ /* Not session-key-reveal of partner thread. Note that we use SidI_2 here.+ A session key reveal can only happen after SidI_2 is logged anyways.+ */+ & (All #i3 #i4 tpartner kpartner.+ SidI_2( tpartner,I,R,hkI,hkR,kpartner ) @i3+ & SesskRev( tpartner ) @ i4 ==> F)+ )"++end
@@ -0,0 +1,120 @@+theory JKL_TS1_2008+begin++builtin: hashing, diffie-hellman++section{* Jeong, Katz, Lee : TS1 (2008) *}+/*+ * Protocol: JKL-TS1-2008+ * Modeler: Cas Cremers+ * Date: January 2012+ * Source: "One-Round Protocols for Two-Party Authenticated Key Exchange"+ * Jeong, Katz, Lee, 2008+ * Note: Although the paper title is the same as the 2004+ * original, the updated version from 2008 includes+ * modified protocols and security models.+ *+ * Status: working+ */++/* Protocol rules */++rule generate_ltk:+ [ Fr(~lk) ] -->+ [ !Ltk( $A, ~lk ), !Pk( $A, 'g'^~lk ), Out( 'g'^~lk ) ]++rule Init_1:+ [ Fr( ~ekI ), !Ltk( $I, ~lkI ) ]+ --[ SidI_1(~ekI,$I,$R, ~ekI ) ]->+ [ Init_1( ~ekI, $I, $R, ~lkI, ~ekI ),+ !Ephk(~ekI),+ Out( ~ekI ) ]++rule Init_2:+ [ Init_1( ~ekI, $I, $R, ~lkI , ~ekI), In( Y ), !Pk( $R,'g'^~lkR ) ]+ --[SidI_2( ~ekI, $I, $R, ~ekI, Y,+ h( < $I, $R, ~ekI, Y, ('g'^~lkR)^~lkI > ) ) ]->+ [ !Sessk( ~ekI, + h( < $I, $R, ~ekI, Y, ('g'^~lkR)^~lkI > ) ) ]++rule Resp_1:+ [ In( X ), Fr( ~ekR ), !Ltk($R, ~lkR), !Pk($I, 'g'^~lkI) ]+ --[ SidR_1( ~ekR, $I, $R, X, ~ekR ,+ h( < $I, $R, X, ~ekR, ('g'^~lkI)^~lkR > ) ) ]->+ [ Out( ~ekR ),+ !Ephk(~ekR),+ !Sessk( ~ekR, + h( < $I, $R, X, ~ekR, ('g'^~lkI)^~lkR > ) ) ]++rule Sessk_reveal: + [ !Sessk(~tid, k) ]+ --[ SesskRev(~tid) ]->+ [ Out(k) ]++rule Ephk_reveal:+ [ !Ephk(~ekI) ]+ --[ EphkRev(~ekI) ]->+ [ Out(~ekI) ]++rule Ltk_reveal:+ [ !Ltk($A, k) ]+ --[ LtkRev($A) ]->+ [ Out(k) ]+++/* Security properties */++/*+lemma key_agreement_reachable:+ "not (Ex #i1 #i2 ekI ekR I R k hkI hkR.+ SidI_2(ekI, I, R, hkI, hkR, k) @ i1 & SidR_1(ekR, I, R, hkI, hkR, k) @ i2)"+*/++/* An attack is valid in the security model if the session key of the test session is deduced and+ the test session is clean.+*/+lemma JKL2008_1_initiator_key:+ "not (Ex #i1 #i2 ttest I R k hkI hkR.+ SidI_2(ttest, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* Not ephemeral-key-reveal */+ & (All #i3 t. EphkRev( t ) @ i3 ==> F)++ /* Not longterm-key-reveal */+ & (All #i3 a. LtkRev( a ) @ i3 ==> F)++ /* Not session-key-reveal of test thread. */+ & (All #i3. SesskRev( ttest ) @ i3 ==> F)++ /* Not session-key-reveal of partner thread. */+ & (All #i3 #i4 tpartner kpartner.+ SidR_1( tpartner,I,R,hkI,hkR,kpartner ) @i3+ & SesskRev( tpartner ) @ i4 ==> F)+ )"++/* An attack is valid in the security model if the session key of the test session is deduced and+ the test session is clean.+*/+lemma JKL2008_1_responder_key:+ "not (Ex #i1 #i2 ttest I R k hkI hkR.+ SidR_1(ttest, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* Not ephemeral-key-reveal */+ & (All #i3 t. EphkRev( t ) @ i3 ==> F)++ /* Not longterm-key-reveal */+ & (All #i3 a. LtkRev( a ) @ i3 ==> F)++ /* Not session-key-reveal of test thread. */+ & (All #i3. SesskRev( ttest ) @ i3 ==> F)++ /* Not session-key-reveal of partner thread. Note that we use SidI_2 here.+ A session key reveal can only happen after SidI_2 is logged anyways.+ */+ & (All #i3 #i4 tpartner kpartner.+ SidI_2( tpartner,I,R,hkI,hkR,kpartner ) @i3+ & SesskRev( tpartner ) @ i4 ==> F)+ )"++end+
@@ -0,0 +1,139 @@+theory JKL_TS1_2008+begin++builtin: hashing, diffie-hellman++section{* Jeong, Katz, Lee : TS1 (2008) *}++/*+ * Protocol: JKL-TS1-2008+ * Modeler: Cas Cremers+ * Date: January 2012+ * Source: "One-Round Protocols for Two-Party Authenticated Key Exchange"+ * Jeong, Katz, Lee, 2008+ * Note: Although the paper title is the same as the 2004+ * original, the updated version from 2008 includes+ * modified protocols and security models.+ *+ * Status: working+ */++/* Protocol rules */++rule generate_ltk:+ [ Fr(~lk) ] -->+ [ !Ltk( $A, ~lk ), !Pk( $A, 'g'^~lk ), Out( 'g'^~lk ) ]++rule Init_1:+ [ Fr( ~ekI ), !Ltk( $I, ~lkI ) ]+ --[ SidI_1(~ekI,$I,$R, ~ekI ) ]->+ [ Init_1( ~ekI, $I, $R, ~lkI, ~ekI ),+ !Ephk(~ekI),+ Out( ~ekI ) ]++rule Init_2:+ [ Init_1( ~ekI, $I, $R, ~lkI , ~ekI), In( Y ), !Pk( $R,'g'^~lkR ) ]+ --[SidI_2( ~ekI, $I, $R, ~ekI, Y,+ h( < $I, $R, ~ekI, Y, ('g'^~lkR)^~lkI > ) ) ]->+ [ !Sessk( ~ekI, + h( < $I, $R, ~ekI, Y, ('g'^~lkR)^~lkI > ) ) ]++rule Resp_1:+ [ In( X ), Fr( ~ekR ), !Ltk($R, ~lkR), !Pk($I, 'g'^~lkI) ]+ --[ SidR_1( ~ekR, $I, $R, X, ~ekR ,+ h( < $I, $R, X, ~ekR, ('g'^~lkI)^~lkR > ) ) ]->+ [ Out( ~ekR ),+ !Ephk(~ekR),+ !Sessk( ~ekR, + h( < $I, $R, X, ~ekR, ('g'^~lkI)^~lkR > ) ) ]++rule Sessk_reveal: + [ !Sessk(~tid, k) ]+ --[ SesskRev(~tid) ]->+ [ Out(k) ]++rule Ephk_reveal:+ [ !Ephk(~ekI) ]+ --[ EphkRev(~ekI) ]->+ [ Out(~ekI) ]++rule Ltk_reveal:+ [ !Ltk($A, k) ]+ --[ LtkRev($A) ]->+ [ Out(k) ]++/* Security properties */++/*+lemma key_agreement_reachable:+ "not (Ex #i1 #i2 ekI ekR I R k hkI hkR.+ SidI_2(ekI, I, R, hkI, hkR, k) @ i1 & SidR_1(ekR, I, R, hkI, hkR, k) @ i2)"+*/++/* An attack is valid in the security model if the session key of the test session is deduced and+ the test session is clean.+*/+lemma JKL2008_2_initiator_key:+ "not (Ex #i1 #i2 ttest I R k hkI hkR.+ SidI_2(ttest, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* Not ephemeral-key-reveal */+ & (All #i3 t. EphkRev( t ) @ i3 ==> F)++ /* Not session-key-reveal of test thread. */+ & (All #i3. SesskRev( ttest ) @ i3 ==> F)++ /* Not session-key-reveal of partner thread. */+ & (All #i3 #i4 tpartner kpartner.+ SidR_1( tpartner,I,R,hkI,hkR,kpartner ) @i3+ & SesskRev( tpartner ) @ i4 ==> F)++ /* If there is no partner thread, then there is no longterm-key-reveal for+ the intended partner.+ (We model wpfs, for pfs, add i1 < i3 to conclusion) */+ & (All #i3. LtkRev( I ) @ i3 ==>+ (Ex #i4 tpartner kpartner.+ (* (i1 < i3) | *)+ SidR_1( tpartner,I,R,hkI,hkR,kpartner ) @i4))+ & (All #i3. LtkRev( R ) @ i3 ==>+ (Ex #i4 tpartner kpartner.+ (* (i1 < i3) | *)+ SidR_1( tpartner,I,R,hkI,hkR,kpartner ) @i4))+ )"++/* An attack is valid in the security model if the session key of the test session is deduced and+ the test session is clean.+*/+lemma JKL2008_2_responder_key:+ "not (Ex #i1 #i2 ttest I R k hkI hkR.+ SidR_1(ttest, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* Not ephemeral-key-reveal */+ & (All #i3 t. EphkRev( t ) @ i3 ==> F)++ /* Not session-key-reveal of test thread. */+ & (All #i3. SesskRev( ttest ) @ i3 ==> F)++ /* Not session-key-reveal of partner thread. Note that we use SidI_2 here.+ A session key reveal can only happen after SidI_2 is logged anyways.+ */+ & (All #i3 #i4 tpartner kpartner.+ SidI_2( tpartner,I,R,hkI,hkR,kpartner ) @i3+ & SesskRev( tpartner ) @ i4 ==> F)++ /* If there is no partner thread, then there is no longterm-key-reveal for+ the actor or intended partner.+ (We model wpfs, for pfs, add i1 < i3 to conclusion)+ */+ & (All #i3. LtkRev( I ) @ i3 ==>+ (Ex #i4 tpartner.+ (* (i1 < i3) | *)+ SidI_1( tpartner,I,R,hkI ) @i4))+ & (All #i3. LtkRev( R ) @ i3 ==>+ (Ex #i4 tpartner.+ (* (i1 < i3) | *)+ SidI_1( tpartner,I,R,hkI ) @i4))+ )"++end+
@@ -0,0 +1,117 @@+theory JKL_TS2_2004+begin++builtin: hashing, diffie-hellman++section{* Jeong, Katz, Lee : TS2 (2004) *}+/*+ * Protocol: JKL-TS2-2004+ * Modeler: Cas Cremers+ * Date: January 2012+ * Source: "One-Round Protocols for Two-Party Authenticated Key Exchange"+ * Jeong, Katz, Lee, 2004+ *+ * Status: working+ */++/* Protocol rules */++rule generate_ltk:+ [ Fr(~lk) ] -->+ [ !Ltk( $A, ~lk ), !Pk( $A, 'g'^~lk ), Out( 'g'^~lk ) ]++rule Init_1:+ [ Fr( ~ekI ), !Ltk( $I, ~lkI ) ]+ --[ SidI_1(~ekI,$I,$R, 'g'^~ekI ) ]->+ [ Init_1( ~ekI, $I, $R, ~lkI, 'g'^~ekI ),+ !Ephk(~ekI),+ Out( 'g'^~ekI ) ]++rule Init_2:+ [ Init_1( ~ekI, $I, $R, ~lkI , hkI), In( Y ), !Pk( $R,'g'^~lkR ) ]+ --[SidI_2( ~ekI, $I, $R, hkI, Y,+ h( < hkI, Y, Y^~ekI, ('g'^~lkR)^~lkI > ) ) ]->+ [ !Sessk( ~ekI, + h( < hkI, Y, Y^~ekI, ('g'^~lkR)^~lkI > ) ) ]++rule Resp_1:+ [ In( X ), Fr( ~ekR ), !Ltk($R, ~lkR), !Pk($I, 'g'^~lkI) ]+ --[ SidR_1( ~ekR, $I, $R, X, 'g'^~ekR ,+ h( < X, 'g'^~ekR, X^~ekR, ('g'^~lkI)^~lkR > ) ) ]->+ [ Out( 'g'^~ekR ),+ !Ephk(~ekR),+ !Sessk( ~ekR, + h( < X, 'g'^~ekR, X^~ekR, ('g'^~lkI)^~lkR > ) ) ]++rule Sessk_reveal: + [ !Sessk(~tid, k) ]+ --[ SesskRev(~tid) ]->+ [ Out(k) ]++rule Ephk_reveal:+ [ !Ephk(~ekI) ]+ --[ EphkRev(~ekI) ]->+ [ Out(~ekI) ]++rule Ltk_reveal:+ [ !Ltk($A, k) ]+ --[ LtkRev($A) ]->+ [ Out(k) ]+++/* Security properties */++/*+lemma key_agreement_reachable:+ "not (Ex #i1 #i2 ekI ekR I R k hkI hkR.+ SidI_2(ekI, I, R, hkI, hkR, k) @ i1 & SidR_1(ekR, I, R, hkI, hkR, k) @ i2)"+*/+++/* An attack is valid in the security model if the session key of the test session is deduced and+ the test session is clean.+*/+lemma JKL2008_1_initiator_key:+ "not (Ex #i1 #i2 ttest I R k hkI hkR.+ SidI_2(ttest, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* Not ephemeral-key-reveal */+ & (All #i3 t. EphkRev( t ) @ i3 ==> F)++ /* Not longterm-key-reveal */+ & (All #i3 a. LtkRev( a ) @ i3 ==> F)++ /* Not session-key-reveal of test thread. */+ & (All #i3. SesskRev( ttest ) @ i3 ==> F)++ /* Not session-key-reveal of partner thread. */+ & (All #i3 #i4 tpartner kpartner.+ SidR_1( tpartner,I,R,hkI,hkR,kpartner ) @i3+ & SesskRev( tpartner ) @ i4 ==> F)+ )"++/* An attack is valid in the security model if the session key of the test session is deduced and+ the test session is clean.+*/+lemma JKL2008_1_responder_key:+ "not (Ex #i1 #i2 ttest I R k hkI hkR.+ SidR_1(ttest, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* Not ephemeral-key-reveal */+ & (All #i3 t. EphkRev( t ) @ i3 ==> F)++ /* Not longterm-key-reveal */+ & (All #i3 a. LtkRev( a ) @ i3 ==> F)++ /* Not session-key-reveal of test thread. */+ & (All #i3. SesskRev( ttest ) @ i3 ==> F)++ /* Not session-key-reveal of partner thread. Note that we use SidI_2 here.+ A session key reveal can only happen after SidI_2 is logged anyways.+ */+ & (All #i3 #i4 tpartner kpartner.+ SidI_2( tpartner,I,R,hkI,hkR,kpartner ) @i3+ & SesskRev( tpartner ) @ i4 ==> F)+ )"++end
@@ -0,0 +1,135 @@+theory JKL_TS2_2004+begin++builtin: hashing, diffie-hellman++section{* Jeong, Katz, Lee : TS2 (2004) *}+/*+ * Protocol: JKL-TS2-2004+ * Modeler: Cas Cremers+ * Date: January 2012+ * Source: "One-Round Protocols for Two-Party Authenticated Key Exchange"+ * Jeong, Katz, Lee, 2004+ *+ * Status: working+ */++/* Protocol rules */++rule generate_ltk:+ [ Fr(~lk) ] -->+ [ !Ltk( $A, ~lk ), !Pk( $A, 'g'^~lk ), Out( 'g'^~lk ) ]++rule Init_1:+ [ Fr( ~ekI ), !Ltk( $I, ~lkI ) ]+ --[ SidI_1(~ekI,$I,$R, 'g'^~ekI ) ]->+ [ Init_1( ~ekI, $I, $R, ~lkI, 'g'^~ekI ),+ !Ephk(~ekI),+ Out( 'g'^~ekI ) ]++rule Init_2:+ [ Init_1( ~ekI, $I, $R, ~lkI , hkI), In( Y ), !Pk( $R,'g'^~lkR ) ]+ --[SidI_2( ~ekI, $I, $R, hkI, Y,+ h( < hkI, Y, Y^~ekI, ('g'^~lkR)^~lkI > ) ) ]->+ [ !Sessk( ~ekI, + h( < hkI, Y, Y^~ekI, ('g'^~lkR)^~lkI > ) ) ]++rule Resp_1:+ [ In( X ), Fr( ~ekR ), !Ltk($R, ~lkR), !Pk($I, 'g'^~lkI) ]+ --[ SidR_1( ~ekR, $I, $R, X, 'g'^~ekR ,+ h( < X, 'g'^~ekR, X^~ekR, ('g'^~lkI)^~lkR > ) ) ]->+ [ Out( 'g'^~ekR ),+ !Ephk(~ekR),+ !Sessk( ~ekR, + h( < X, 'g'^~ekR, X^~ekR, ('g'^~lkI)^~lkR > ) ) ]++rule Sessk_reveal: + [ !Sessk(~tid, k) ]+ --[ SesskRev(~tid) ]->+ [ Out(k) ]++rule Ephk_reveal:+ [ !Ephk(~ekI) ]+ --[ EphkRev(~ekI) ]->+ [ Out(~ekI) ]++rule Ltk_reveal:+ [ !Ltk($A, k) ]+ --[ LtkRev($A) ]->+ [ Out(k) ]++/* Security properties */++/*+lemma key_agreement_reachable:+ "not (Ex #i1 #i2 ekI ekR I R k hkI hkR.+ SidI_2(ekI, I, R, hkI, hkR, k) @ i1 & SidR_1(ekR, I, R, hkI, hkR, k) @ i2)"+*/+++/* An attack is valid in the security model if the session key of the test session is deduced and+ the test session is clean.+*/+lemma JKL2008_2_initiator_key:+ "not (Ex #i1 #i2 ttest I R k hkI hkR.+ SidI_2(ttest, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* Not ephemeral-key-reveal */+ & (All #i3 t. EphkRev( t ) @ i3 ==> F)++ /* Not session-key-reveal of test thread. */+ & (All #i3. SesskRev( ttest ) @ i3 ==> F)++ /* Not session-key-reveal of partner thread. */+ & (All #i3 #i4 tpartner kpartner.+ SidR_1( tpartner,I,R,hkI,hkR,kpartner ) @i3+ & SesskRev( tpartner ) @ i4 ==> F)++ /* If there is no partner thread, then there is no longterm-key-reveal for+ the intended partner.+ (We model wpfs, for pfs, add i1 < i3 to conclusion) */+ & (All #i3. LtkRev( I ) @ i3 ==>+ (Ex #i4 tpartner kpartner.+ (* (i1 < i3) | *)+ SidR_1( tpartner,I,R,hkI,hkR,kpartner ) @i4))+ & (All #i3. LtkRev( R ) @ i3 ==>+ (Ex #i4 tpartner kpartner.+ (* (i1 < i3) | *)+ SidR_1( tpartner,I,R,hkI,hkR,kpartner ) @i4))+ )"++/* An attack is valid in the security model if the session key of the test session is deduced and+ the test session is clean.+*/+lemma JKL2008_2_responder_key:+ "not (Ex #i1 #i2 ttest I R k hkI hkR.+ SidR_1(ttest, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* Not ephemeral-key-reveal */+ & (All #i3 t. EphkRev( t ) @ i3 ==> F)++ /* Not session-key-reveal of test thread. */+ & (All #i3. SesskRev( ttest ) @ i3 ==> F)++ /* Not session-key-reveal of partner thread. Note that we use SidI_2 here.+ A session key reveal can only happen after SidI_2 is logged anyways.+ */+ & (All #i3 #i4 tpartner kpartner.+ SidI_2( tpartner,I,R,hkI,hkR,kpartner ) @i3+ & SesskRev( tpartner ) @ i4 ==> F)++ /* If there is no partner thread, then there is no longterm-key-reveal for+ the actor or intended partner.+ (We model wpfs, for pfs, add i1 < i3 to conclusion)+ */+ & (All #i3. LtkRev( I ) @ i3 ==>+ (Ex #i4 tpartner.+ (* (i1 < i3) | *)+ SidI_1( tpartner,I,R,hkI ) @i4))+ & (All #i3. LtkRev( R ) @ i3 ==>+ (Ex #i4 tpartner.+ (* (i1 < i3) | *)+ SidI_1( tpartner,I,R,hkI ) @i4))+ )"++end
@@ -0,0 +1,120 @@+theory JKL_TS2_2008+begin++builtin: hashing, diffie-hellman++section{* Jeong, Katz, Lee : TS2 (2008) *}+/*+ * Protocol: JKL-TS2-2008+ * Modeler: Cas Cremers+ * Date: January 2012+ * Source: "One-Round Protocols for Two-Party Authenticated Key Exchange"+ * Jeong, Katz, Lee, 2008+ * Note: Although the paper title is the same as the 2004+ * original, the updated version from 2008 includes+ * modified protocols and security models.+ *+ * Status: working+ */++/* Protocol rules */++rule generate_ltk:+ [ Fr(~lk) ] -->+ [ !Ltk( $A, ~lk ), !Pk( $A, 'g'^~lk ), Out( 'g'^~lk ) ]++rule Init_1:+ [ Fr( ~ekI ), !Ltk( $I, ~lkI ) ]+ --[ SidI_1(~ekI,$I,$R, 'g'^~ekI ) ]->+ [ Init_1( ~ekI, $I, $R, ~lkI, 'g'^~ekI ),+ !Ephk(~ekI),+ Out( 'g'^~ekI ) ]++rule Init_2:+ [ Init_1( ~ekI, $I, $R, ~lkI , hkI), In( Y ), !Pk( $R,'g'^~lkR ) ]+ --[SidI_2( ~ekI, $I, $R, hkI, Y,+ h( < $I, $R, hkI, Y, Y^~ekI, ('g'^~lkR)^~lkI > ) ) ]->+ [ !Sessk( ~ekI, + h( < $I, $R, hkI, Y, Y^~ekI, ('g'^~lkR)^~lkI > ) ) ]++rule Resp_1:+ [ In( X ), Fr( ~ekR ), !Ltk($R, ~lkR), !Pk($I, 'g'^~lkI) ]+ --[ SidR_1( ~ekR, $I, $R, X, 'g'^~ekR ,+ h( < $I, $R, X, 'g'^~ekR, X^~ekR, ('g'^~lkI)^~lkR > ) ) ]->+ [ Out( 'g'^~ekR ),+ !Ephk(~ekR),+ !Sessk( ~ekR, + h( < $I, $R, X, 'g'^~ekR, X^~ekR, ('g'^~lkI)^~lkR > ) ) ]++rule Sessk_reveal: + [ !Sessk(~tid, k) ]+ --[ SesskRev(~tid) ]->+ [ Out(k) ]++rule Ephk_reveal:+ [ !Ephk(~ekI) ]+ --[ EphkRev(~ekI) ]->+ [ Out(~ekI) ]++rule Ltk_reveal:+ [ !Ltk($A, k) ]+ --[ LtkRev($A) ]->+ [ Out(k) ]+++/* Security properties */++/*+lemma key_agreement_reachable:+ "not (Ex #i1 #i2 ekI ekR I R k hkI hkR.+ SidI_2(ekI, I, R, hkI, hkR, k) @ i1 & SidR_1(ekR, I, R, hkI, hkR, k) @ i2)"+*/+++/* An attack is valid in the security model if the session key of the test session is deduced and+ the test session is clean.+*/+lemma JKL2008_1_initiator_key:+ "not (Ex #i1 #i2 ttest I R k hkI hkR.+ SidI_2(ttest, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* Not ephemeral-key-reveal */+ & (All #i3 t. EphkRev( t ) @ i3 ==> F)++ /* Not longterm-key-reveal */+ & (All #i3 a. LtkRev( a ) @ i3 ==> F)++ /* Not session-key-reveal of test thread. */+ & (All #i3. SesskRev( ttest ) @ i3 ==> F)++ /* Not session-key-reveal of partner thread. */+ & (All #i3 #i4 tpartner kpartner.+ SidR_1( tpartner,I,R,hkI,hkR,kpartner ) @i3+ & SesskRev( tpartner ) @ i4 ==> F)+ )"++/* An attack is valid in the security model if the session key of the test session is deduced and+ the test session is clean.+*/+lemma JKL2008_1_responder_key:+ "not (Ex #i1 #i2 ttest I R k hkI hkR.+ SidR_1(ttest, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* Not ephemeral-key-reveal */+ & (All #i3 t. EphkRev( t ) @ i3 ==> F)++ /* Not longterm-key-reveal */+ & (All #i3 a. LtkRev( a ) @ i3 ==> F)++ /* Not session-key-reveal of test thread. */+ & (All #i3. SesskRev( ttest ) @ i3 ==> F)++ /* Not session-key-reveal of partner thread. Note that we use SidI_2 here.+ A session key reveal can only happen after SidI_2 is logged anyways.+ */+ & (All #i3 #i4 tpartner kpartner.+ SidI_2( tpartner,I,R,hkI,hkR,kpartner ) @i3+ & SesskRev( tpartner ) @ i4 ==> F)+ )"++end
@@ -0,0 +1,139 @@+theory JKL_TS2_2008+begin++builtin: hashing, diffie-hellman++section{* Jeong, Katz, Lee : TS2 (2008) *}+/*+ * Protocol: JKL-TS2-2008+ * Modeler: Cas Cremers+ * Date: January 2012+ * Source: "One-Round Protocols for Two-Party Authenticated Key Exchange"+ * Jeong, Katz, Lee, 2008+ * Note: Although the paper title is the same as the 2004+ * original, the updated version from 2008 includes+ * modified protocols and security models.+ *+ * Status: working+ */++/* Protocol rules */++rule generate_ltk:+ [ Fr(~lk) ] -->+ [ !Ltk( $A, ~lk ), !Pk( $A, 'g'^~lk ), Out( 'g'^~lk ) ]++rule Init_1:+ [ Fr( ~ekI ), !Ltk( $I, ~lkI ) ]+ --[ SidI_1(~ekI,$I,$R, 'g'^~ekI ) ]->+ [ Init_1( ~ekI, $I, $R, ~lkI, 'g'^~ekI ),+ !Ephk(~ekI),+ Out( 'g'^~ekI ) ]++rule Init_2:+ [ Init_1( ~ekI, $I, $R, ~lkI , hkI), In( Y ), !Pk( $R,'g'^~lkR ) ]+ --[SidI_2( ~ekI, $I, $R, hkI, Y,+ h( < $I, $R, hkI, Y, Y^~ekI, ('g'^~lkR)^~lkI > ) ) ]->+ [ !Sessk( ~ekI, + h( < $I, $R, hkI, Y, Y^~ekI, ('g'^~lkR)^~lkI > ) ) ]++rule Resp_1:+ [ In( X ), Fr( ~ekR ), !Ltk($R, ~lkR), !Pk($I, 'g'^~lkI) ]+ --[ SidR_1( ~ekR, $I, $R, X, 'g'^~ekR ,+ h( < $I, $R, X, 'g'^~ekR, X^~ekR, ('g'^~lkI)^~lkR > ) ) ]->+ [ Out( 'g'^~ekR ),+ !Ephk(~ekR),+ !Sessk( ~ekR, + h( < $I, $R, X, 'g'^~ekR, X^~ekR, ('g'^~lkI)^~lkR > ) ) ]++rule Sessk_reveal: + [ !Sessk(~tid, k) ]+ --[ SesskRev(~tid) ]->+ [ Out(k) ]++rule Ephk_reveal:+ [ !Ephk(~ekI) ]+ --[ EphkRev(~ekI) ]->+ [ Out(~ekI) ]++rule Ltk_reveal:+ [ !Ltk($A, k) ]+ --[ LtkRev($A) ]->+ [ Out(k) ]+++/* Security properties */++/*+lemma key_agreement_reachable:+ "not (Ex #i1 #i2 ekI ekR I R k hkI hkR.+ SidI_2(ekI, I, R, hkI, hkR, k) @ i1 & SidR_1(ekR, I, R, hkI, hkR, k) @ i2)"+*/+++/* An attack is valid in the security model if the session key of the test session is deduced and+ the test session is clean.+*/+lemma JKL2008_2_initiator_key:+ "not (Ex #i1 #i2 ttest I R k hkI hkR.+ SidI_2(ttest, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* Not ephemeral-key-reveal */+ & (All #i3 t. EphkRev( t ) @ i3 ==> F)++ /* Not session-key-reveal of test thread. */+ & (All #i3. SesskRev( ttest ) @ i3 ==> F)++ /* Not session-key-reveal of partner thread. */+ & (All #i3 #i4 tpartner kpartner.+ SidR_1( tpartner,I,R,hkI,hkR,kpartner ) @i3+ & SesskRev( tpartner ) @ i4 ==> F)++ /* If there is no partner thread, then there is no longterm-key-reveal for+ the intended partner.+ (We model wpfs, for pfs, add i1 < i3 to conclusion) */+ & (All #i3. LtkRev( I ) @ i3 ==>+ (Ex #i4 tpartner kpartner.+ (* (i1 < i3) | *)+ SidR_1( tpartner,I,R,hkI,hkR,kpartner ) @i4))+ & (All #i3. LtkRev( R ) @ i3 ==>+ (Ex #i4 tpartner kpartner.+ (* (i1 < i3) | *)+ SidR_1( tpartner,I,R,hkI,hkR,kpartner ) @i4))+ )"++/* An attack is valid in the security model if the session key of the test session is deduced and+ the test session is clean.+*/+lemma JKL2008_2_responder_key:+ "not (Ex #i1 #i2 ttest I R k hkI hkR.+ SidR_1(ttest, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* Not ephemeral-key-reveal */+ & (All #i3 t. EphkRev( t ) @ i3 ==> F)++ /* Not session-key-reveal of test thread. */+ & (All #i3. SesskRev( ttest ) @ i3 ==> F)++ /* Not session-key-reveal of partner thread. Note that we use SidI_2 here.+ A session key reveal can only happen after SidI_2 is logged anyways.+ */+ & (All #i3 #i4 tpartner kpartner.+ SidI_2( tpartner,I,R,hkI,hkR,kpartner ) @i3+ & SesskRev( tpartner ) @ i4 ==> F)++ /* If there is no partner thread, then there is no longterm-key-reveal for+ the actor or intended partner.+ (We model wpfs, for pfs, add i1 < i3 to conclusion)+ */+ & (All #i3. LtkRev( I ) @ i3 ==>+ (Ex #i4 tpartner.+ (* (i1 < i3) | *)+ SidI_1( tpartner,I,R,hkI ) @i4))+ & (All #i3. LtkRev( R ) @ i3 ==>+ (Ex #i4 tpartner.+ (* (i1 < i3) | *)+ SidI_1( tpartner,I,R,hkI ) @i4))+ )"++end
@@ -0,0 +1,199 @@+theory JKL_TS3_2004+begin++builtin: hashing, diffie-hellman++section{* Jeong, Katz, Lee : TS3 (2004) *}+/*+ * Protocol: JKL-TS3-2004+ * Modeler: Cas Cremers+ * Date: January 2012+ * Source: "One-Round Protocols for Two-Party Authenticated Key Exchange"+ * Jeong, Katz, Lee, 2004+ *+ * Status: working+ */++/* Protocol rules */++rule generate_ltk:+ [ Fr(~lk) ] -->+ [ !Ltk( $A, ~lk ), !Pk( $A, 'g'^~lk ), Out( 'g'^~lk ) ]++rule Init_1:+ [ Fr( ~ekI ), !Ltk( $I, ~lkI ), !Pk($R,'g'^~lkR) ]+ --[ SidI_1(~ekI,$I,$R, 'g'^~ekI ), Roles($I, $R) ]->+ [ Init_1( ~ekI, $I, $R, ~lkI, 'g'^~ekI ),+ !Ephk(~ekI),+ Out( < 'g'^~ekI, h( ('g'^~lkR)^~lkI,$I,$R,'g'^~ekI ) > ) ]++rule Init_2:+ [ Init_1( ~ekI, $I, $R, ~lkI , hkI), !Pk($R,'g'^~lkR), + In( < Y, h(('g'^~lkI)^~lkR,$R,$I,Y )> ) ]+ --[SidI_2( ~ekI, $I, $R, hkI, Y,+ Y^~ekI ), Roles($I, $R) ]->+ [ !Sessk( ~ekI, + Y^~ekI ) ]++rule Resp_1:+ [ In( < X, h( ('g'^~lkR)^~lkI,$I,$R,X ) > ), Fr( ~ekR ), !Ltk($R, ~lkR), !Pk($I, 'g'^~lkI) ]+ --[ SidR_1( ~ekR, $I, $R, X, 'g'^~ekR ,+ X^~ekR ), Roles($I, $R) ]->+ [ Out( < 'g'^~ekR, h( ('g'^~lkI)^~lkR,$R,$I,'g'^~ekR ) > ),+ !Ephk(~ekR),+ !Sessk( ~ekR, + X^~ekR ) ]++rule Sessk_reveal: + [ !Sessk(~tid, k) ]+ --[ SesskRev(~tid) ]->+ [ Out(k) ]++rule Ephk_reveal:+ [ !Ephk(~ekI) ]+ --[ EphkRev(~ekI) ]->+ [ Out(~ekI) ]++rule Ltk_reveal:+ [ !Ltk($A, k) ]+ --[ LtkRev($A) ]->+ [ Out(k) ]+++/* Security properties */++/* Only non-reflected executions */+/*+lemma key_agreement_reachable:+ "not (Ex #i1 #i2 ekI ekR I R k hkI hkR.+ SidI_2(ekI, I, R, hkI, hkR, k) @ i1 & SidR_1(ekR, I, R, hkI, hkR, k) @ i2+ + & (All #tid A. Roles(A, A) @ tid ==> F )+ )"+*/++/* An attack is valid in the security model if the session key of the test session is deduced and+ the test session is clean.+*/+lemma JKL2004_1_initiator_key:+ "not (Ex #i1 #i2 ttest I R k hkI hkR.+ SidI_2(ttest, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* Only non-reflected executions */+ & (All #tid A. Roles(A, A) @ tid ==> F )++ /* Not ephemeral-key-reveal */+ & (All #i3 t. EphkRev( t ) @ i3 ==> F)++ /* Not longterm-key-reveal */+ & (All #i3 a. LtkRev( a ) @ i3 ==> F)++ /* Not session-key-reveal of test thread. */+ & (All #i3. SesskRev( ttest ) @ i3 ==> F)++ /* Not session-key-reveal of partner thread. */+ & (All #i3 #i4 tpartner kpartner.+ SidR_1( tpartner,I,R,hkI,hkR,kpartner ) @i3+ & SesskRev( tpartner ) @ i4 ==> F)+ )"++/*+/* An attack is valid in the security model if the session key of the test session is deduced and+ the test session is clean.+*/+lemma JKL2004_1_responder_key:+ "not (Ex #i1 #i2 ttest I R k hkI hkR.+ SidR_1(ttest, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* Only non-reflected executions */+ & (All #tid A. Roles(A, A) @ tid ==> F )++ /* Not ephemeral-key-reveal */+ & (All #i3 t. EphkRev( t ) @ i3 ==> F)++ /* Not longterm-key-reveal */+ & (All #i3 a. LtkRev( a ) @ i3 ==> F)++ /* Not session-key-reveal of test thread. */+ & (All #i3. SesskRev( ttest ) @ i3 ==> F)++ /* Not session-key-reveal of partner thread. Note that we use SidI_2 here.+ A session key reveal can only happen after SidI_2 is logged anyways.+ */+ & (All #i3 #i4 tpartner kpartner.+ SidI_2( tpartner,I,R,hkI,hkR,kpartner ) @i3+ & SesskRev( tpartner ) @ i4 ==> F)+ )"++/* An attack is valid in the security model if the session key of the test session is deduced and+ the test session is clean.+*/+lemma JKL2004_2_initiator_key:+ "not (Ex #i1 #i2 ttest I R k hkI hkR.+ SidI_2(ttest, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* Only non-reflected executions */+ & (All #tid A. Roles(A, A) @ tid ==> F )++ /* Not ephemeral-key-reveal */+ & (All #i3 t. EphkRev( t ) @ i3 ==> F)++ /* Not session-key-reveal of test thread. */+ & (All #i3. SesskRev( ttest ) @ i3 ==> F)++ /* Not session-key-reveal of partner thread. */+ & (All #i3 #i4 tpartner kpartner.+ SidR_1( tpartner,I,R,hkI,hkR,kpartner ) @i3+ & SesskRev( tpartner ) @ i4 ==> F)++ /* If there is no partner thread, then there is no longterm-key-reveal for+ the intended partner.+ (We model wpfs, for pfs, add i1 < i3 to conclusion) */+ & (All #i3. LtkRev( I ) @ i3 ==>+ (Ex #i4 tpartner kpartner.+ (* (i1 < i3) | *)+ SidR_1( tpartner,I,R,hkI,hkR,kpartner ) @i4))+ & (All #i3. LtkRev( R ) @ i3 ==>+ (Ex #i4 tpartner kpartner.+ (* (i1 < i3) | *)+ SidR_1( tpartner,I,R,hkI,hkR,kpartner ) @i4))+ )"++/* An attack is valid in the security model if the session key of the test session is deduced and+ the test session is clean.+*/+lemma JKL2004_2_responder_key:+ "not (Ex #i1 #i2 ttest I R k hkI hkR.+ SidR_1(ttest, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* Only non-reflected executions */+ & (All #tid A. Roles(A, A) @ tid ==> F )++ /* Not ephemeral-key-reveal */+ & (All #i3 t. EphkRev( t ) @ i3 ==> F)++ /* Not session-key-reveal of test thread. */+ & (All #i3. SesskRev( ttest ) @ i3 ==> F)++ /* Not session-key-reveal of partner thread. Note that we use SidI_2 here.+ A session key reveal can only happen after SidI_2 is logged anyways.+ */+ & (All #i3 #i4 tpartner kpartner.+ SidI_2( tpartner,I,R,hkI,hkR,kpartner ) @i3+ & SesskRev( tpartner ) @ i4 ==> F)++ /* If there is no partner thread, then there is no longterm-key-reveal for+ the actor or intended partner.+ (We model wpfs, for pfs, add i1 < i3 to conclusion)+ */+ & (All #i3. LtkRev( I ) @ i3 ==>+ (Ex #i4 tpartner.+ (* (i1 < i3) | *)+ SidI_1( tpartner,I,R,hkI ) @i4))+ & (All #i3. LtkRev( R ) @ i3 ==>+ (Ex #i4 tpartner.+ (* (i1 < i3) | *)+ SidI_1( tpartner,I,R,hkI ) @i4))+ )"+*/+end
@@ -0,0 +1,188 @@+theory JKL_TS3_2008+begin++builtin: hashing, diffie-hellman++section{* Jeong, Katz, Lee : TS3 (2008) *}+/*+ * Protocol: JKL-TS3-2008+ * Modeler: Cas Cremers+ * Date: January 2012+ * Source: "One-Round Protocols for Two-Party Authenticated Key Exchange"+ * Jeong, Katz, Lee, 2008+ * Note: Although the paper title is the same as the 2004+ * original, the updated version from 2008 includes+ * modified protocols and security models.+ *+ * Status: working+ */++/* Protocol rules */++rule generate_ltk:+ [ Fr(~lk) ] -->+ [ !Ltk( $A, ~lk ), !Pk( $A, 'g'^~lk ), Out( 'g'^~lk ) ]++rule Init_1:+ [ Fr( ~ekI ), !Ltk( $I, ~lkI ), !Pk($R,'g'^~lkR) ]+ --[ SidI_1(~ekI,$I,$R, 'g'^~ekI ) ]->+ [ Init_1( ~ekI, $I, $R, ~lkI, 'g'^~ekI ),+ !Ephk(~ekI),+ Out( < 'g'^~ekI, h( ('g'^~lkR)^~lkI,'1','2','g'^~ekI ) > ) ]++rule Init_2:+ [ Init_1( ~ekI, $I, $R, ~lkI , hkI), !Pk($R,'g'^~lkR),+ In( < Y, h(('g'^~lkI)^~lkR,'2','1',Y )> ) ]+ --[SidI_2( ~ekI, $I, $R, hkI, Y,+ Y^~ekI ) ]->+ [ !Sessk( ~ekI, + Y^~ekI ) ]++rule Resp_1:+ [ In( < X, h( ('g'^~lkR)^~lkI,'1','2',X ) > ), Fr( ~ekR ), !Ltk($R, ~lkR), !Pk($I, 'g'^~lkI) ]+ --[ SidR_1( ~ekR, $I, $R, X, 'g'^~ekR ,+ X^~ekR ) ]->+ [ Out( < 'g'^~ekR, h( ('g'^~lkI)^~lkR,'2','1','g'^~ekR ) > ),+ !Ephk(~ekR),+ !Sessk( ~ekR, + X^~ekR ) ]++rule Sessk_reveal: + [ !Sessk(~tid, k) ]+ --[ SesskRev(~tid) ]->+ [ Out(k) ]++rule Ephk_reveal:+ [ !Ephk(~ekI) ]+ --[ EphkRev(~ekI) ]->+ [ Out(~ekI) ]++rule Ltk_reveal:+ [ !Ltk($A, k) ]+ --[ LtkRev($A) ]->+ [ Out(k) ]+++/* Security properties */++/*+lemma key_agreement_reachable:+ "not (Ex #i1 #i2 ekI ekR I R k hkI hkR.+ SidI_2(ekI, I, R, hkI, hkR, k) @ i1 & SidR_1(ekR, I, R, hkI, hkR, k) @ i2)"+*/+++/* An attack is valid in the security model if the session key of the test session is deduced and+ the test session is clean.+*/+lemma JKL2008_1_initiator_key:+ "not (Ex #i1 #i2 ttest I R k hkI hkR.+ SidI_2(ttest, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* Not ephemeral-key-reveal */+ & (All #i3 t. EphkRev( t ) @ i3 ==> F)++ /* Not longterm-key-reveal */+ & (All #i3 a. LtkRev( a ) @ i3 ==> F)++ /* Not session-key-reveal of test thread. */+ & (All #i3. SesskRev( ttest ) @ i3 ==> F)++ /* Not session-key-reveal of partner thread. */+ & (All #i3 #i4 tpartner kpartner.+ SidR_1( tpartner,I,R,hkI,hkR,kpartner ) @i3+ & SesskRev( tpartner ) @ i4 ==> F)+ )"+/*++/* An attack is valid in the security model if the session key of the test session is deduced and+ the test session is clean.+*/+lemma JKL2008_1_responder_key:+ "not (Ex #i1 #i2 ttest I R k hkI hkR.+ SidR_1(ttest, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* Not ephemeral-key-reveal */+ & (All #i3 t. EphkRev( t ) @ i3 ==> F)++ /* Not longterm-key-reveal */+ & (All #i3 a. LtkRev( a ) @ i3 ==> F)++ /* Not session-key-reveal of test thread. */+ & (All #i3. SesskRev( ttest ) @ i3 ==> F)++ /* Not session-key-reveal of partner thread. Note that we use SidI_2 here.+ A session key reveal can only happen after SidI_2 is logged anyways.+ */+ & (All #i3 #i4 tpartner kpartner.+ SidI_2( tpartner,I,R,hkI,hkR,kpartner ) @i3+ & SesskRev( tpartner ) @ i4 ==> F)+ )"++/* An attack is valid in the security model if the session key of the test session is deduced and+ the test session is clean.+*/+lemma JKL2008_2_initiator_key:+ "not (Ex #i1 #i2 ttest I R k hkI hkR.+ SidI_2(ttest, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* Not ephemeral-key-reveal */+ & (All #i3 t. EphkRev( t ) @ i3 ==> F)++ /* Not session-key-reveal of test thread. */+ & (All #i3. SesskRev( ttest ) @ i3 ==> F)++ /* Not session-key-reveal of partner thread. */+ & (All #i3 #i4 tpartner kpartner.+ SidR_1( tpartner,I,R,hkI,hkR,kpartner ) @i3+ & SesskRev( tpartner ) @ i4 ==> F)++ /* If there is no partner thread, then there is no longterm-key-reveal for+ the intended partner.+ (We model wpfs, for pfs, add i1 < i3 to conclusion) */+ & (All #i3. LtkRev( I ) @ i3 ==>+ (Ex #i4 tpartner kpartner.+ (* (i1 < i3) | *)+ SidR_1( tpartner,I,R,hkI,hkR,kpartner ) @i4))+ & (All #i3. LtkRev( R ) @ i3 ==>+ (Ex #i4 tpartner kpartner.+ (* (i1 < i3) | *)+ SidR_1( tpartner,I,R,hkI,hkR,kpartner ) @i4))+ )"++/* An attack is valid in the security model if the session key of the test session is deduced and+ the test session is clean.+*/+lemma JKL2008_2_responder_key:+ "not (Ex #i1 #i2 ttest I R k hkI hkR.+ SidR_1(ttest, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* Not ephemeral-key-reveal */+ & (All #i3 t. EphkRev( t ) @ i3 ==> F)++ /* Not session-key-reveal of test thread. */+ & (All #i3. SesskRev( ttest ) @ i3 ==> F)++ /* Not session-key-reveal of partner thread. Note that we use SidI_2 here.+ A session key reveal can only happen after SidI_2 is logged anyways.+ */+ & (All #i3 #i4 tpartner kpartner.+ SidI_2( tpartner,I,R,hkI,hkR,kpartner ) @i3+ & SesskRev( tpartner ) @ i4 ==> F)++ /* If there is no partner thread, then there is no longterm-key-reveal for+ the actor or intended partner.+ (We model wpfs, for pfs, add i1 < i3 to conclusion)+ */+ & (All #i3. LtkRev( I ) @ i3 ==>+ (Ex #i4 tpartner.+ (* (i1 < i3) | *)+ SidI_1( tpartner,I,R,hkI ) @i4))+ & (All #i3. LtkRev( R ) @ i3 ==>+ (Ex #i4 tpartner.+ (* (i1 < i3) | *)+ SidI_1( tpartner,I,R,hkI ) @i4))+ )"+*/++end
@@ -0,0 +1,159 @@+theory KEA_plus_KCI+begin++builtin: hashing, diffie-hellman++section{* KEA+ *}+/*+ * Protocol: KEA++ * Modeler: Cas Cremers+ * Date: January 2012+ * Source: "Security Analysis of KEA Authenticated Key Exchange Protocol"+ * Lauter, Mityagin, 2006+ * Property: KI, KCI+ *+ * Status: working+ */++/* Protocol rules */++rule generate_ltk:+ [ Fr(~lk) ] + --[ RegKey($A) ]->+ [ !Ltk( $A, ~lk ), !Pk( $A, 'g'^~lk ), Out( 'g'^~lk ) ]++rule Init_1:+ [ Fr( ~ekI ), !Ltk( $I, ~lkI ) ]+ --[ SidI_1(~ekI,$I,$R, 'g'^~ekI ) ]->+ [ Init_1( ~ekI, $I, $R, ~lkI, 'g'^~ekI ),+ !Ephk(~ekI),+ Out( 'g'^~ekI ) ]++rule Init_2:+ [ Init_1( ~ekI, $I, $R, ~lkI , hkI), In( Y ), !Pk( $R,'g'^~lkR ) ]+ --[SidI_2( ~ekI, $I, $R, hkI, Y,+ h( <Y^~lkI, ('g'^~lkR)^~ekI, $I, $R > ) ) ]->+ [ !Sessk( ~ekI, + h( <Y^~lkI, ('g'^~lkR)^~ekI, $I, $R > ) ) ]+++rule Resp_1:+ [ In( X ), Fr( ~ekR ), !Ltk($R, ~lkR), !Pk($I, 'g'^~lkI) ]+ --[ SidR_1( ~ekR, $I, $R, X, 'g'^~ekR ,+ h( <('g'^~lkI)^~ekR, X^~lkR, $I, $R > ) ) ]->+ [ Out( 'g'^~ekR ),+ !Ephk(~ekR),+ !Sessk( ~ekR, + h( <('g'^~lkI)^~ekR, X^~lkR, $I, $R > ) ) ]++rule Sessk_reveal: + [ !Sessk(~tid, k) ]+ --[ SesskRev(~tid) ]->+ [ Out(k) ]++rule Ephk_reveal:+ [ !Ephk(~ekI) ]+ --[ EphkRev(~ekI) ]->+ [ Out(~ekI) ]++rule Ltk_reveal:+ [ !Ltk($A, k) ]+ --[ LtkRev($A) ]->+ [ Out(k) ]+++/* Security properties */++/*+lemma key_agreement_reachable:+ "not (Ex #i1 #i2 ekI ekR I R k hkI hkR.+ SidI_2(ekI, I, R, hkI, hkR, k) @ i1 & SidR_1(ekR, I, R, hkI, hkR, k) @ i2)"+*/++/* Security notion.+ *+ * We model the claims in the KEA+ paper except for the (non-standard)+ * weakened notion of wPFS, in which the adversary can learn A or B's+ * key after the test thread ends, but not both. "Real" wPFS does not+ * hold for this protocol anyway.+ * However, by modeling KCI attacks, we are also modeling half of+ * KEA+'s wPFS notion: the adversary can learn the long-term key of the+ * actor (and thus also after the end of the test session).+ *+ * We model ephemeral key reveals for non-partner threads. This+ * corresponds to a session-state-reveal analysis where the+ * session-state is defined as the randomness generated by the parties.+ * This property is not implied by the proof (sketch) in the KEA+ paper.+ */++/* An attack is valid in the security notion if the session key of the test session is deduced and+ the test session is clean.+*/+lemma keaplus_initiator_key:+ " /* If every agent registered at most one public key */+ (All A #i #j. RegKey(A)@i & RegKey(A)@j ==> (#i = #j))+ ==>+ /* then there is not attack */+ (not(Ex #i1 #i2 ttest I R k hkI hkR.+ SidI_2(ttest, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* No ephemeral-key-reveal of test thread */+ & (All #i3. EphkRev( ttest ) @ i3 ==> F)++ /* Not session-key-reveal of test thread. */+ & (All #i3. SesskRev( ttest ) @ i3 ==> F)++ /* Not ephemeral-key-reveal of partner thread. */+ & (All #i3 #i4 tpartner kpartner.+ SidR_1( tpartner,I,R,hkI,hkR,kpartner ) @i3+ & EphkRev( tpartner ) @ i4 ==> F)++ /* Not session-key-reveal of partner thread. */+ & (All #i3 #i4 tpartner kpartner.+ SidR_1( tpartner,I,R,hkI,hkR,kpartner ) @i3+ & SesskRev( tpartner ) @ i4 ==> F)++ /* Not longterm-key-reveal of intended peer. */+ & (All #i3. LtkRev( R ) @ i3 ==> F)+ ) )"++/* An attack is valid in the security notion if the session key of the test session is deduced and+ the test session is clean.+*/+lemma keaplus_responder_key:+ " /* If every agent registered at most one public key */+ (All A #i #j. RegKey(A)@i & RegKey(A)@j ==> (#i = #j))+ ==>+ /* then there is not attack */+ (not (Ex #i1 #i2 ttest I R k hkI hkR.+ SidR_1(ttest, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* Not ephemeral-key-reveal of test thread. */+ & (All #i3. EphkRev( ttest ) @ i3 ==> F)++ /* Not session-key-reveal of test thread. */+ & (All #i3. SesskRev( ttest ) @ i3 ==> F)++ /* Not ephemeral-key-reveal of partner thread. */+ /* Note we distinguish explicitly between an incomplete+ * and complete partner thread case.+ */+ & (All #i3 #i4 tpartner lki.+ SidI_1( tpartner,I,R,lki ) @i3+ & EphkRev( tpartner ) @ i4 ==> F) + & (All #i3 #i4 tpartner kpartner.+ SidI_2( tpartner,I,R,hkI,hkR,kpartner ) @i3+ & EphkRev( tpartner ) @ i4 ==> F)++ /* Not session-key-reveal of partner thread. Note that we use SidI_2 here.+ A session key reveal can only happen after SidI_2 is logged anyways.+ */+ & (All #i3 #i4 tpartner kpartner.+ SidI_2( tpartner,I,R,hkI,hkR,kpartner ) @i3+ & SesskRev( tpartner ) @ i4 ==> F)++ /* Not longterm-key-reveal of intended peer. */+ & (All #i3. LtkRev( I ) @ i3 ==> F)+ ) )"++end
@@ -0,0 +1,155 @@+theory KEA_plus_wPFS+begin++builtin: hashing, diffie-hellman++section{* KEA+ *}+/*+ * Protocol: KEA++ * Modeler: Cas Cremers+ * Date: January 2012+ * Source: "Security Analysis of KEA Authenticated Key Exchange Protocol"+ * Lauter, Mityagin, 2006+ * Property: KI, KCI, wPFS+ *+ * Status: working+ */++/* Protocol rules */++rule generate_ltk:+ [ Fr(~lk) ] -->+ [ !Ltk( $A, ~lk ), !Pk( $A, 'g'^~lk ), Out( 'g'^~lk ) ]++rule Init_1:+ [ Fr( ~ekI ), !Ltk( $I, ~lkI ) ]+ --[ SidI_1(~ekI,$I,$R, 'g'^~ekI ) ]->+ [ Init_1( ~ekI, $I, $R, ~lkI, 'g'^~ekI ),+ !Ephk(~ekI),+ Out( 'g'^~ekI ) ]++rule Init_2:+ [ Init_1( ~ekI, $I, $R, ~lkI , hkI), In( Y ), !Pk( $R,'g'^~lkR ) ]+ --[SidI_2( ~ekI, $I, $R, hkI, Y,+ h( <Y^~lkI, ('g'^~lkR)^~ekI, $I, $R > ) ) ]->+ [ !Sessk( ~ekI, + h( <Y^~lkI, ('g'^~lkR)^~ekI, $I, $R > ) ) ]+++rule Resp_1:+ [ In( X ), Fr( ~ekR ), !Ltk($R, ~lkR), !Pk($I, 'g'^~lkI) ]+ --[ SidR_1( ~ekR, $I, $R, X, 'g'^~ekR ,+ h( <('g'^~lkI)^~ekR, X^~lkR, $I, $R > ) ) ]->+ [ Out( 'g'^~ekR ),+ !Ephk(~ekR),+ !Sessk( ~ekR, + h( <('g'^~lkI)^~ekR, X^~lkR, $I, $R > ) ) ]++rule Sessk_reveal: + [ !Sessk(~tid, k) ]+ --[ SesskRev(~tid) ]->+ [ Out(k) ]++rule Ephk_reveal:+ [ !Ephk(~ekI) ]+ --[ EphkRev(~ekI) ]->+ [ Out(~ekI) ]++rule Ltk_reveal:+ [ !Ltk($A, k) ]+ --[ LtkRev($A) ]->+ [ Out(k) ]+++/* Security properties */++/*+lemma key_agreement_reachable:+ "not (Ex #i1 #i2 ekI ekR I R k hkI hkR.+ SidI_2(ekI, I, R, hkI, hkR, k) @ i1 & SidR_1(ekR, I, R, hkI, hkR, k) @ i2)"+*/++/* Security notion.+ *+ * We model the security property in the KEA+ paper except that we model+ * "real" weak Perfect Forward Secrecy. + *+ * The original KEA PFS notion is a weakened notion of wPFS, in which the+ * adversary can learn A or B's key after the test thread ends, but not+ * both. + *+ * Below we model real wPFS in combination with KCI resilience.+ */++/* An attack is valid in the security notion if the session key of the test session is deduced and+ the test session is clean.+*/+lemma keaplus_initiator_key:+ "not (Ex #i1 #i2 ttest I R k hkI hkR.+ SidI_2(ttest, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* No ephemeral-key-reveal of test thread */+ & (All #i3. EphkRev( ttest ) @ i3 ==> F)++ /* Not session-key-reveal of test thread. */+ & (All #i3. SesskRev( ttest ) @ i3 ==> F)++ /* Not ephemeral-key-reveal of partner thread. */+ & (All #i3 #i4 tpartner kpartner.+ SidR_1( tpartner,I,R,hkI,hkR,kpartner ) @i3+ & EphkRev( tpartner ) @ i4 ==> F)++ /* Not session-key-reveal of partner thread. */+ & (All #i3 #i4 tpartner kpartner.+ SidR_1( tpartner,I,R,hkI,hkR,kpartner ) @i3+ & SesskRev( tpartner ) @ i4 ==> F)++ /* If there is no partner thread, then there is no longterm-key-reveal for+ the intended partner. */+ & (All #i3. LtkRev( R ) @ i3 ==>+ (i1 < i3) + & (Ex #i4 tpartner kpartner.+ SidR_1( tpartner,I,R,hkI,hkR,kpartner ) @i4))+ )"++/* An attack is valid in the security notion if the session key of the test session is deduced and+ the test session is clean.+*/+lemma keaplus_responder_key:+ "not (Ex #i1 #i2 ttest I R k hkI hkR.+ SidR_1(ttest, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* Not ephemeral-key-reveal of test thread. */+ & (All #i3. EphkRev( ttest ) @ i3 ==> F)++ /* Not session-key-reveal of test thread. */+ & (All #i3. SesskRev( ttest ) @ i3 ==> F)++ /* Not ephemeral-key-reveal of partner thread. */+ /* Note we distinguish explicitly between an incomplete+ * and complete partner thread case.+ */+ & (All #i3 #i4 tpartner lki.+ SidI_1( tpartner,I,R,lki ) @i3+ & EphkRev( tpartner ) @ i4 ==> F) + & (All #i3 #i4 tpartner kpartner.+ SidI_2( tpartner,I,R,hkI,hkR,kpartner ) @i3+ & EphkRev( tpartner ) @ i4 ==> F)++ /* Not session-key-reveal of partner thread. Note that we use SidI_2 here.+ A session key reveal can only happen after SidI_2 is logged anyways.+ */+ & (All #i3 #i4 tpartner kpartner.+ SidI_2( tpartner,I,R,hkI,hkR,kpartner ) @i3+ & SesskRev( tpartner ) @ i4 ==> F)++ /* If there is no partner thread, then there is no longterm-key-reveal for+ the intended partner.+ */+ & (All #i3. LtkRev( I ) @ i3 ==>+ (i1 < i3)+ & (Ex #i4 tpartner.+ SidI_1( tpartner,I,R,hkI ) @i4))+ )"++end
@@ -0,0 +1,155 @@+theory KEA_plus_KCI_wPFS+begin++builtin: hashing, diffie-hellman++section{* KEA+ *}+/*+ * Protocol: KEA++ * Modeler: Cas Cremers+ * Date: January 2012+ * Source: "Security Analysis of KEA Authenticated Key Exchange Protocol"+ * Lauter, Mityagin, 2006+ * Property: eCK security+ *+ * Status: working+ */++/* Protocol rules */++rule generate_ltk:+ [ Fr(~lk) ] + --[ RegKey($A) ]->+ [ !Ltk( $A, ~lk ), !Pk( $A, 'g'^~lk ), Out( 'g'^~lk ) ]++rule Init_1:+ [ Fr( ~ekI ), !Ltk( $I, ~lkI ) ]+ --[ SidI_1(~ekI,$I,$R, 'g'^~ekI ) ]->+ [ Init_1( ~ekI, $I, $R, ~lkI, 'g'^~ekI ),+ !Ephk(~ekI),+ Out( 'g'^~ekI ) ]++rule Init_2:+ [ Init_1( ~ekI, $I, $R, ~lkI , hkI), In( Y ), !Pk( $R,'g'^~lkR ) ]+ --[SidI_2( ~ekI, $I, $R, hkI, Y,+ h( <Y^~lkI, ('g'^~lkR)^~ekI, $I, $R > ) ) ]->+ [ !Sessk( ~ekI, + h( <Y^~lkI, ('g'^~lkR)^~ekI, $I, $R > ) ) ]+++rule Resp_1:+ [ In( X ), Fr( ~ekR ), !Ltk($R, ~lkR), !Pk($I, 'g'^~lkI) ]+ --[ SidR_1( ~ekR, $I, $R, X, 'g'^~ekR ,+ h( <('g'^~lkI)^~ekR, X^~lkR, $I, $R > ) ) ]->+ [ Out( 'g'^~ekR ),+ !Ephk(~ekR),+ !Sessk( ~ekR, + h( <('g'^~lkI)^~ekR, X^~lkR, $I, $R > ) ) ]++/* Key Reveals for the eCK model */+rule Sessk_reveal: + [ !Sessk(~tid, k) ]+ --[ SesskRev(~tid) ]->+ [ Out(k) ]++rule Ltk_reveal:+ [ !Ltk($A, lkA) ]+ --[ LtkRev($A) ]->+ [ Out(lkA) ]++rule Ephk_reveal:+ [ !Ephk(~ekA) ]+ --[ EphkRev(~ekA) ]->+ [ Out(~ekA) ]+++/* Security properties */++/*+lemma key_agreement_reachable:+ "not (Ex #i1 #i2 ekI ekR I R k hkI hkR.+ SidI_2(ekI, I, R, hkI, hkR, k) @ i1 & SidR_1(ekR, I, R, hkI, hkR, k) @ i2)"+*/++/* An attack is valid in eCK if the session key of the test session is deduced and+ the test session is clean.+*/+lemma eCK_initiator_key:+ " /* If every agent registered at most one public key */+ (All A #i #j. RegKey(A)@i & RegKey(A)@j ==> (#i = #j))+ ==>+ /* then there is not attack */+ (not(Ex #i1 #i2 ekI I R k hkI hkR.+ SidI_2(ekI, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* Not both longterm-key-reveal _and_ ephemeral-key-reveal+ * for test thread. */+ & not(Ex #i3 #i4. LtkRev( I ) @ i3 & EphkRev( ekI ) @ i4)++ /* No session-key-reveal of test thread. */+ & not(Ex #i3. SesskRev( ekI ) @ i3 )++ /* No session-key-reveal for matching session. */+ & not(Ex #i3 #i4 ekR kpartner.+ SidR_1( ekR,I,R,hkI,hkR,kpartner ) @i3+ & SesskRev( ekR ) @ i4 )++ /* Not both long-term-key-reveal and ephemeral-key-reveal+ * for matching session */+ & not(Ex #i3 #i4 #i5 ekR kpartner.+ SidR_1( ekR,I,R,hkI,hkR,kpartner ) @i3+ & LtkRev( R ) @ i4+ & EphkRev( ekR ) @ i5 )++ /* Longterm-key-reveal of partner only if there is a+ * matching session. */+ /* (We model eCK-wpfs, for eCK-pfs, add i1 < i3 to conclusion) */+ & (All #i3. LtkRev( R ) @ i3 ==>+ (* (i1 < i3) | *)+ (Ex #i4 ekR kpartner.+ SidR_1( ekR,I,R,hkI,hkR,kpartner ) @i4))+++ ) )"++/* An attack is valid in eCK if the session key of the test session is deduced and+ the test session is clean.+*/+lemma eCK_responder_key:+ " /* If every agent registered at most one public key */+ (All A #i #j. RegKey(A)@i & RegKey(A)@j ==> (#i = #j))+ ==>+ /* then there is not attack */+ (not (Ex #i1 #i2 ekR I R k hkI hkR.+ SidR_1(ekR, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* Not longterm-key-reveal _and_ ephemeral-key-reveal of actor . */+ & not(Ex #i3 #i4. LtkRev( R ) @ i3 & EphkRev( ekR ) @ i4)++ /* Not session-key-reveal of test thread. */+ & not(Ex #i3. SesskRev( ekR ) @ i3 )++ /* Not session-key-reveal of partner thread. Note that we use SidI_2 here.+ A session key reveal can only happen after SidI_2 is logged anyways.+ */+ & not(Ex #i3 #i4 ekI kpartner.+ SidI_2( ekI,I,R,hkI,hkR,kpartner ) @i3+ & SesskRev( ekI ) @ i4 )++ /* If there is a partner thread, then not long-term-key-reveal and ephemeral-key-reveal. */+ & not(Ex #i3 #i4 #i5 ekI.+ SidI_1( ekI,I,R,hkI ) @i3+ & LtkRev( I ) @ i4+ & EphkRev( ekI ) @ i5 )++ /* If there is no partner thread, then there is no longterm-key-reveal for+ the intended partner.+ (We model eCK-wpfs, for eCK-pfs, add i1 < i3 to conclusion)+ */+ & (All #i3. LtkRev( I ) @ i3 ==>+ (* (i1 < i3) | *)+ (Ex #i4 ekI.+ SidI_1( ekI,I,R,hkI ) @i4) )+ ) )"++end
@@ -0,0 +1,156 @@+theory NAXOS_eCK+begin++builtin: diffie-hellman, hashing++section{* NAXOS *}++/*+ * Protocol: NAXOS+ * Modeler: Cas Cremers, Benedikt Schmidt+ * Date: January 2012+ * Source: "Stronger Security of Authenticated Key Exchange"+ * LaMacchia, Lauter, Mityagin, 2007+ * Property: eCK security+ *+ * Status: working+ */++/* Protocol rules */++/* In the description in the paper, we omitted the sorts. + * In this description they are made explicit.+ * '$A' is equivalent to 'A:pub'+ * '~x' is equivalent to 'x:fresh'+ */++/* Generate long-term keypair */+rule generate_ltk:+ [ Fr(~lkA) ] -->+ [ !Ltk( $A, ~lkA ), !Pk( $A, 'g'^~lkA ), Out( 'g'^~lkA ) ]++/* Initiator */+/* To formulate the responder property, we also define a SidI action for+ * the first rule. For brevity, we omitted this from the description in+ * the paper because there the responder property is not specified. */++rule Init_1:+ [ Fr( ~ekI ), !Ltk( $I, ~lkI ) ]+ --[ SidI_1(~ekI,$I,$R, 'g'^h(< '1', ~ekI, ~lkI >)) ]->+ [ Init_1( ~ekI, $I, $R, ~lkI, 'g'^h(< '1', ~ekI, ~lkI >) ),+ !Ephk(~ekI),+ Out( 'g'^h(< '1', ~ekI, ~lkI >) ) ]++rule Init_2:+ [ Init_1( ~ekI, $I, $R, ~lkI , hkI), In( Y ), !Pk( $R,'g'^~lkR ) ]+ --[SidI_2( ~ekI, $I, $R, hkI, Y,+ h( < '2', Y^~lkI, ('g'^~lkR)^h(< '1', ~ekI, ~lkI>), Y^h(< '1', ~ekI, ~lkI>), $I, $R> ) ) ]->+ [ !Sessk( ~ekI, + h(< '2', Y^~lkI, ('g'^~lkR)^h(< '1', ~ekI, ~lkI> ), Y^h(< '1', ~ekI, ~lkI >), $I, $R>) ) ]++/* Responder */+rule Resp_1:+ [ In( X ), Fr( ~ekR ), !Ltk($R, ~lkR), !Pk($I, 'g'^~lkI) ]+ --[ SidR_1( ~ekR, $I, $R, X, 'g'^h( < '1', ~ekR, ~lkR > ),+ h(< '2', ('g'^~lkI)^h(< '1', ~ekR, ~lkR >) ,X^~lkR, X^h(< '1', ~ekR, ~lkR >), $I, $R >) ) ]->+ [ Out( 'g'^h(<'1', ~ekR, ~lkR >) ),+ !Ephk(~ekR),+ !Sessk( ~ekR, + h(< '2', ('g'^~lkI)^h(<'1', ~ekR, ~lkR >) ,X^~lkR, X^h(<'1', ~ekR, ~lkR >), $I, $R >) ) ]++/* Key Reveals for the eCK model */+rule Sessk_reveal: + [ !Sessk(~tid, k) ]+ --[ SesskRev(~tid) ]->+ [ Out(k) ]++rule Ltk_reveal:+ [ !Ltk($A, lkA) ]+ --[ LtkRev($A) ]->+ [ Out(lkA) ]++rule Ephk_reveal:+ [ !Ephk(~ekA) ]+ --[ EphkRev(~ekA) ]->+ [ Out(~ekA) ]+++/* Security properties */++/*+lemma key_agreement_reachable:+ "not (Ex #i1 #i2 ekI ekR I R k hkI hkR.+ SidI_2(ekI, I, R, hkI, hkR, k) @ i1 & SidR_1(ekR, I, R, hkI, hkR, k) @ i2)"+*/++/* An attack is valid in eCK if the session key of the test session is deduced and+ the test session is clean.+*/+lemma eCK_initiator_key:+ "not (Ex #i1 #i2 ekI I R k hkI hkR.+ SidI_2(ekI, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* Not both longterm-key-reveal _and_ ephemeral-key-reveal+ * for test thread. */+ & not(Ex #i3 #i4. LtkRev( I ) @ i3 & EphkRev( ekI ) @ i4)++ /* No session-key-reveal of test thread. */+ & not(Ex #i3. SesskRev( ekI ) @ i3 )++ /* No session-key-reveal for matching session. */+ & not(Ex #i3 #i4 ekR kpartner.+ SidR_1( ekR,I,R,hkI,hkR,kpartner ) @i3+ & SesskRev( ekR ) @ i4 )++ /* Not both long-term-key-reveal and ephemeral-key-reveal+ * for matching session */+ & not(Ex #i3 #i4 #i5 ekR kpartner.+ SidR_1( ekR,I,R,hkI,hkR,kpartner ) @i3+ & LtkRev( R ) @ i4+ & EphkRev( ekR ) @ i5 )++ /* Longterm-key-reveal of partner only if there is a+ * matching session. */+ /* (We model eCK-wpfs, for eCK-pfs, add i1 < i3 to conclusion) */+ & (All #i3. LtkRev( R ) @ i3 ==>+ (* (i1 < i3) | *)+ (Ex #i4 ekR kpartner.+ SidR_1( ekR,I,R,hkI,hkR,kpartner ) @i4)))"+++/* An attack is valid in eCK if the session key of the test session is deduced and+ the test session is clean.+*/+lemma eCK_responder_key:+ "not (Ex #i1 #i2 ekR I R k hkI hkR.+ SidR_1(ekR, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* Not longterm-key-reveal _and_ ephemeral-key-reveal of actor . */+ & not(Ex #i3 #i4. LtkRev( R ) @ i3 & EphkRev( ekR ) @ i4)++ /* Not session-key-reveal of test thread. */+ & not(Ex #i3. SesskRev( ekR ) @ i3 )++ /* Not session-key-reveal of partner thread. Note that we use SidI_2 here.+ A session key reveal can only happen after SidI_2 is logged anyways.+ */+ & not(Ex #i3 #i4 ekI kpartner.+ SidI_2( ekI,I,R,hkI,hkR,kpartner ) @i3+ & SesskRev( ekI ) @ i4 )++ /* If there is a partner thread, then not long-term-key-reveal and ephemeral-key-reveal. */+ & not(Ex #i3 #i4 #i5 ekI.+ SidI_1( ekI,I,R,hkI ) @i3+ & LtkRev( I ) @ i4+ & EphkRev( ekI ) @ i5 )++ /* If there is no partner thread, then there is no longterm-key-reveal for+ the intended partner.+ (We model eCK-wpfs, for eCK-pfs, add i1 < i3 to conclusion)+ */+ & (All #i3. LtkRev( I ) @ i3 ==>+ (* (i1 < i3) | *)+ (Ex #i4 ekI.+ SidI_1( ekI,I,R,hkI ) @i4)))"++end
@@ -0,0 +1,153 @@+theory NAXOS_eCK_PFS+begin++builtin: diffie-hellman, hashing++section{* NAXOS *}++/*+ * Protocol: NAXOS+ * Modeler: Cas Cremers, Benedikt Schmidt+ * Date: January 2012+ * Source: "Stronger Security of Authenticated Key Exchange"+ * LaMacchia, Lauter, Mityagin, 2007+ *+ * Status: working+ */++/* Protocol rules */++/* In the description in the paper, we omitted the sorts. + * In this description they are made explicit.+ * '$A' is equivalent to 'A:pub'+ * '~x' is equivalent to 'x:fresh'+ */++/* Generate long-term keypair */+rule generate_ltk:+ [ Fr(~lkA) ] -->+ [ !Ltk( $A, ~lkA ), !Pk( $A, 'g'^~lkA ), Out( 'g'^~lkA ) ]++/* Initiator */+/* To formulate the responder property, we also define a SidI action for+ * the first rule. For brevity, we omitted this from the description in+ * the paper because there the responder property is not specified. */++rule Init_1:+ [ Fr( ~ekI ), !Ltk( $I, ~lkI ) ]+ --[ SidI_1(~ekI,$I,$R, 'g'^h(< '1', ~ekI, ~lkI >)) ]->+ [ Init_1( ~ekI, $I, $R, ~lkI, 'g'^h(< '1', ~ekI, ~lkI >) ),+ !Ephk(~ekI),+ Out( 'g'^h(< '1', ~ekI, ~lkI >) ) ]++rule Init_2:+ [ Init_1( ~ekI, $I, $R, ~lkI , hkI), In( Y ), !Pk( $R,'g'^~lkR ) ]+ --[SidI_2( ~ekI, $I, $R, hkI, Y,+ h( < '2', Y^~lkI, ('g'^~lkR)^h(< '1', ~ekI, ~lkI>), Y^h(< '1', ~ekI, ~lkI>), $I, $R> ) ) ]->+ [ !Sessk( ~ekI, + h(< '2', Y^~lkI, ('g'^~lkR)^h(< '1', ~ekI, ~lkI> ), Y^h(< '1', ~ekI, ~lkI >), $I, $R>) ) ]++/* Responder */+rule Resp_1:+ [ In( X ), Fr( ~ekR ), !Ltk($R, ~lkR), !Pk($I, 'g'^~lkI) ]+ --[ SidR_1( ~ekR, $I, $R, X, 'g'^h( < '1', ~ekR, ~lkR > ),+ h(< '2', ('g'^~lkI)^h(< '1', ~ekR, ~lkR >) ,X^~lkR, X^h(< '1', ~ekR, ~lkR >), $I, $R >) ) ]->+ [ Out( 'g'^h(<'1', ~ekR, ~lkR >) ),+ !Ephk(~ekR),+ !Sessk( ~ekR, + h(< '2', ('g'^~lkI)^h(<'1', ~ekR, ~lkR >) ,X^~lkR, X^h(<'1', ~ekR, ~lkR >), $I, $R >) ) ]++/* Key Reveals for the eCK model */+rule Sessk_reveal: + [ !Sessk(~tid, k) ]+ --[ SesskRev(~tid) ]->+ [ Out(k) ]++rule Ltk_reveal:+ [ !Ltk($A, lkA) ]+ --[ LtkRev($A) ]->+ [ Out(lkA) ]++rule Ephk_reveal:+ [ !Ephk(~ekA) ]+ --[ EphkRev(~ekA) ]->+ [ Out(~ekA) ]+++/* Security properties */++/*+lemma key_agreement_reachable:+ "not (Ex #i1 #i2 ekI ekR I R k hkI hkR.+ SidI_2(ekI, I, R, hkI, hkR, k) @ i1 & SidR_1(ekR, I, R, hkI, hkR, k) @ i2)"+*/++/* An attack is valid in eCK if the session key of the test session is deduced and+ the test session is clean.+*/+lemma eCK_initiator_key:+ "not (Ex #i1 #i2 ekI I R k hkI hkR.+ SidI_2(ekI, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* Not both longterm-key-reveal _and_ ephemeral-key-reveal+ * for test thread. */+ & not(Ex #i3 #i4. LtkRev( I ) @ i3 & EphkRev( ekI ) @ i4)++ /* No session-key-reveal of test thread. */+ & not(Ex #i3. SesskRev( ekI ) @ i3 )++ /* No session-key-reveal for matching session. */+ & not(Ex #i3 #i4 ekR kpartner.+ SidR_1( ekR,I,R,hkI,hkR,kpartner ) @i3+ & SesskRev( ekR ) @ i4 )++ /* Not both long-term-key-reveal and ephemeral-key-reveal+ * for matching session */+ & not(Ex #i3 #i4 #i5 ekR kpartner.+ SidR_1( ekR,I,R,hkI,hkR,kpartner ) @i3+ & LtkRev( R ) @ i4+ & EphkRev( ekR ) @ i5 )++ /* If there is a longterm key reveal, then it must occur after the initiator is finished+ or there must be a matching session+ */+ & (All #i3. LtkRev( R ) @ i3 ==> + (i1 < i3)+ | (Ex #i4 ekR kpartner.+ SidR_1( ekR,I,R,hkI,hkR,kpartner ) @i4)))"++/* An attack is valid in eCK if the session key of the test session is deduced and+ the test session is clean.+*/+lemma eCK_responder_key:+ "not (Ex #i1 #i2 ekR I R k hkI hkR.+ SidR_1(ekR, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* Not longterm-key-reveal _and_ ephemeral-key-reveal of actor . */+ & not(Ex #i3 #i4. LtkRev( R ) @ i3 & EphkRev( ekR ) @ i4)++ /* Not session-key-reveal of test thread. */+ & not(Ex #i3. SesskRev( ekR ) @ i3 )++ /* Not session-key-reveal of partner thread. Note that we use SidI_2 here.+ A session key reveal can only happen after SidI_2 is logged anyways.+ */+ & not(Ex #i3 #i4 ekI kpartner.+ SidI_2( ekI,I,R,hkI,hkR,kpartner ) @i3+ & SesskRev( ekI ) @ i4 )++ /* If there is a partner thread, then not long-term-key-reveal and ephemeral-key-reveal. */+ & not(Ex #i3 #i4 #i5 ekI.+ SidI_1( ekI,I,R,hkI ) @i3+ & LtkRev( I ) @ i4+ & EphkRev( ekI ) @ i5 )++ /* If there is a longterm key reveal, then it must occur after the responder is finished+ or there must be a matching session.+ */+ & (All #i3. LtkRev( I ) @ i3 ==>+ (i1 < i3)+ | (Ex #i4 ekI.+ SidI_1( ekI,I,R,hkI ) @i4)))"++end
@@ -0,0 +1,123 @@+theory STS_MAC_FIX1+begin++builtin: diffie-hellman, hashing, signing++functions: mac/2++section{* The Station-To-Station Protocol (MAC version, fix UKS attack with proof-of-possession of exponent) *}++/*+ * Protocol: Station-To-Station, MAC variant: fix with CA Proof-of-Possession check+ * Modeler: Cas Cremers+ * Date: January 2012+ * Source: "Unknown Key-Share Attacks on the Station-to-Station (STS) Protocol"+ * Blake-Wilson, Simon and Menezes, Alfred+ * PKC '99, Springer, 1999+ *+ * Status: working+ */++// Public key infrastructure+/**+ * The !Pk facts can be regarded as certificates+ */+rule Register_pk_normal:+ [ Fr(~ltk) ] + --> + [ !Ltk($A, ~ltk), !Pk($A, pk(~ltk)), Out(pk(~ltk)) ]++// Can register a key, but only if we know the exponent+// Models proof-of-possession check.+rule Register_pk_evil:+ [ In(ltk) ] + --[ Corrupt($E) ]-> + [ !Ltk($E, ltk), !Pk($E, pk(ltk)), Out(pk(ltk)) ]++// Protocol+rule Init_1:+ [ Fr(~ekI), !Ltk($I, ~ltkI) ]+ -->+ [ Init_1( $I, $R, ~ltkI, ~ekI )+ , Out( <$I, $R, 'g' ^ ~ekI> ) ]++rule Init_2:+ [ Init_1( $I, $R, ~ltkI, ~ekI )+ , !Pk($R, pk(~ltkR))+ , In( <$R, $I, Y, + sign{ Y, 'g'^~ekI }~ltkR,+ mac(Y^~ekI,+ sign{ Y, 'g'^~ekI }~ltkR+ )+ > ) ]+ --[ AcceptedI(~ekI,$I,$R,'g'^~ekI,Y, h(Y ^ ~ekI)) ]->+ [ Out( <$I, $R, + sign{ 'g' ^ ~ekI, Y }~ltkI,+ mac( Y^~ekI,+ sign{ 'g' ^ ~ekI, Y }~ltkI+ )+ > ),+ !SessionKey(~ekI,$I,$R, h(Y ^ ~ekI))+ ]++rule Resp_1:+ [ !Ltk($R, ~ltkR)+ , Fr(~ekR)+ , In( <$I, $R, X > ) ]+ -->+ [ Resp_1( $I, $R, ~ltkR, ~ekR, X )+ , Out( <$R, $I, 'g' ^ ~ekR,+ sign{ 'g' ^ ~ekR, X }~ltkR,+ mac( X^~ekR,+ sign{ 'g' ^ ~ekR, X }~ltkR+ )+ > ) ]++rule Resp_2:+ [ !Pk($I, pk(~ltkI))+ , Resp_1( $I, $R, ~ltkR, ~ekR, X )+ , In( <$I, $R, + sign{ X, 'g'^~ekR }~ltkI,+ mac(X^~ekR,+ sign{ X, 'g'^~ekR }~ltkI+ )+ > ) ]+ --[ AcceptedR(~ekR,$I,$R,X,'g'^~ekR, h(X ^ ~ekR)) ]->+ [ !SessionKey(~ekR,$I,$R, h(X ^ ~ekR) ) ]++rule Sessionkey_Reveal:+ [ !SessionKey(~tid, $I,$R,k) ]+ --[ SesskRev(~tid) ]->+ [ Out(k) ]++lemma KI_Perfect_Forward_Secrecy_I:+ "not (Ex ttest I R sessKey #i1 #k hki hkr.+ AcceptedI(ttest,I,R,hki,hkr,sessKey) @ i1 &+ not (Ex #r. Corrupt(I) @ r) &+ not (Ex #r. Corrupt(R) @ r) &+ K(sessKey) @ k &+ // No session key reveal of test+ not (Ex #i3. SesskRev(ttest) @ i3) &+ // No session key reveal of partner+ not (Ex #i3 #i4 tpartner kpartner. SesskRev(tpartner) @ i3+ & AcceptedR(tpartner,I,R,hki,hkr,kpartner) @ i4+ ) + )+ "++lemma KI_Perfect_Forward_Secrecy_R:+ "not (Ex ttest I R sessKey #i1 #k hki hkr.+ AcceptedR(ttest,I,R,hki,hkr,sessKey) @ i1 &+ not (Ex #r. Corrupt(I) @ r) &+ not (Ex #r. Corrupt(R) @ r) &+ K(sessKey) @ k &+ // No session key reveal of test+ not (Ex #i2. SesskRev(ttest) @ i2) &+ // No session key reveal of partner+ not (Ex #i2 #i3 tpartner kpartner. SesskRev(tpartner) @ i2+ & AcceptedI(tpartner,I,R,hki,hkr,kpartner) @ i3+ ) + )+ "++end
@@ -0,0 +1,122 @@+theory STS_MAC_FIX2+begin++builtin: diffie-hellman, hashing, signing++functions: mac/2++section{* The Station-To-Station Protocol (MAC version, fixed with names and tags) *}++/*+ * Protocol: Station-To-Station, MAC variant: fix with names and tags inside signatures+ * Modeler: Cas Cremers+ * Date: January 2012+ * Source: "Unknown Key-Share Attacks on the Station-to-Station (STS) Protocol"+ * Blake-Wilson, Simon and Menezes, Alfred+ * PKC '99, Springer, 1999+ *+ * Status: working+ */++// Public key infrastructure+/**+ * The !Pk facts can be regarded as certificates+ *+ * Here we model that the adversary might (and in fact always does)+ * re-registers the public keys as his own, i.e., he claims a copy of+ * the public key for the corrupt name E.+ */+rule Register_pk_clone:+ [ Fr(~ltk) ] + --[ LtkSet($A, ~ltk), Corrupt($E) ]-> + [ !Ltk($A, ~ltk), !Pk($A, pk(~ltk)), !Pk($E, pk(~ltk)), Out(pk(~ltk)) ]++// Protocol+rule Init_1:+ [ Fr(~ekI), !Ltk($I, ~ltkI) ]+ -->+ [ Init_1( $I, $R, ~ltkI, ~ekI )+ , Out( <$I, $R, 'g' ^ ~ekI> ) ]++rule Init_2:+ [ Init_1( $I, $R, ~ltkI, ~ekI )+ , !Pk($R, pk(~ltkR))+ , In( <$R, $I, Y, + sign{ '1', $I, $R, Y, 'g'^~ekI }~ltkR,+ mac(Y^~ekI,+ sign{ '1', $I, $R, Y, 'g'^~ekI }~ltkR+ )+ > ) ]+ --[ AcceptedI(~ekI,$I,$R,'g'^~ekI,Y, h(Y ^ ~ekI) ) ]->+ [ Out( <$I, $R, + sign{ '2', $I, $R, 'g' ^ ~ekI, Y }~ltkI,+ mac( Y^~ekI,+ sign{ '2', $I, $R, 'g' ^ ~ekI, Y }~ltkI+ )+ > ),+ !SessionKey(~ekI,$I,$R, h(Y ^ ~ekI))+ ]++rule Resp_1:+ [ !Ltk($R, ~ltkR)+ , Fr(~ekR)+ , In( <$I, $R, X > ) ]+ -->+ [ Resp_1( $I, $R, ~ltkR, ~ekR, X )+ , Out( <$R, $I, 'g' ^ ~ekR,+ sign{ '1', $I, $R, 'g' ^ ~ekR, X }~ltkR,+ mac( X^~ekR,+ sign{ '1', $I, $R, 'g' ^ ~ekR, X }~ltkR+ )+ > ) ]++rule Resp_2:+ [ !Pk($I, pk(~ltkI))+ , Resp_1( $I, $R, ~ltkR, ~ekR, X )+ , In( <$I, $R, + sign{ '2', $I, $R, X, 'g'^~ekR }~ltkI,+ mac(X^~ekR,+ sign{ '2', $I, $R, X, 'g'^~ekR }~ltkI+ )+ > ) ]+ --[ AcceptedR(~ekR,$I,$R,X,'g'^~ekR, h(X ^ ~ekR) ) ]->+ [ !SessionKey(~ekR,$I,$R, h(X ^ ~ekR) ) ]++rule Sessionkey_Reveal:+ [ !SessionKey(~tid, $I,$R,k) ]+ --[ SesskRev(~tid) ]->+ [ Out(k) ]++lemma KI_Perfect_Forward_Secrecy_I:+ "not (Ex ttest I R sessKey #i1 #k hki hkr.+ AcceptedI(ttest,I,R,hki,hkr,sessKey) @ i1 &+ not (Ex #r. Corrupt(I) @ r) &+ not (Ex #r. Corrupt(R) @ r) &+ K(sessKey) @ k &+ // No session key reveal of test+ not (Ex #i3. SesskRev(ttest) @ i3) &+ // No session key reveal of partner+ not (Ex #i3 #i4 tpartner kpartner. SesskRev(tpartner) @ i3+ & AcceptedR(tpartner,I,R,hki,hkr,kpartner) @ i4+ )+ )+ "++lemma KI_Perfect_Forward_Secrecy_R:+ "not (Ex ttest I R sessKey #i1 #k hki hkr.+ AcceptedR(ttest,I,R,hki,hkr,sessKey) @ i1 &+ not (Ex #r. Corrupt(I) @ r) &+ not (Ex #r. Corrupt(R) @ r) &+ K(sessKey) @ k &+ // No session key reveal of test+ not (Ex #i3. SesskRev(ttest) @ i3) &+ // No session key reveal of partner+ not (Ex #i3 #i4 tpartner kpartner. SesskRev(tpartner) @ i3+ & AcceptedI(tpartner,I,R,hki,hkr,kpartner) @ i4+ ) + )+ "++++end
@@ -0,0 +1,122 @@+theory STS_MAC+begin++builtin: diffie-hellman, hashing, signing++functions: mac/2++section{* The Station-To-Station Protocol (MAC version) *}++/*+ * Protocol: Station-To-Station, MAC variant+ * Modeler: Cas Cremers+ * Date: January 2012+ * Source: "Unknown Key-Share Attacks on the Station-to-Station (STS) Protocol"+ * Blake-Wilson, Simon and Menezes, Alfred+ * PKC '99, Springer, 1999+ *+ * Status: working+ */++// Public key infrastructure+/**+ * The !Pk facts can be regarded as certificates+ *+ * Here we model that the adversary might (and in fact always does)+ * re-registers the public keys as his own, i.e., he claims a copy of+ * the public key for the corrupt name E.+ */+rule Register_pk_clone:+ [ Fr(~ltk) ] + --[ LtkSet($A, ~ltk), Corrupt($E) ]-> + [ !Ltk($A, ~ltk), !Pk($A, pk(~ltk)), !Pk($E, pk(~ltk)), Out(pk(~ltk)) ]++// Protocol+rule Init_1:+ [ Fr(~ekI), !Ltk($I, ~ltkI) ]+ -->+ [ Init_1( $I, $R, ~ltkI, ~ekI )+ , Out( <$I, $R, 'g' ^ ~ekI> ) ]++rule Init_2:+ [ Init_1( $I, $R, ~ltkI, ~ekI )+ , !Pk($R, pk(~ltkR))+ , In( <$R, $I, Y, + sign{ Y, 'g'^~ekI }~ltkR,+ mac(Y^~ekI,+ sign{ Y, 'g'^~ekI }~ltkR+ )+ > ) ]+ --[ AcceptedI(~ekI,$I,$R,'g'^~ekI,Y, h(Y ^ ~ekI) ) ]->+ [ Out( <$I, $R, + sign{ 'g' ^ ~ekI, Y }~ltkI,+ mac( Y^~ekI,+ sign{ 'g' ^ ~ekI, Y }~ltkI+ )+ > ),+ !SessionKey(~ekI,$I,$R, h(Y ^ ~ekI))+ ]++rule Resp_1:+ [ !Ltk($R, ~ltkR)+ , Fr(~ekR)+ , In( <$I, $R, X > ) ]+ -->+ [ Resp_1( $I, $R, ~ltkR, ~ekR, X )+ , Out( <$R, $I, 'g' ^ ~ekR,+ sign{ 'g' ^ ~ekR, X }~ltkR,+ mac( X^~ekR,+ sign{ 'g' ^ ~ekR, X }~ltkR+ )+ > ) ]++rule Resp_2:+ [ !Pk($I, pk(~ltkI))+ , Resp_1( $I, $R, ~ltkR, ~ekR, X )+ , In( <$I, $R, + sign{ X, 'g'^~ekR }~ltkI,+ mac(X^~ekR,+ sign{ X, 'g'^~ekR }~ltkI+ )+ > ) ]+ --[ AcceptedR(~ekR,$I,$R,X,'g'^~ekR, h(X ^ ~ekR) ) ]->+ [ !SessionKey(~ekR,$I,$R, h(X ^ ~ekR) ) ]++rule Sessionkey_Reveal:+ [ !SessionKey(~tid, $I,$R,k) ]+ --[ SesskRev(~tid) ]->+ [ Out(k) ]++lemma KI_Perfect_Forward_Secrecy_I:+ "not (Ex ttest I R sessKey #i1 #k hki hkr.+ AcceptedI(ttest,I,R,hki,hkr,sessKey) @ i1 &+ not (Ex #r. Corrupt(I) @ r) &+ not (Ex #r. Corrupt(R) @ r) &+ K(sessKey) @ k &+ // No session key reveal of test+ not (Ex #i3. SesskRev(ttest) @ i3) &+ // No session key reveal of partner+ not (Ex #i3 #i4 tpartner kpartner. SesskRev(tpartner) @ i3+ & AcceptedR(tpartner,I,R,hki,hkr,kpartner) @ i4+ ) + )+ "++lemma KI_Perfect_Forward_Secrecy_R:+ "not (Ex ttest I R sessKey #i1 #k hki hkr.+ AcceptedR(ttest,I,R,hki,hkr,sessKey) @ i1 &+ not (Ex #r. Corrupt(I) @ r) &+ not (Ex #r. Corrupt(R) @ r) &+ K(sessKey) @ k &+ // No session key reveal of test+ not (Ex #i3. SesskRev(ttest) @ i3) &+ // No session key reveal of partner+ not (Ex #i3 #i4 tpartner kpartner. SesskRev(tpartner) @ i3+ & AcceptedI(tpartner,I,R,hki,hkr,kpartner) @ i4+ ) + )+ "++++end
@@ -0,0 +1,69 @@+theory SignedDH+begin++section{* The Signed Diffie-Hellman Protocol *}++/*+ * Protocol: Signed Diffie-Hellman+ * Modeler: Simon Meier, Benedikt Schmidt+ * Date: January 2012+ *+ * Status: working+ */++builtin: diffie-hellman, signing++// Public key infrastructure+rule Register_pk:+ [ Fr(~ltk) ] + --> + [ !Ltk($A, ~ltk), !Pk($A, pk(~ltk)) ]++rule Get_pk:+ [ !Pk(A, pk) ] + --> + [ Out(pk) ]++rule Reveal_ltk:+ [ !Ltk(A, ltk) ]+ --[ LtkReveal(A) ]->+ [ Out(ltk) ]++// Protocol+rule Init_1:+ [ Fr(~ekI), !Ltk($I, ltkI) ]+ -->+ [ Init_1( $I, $R, ~ekI )+ , Out( <$I, $R, 'g' ^ ~ekI, sign{'1', $I, $R,'g' ^ ~ekI }ltkI> ) ]++rule Init_2:+ [ Init_1( $I, $R, ~ekI )+ , !Pk($R, pk(ltkR))+ , In( <$R, $I, Y, sign{'2', $R, $I, Y }ltkR> ) + ]+ --[ SessionKey($I,$R, Y ^ ~ekI) ]->+ []++rule Resp:+ [ !Pk($I, pk(ltkI))+ , !Ltk($R, ltkR)+ , Fr(~ekR)+ , In( <$I, $R, X, sign{'1', $I, $R, X }ltkI> ) + ]+ --[ SessionKey($I,$R, X ^ ~ekR) ]->+ [+ Out( <$R, $I, 'g' ^ ~ekR, sign{'2', $R, $I, 'g' ^ ~ekR }ltkR> ) + ]++lemma Perfect_Forward_Secrecy:+ "All I R sessKey #i #k. + SessionKey(I,R,sessKey) @ i &+ K(sessKey) @ k+ ==>+ ( (Ex #r. LtkReveal(I) @ r & r < i)+ | (Ex #r. LtkReveal(R) @ r & r < i)+ )+ "+++end
@@ -0,0 +1,140 @@+theory SignedDH_eCK+begin++builtin: diffie-hellman, signing++section{* The Signed Diffie-Hellman Protocol in the eCK model *}++/*+ * Protocol: Signed Diffie-Hellman+ * Modeler: Simon Meier, Benedikt Schmidt+ * Date: January 2012+ * Property: eCK model+ * "Stronger Security of Authenticated Key Exchange"+ * LaMacchia, Lauter, Mityagin, 2007+ *+ * Status: working+ */++// Public key infrastructure+rule Register_pk:+ [ Fr(~ltk) ] + --> + [ !Ltk($A, ~ltk), !Pk($A, pk(~ltk)), Out(pk(~ltk)) ]++// Protocol+/* Initiator */+rule Init_1:+ [ Fr(~ekI), !Ltk($I, ltkI) ]+ --[ SidI_1(~ekI, $I, $R, 'g'^~ekI) ]->+ [ Init_1( ~ekI, $I, $R, ~ekI, 'g' ^ ~ekI )+ , !Ephk(~ekI)+ , Out( <$I, $R, 'g' ^ ~ekI, sign{'1', $I, $R,'g' ^ ~ekI }ltkI> ) ]++rule Init_2:+ [ Init_1( ~ekI, $I, $R, ~ekI, hkI )+ , !Pk($R, pk(ltkR))+ , In( <$R, $I, Y, sign{'2', $R, $I, Y }ltkR> ) + ]+ --[ SidI_2(~ekI, $I, $R, hkI, Y, Y ^ ~ekI ) ]->+ [ !Sessk(~ekI, Y ^ ~ekI) ]++/* Responder */+rule Resp:+ [ !Pk($I, pk(ltkI))+ , !Ltk($R, ltkR)+ , Fr(~ekR)+ , In( <$I, $R, X, sign{'1', $I, $R, X }ltkI> ) + ]+ --[ SidR_1(~ekR, $I, $R, X, 'g' ^ ~ekR, X ^ ~ekR) ]->+ [ !Ephk(~ekR)+ , !Sessk(~ekR, X ^ ~ekR)+ , Out( <$R, $I, 'g' ^ ~ekR, sign{'2', $R, $I, 'g' ^ ~ekR }ltkR> ) + ]++/* Key Reveals for the eCK model */+rule Sessk_reveal: + [ !Sessk(~tid, k) ]+ --[ SesskRev(~tid) ]->+ [ Out(k) ]++rule Ltk_reveal:+ [ !Ltk($A, lkA) ]+ --[ LtkRev($A) ]->+ [ Out(lkA) ]++rule Ephk_reveal:+ [ !Ephk(~ekA) ]+ --[ EphkRev(~ekA) ]->+ [ Out(~ekA) ]++/* An attack is valid in eCK if the session key of the test session is deduced and+ the test session is clean.+*/+lemma eCK_initiator_key:+ "not (Ex #i1 #i2 ttest I R k hkI hkR.+ SidI_2(ttest, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* Not both longterm-key-reveal _and_ ephemeral-key-reveal+ * for test thread. */+ & not(Ex #i3 #i4. LtkRev( I ) @ i3 & EphkRev( ttest ) @ i4)++ /* No session-key-reveal of test thread. */+ & not(Ex #i3. SesskRev( ttest ) @ i3 )++ /* No session-key-reveal for matching session. */+ & not(Ex #i3 #i4 tpartner kpartner.+ SidR_1( tpartner,I,R,hkI,hkR,kpartner ) @i3+ & SesskRev( tpartner ) @ i4 )++ /* Not both long-term-key-reveal and ephemeral-key-reveal+ * for matching session */+ & not(Ex #i3 #i4 #i5 tpartner kpartner.+ SidR_1( tpartner,I,R,hkI,hkR,kpartner ) @i3+ & LtkRev( R ) @ i4+ & EphkRev( tpartner ) @ i5 )++ /* Longterm-key-reveal of partner only if there is a+ * matching session. */+ /* (We model eCK-wpfs, for eCK-pfs, add i1 < i3 to conclusion) */+ & (All #i3. LtkRev( R ) @ i3 ==>+ (Ex #i4 tpartner kpartner.+ (* (i1 < i3) | *)+ SidR_1( tpartner,I,R,hkI,hkR,kpartner ) @i4)))"++/* An attack is valid in eCK if the session key of the test session is deduced and+ the test session is clean.+*/+lemma eCK_responder_key:+ "not (Ex #i1 #i2 ttest I R k hkI hkR.+ SidR_1(ttest, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* Not longterm-key-reveal _and_ ephemeral-key-reveal of actor . */+ & not(Ex #i3 #i4. LtkRev( R ) @ i3 & EphkRev( ttest ) @ i4)++ /* Not session-key-reveal of test thread. */+ & not(Ex #i3. SesskRev( ttest ) @ i3 )++ /* Not session-key-reveal of partner thread. Note that we use SidI_2 here.+ A session key reveal can only happen after SidI_2 is logged anyways.+ */+ & not(Ex #i3 #i4 tpartner kpartner.+ SidI_2( tpartner,I,R,hkI,hkR,kpartner ) @i3+ & SesskRev( tpartner ) @ i4 )++ /* If there is a partner thread, then not long-term-key-reveal and ephemeral-key-reveal. */+ & not(Ex #i3 #i4 #i5 tpartner.+ SidI_1( tpartner,I,R,hkI ) @i3+ & LtkRev( I ) @ i4+ & EphkRev( tpartner ) @ i5 )++ /* If there is no partner thread, then there is no longterm-key-reveal for+ the intended partner.+ (We model eCK-wpfs, for eCK-pfs, add i1 < i3 to conclusion)+ */+ & (All #i3. LtkRev( I ) @ i3 ==>+ (Ex #i4 tpartner.+ (* (i1 < i3) | *)+ SidI_1( tpartner,I,R,hkI ) @i4)))"++end
@@ -0,0 +1,112 @@+theory UM_PFS+begin++builtin: hashing, diffie-hellman++section{* The Unified Model (UM) Key-Exchange Protocol *}++/*+ * Protocol: Unified Model (UM)+ * Modeler: Cas Cremers+ * Date: January 2012+ * Source: "Authenticated Diffie-Hellman Key Agreement Protocols"+ * Simon Blake-Wilson and Alfred Menezes+ * LNCS 1556, 1999+ * Property: Perfect Forward Secrecy (PFS)+ *+ * Status: working+ */++/* Protocol rules */++rule generate_ltk:+ [ Fr(~lk) ] -->+ [ !Ltk( $A, ~lk ), !Pk( $A, 'g'^~lk ), Out( 'g'^~lk ) ]++rule Init_1:+ [ Fr( ~ekI ), !Ltk( $I, ~lkI ) ]+ --[ SidI_1(~ekI,$I,$R, 'g'^~ekI ) ]->+ [ Init_1( ~ekI, $I, $R, ~lkI, 'g'^~ekI ),+ !Ephk(~ekI),+ Out( 'g'^~ekI ) ]++rule Init_2:+ [ Init_1( ~ekI, $I, $R, ~lkI , hkI), In( Y ), !Pk( $R,'g'^~lkR ) ]+ --[SidI_2( ~ekI, $I, $R, hkI, Y,+ h( <Y^~ekI, ('g'^~lkR)^~lkI > ) ) ]->+ [ !Sessk( ~ekI, + h( <Y^~ekI, ('g'^~lkR)^~lkI > ) ) ]+++rule Resp_1:+ [ In( X ), Fr( ~ekR ), !Ltk($R, ~lkR), !Pk($I, 'g'^~lkI) ]+ --[ SidR_1( ~ekR, $I, $R, X, 'g'^~ekR ,+ h( <X^~ekR, ('g'^~lkI)^~lkR > ) ) ]->+ [ Out( 'g'^~ekR ),+ !Ephk(~ekR),+ !Sessk( ~ekR, + h( <X^~ekR, ('g'^~lkI)^~lkR > ) ) ]++rule Sessk_reveal: + [ !Sessk(~tid, k) ]+ --[ SesskRev(~tid) ]->+ [ Out(k) ]++rule Ephk_reveal:+ [ !Ephk(~ekI) ]+ --[ EphkRev(~ekI) ]->+ [ Out(~ekI) ]++rule Ltk_reveal:+ [ !Ltk($A, k) ]+ --[ LtkRev($A) ]->+ [ Out(k) ]+++/* Security properties */++/*+lemma key_agreement_reachable:+ "not (Ex #i1 #i2 ekI ekR I R k hkI hkR.+ SidI_2(ekI, I, R, hkI, hkR, k) @ i1 & SidR_1(ekR, I, R, hkI, hkR, k) @ i2)"+*/++/* An attack is valid in the security model if the session key of the test session is deduced and+ the test session is clean.+*/+lemma wPFS_initiator_key:+ "not (Ex #i1 #i2 ttest I R k hkI hkR.+ SidI_2(ttest, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* No ephemeral-key-reveal */+ & (All #i3 t. EphkRev( t ) @ i3 ==> F)++ /* No session-key-reveal */+ & (All #i3 t. SesskRev( t ) @ i3 ==> F)++ /* Long-term key reveals are after the end of the test+ * thread. */+ & (All #i3. (LtkRev( I )@ i3 ) ==> (i1 < i3))+ & (All #i3. (LtkRev( R )@ i3 ) ==> (i1 < i3))+ )"++/* An attack is valid in the security model if the session key of the test session is deduced and+ the test session is clean.+*/+lemma wPFS_responder_key:+ "not (Ex #i1 #i2 ttest I R k hkI hkR.+ SidR_1(ttest, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* No ephemeral-key-reveal */+ & (All #i3 t. EphkRev( t ) @ i3 ==> F)++ /* No session-key-reveal */+ & (All #i3 t. SesskRev( t ) @ i3 ==> F)++ /* Long-term key reveals are after the end of the test+ * thread. */+ & (All #i3. (LtkRev( I )@ i3 ) ==> (i1 < i3))+ & (All #i3. (LtkRev( R )@ i3 ) ==> (i1 < i3))+ )"++end
@@ -0,0 +1,140 @@+theory UM_eCK+begin++builtin: hashing, diffie-hellman++section{* The Unified Model (UM) Key-Exchange Protocol *}++/*+ * Protocol: Unified Model (UM)+ * Modeler: Cas Cremers+ * Date: January 2012+ * Source: "Authenticated Diffie-Hellman Key Agreement Protocols"+ * Simon Blake-Wilson and Alfred Menezes+ * LNCS 1556, 1999+ *+ * Status: working+ */++/* Protocol rules */++rule generate_ltk:+ [ Fr(~lk) ] -->+ [ !Ltk( $A, ~lk ), !Pk( $A, 'g'^~lk ), Out( 'g'^~lk ) ]++rule Init_1:+ [ Fr( ~ekI ), !Ltk( $I, ~lkI ) ]+ --[ SidI_1(~ekI,$I,$R, 'g'^~ekI ) ]->+ [ Init_1( ~ekI, $I, $R, ~lkI, 'g'^~ekI ),+ !Ephk(~ekI),+ Out( 'g'^~ekI ) ]++rule Init_2:+ [ Init_1( ~ekI, $I, $R, ~lkI , hkI), In( Y ), !Pk( $R,'g'^~lkR ) ]+ --[SidI_2( ~ekI, $I, $R, hkI, Y,+ h( <Y^~ekI, ('g'^~lkR)^~lkI > ) ) ]->+ [ !Sessk( ~ekI, + h( <Y^~ekI, ('g'^~lkR)^~lkI > ) ) ]+++rule Resp_1:+ [ In( X ), Fr( ~ekR ), !Ltk($R, ~lkR), !Pk($I, 'g'^~lkI) ]+ --[ SidR_1( ~ekR, $I, $R, X, 'g'^~ekR ,+ h( <X^~ekR, ('g'^~lkI)^~lkR > ) ) ]->+ [ Out( 'g'^~ekR ),+ !Ephk(~ekR),+ !Sessk( ~ekR, + h( <X^~ekR, ('g'^~lkI)^~lkR > ) ) ]++rule Sessk_reveal: + [ !Sessk(~tid, k) ]+ --[ SesskRev(~tid) ]->+ [ Out(k) ]++rule Ephk_reveal:+ [ !Ephk(~ekI) ]+ --[ EphkRev(~ekI) ]->+ [ Out(~ekI) ]++rule Ltk_reveal:+ [ !Ltk($A, k) ]+ --[ LtkRev($A) ]->+ [ Out(k) ]+++/* Security properties */++/*+lemma key_agreement_reachable:+ "not (Ex #i1 #i2 ekI ekR I R k hkI hkR.+ SidI_2(ekI, I, R, hkI, hkR, k) @ i1 & SidR_1(ekR, I, R, hkI, hkR, k) @ i2)"+*/++/* An attack is valid in eCK if the session key of the test session is deduced and+ the test session is clean.+*/+lemma eCK_initiator_key:+ "not (Ex #i1 #i2 ttest I R k hkI hkR.+ SidI_2(ttest, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* Not longterm-key-reveal _and_ ephemeral-key-reveal of actor . */+ & (All #i3 #i4. LtkRev( I ) @ i3 & EphkRev( ttest ) @ i4 ==> F)++ /* Not session-key-reveal of test thread. */+ & (All #i3. SesskRev( ttest ) @ i3 ==> F)++ /* Not session-key-reveal of partner thread. */+ & (All #i3 #i4 tpartner kpartner.+ SidR_1( tpartner,I,R,hkI,hkR,kpartner ) @i3+ & SesskRev( tpartner ) @ i4 ==> F)++ /* If there is a partner thread, then not long-term-key-reveal and ephemeral-key-reveal */+ & (All #i4 #i5 #i6 tpartner kpartner.+ SidR_1( tpartner,I,R,hkI,hkR,kpartner ) @i4+ & LtkRev( R ) @ i5+ & EphkRev( tpartner ) @ i6 ==> F)++ /* If there is no partner thread, then there is no longterm-key-reveal for+ the intended partner.+ (We model eCK-wpfs, for eCK-pfs, add i1 < i3 to conclusion) */+ & (All #i3. LtkRev( R ) @ i3 ==>+ (Ex #i4 tpartner kpartner.+ (* (i1 < i3) | *)+ SidR_1( tpartner,I,R,hkI,hkR,kpartner ) @i4)))"++/* An attack is valid in eCK if the session key of the test session is deduced and+ the test session is clean.+*/+lemma eCK_responder_key:+ "not (Ex #i1 #i2 ttest I R k hkI hkR.+ SidR_1(ttest, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* Not longterm-key-reveal _and_ ephemeral-key-reveal of actor . */+ & (All #i3 #i4. LtkRev( R ) @ i3 & EphkRev( ttest ) @ i4 ==> F)++ /* Not session-key-reveal of test thread. */+ & (All #i3. SesskRev( ttest ) @ i3 ==> F)++ /* Not session-key-reveal of partner thread. Note that we use SidI_2 here.+ A session key reveal can only happen after SidI_2 is logged anyways.+ */+ & (All #i3 #i4 tpartner kpartner.+ SidI_2( tpartner,I,R,hkI,hkR,kpartner ) @i3+ & SesskRev( tpartner ) @ i4 ==> F)++ /* If there is a partner thread, then not long-term-key-reveal and ephemeral-key-reveal. */+ & (All #i4 #i5 #i6 tpartner.+ SidI_1( tpartner,I,R,hkI ) @i4+ & LtkRev( I ) @ i5+ & EphkRev( tpartner ) @ i6 ==> F)++ /* If there is no partner thread, then there is no longterm-key-reveal for+ the intended partner.+ (We model eCK-wpfs, for eCK-pfs, add i1 < i3 to conclusion)+ */+ & (All #i3. LtkRev( I ) @ i3 ==>+ (Ex #i4 tpartner.+ (* (i1 < i3) | *)+ SidI_1( tpartner,I,R,hkI ) @i4)))"++end
@@ -0,0 +1,140 @@+theory UM_eCK_noKCI+begin++builtin: hashing, diffie-hellman++section{* The Unified Model (UM) Key-Exchange Protocol *}++/*+ * Protocol: Unified Model (UM)+ * Modeler: Cas Cremers+ * Date: January 2012+ * Source: "Authenticated Diffie-Hellman Key Agreement Protocols"+ * Simon Blake-Wilson and Alfred Menezes+ * LNCS 1556, 1999+ *+ * Status: working+ */++/* Protocol rules */++rule generate_ltk:+ [ Fr(~lk) ] -->+ [ !Ltk( $A, ~lk ), !Pk( $A, 'g'^~lk ), Out( 'g'^~lk ) ]++rule Init_1:+ [ Fr( ~ekI ), !Ltk( $I, ~lkI ) ]+ --[ SidI_1(~ekI,$I,$R, 'g'^~ekI ) ]->+ [ Init_1( ~ekI, $I, $R, ~lkI, 'g'^~ekI ),+ !Ephk(~ekI),+ Out( 'g'^~ekI ) ]++rule Init_2:+ [ Init_1( ~ekI, $I, $R, ~lkI , hkI), In( Y ), !Pk( $R,'g'^~lkR ) ]+ --[SidI_2( ~ekI, $I, $R, hkI, Y,+ h( <Y^~ekI, ('g'^~lkR)^~lkI > ) ) ]->+ [ !Sessk( ~ekI, + h( <Y^~ekI, ('g'^~lkR)^~lkI > ) ) ]+++rule Resp_1:+ [ In( X ), Fr( ~ekR ), !Ltk($R, ~lkR), !Pk($I, 'g'^~lkI) ]+ --[ SidR_1( ~ekR, $I, $R, X, 'g'^~ekR ,+ h( <X^~ekR, ('g'^~lkI)^~lkR > ) ) ]->+ [ Out( 'g'^~ekR ),+ !Ephk(~ekR),+ !Sessk( ~ekR, + h( <X^~ekR, ('g'^~lkI)^~lkR > ) ) ]++rule Sessk_reveal: + [ !Sessk(~tid, k) ]+ --[ SesskRev(~tid) ]->+ [ Out(k) ]++rule Ephk_reveal:+ [ !Ephk(~ekI) ]+ --[ EphkRev(~ekI) ]->+ [ Out(~ekI) ]++rule Ltk_reveal:+ [ !Ltk($A, k) ]+ --[ LtkRev($A) ]->+ [ Out(k) ]+++/* Security properties */++/*+lemma key_agreement_reachable:+ "not (Ex #i1 #i2 ekI ekR I R k hkI hkR.+ SidI_2(ekI, I, R, hkI, hkR, k) @ i1 & SidR_1(ekR, I, R, hkI, hkR, k) @ i2)"+*/++/* An attack is valid in eCK if the session key of the test session is deduced and+ the test session is clean.+*/+lemma eCK_initiator_key:+ "not (Ex #i1 #i2 ttest I R k hkI hkR.+ SidI_2(ttest, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* Not longterm-key-reveal of actor . */+ & (All #i3. LtkRev( I ) @ i3 ==> F)++ /* Not session-key-reveal of test thread. */+ & (All #i3. SesskRev( ttest ) @ i3 ==> F)++ /* Not session-key-reveal of partner thread. */+ & (All #i3 #i4 tpartner kpartner.+ SidR_1( tpartner,I,R,hkI,hkR,kpartner ) @i3+ & SesskRev( tpartner ) @ i4 ==> F)++ /* If there is a partner thread, then not long-term-key-reveal and ephemeral-key-reveal */+ & (All #i4 #i5 #i6 tpartner kpartner.+ SidR_1( tpartner,I,R,hkI,hkR,kpartner ) @i4+ & LtkRev( R ) @ i5+ & EphkRev( tpartner ) @ i6 ==> F)++ /* If there is no partner thread, then there is no longterm-key-reveal for+ the intended partner.+ (We model eCK-wpfs, for eCK-pfs, add i1 < i3 to conclusion) */+ & (All #i3. LtkRev( R ) @ i3 ==>+ (Ex #i4 tpartner kpartner.+ (* (i1 < i3) | *)+ SidR_1( tpartner,I,R,hkI,hkR,kpartner ) @i4)))"++/* An attack is valid in eCK if the session key of the test session is deduced and+ the test session is clean.+*/+lemma eCK_responder_key:+ "not (Ex #i1 #i2 ttest I R k hkI hkR.+ SidR_1(ttest, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* Not longterm-key-reveal of actor . */+ & (All #i3. LtkRev( R ) @ i3 ==> F)++ /* Not session-key-reveal of test thread. */+ & (All #i3. SesskRev( ttest ) @ i3 ==> F)++ /* Not session-key-reveal of partner thread. Note that we use SidI_2 here.+ A session key reveal can only happen after SidI_2 is logged anyways.+ */+ & (All #i3 #i4 tpartner kpartner.+ SidI_2( tpartner,I,R,hkI,hkR,kpartner ) @i3+ & SesskRev( tpartner ) @ i4 ==> F)++ /* If there is a partner thread, then not long-term-key-reveal and ephemeral-key-reveal. */+ & (All #i4 #i5 #i6 tpartner.+ SidI_1( tpartner,I,R,hkI ) @i4+ & LtkRev( I ) @ i5+ & EphkRev( tpartner ) @ i6 ==> F)++ /* If there is no partner thread, then there is no longterm-key-reveal for+ the intended partner.+ (We model eCK-wpfs, for eCK-pfs, add i1 < i3 to conclusion)+ */+ & (All #i3. LtkRev( I ) @ i3 ==>+ (Ex #i4 tpartner.+ (* (i1 < i3) | *)+ SidI_1( tpartner,I,R,hkI ) @i4)))"++end
@@ -0,0 +1,131 @@+theory UM_wPFS+begin++builtin: hashing, diffie-hellman++section{* The Unified Model (UM) Key-Exchange Protocol *}++/*+ * Protocol: Unified Model (UM)+ * Modeler: Cas Cremers+ * Date: January 2012+ * Source: "Authenticated Diffie-Hellman Key Agreement Protocols"+ * Simon Blake-Wilson and Alfred Menezes+ * LNCS 1556, 1999+ * Property: weak Perfect Forward Secrecy (wPFS), from+ * "HMQV: A High-Performance Secure Diffie-Hellman Protocol"+ * H. Krawczyk+ * CRYPTO 2005, LNCS 3621, 2005+ *+ * Status: working+ */++/* Protocol rules */++rule generate_ltk:+ [ Fr(~lk) ] -->+ [ !Ltk( $A, ~lk ), !Pk( $A, 'g'^~lk ), Out( 'g'^~lk ) ]++rule Init_1:+ [ Fr( ~ekI ), !Ltk( $I, ~lkI ) ]+ --[ SidI_1(~ekI,$I,$R, 'g'^~ekI ) ]->+ [ Init_1( ~ekI, $I, $R, ~lkI, 'g'^~ekI ),+ !Ephk(~ekI),+ Out( 'g'^~ekI ) ]++rule Init_2:+ [ Init_1( ~ekI, $I, $R, ~lkI , hkI), In( Y ), !Pk( $R,'g'^~lkR ) ]+ --[SidI_2( ~ekI, $I, $R, hkI, Y,+ h( <Y^~ekI, ('g'^~lkR)^~lkI > ) ) ]->+ [ !Sessk( ~ekI, + h( <Y^~ekI, ('g'^~lkR)^~lkI > ) ) ]+++rule Resp_1:+ [ In( X ), Fr( ~ekR ), !Ltk($R, ~lkR), !Pk($I, 'g'^~lkI) ]+ --[ SidR_1( ~ekR, $I, $R, X, 'g'^~ekR ,+ h( <X^~ekR, ('g'^~lkI)^~lkR > ) ) ]->+ [ Out( 'g'^~ekR ),+ !Ephk(~ekR),+ !Sessk( ~ekR, + h( <X^~ekR, ('g'^~lkI)^~lkR > ) ) ]++rule Sessk_reveal: + [ !Sessk(~tid, k) ]+ --[ SesskRev(~tid) ]->+ [ Out(k) ]++rule Ephk_reveal:+ [ !Ephk(~ekI) ]+ --[ EphkRev(~ekI) ]->+ [ Out(~ekI) ]++rule Ltk_reveal:+ [ !Ltk($A, k) ]+ --[ LtkRev($A) ]->+ [ Out(k) ]+++/* Security properties */++/*+lemma key_agreement_reachable:+ "not (Ex #i1 #i2 ekI ekR I R k hkI hkR.+ SidI_2(ekI, I, R, hkI, hkR, k) @ i1 & SidR_1(ekR, I, R, hkI, hkR, k) @ i2)"+*/++/* An attack is valid in the security model if the session key of the test session is deduced and+ the test session is clean.+*/+lemma wPFS_initiator_key:+ "not (Ex #i1 #i2 ttest I R k hkI hkR.+ SidI_2(ttest, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* No ephemeral-key-reveal */+ & (All #i3 t. EphkRev( t ) @ i3 ==> F)++ /* No session-key-reveal */+ & (All #i3 t. SesskRev( t ) @ i3 ==> F)++ /* Long-term key reveals are after the end of the test+ * thread. Furthermore, if there is no partner thread, then there is no longterm-key-reveal for+ the actor or the intended peer.+ */+ & (All #i3. (LtkRev( I )@ i3 ) ==>+ ( (i1 < i3) &+ (Ex #i4 tpartner kpartner.+ SidR_1( tpartner,I,R,hkI,hkR,kpartner ) @i4)))+ & (All #i3. (LtkRev( R )@ i3 ) ==>+ ( (i1 < i3) &+ (Ex #i4 tpartner kpartner.+ SidR_1( tpartner,I,R,hkI,hkR,kpartner ) @i4)))+ )"++/* An attack is valid in the security model if the session key of the test session is deduced and+ the test session is clean.+*/+lemma wPFS_responder_key:+ "not (Ex #i1 #i2 ttest I R k hkI hkR.+ SidR_1(ttest, I, R, hkI, hkR, k) @ i1 & K( k ) @ i2++ /* No ephemeral-key-reveal */+ & (All #i3 t. EphkRev( t ) @ i3 ==> F)++ /* No session-key-reveal */+ & (All #i3 t. SesskRev( t ) @ i3 ==> F)++ /* Long-term key reveals are after the end of the test+ * thread. Furthermore, if there is no partner thread, then there is no longterm-key-reveal for+ the actor or the intended peer.+ */+ & (All #i3. (LtkRev( I )@ i3 ) ==>+ ( (i1 < i3) &+ (Ex #i4 tpartner.+ SidI_1( tpartner,I,R,hkI ) @i4)))+ & (All #i3. (LtkRev( R )@ i3 ) ==>+ ( (i1 < i3) &+ (Ex #i4 tpartner.+ SidI_1( tpartner,I,R,hkI ) @i4)))+ )"++end
binary file changed (absent → 847 bytes)
binary file changed (absent → 676 bytes)
binary file changed (absent → 820 bytes)
binary file changed (absent → 464 bytes)
binary file changed (absent → 1342 bytes)
binary file changed (absent → 653 bytes)
binary file changed (absent → 695 bytes)
@@ -0,0 +1,272 @@+theory intruder_variants begin++ builtin: diffie-hellman++section{* Finite Variants of the Intruder Rules *}++ rule (modulo AC) exp:+ [ !KU( 'noexp', x ), !KU( f_.2, x.1 ) ] --> [ !KU( 'exp', x^x.1 ) ]+ + rule (modulo AC) inv:+ [ !KU( f_.1, x ) ] --> [ !KU( 'noexp', inv(x) ) ]+ + rule (modulo AC) exp:+ [ !KD( 'noexp', x.3^x.4 ), !KU( f_.2, x.1 ) ]+ -->+ [ !KD( 'exp', x.3^(x.1*x.4) ) ]+ + rule (modulo AC) exp:+ [ !KD( 'noexp', x.4^x.3 ), !KU( f_.2, inv(x.3) ) ]+ -->+ [ !KD( 'exp', x.4 ) ]+ + rule (modulo AC) exp:+ [ !KD( 'noexp', x.4^inv(x.3) ), !KU( f_.2, x.3 ) ]+ -->+ [ !KD( 'exp', x.4 ) ]+ + rule (modulo AC) exp:+ [ !KD( 'noexp', x.4^inv(x.5) ), !KU( f_.2, inv(x.3) ) ]+ -->+ [ !KD( 'exp', x.4^inv((x.3*x.5)) ) ]+ + rule (modulo AC) exp:+ [ !KD( 'noexp', x.4^inv((x.3*x.5)) ), !KU( f_.2, x.3 ) ]+ -->+ [ !KD( 'exp', x.4^inv(x.5) ) ]+ + rule (modulo AC) exp:+ [ !KD( 'noexp', x.4^(x.3*x.5) ), !KU( f_.2, inv(x.3) ) ]+ -->+ [ !KD( 'exp', x.4^x.5 ) ]+ + rule (modulo AC) exp:+ [ !KD( 'noexp', x.4^(x.5*inv(x.3)) ), !KU( f_.2, x.3 ) ]+ -->+ [ !KD( 'exp', x.4^x.5 ) ]+ + rule (modulo AC) exp:+ [ !KD( 'noexp', x.3^x.4 ), !KU( f_.2, inv((x.4*x.5)) ) ]+ -->+ [ !KD( 'exp', x.3^inv(x.5) ) ]+ + rule (modulo AC) exp:+ [ !KD( 'noexp', x.3^x.4 ), !KU( f_.2, (x.5*inv(x.4)) ) ]+ -->+ [ !KD( 'exp', x.3^x.5 ) ]+ + rule (modulo AC) exp:+ [ !KD( 'noexp', x.5^inv(x.4) ), !KU( f_.2, (x.3*x.4) ) ]+ -->+ [ !KD( 'exp', x.5^x.3 ) ]+ + rule (modulo AC) exp:+ [ !KD( 'noexp', x.4^(x.5*inv(x.6)) ), !KU( f_.2, inv(x.3) ) ]+ -->+ [ !KD( 'exp', x.4^(x.5*inv((x.3*x.6))) ) ]+ + rule (modulo AC) exp:+ [ !KD( 'noexp', x.3^inv(x.4) ), !KU( f_.2, (x.5*inv(x.6)) ) ]+ -->+ [ !KD( 'exp', x.3^(x.5*inv((x.4*x.6))) ) ]+ + rule (modulo AC) exp:+ [ !KD( 'noexp', x.4^(x.5*inv((x.3*x.6))) ), !KU( f_.2, x.3 ) ]+ -->+ [ !KD( 'exp', x.4^(x.5*inv(x.6)) ) ]+ + rule (modulo AC) exp:+ [ !KD( 'noexp', x.5^inv((x.4*x.6)) ), !KU( f_.2, (x.3*x.4) ) ]+ -->+ [ !KD( 'exp', x.5^(x.3*inv(x.6)) ) ]+ + rule (modulo AC) exp:+ [ !KD( 'noexp', x.5^(x.4*x.6) ), !KU( f_.2, inv((x.3*x.4)) ) ]+ -->+ [ !KD( 'exp', x.5^(x.6*inv(x.3)) ) ]+ + rule (modulo AC) exp:+ [ !KD( 'noexp', x.5^(x.4*x.6) ), !KU( f_.2, (x.3*inv(x.4)) ) ]+ -->+ [ !KD( 'exp', x.5^(x.3*x.6) ) ]+ + rule (modulo AC) exp:+ [ !KD( 'noexp', x.5^(x.6*inv(x.4)) ), !KU( f_.2, (x.3*x.4) ) ]+ -->+ [ !KD( 'exp', x.5^(x.3*x.6) ) ]+ + rule (modulo AC) exp:+ [ !KD( 'noexp', x.3^x.4 ), !KU( f_.2, (x.5*inv((x.4*x.6))) ) ]+ -->+ [ !KD( 'exp', x.3^(x.5*inv(x.6)) ) ]+ + rule (modulo AC) exp:+ [ !KD( 'noexp', x.5^(x.6*inv(x.7)) ), !KU( f_.2, (x.3*inv(x.4)) ) ]+ -->+ [ !KD( 'exp', x.5^(x.3*x.6*inv((x.4*x.7))) ) ]+ + rule (modulo AC) exp:+ [ !KD( 'noexp', x.5^(x.4*inv(x.3)) ), !KU( f_.2, (x.3*inv(x.4)) ) ]+ -->+ [ !KD( 'exp', x.5 ) ]+ + rule (modulo AC) exp:+ [ !KD( 'noexp', x.5^(x.4*inv(x.6)) ), !KU( f_.2, inv((x.3*x.4)) ) ]+ -->+ [ !KD( 'exp', x.5^inv((x.3*x.6)) ) ]+ + rule (modulo AC) exp:+ [ !KD( 'noexp', x.5^inv((x.3*x.6)) ), !KU( f_.2, (x.3*inv(x.4)) ) ]+ -->+ [ !KD( 'exp', x.5^inv((x.4*x.6)) ) ]+ + rule (modulo AC) exp:+ [ !KD( 'noexp', x.5^(x.6*inv((x.4*x.7))) ), !KU( f_.2, (x.3*x.4) ) ]+ -->+ [ !KD( 'exp', x.5^(x.3*x.6*inv(x.7)) ) ]+ + rule (modulo AC) exp:+ [ !KD( 'noexp', x.3^(x.4*x.5) ), !KU( f_.2, (x.6*inv((x.5*x.7))) ) ]+ -->+ [ !KD( 'exp', x.3^(x.4*x.6*inv(x.7)) ) ]+ + rule (modulo AC) exp:+ [ !KD( 'noexp', x.5^(x.4*x.6*inv(x.3)) ), !KU( f_.2, (x.3*inv(x.4)) ) ]+ -->+ [ !KD( 'exp', x.5^x.6 ) ]+ + rule (modulo AC) exp:+ [ !KD( 'noexp', x.6^(x.5*inv(x.4)) ), !KU( f_.2, (x.3*x.4*inv(x.5)) ) ]+ -->+ [ !KD( 'exp', x.6^x.3 ) ]+ + rule (modulo AC) exp:+ [ !KD( 'noexp', x.5^(x.4*x.6*inv(x.7)) ), !KU( f_.2, inv((x.3*x.4)) ) ]+ -->+ [ !KD( 'exp', x.5^(x.6*inv((x.3*x.7))) ) ]+ + rule (modulo AC) exp:+ [ !KD( 'noexp', x.6^inv((x.4*x.7)) ), !KU( f_.2, (x.3*x.4*inv(x.5)) ) ]+ -->+ [ !KD( 'exp', x.6^(x.3*inv((x.5*x.7))) ) ]+ + rule (modulo AC) exp:+ [ !KD( 'noexp', x.5^(x.4*inv((x.3*x.6))) ), !KU( f_.2, (x.3*inv(x.4)) ) ]+ -->+ [ !KD( 'exp', x.5^inv(x.6) ) ]+ + rule (modulo AC) exp:+ [ !KD( 'noexp', x.3^(x.4*inv(x.5)) ), !KU( f_.2, (x.5*inv((x.4*x.6))) ) ]+ -->+ [ !KD( 'exp', x.3^inv(x.6) ) ]+ + rule (modulo AC) exp:+ [ !KD( 'noexp', x.3^(x.4*inv(x.5)) ), !KU( f_.2, (x.6*inv((x.4*x.7))) ) ]+ -->+ [ !KD( 'exp', x.3^(x.6*inv((x.5*x.7))) ) ]+ + rule (modulo AC) exp:+ [ !KD( 'noexp', x.6^(x.5*x.7*inv(x.4)) ), !KU( f_.2, (x.3*x.4*inv(x.5)) )+ ]+ -->+ [ !KD( 'exp', x.6^(x.3*x.7) ) ]+ + rule (modulo AC) exp:+ [ !KD( 'noexp', x.5^(x.6*inv((x.3*x.7))) ), !KU( f_.2, (x.3*inv(x.4)) ) ]+ -->+ [ !KD( 'exp', x.5^(x.6*inv((x.4*x.7))) ) ]+ + rule (modulo AC) exp:+ [+ !KD( 'noexp', x.3^(x.4*inv(x.5)) ), !KU( f_.2, (x.5*x.6*inv((x.4*x.7))) )+ ]+ -->+ [ !KD( 'exp', x.3^(x.6*inv(x.7)) ) ]+ + rule (modulo AC) exp:+ [+ !KD( 'noexp', x.5^(x.4*x.6*inv((x.3*x.7))) ), !KU( f_.2, (x.3*inv(x.4)) )+ ]+ -->+ [ !KD( 'exp', x.5^(x.6*inv(x.7)) ) ]+ + rule (modulo AC) exp:+ [+ !KD( 'noexp', x.6^(x.5*inv((x.4*x.7))) ), !KU( f_.2, (x.3*x.4*inv(x.5)) )+ ]+ -->+ [ !KD( 'exp', x.6^(x.3*inv(x.7)) ) ]+ + rule (modulo AC) exp:+ [+ !KD( 'noexp', x.6^(x.5*x.7*inv(x.3)) ), !KU( f_.2, (x.3*inv((x.4*x.5))) )+ ]+ -->+ [ !KD( 'exp', x.6^(x.7*inv(x.4)) ) ]+ + rule (modulo AC) exp:+ [+ !KD( 'noexp', x.6^(x.5*x.7*inv(x.8)) ), !KU( f_.2, (x.3*inv((x.4*x.5))) )+ ]+ -->+ [ !KD( 'exp', x.6^(x.3*x.7*inv((x.4*x.8))) ) ]+ + rule (modulo AC) exp:+ [+ !KD( 'noexp', x.6^(x.7*inv((x.4*x.8))) ), !KU( f_.2, (x.3*x.4*inv(x.5)) )+ ]+ -->+ [ !KD( 'exp', x.6^(x.3*x.7*inv((x.5*x.8))) ) ]+ + rule (modulo AC) exp:+ [+ !KD( 'noexp', x.6^(x.5*inv((x.3*x.7))) ),+ !KU( f_.2, (x.3*inv((x.4*x.5))) )+ ]+ -->+ [ !KD( 'exp', x.6^inv((x.4*x.7)) ) ]+ + rule (modulo AC) exp:+ [+ !KD( 'noexp', x.3^(x.4*x.5*inv(x.6)) ),+ !KU( f_.2, (x.6*x.7*inv((x.5*x.8))) )+ ]+ -->+ [ !KD( 'exp', x.3^(x.4*x.7*inv(x.8)) ) ]+ + rule (modulo AC) exp:+ [+ !KD( 'noexp', x.6^(x.5*x.7*inv((x.4*x.8))) ),+ !KU( f_.2, (x.3*x.4*inv(x.5)) )+ ]+ -->+ [ !KD( 'exp', x.6^(x.3*x.7*inv(x.8)) ) ]+ + rule (modulo AC) exp:+ [+ !KD( 'noexp', x.7^(x.6*inv((x.4*x.8))) ),+ !KU( f_.2, (x.3*x.4*inv((x.5*x.6))) )+ ]+ -->+ [ !KD( 'exp', x.7^(x.3*inv((x.5*x.8))) ) ]+ + rule (modulo AC) exp:+ [+ !KD( 'noexp', x.6^(x.5*x.7*inv((x.3*x.8))) ),+ !KU( f_.2, (x.3*inv((x.4*x.5))) )+ ]+ -->+ [ !KD( 'exp', x.6^(x.7*inv((x.4*x.8))) ) ]+ + rule (modulo AC) exp:+ [+ !KD( 'noexp', x.7^(x.6*x.8*inv((x.4*x.9))) ),+ !KU( f_.2, (x.3*x.4*inv((x.5*x.6))) )+ ]+ -->+ [ !KD( 'exp', x.7^(x.3*x.8*inv((x.5*x.9))) ) ]+ + rule (modulo AC) inv:+ [ !KD( f_.1, inv(x.2) ) ] --> [ !KD( 'noexp', x.2 ) ]++end
@@ -0,0 +1,211 @@+// jQuery Context Menu Plugin +// +// Version 1.01 +// +// Cory S.N. LaViska +// A Beautiful Site (http://abeautifulsite.net/) +// +// More info: http://abeautifulsite.net/2008/09/jquery-context-menu-plugin/ +// +// Terms of Use +// +// This plugin is dual-licensed under the GNU General Public License +// and the MIT License and is copyright A Beautiful Site, LLC. +// +if(jQuery)( function() { + $.extend($.fn, { + + contextMenu: function(o, callback) { + // Defaults + if( o.menu == undefined ) return false; + if( o.inSpeed == undefined ) o.inSpeed = 150; + if( o.outSpeed == undefined ) o.outSpeed = 75; + // 0 needs to be -1 for expected results (no fade) + if( o.inSpeed == 0 ) o.inSpeed = -1; + if( o.outSpeed == 0 ) o.outSpeed = -1; + // Loop each context menu + $(this).each( function() { + var el = $(this); + var offset = $(el).offset(); + // Add contextMenu class + $('#' + o.menu).addClass('contextMenu'); + // Simulate a true right click + $(this).mousedown( function(e) { + var evt = e; + evt.stopPropagation(); + $(this).mouseup( function(e) { + e.stopPropagation(); + var srcElement = $(this); + $(this).unbind('mouseup'); + if( evt.button == 2 ) { + // Hide context menus that may be showing + $(".contextMenu").hide(); + // Get this context menu + var menu = $('#' + o.menu); + + if( $(el).hasClass('disabled') ) return false; + + // Detect mouse position + var d = {}, x, y; + if( self.innerHeight ) { + d.pageYOffset = self.pageYOffset; + d.pageXOffset = self.pageXOffset; + d.innerHeight = self.innerHeight; + d.innerWidth = self.innerWidth; + } else if( document.documentElement && + document.documentElement.clientHeight ) { + d.pageYOffset = document.documentElement.scrollTop; + d.pageXOffset = document.documentElement.scrollLeft; + d.innerHeight = document.documentElement.clientHeight; + d.innerWidth = document.documentElement.clientWidth; + } else if( document.body ) { + d.pageYOffset = document.body.scrollTop; + d.pageXOffset = document.body.scrollLeft; + d.innerHeight = document.body.clientHeight; + d.innerWidth = document.body.clientWidth; + } + (e.pageX) ? x = e.pageX : x = e.clientX + d.scrollLeft; + (e.pageY) ? y = e.pageY : y = e.clientY + d.scrollTop; + + // Show the menu + $(document).unbind('click'); + $(menu).css({ top: y, left: x }).fadeIn(o.inSpeed); + // Hover events + $(menu).find('A').mouseover( function() { + $(menu).find('LI.hover').removeClass('hover'); + $(this).parent().addClass('hover'); + }).mouseout( function() { + $(menu).find('LI.hover').removeClass('hover'); + }); + + // Keyboard + $(document).keypress( function(e) { + switch( e.keyCode ) { + case 38: // up + if( $(menu).find('LI.hover').size() == 0 ) { + $(menu).find('LI:last').addClass('hover'); + } else { + $(menu).find('LI.hover').removeClass('hover').prevAll('LI:not(.disabled)').eq(0).addClass('hover'); + if( $(menu).find('LI.hover').size() == 0 ) $(menu).find('LI:last').addClass('hover'); + } + break; + case 40: // down + if( $(menu).find('LI.hover').size() == 0 ) { + $(menu).find('LI:first').addClass('hover'); + } else { + $(menu).find('LI.hover').removeClass('hover').nextAll('LI:not(.disabled)').eq(0).addClass('hover'); + if( $(menu).find('LI.hover').size() == 0 ) $(menu).find('LI:first').addClass('hover'); + } + break; + case 13: // enter + $(menu).find('LI.hover A').trigger('click'); + break; + case 27: // esc + $(document).trigger('click'); + break + } + }); + + // When items are selected + $('#' + o.menu).find('A').unbind('click'); + $('#' + o.menu).find('LI:not(.disabled) A').click( function() { + $(document).unbind('click').unbind('keypress'); + $(".contextMenu").hide(); + // Callback + if( callback ) callback( $(this).attr('href').substr(1), $(srcElement), {x: x - offset.left, y: y - offset.top, docX: x, docY: y} ); + return false; + }); + + // Hide bindings + setTimeout( function() { // Delay for Mozilla + $(document).click( function() { + $(document).unbind('click').unbind('keypress'); + $(menu).fadeOut(o.outSpeed); + return false; + }); + }, 0); + } + }); + }); + + // Disable text selection + if( $.browser.mozilla ) { + $('#' + o.menu).each( function() { $(this).css({ 'MozUserSelect' : 'none' }); }); + } else if( $.browser.msie ) { + $('#' + o.menu).each( function() { $(this).bind('selectstart.disableTextSelect', function() { return false; }); }); + } else { + $('#' + o.menu).each(function() { $(this).bind('mousedown.disableTextSelect', function() { return false; }); }); + } + // Disable browser context menu (requires both selectors to work in IE/Safari + FF/Chrome) + $(el).add($('UL.contextMenu')).bind('contextmenu', function() { return false; }); + + }); + return $(this); + }, + + // Disable context menu items on the fly + disableContextMenuItems: function(o) { + if( o == undefined ) { + // Disable all + $(this).find('LI').addClass('disabled'); + return( $(this) ); + } + $(this).each( function() { + if( o != undefined ) { + var d = o.split(','); + for( var i = 0; i < d.length; i++ ) { + $(this).find('A[href="' + d[i] + '"]').parent().addClass('disabled'); + + } + } + }); + return( $(this) ); + }, + + // Enable context menu items on the fly + enableContextMenuItems: function(o) { + if( o == undefined ) { + // Enable all + $(this).find('LI.disabled').removeClass('disabled'); + return( $(this) ); + } + $(this).each( function() { + if( o != undefined ) { + var d = o.split(','); + for( var i = 0; i < d.length; i++ ) { + $(this).find('A[href="' + d[i] + '"]').parent().removeClass('disabled'); + + } + } + }); + return( $(this) ); + }, + + // Disable context menu(s) + disableContextMenu: function() { + $(this).each( function() { + $(this).addClass('disabled'); + }); + return( $(this) ); + }, + + // Enable context menu(s) + enableContextMenu: function() { + $(this).each( function() { + $(this).removeClass('disabled'); + }); + return( $(this) ); + }, + + // Destroy context menu(s) + destroyContextMenu: function() { + // Destroy specified context menus + $(this).each( function() { + // Disable action + $(this).unbind('mousedown').unbind('mouseup'); + }); + return( $(this) ); + } + + }); +})(jQuery);
@@ -0,0 +1,91 @@+/*jslint browser: true */ /*global jQuery: true */++/**+ * jQuery Cookie plugin+ *+ * Copyright (c) 2010 Klaus Hartl (stilbuero.de)+ * Dual licensed under the MIT and GPL licenses:+ * http://www.opensource.org/licenses/mit-license.php+ * http://www.gnu.org/licenses/gpl.html+ *+ */++// TODO JsDoc++/**+ * Create a cookie with the given key and value and other optional parameters.+ *+ * @example $.cookie('the_cookie', 'the_value');+ * @desc Set the value of a cookie.+ * @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true });+ * @desc Create a cookie with all available options.+ * @example $.cookie('the_cookie', 'the_value');+ * @desc Create a session cookie.+ * @example $.cookie('the_cookie', null);+ * @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain+ * used when the cookie was set.+ *+ * @param String key The key of the cookie.+ * @param String value The value of the cookie.+ * @param Object options An object literal containing key/value pairs to provide optional cookie attributes.+ * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object.+ * If a negative value is specified (e.g. a date in the past), the cookie will be deleted.+ * If set to null or omitted, the cookie will be a session cookie and will not be retained+ * when the the browser exits.+ * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie).+ * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie).+ * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will+ * require a secure protocol (like HTTPS).+ * @type undefined+ *+ * @name $.cookie+ * @cat Plugins/Cookie+ * @author Klaus Hartl/klaus.hartl@stilbuero.de+ */++/**+ * Get the value of a cookie with the given key.+ *+ * @example $.cookie('the_cookie');+ * @desc Get the value of a cookie.+ *+ * @param String key The key of the cookie.+ * @return The value of the cookie.+ * @type String+ *+ * @name $.cookie+ * @cat Plugins/Cookie+ * @author Klaus Hartl/klaus.hartl@stilbuero.de+ */+jQuery.cookie = function (key, value, options) {+ + // key and at least value given, set cookie...+ if (arguments.length > 1 && String(value) !== "[object Object]") {+ options = jQuery.extend({}, options);++ if (value === null || value === undefined) {+ options.expires = -1;+ }++ if (typeof options.expires === 'number') {+ var days = options.expires, t = options.expires = new Date();+ t.setDate(t.getDate() + days);+ }+ + value = String(value);+ + return (document.cookie = [+ encodeURIComponent(key), '=',+ options.raw ? value : encodeURIComponent(value),+ options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE+ options.path ? '; path=' + options.path : '',+ options.domain ? '; domain=' + options.domain : '',+ options.secure ? '; secure' : ''+ ].join(''));+ }++ // key and possibly options given, get cookie...+ options = value || {};+ var result, decode = options.raw ? function (s) { return s; } : decodeURIComponent;+ return (result = new RegExp('(?:^|; )' + encodeURIComponent(key) + '=([^;]*)').exec(document.cookie)) ? decode(result[1]) : null;+};
@@ -0,0 +1,4332 @@+/** + * @preserve jquery.layout 1.3.0 - Release Candidate 29.14 + * $Date: 2011-02-13 08:00:00 (Sun, 13 Feb 2011) $ + * $Rev: 302914 $ + * + * Copyright (c) 2010 + * Fabrizio Balliano (http://www.fabrizioballiano.net) + * Kevin Dalman (http://allpro.net) + * + * Dual licensed under the GPL (http://www.gnu.org/licenses/gpl.html) + * and MIT (http://www.opensource.org/licenses/mit-license.php) licenses. + * + * Changelog: http://layout.jquery-dev.net/changelog.cfm#1.3.0.rc29.13 + * + * Docs: http://layout.jquery-dev.net/documentation.html + * Tips: http://layout.jquery-dev.net/tips.html + * Help: http://groups.google.com/group/jquery-ui-layout + */ + +// NOTE: For best readability, view with a fixed-width font and tabs equal to 4-chars + +;(function ($) { + +var $b = $.browser; + +/* + * GENERIC $.layout METHODS - used by all layouts + */ +$.layout = { + + // can update code here if $.browser is phased out + browser: { + mozilla: !!$b.mozilla + , webkit: !!$b.webkit || !!$b.safari // webkit = jQ 1.4 + , msie: !!$b.msie + , isIE6: !!$b.msie && $b.version == 6 + , boxModel: false // page must load first, so will be updated set by _create + //, version: $b.version - not used + } + + /* + * USER UTILITIES + */ + + // calculate and return the scrollbar width, as an integer +, scrollbarWidth: function () { return window.scrollbarWidth || $.layout.getScrollbarSize('width'); } +, scrollbarHeight: function () { return window.scrollbarHeight || $.layout.getScrollbarSize('height'); } +, getScrollbarSize: function (dim) { + var $c = $('<div style="position: absolute; top: -10000px; left: -10000px; width: 100px; height: 100px; overflow: scroll;"></div>').appendTo("body"); + var d = { width: $c.width() - $c[0].clientWidth, height: $c.height() - $c[0].clientHeight }; + $c.remove(); + window.scrollbarWidth = d.width; + window.scrollbarHeight = d.height; + return dim.match(/^(width|height)$/i) ? d[dim] : d; + } + + + /** + * Returns hash container 'display' and 'visibility' + * + * @see $.swap() - swaps CSS, runs callback, resets CSS + */ +, showInvisibly: function ($E, force) { + if (!$E) return {}; + if (!$E.jquery) $E = $($E); + var CSS = { + display: $E.css('display') + , visibility: $E.css('visibility') + }; + if (force || CSS.display == "none") { // only if not *already hidden* + $E.css({ display: "block", visibility: "hidden" }); // show element 'invisibly' so can be measured + return CSS; + } + else return {}; + } + + /** + * Returns data for setting size of an element (container or a pane). + * + * @see _create(), onWindowResize() for container, plus others for pane + * @return JSON Returns a hash of all dimensions: top, bottom, left, right, outerWidth, innerHeight, etc + */ +, getElemDims: function ($E) { + var + d = {} // dimensions hash + , x = d.css = {} // CSS hash + , i = {} // TEMP insets + , b, p // TEMP border, padding + , off = $E.offset() + ; + d.offsetLeft = off.left; + d.offsetTop = off.top; + + $.each("Left,Right,Top,Bottom".split(","), function (idx, e) { // e = edge + b = x["border" + e] = $.layout.borderWidth($E, e); + p = x["padding"+ e] = $.layout.cssNum($E, "padding"+e); + i[e] = b + p; // total offset of content from outer side + d["inset"+ e] = p; + /* WRONG ??? + // if BOX MODEL, then 'position' = PADDING (ignore borderWidth) + if ($E == $Container) + d["inset"+ e] = (browser.boxModel ? p : 0); + */ + }); + + d.offsetWidth = $E.innerWidth(); + d.offsetHeight = $E.innerHeight(); + d.outerWidth = $E.outerWidth(); + d.outerHeight = $E.outerHeight(); + d.innerWidth = d.outerWidth - i.Left - i.Right; + d.innerHeight = d.outerHeight - i.Top - i.Bottom; + + // TESTING + x.width = $E.width(); + x.height = $E.height(); + + return d; + } + +, getElemCSS: function ($E, list) { + var + CSS = {} + , style = $E[0].style + , props = list.split(",") + , sides = "Top,Bottom,Left,Right".split(",") + , attrs = "Color,Style,Width".split(",") + , p, s, a, i, j, k + ; + for (i=0; i < props.length; i++) { + p = props[i]; + if (p.match(/(border|padding|margin)$/)) + for (j=0; j < 4; j++) { + s = sides[j]; + if (p == "border") + for (k=0; k < 3; k++) { + a = attrs[k]; + CSS[p+s+a] = style[p+s+a]; + } + else + CSS[p+s] = style[p+s]; + } + else + CSS[p] = style[p]; + }; + return CSS + } + + /** + * Contains logic to check boxModel & browser, and return the correct width/height for the current browser/doctype + * + * @see initPanes(), sizeMidPanes(), initHandles(), sizeHandles() + * @param {Array.<Object>} $E Must pass a jQuery object - first element is processed + * @param {number=} outerWidth/outerHeight (optional) Can pass a width, allowing calculations BEFORE element is resized + * @return {number} Returns the innerWidth/Height of the elem by subtracting padding and borders + */ +, cssWidth: function ($E, outerWidth) { + var + b = $.layout.borderWidth + , n = $.layout.cssNum + ; + // a 'calculated' outerHeight can be passed so borders and/or padding are removed if needed + if (outerWidth <= 0) return 0; + + if (!$.layout.browser.boxModel) return outerWidth; + + // strip border and padding from outerWidth to get CSS Width + var W = outerWidth + - b($E, "Left") + - b($E, "Right") + - n($E, "paddingLeft") + - n($E, "paddingRight") + ; + + return Math.max(0,W); + } + +, cssHeight: function ($E, outerHeight) { + var + b = $.layout.borderWidth + , n = $.layout.cssNum + ; + // a 'calculated' outerHeight can be passed so borders and/or padding are removed if needed + if (outerHeight <= 0) return 0; + + if (!$.layout.browser.boxModel) return outerHeight; + + // strip border and padding from outerHeight to get CSS Height + var H = outerHeight + - b($E, "Top") + - b($E, "Bottom") + - n($E, "paddingTop") + - n($E, "paddingBottom") + ; + + return Math.max(0,H); + } + + /** + * Returns the 'current CSS numeric value' for an element - returns 0 if property does not exist + * + * @see Called by many methods + * @param {Array.<Object>} $E Must pass a jQuery object - first element is processed + * @param {string} prop The name of the CSS property, eg: top, width, etc. + * @return {*} Usually is used to get an integer value for position (top, left) or size (height, width) + */ +, cssNum: function ($E, prop) { + if (!$E.jquery) $E = $($E); + var CSS = $.layout.showInvisibly($E); + var val = parseInt($.curCSS($E[0], prop, true), 10) || 0; + $E.css( CSS ); // RESET + return val; + } + +, borderWidth: function (el, side) { + if (el.jquery) el = el[0]; + var b = "border"+ side.substr(0,1).toUpperCase() + side.substr(1); // left => Left + return $.curCSS(el, b+"Style", true) == "none" ? 0 : (parseInt($.curCSS(el, b+"Width", true), 10) || 0); + } + + /** + * SUBROUTINE for preventPrematureSlideClose option + * + * @param {Object} evt + * @param {Object=} el + */ +, isMouseOverElem: function (evt, el) { + var + $E = $(el || this) + , d = $E.offset() + , T = d.top + , L = d.left + , R = L + $E.outerWidth() + , B = T + $E.outerHeight() + , x = evt.pageX + , y = evt.pageY + ; + // if X & Y are < 0, probably means is over an open SELECT + return ($.layout.browser.msie && x < 0 && y < 0) || ((x >= L && x <= R) && (y >= T && y <= B)); + } + +}; + +$.fn.layout = function (opts) { + +/* + * ########################### + * WIDGET CONFIG & OPTIONS + * ########################### + */ + + // LANGUAGE CUSTOMIZATION - will be *externally customizable* in next version + var lang = { + Pane: "Pane" + , Open: "Open" // eg: "Open Pane" + , Close: "Close" + , Resize: "Resize" + , Slide: "Slide Open" + , Pin: "Pin" + , Unpin: "Un-Pin" + , selector: "selector" + , msgNoRoom: "Not enough room to show this pane." + , errContainerMissing: "UI Layout Initialization Error\n\nThe specified layout-container does not exist." + , errCenterPaneMissing: "UI Layout Initialization Error\n\nThe center-pane element does not exist.\n\nThe center-pane is a required element." + , errContainerHeight: "UI Layout Initialization Warning\n\nThe layout-container \"CONTAINER\" has no height.\n\nTherefore the layout is 0-height and hence 'invisible'!" + , errButton: "Error Adding Button \n\nInvalid " + }; + + // DEFAULT OPTIONS - CHANGE IF DESIRED + var options = { + name: "" // Not required, but useful for buttons and used for the state-cookie + , containerClass: "ui-layout-container" // layout-container element + , scrollToBookmarkOnLoad: true // after creating a layout, scroll to bookmark in URL (.../page.htm#myBookmark) + , resizeWithWindow: true // bind thisLayout.resizeAll() to the window.resize event + , resizeWithWindowDelay: 200 // delay calling resizeAll because makes window resizing very jerky + , resizeWithWindowMaxDelay: 0 // 0 = none - force resize every XX ms while window is being resized + , onresizeall_start: null // CALLBACK when resizeAll() STARTS - NOT pane-specific + , onresizeall_end: null // CALLBACK when resizeAll() ENDS - NOT pane-specific + , onload_start: null // CALLBACK when Layout inits - after options initialized, but before elements + , onload_end: null // CALLBACK when Layout inits - after EVERYTHING has been initialized + , onunload_start: null // CALLBACK when Layout is destroyed OR onWindowUnload + , onunload_end: null // CALLBACK when Layout is destroyed OR onWindowUnload + , autoBindCustomButtons: false // search for buttons with ui-layout-button class and auto-bind them + , zIndex: null // the PANE zIndex - resizers and masks will be +1 + // PANE SETTINGS + , defaults: { // default options for 'all panes' - will be overridden by 'per-pane settings' + applyDemoStyles: false // NOTE: renamed from applyDefaultStyles for clarity + , closable: true // pane can open & close + , resizable: true // when open, pane can be resized + , slidable: true // when closed, pane can 'slide open' over other panes - closes on mouse-out + , initClosed: false // true = init pane as 'closed' + , initHidden: false // true = init pane as 'hidden' - no resizer-bar/spacing + // SELECTORS + //, paneSelector: "" // MUST be pane-specific - jQuery selector for pane + , contentSelector: ".ui-layout-content" // INNER div/element to auto-size so only it scrolls, not the entire pane! + , contentIgnoreSelector: ".ui-layout-ignore" // element(s) to 'ignore' when measuring 'content' + , findNestedContent: false // true = $P.find(contentSelector), false = $P.children(contentSelector) + // GENERIC ROOT-CLASSES - for auto-generated classNames + , paneClass: "ui-layout-pane" // border-Pane - default: 'ui-layout-pane' + , resizerClass: "ui-layout-resizer" // Resizer Bar - default: 'ui-layout-resizer' + , togglerClass: "ui-layout-toggler" // Toggler Button - default: 'ui-layout-toggler' + , buttonClass: "ui-layout-button" // CUSTOM Buttons - default: 'ui-layout-button-toggle/-open/-close/-pin' + // ELEMENT SIZE & SPACING + //, size: 100 // MUST be pane-specific -initial size of pane + , minSize: 0 // when manually resizing a pane + , maxSize: 0 // ditto, 0 = no limit + , spacing_open: 6 // space between pane and adjacent panes - when pane is 'open' + , spacing_closed: 6 // ditto - when pane is 'closed' + , togglerLength_open: 50 // Length = WIDTH of toggler button on north/south sides - HEIGHT on east/west sides + , togglerLength_closed: 50 // 100% OR -1 means 'full height/width of resizer bar' - 0 means 'hidden' + , togglerAlign_open: "center" // top/left, bottom/right, center, OR... + , togglerAlign_closed: "center" // 1 => nn = offset from top/left, -1 => -nn == offset from bottom/right + , togglerTip_open: lang.Close // Toggler tool-tip (title) + , togglerTip_closed: lang.Open // ditto + , togglerContent_open: "" // text or HTML to put INSIDE the toggler + , togglerContent_closed: "" // ditto + // RESIZING OPTIONS + , resizerDblClickToggle: true // + , autoResize: true // IF size is 'auto' or a percentage, then recalc 'pixel size' whenever the layout resizes + , autoReopen: true // IF a pane was auto-closed due to noRoom, reopen it when there is room? False = leave it closed + , resizerDragOpacity: 1 // option for ui.draggable + //, resizerCursor: "" // MUST be pane-specific - cursor when over resizer-bar + , maskIframesOnResize: true // true = all iframes OR = iframe-selector(s) - adds masking-div during resizing/dragging + , resizeNestedLayout: true // true = trigger nested.resizeAll() when a 'pane' of this layout is the 'container' for another + , resizeWhileDragging: false // true = LIVE Resizing as resizer is dragged + , resizeContentWhileDragging: false // true = re-measure header/footer heights as resizer is dragged + // TIPS & MESSAGES - also see lang object + , noRoomToOpenTip: lang.msgNoRoom + , resizerTip: lang.Resize // Resizer tool-tip (title) + , sliderTip: lang.Slide // resizer-bar triggers 'sliding' when pane is closed + , sliderCursor: "pointer" // cursor when resizer-bar will trigger 'sliding' + , slideTrigger_open: "click" // click, dblclick, mouseenter + , slideTrigger_close: "mouseleave"// click, mouseleave + , slideDelay_open: 300 // applies only for mouseenter event - 0 = instant open + , slideDelay_close: 300 // applies only for mouseleave event (300ms is the minimum!) + , hideTogglerOnSlide: false // when pane is slid-open, should the toggler show? + , preventQuickSlideClose: !!($.browser.webkit || $.browser.safari) // Chrome triggers slideClosed as is opening + , preventPrematureSlideClose: false + // HOT-KEYS & MISC + , showOverflowOnHover: false // will bind allowOverflow() utility to pane.onMouseOver + , enableCursorHotkey: true // enabled 'cursor' hotkeys + //, customHotkey: "" // MUST be pane-specific - EITHER a charCode OR a character + , customHotkeyModifier: "SHIFT" // either 'SHIFT', 'CTRL' or 'CTRL+SHIFT' - NOT 'ALT' + // PANE ANIMATION + // NOTE: fxSss_open & fxSss_close options (eg: fxName_open) are auto-generated if not passed + , fxName: "slide" // ('none' or blank), slide, drop, scale + , fxSpeed: null // slow, normal, fast, 200, nnn - if passed, will OVERRIDE fxSettings.duration + , fxSettings: {} // can be passed, eg: { easing: "easeOutBounce", duration: 1500 } + , fxOpacityFix: true // tries to fix opacity in IE to restore anti-aliasing after animation + // CALLBACKS + , triggerEventsOnLoad: false // true = trigger onopen OR onclose callbacks when layout initializes + , triggerEventsWhileDragging: true // true = trigger onresize callback REPEATEDLY if resizeWhileDragging==true + , onshow_start: null // CALLBACK when pane STARTS to Show - BEFORE onopen/onhide_start + , onshow_end: null // CALLBACK when pane ENDS being Shown - AFTER onopen/onhide_end + , onhide_start: null // CALLBACK when pane STARTS to Close - BEFORE onclose_start + , onhide_end: null // CALLBACK when pane ENDS being Closed - AFTER onclose_end + , onopen_start: null // CALLBACK when pane STARTS to Open + , onopen_end: null // CALLBACK when pane ENDS being Opened + , onclose_start: null // CALLBACK when pane STARTS to Close + , onclose_end: null // CALLBACK when pane ENDS being Closed + , onresize_start: null // CALLBACK when pane STARTS being Resized ***FOR ANY REASON*** + , onresize_end: null // CALLBACK when pane ENDS being Resized ***FOR ANY REASON*** + , onsizecontent_start: null // CALLBACK when sizing of content-element STARTS + , onsizecontent_end: null // CALLBACK when sizing of content-element ENDS + , onswap_start: null // CALLBACK when pane STARTS to Swap + , onswap_end: null // CALLBACK when pane ENDS being Swapped + , ondrag_start: null // CALLBACK when pane STARTS being ***MANUALLY*** Resized + , ondrag_end: null // CALLBACK when pane ENDS being ***MANUALLY*** Resized + } + , north: { + paneSelector: ".ui-layout-north" + , size: "auto" // eg: "auto", "30%", 200 + , resizerCursor: "n-resize" // custom = url(myCursor.cur) + , customHotkey: "" // EITHER a charCode OR a character + } + , south: { + paneSelector: ".ui-layout-south" + , size: "auto" + , resizerCursor: "s-resize" + , customHotkey: "" + } + , east: { + paneSelector: ".ui-layout-east" + , size: 200 + , resizerCursor: "e-resize" + , customHotkey: "" + } + , west: { + paneSelector: ".ui-layout-west" + , size: 200 + , resizerCursor: "w-resize" + , customHotkey: "" + } + , center: { + paneSelector: ".ui-layout-center" + , minWidth: 0 + , minHeight: 0 + } + + // STATE MANAGMENT + , useStateCookie: false // Enable cookie-based state-management - can fine-tune with cookie.autoLoad/autoSave + , cookie: { + name: "" // If not specified, will use Layout.name, else just "Layout" + , autoSave: true // Save a state cookie when page exits? + , autoLoad: true // Load the state cookie when Layout inits? + // Cookie Options + , domain: "" + , path: "" + , expires: "" // 'days' to keep cookie - leave blank for 'session cookie' + , secure: false + // List of options to save in the cookie - must be pane-specific + , keys: "north.size,south.size,east.size,west.size,"+ + "north.isClosed,south.isClosed,east.isClosed,west.isClosed,"+ + "north.isHidden,south.isHidden,east.isHidden,west.isHidden" + } + }; + + + // PREDEFINED EFFECTS / DEFAULTS + var effects = { // LIST *PREDEFINED EFFECTS* HERE, even if effect has no settings + slide: { + all: { duration: "fast" } // eg: duration: 1000, easing: "easeOutBounce" + , north: { direction: "up" } + , south: { direction: "down" } + , east: { direction: "right"} + , west: { direction: "left" } + } + , drop: { + all: { duration: "slow" } // eg: duration: 1000, easing: "easeOutQuint" + , north: { direction: "up" } + , south: { direction: "down" } + , east: { direction: "right"} + , west: { direction: "left" } + } + , scale: { + all: { duration: "fast" } + } + }; + + + // DYNAMIC DATA - IS READ-ONLY EXTERNALLY! + var state = { + // generate unique ID to use for event.namespace so can unbind only events added by 'this layout' + id: "layout"+ new Date().getTime() // code uses alias: sID + , initialized: false + , container: {} // init all keys + , north: {} + , south: {} + , east: {} + , west: {} + , center: {} + , cookie: {} // State Managment data storage + }; + + + // INTERNAL CONFIG DATA - DO NOT CHANGE THIS! + var _c = { + allPanes: "north,south,west,east,center" + , borderPanes: "north,south,west,east" + , altSide: { + north: "south" + , south: "north" + , east: "west" + , west: "east" + } + // CSS used in multiple places + , hidden: { visibility: "hidden" } + , visible: { visibility: "visible" } + // layout element settings + , zIndex: { // set z-index values here + pane_normal: 1 // normal z-index for panes + , resizer_normal: 2 // normal z-index for resizer-bars + , iframe_mask: 2 // overlay div used to mask pane(s) during resizing + , pane_sliding: 100 // applied to *BOTH* the pane and its resizer when a pane is 'slid open' + , pane_animate: 1000 // applied to the pane when being animated - not applied to the resizer + , resizer_drag: 10000 // applied to the CLONED resizer-bar when being 'dragged' + } + , resizers: { + cssReq: { + position: "absolute" + , padding: 0 + , margin: 0 + , fontSize: "1px" + , textAlign: "left" // to counter-act "center" alignment! + , overflow: "hidden" // prevent toggler-button from overflowing + // SEE c.zIndex.resizer_normal + } + , cssDemo: { // DEMO CSS - applied if: options.PANE.applyDemoStyles=true + background: "#DDD" + , border: "none" + } + } + , togglers: { + cssReq: { + position: "absolute" + , display: "block" + , padding: 0 + , margin: 0 + , overflow: "hidden" + , textAlign: "center" + , fontSize: "1px" + , cursor: "pointer" + , zIndex: 1 + } + , cssDemo: { // DEMO CSS - applied if: options.PANE.applyDemoStyles=true + background: "#AAA" + } + } + , content: { + cssReq: { + position: "relative" /* contain floated or positioned elements */ + } + , cssDemo: { // DEMO CSS - applied if: options.PANE.applyDemoStyles=true + overflow: "auto" + , padding: "10px" + } + , cssDemoPane: { // DEMO CSS - REMOVE scrolling from 'pane' when it has a content-div + overflow: "hidden" + , padding: 0 + } + } + , panes: { // defaults for ALL panes - overridden by 'per-pane settings' below + cssReq: { + position: "absolute" + , margin: 0 + // SEE c.zIndex.pane_normal + } + , cssDemo: { // DEMO CSS - applied if: options.PANE.applyDemoStyles=true + padding: "10px" + , background: "#FFF" + , border: "1px solid #BBB" + , overflow: "auto" + } + } + , north: { + side: "Top" + , sizeType: "Height" + , dir: "horz" + , cssReq: { + top: 0 + , bottom: "auto" + , left: 0 + , right: 0 + , width: "auto" + // height: DYNAMIC + } + , pins: [] // array of 'pin buttons' to be auto-updated on open/close (classNames) + } + , south: { + side: "Bottom" + , sizeType: "Height" + , dir: "horz" + , cssReq: { + top: "auto" + , bottom: 0 + , left: 0 + , right: 0 + , width: "auto" + // height: DYNAMIC + } + , pins: [] + } + , east: { + side: "Right" + , sizeType: "Width" + , dir: "vert" + , cssReq: { + left: "auto" + , right: 0 + , top: "auto" // DYNAMIC + , bottom: "auto" // DYNAMIC + , height: "auto" + // width: DYNAMIC + } + , pins: [] + } + , west: { + side: "Left" + , sizeType: "Width" + , dir: "vert" + , cssReq: { + left: 0 + , right: "auto" + , top: "auto" // DYNAMIC + , bottom: "auto" // DYNAMIC + , height: "auto" + // width: DYNAMIC + } + , pins: [] + } + , center: { + dir: "center" + , cssReq: { + left: "auto" // DYNAMIC + , right: "auto" // DYNAMIC + , top: "auto" // DYNAMIC + , bottom: "auto" // DYNAMIC + , height: "auto" + , width: "auto" + } + } + }; + + +/* + * ########################### + * INTERNAL HELPER FUNCTIONS + * ########################### + */ + + /** + * Manages all internal timers + */ + var timer = { + data: {} + , set: function (s, fn, ms) { timer.clear(s); timer.data[s] = setTimeout(fn, ms); } + , clear: function (s) { var t=timer.data; if (t[s]) {clearTimeout(t[s]); delete t[s];} } + }; + + /** + * Returns true if passed param is EITHER a simple string OR a 'string object' - otherwise returns false + */ + var isStr = function (o) { + try { return typeof o == "string" + || (typeof o == "object" && o.constructor.toString().match(/string/i) !== null); } + catch (e) { return false; } + }; + + /** + * Returns a simple string if passed EITHER a simple string OR a 'string object', + * else returns the original object + */ + var str = function (o) { // trim converts 'String object' to a simple string + return isStr(o) ? $.trim(o) : o == undefined || o == null ? "" : o; + }; + + /** + * min / max + * + * Aliases for Math methods to simplify coding + */ + var min = function (x,y) { return Math.min(x,y); }; + var max = function (x,y) { return Math.max(x,y); }; + + /** + * Processes the options passed in and transforms them into the format used by layout() + * Missing keys are added, and converts the data if passed in 'flat-format' (no sub-keys) + * In flat-format, pane-specific-settings are prefixed like: north__optName (2-underscores) + * To update effects, options MUST use nested-keys format, with an effects key ??? + * + * @see initOptions() + * @param {Object} d Data/options passed by user - may be a single level or nested levels + * @return {Object} Creates a data struture that perfectly matches 'options', ready to be imported + */ + var _transformData = function (d) { + var a, json = { cookie:{}, defaults:{fxSettings:{}}, north:{fxSettings:{}}, south:{fxSettings:{}}, east:{fxSettings:{}}, west:{fxSettings:{}}, center:{fxSettings:{}} }; + d = d || {}; + if (d.effects || d.cookie || d.defaults || d.north || d.south || d.west || d.east || d.center) + json = $.extend( true, json, d ); // already in json format - add to base keys + else + // convert 'flat' to 'nest-keys' format - also handles 'empty' user-options + $.each( d, function (key,val) { + a = key.split("__"); + if (!a[1] || json[a[0]]) // check for invalid keys + json[ a[1] ? a[0] : "defaults" ][ a[1] ? a[1] : a[0] ] = val; + }); + return json; + }; + + /** + * Set an INTERNAL callback to avoid simultaneous animation + * Runs only if needed and only if all callbacks are not 'already set' + * Called by open() and close() when isLayoutBusy=true + * + * @param {string} action Either 'open' or 'close' + * @param {string} pane A valid border-pane name, eg 'west' + * @param {boolean=} param Extra param for callback (optional) + */ + var _queue = function (action, pane, param) { + var tried = []; + + // if isLayoutBusy, then some pane must be 'moving' + $.each(_c.borderPanes.split(","), function (i, p) { + if (_c[p].isMoving) { + bindCallback(p); // TRY to bind a callback + return false; // BREAK + } + }); + + // if pane does NOT have a callback, then add one, else follow the callback chain... + function bindCallback (p) { + var c = _c[p]; + if (!c.doCallback) { + c.doCallback = true; + c.callback = action +","+ pane +","+ (param ? 1 : 0); + } + else { // try to 'chain' this callback + tried.push(p); + var cbPane = c.callback.split(",")[1]; // 2nd param of callback is 'pane' + // ensure callback target NOT 'itself' and NOT 'target pane' and NOT already tried (avoid loop) + if (cbPane != pane && !$.inArray(cbPane, tried) >= 0) + bindCallback(cbPane); // RECURSE + } + } + }; + + /** + * RUN the INTERNAL callback for this pane - if one exists + * + * @param {string} pane A valid border-pane name, eg 'west' + */ + var _dequeue = function (pane) { + var c = _c[pane]; + + // RESET flow-control flags + _c.isLayoutBusy = false; + delete c.isMoving; + if (!c.doCallback || !c.callback) return; + + c.doCallback = false; // RESET logic flag + + // EXECUTE the callback + var + cb = c.callback.split(",") + , param = (cb[2] > 0 ? true : false) + ; + if (cb[0] == "open") + open( cb[1], param ); + else if (cb[0] == "close") + close( cb[1], param ); + + if (!c.doCallback) c.callback = null; // RESET - unless callback above enabled it again! + }; + + /** + * Executes a Callback function after a trigger event, like resize, open or close + * + * @param {?string} pane This is passed only so we can pass the 'pane object' to the callback + * @param {(string|function())} v_fn Accepts a function name, OR a comma-delimited array: [0]=function name, [1]=argument + */ + var _execCallback = function (pane, v_fn) { + if (!v_fn) return; + var fn; + try { + if (typeof v_fn == "function") + fn = v_fn; + else if (!isStr(v_fn)) + return; + else if (v_fn.match(/,/)) { + // function name cannot contain a comma, so must be a function name AND a 'name' parameter + var args = v_fn.split(","); + fn = eval(args[0]); + if (typeof fn=="function" && args.length > 1) + return fn(args[1]); // pass the argument parsed from 'list' + } + else // just the name of an external function? + fn = eval(v_fn); + + if (typeof fn=="function") { + if (pane && $Ps[pane]) + // pass data: pane-name, pane-element, pane-state (copy), pane-options, and layout-name + return fn( pane, $Ps[pane], $.extend({},state[pane]), options[pane], options.name ); + else // must be a layout/container callback - pass suitable info + return fn( Instance, $.extend({},state), options, options.name ); + } + } + catch (ex) {} + }; + + /** + * Returns hash container 'display' and 'visibility' + * + * @see $.swap() - swaps CSS, runs callback, resets CSS + * @param {!Object} $E + * @param {boolean=} force + */ + var _showInvisibly = function ($E, force) { + if (!$E) return {}; + if (!$E.jquery) $E = $($E); + var CSS = { + display: $E.css('display') + , visibility: $E.css('visibility') + }; + if (force || CSS.display == "none") { // only if not *already hidden* + $E.css({ display: "block", visibility: "hidden" }); // show element 'invisibly' so can be measured + return CSS; + } + else return {}; + }; + + /** + * cure iframe display issues in IE & other browsers + */ + var _fixIframe = function (pane) { + if (state.browser.mozilla) return; // skip FireFox - it auto-refreshes iframes onShow + var $P = $Ps[pane]; + // if the 'pane' is an iframe, do it + if (state[pane].tagName == "IFRAME") + $P.css(_c.hidden).css(_c.visible); + else // ditto for any iframes INSIDE the pane + $P.find('IFRAME').css(_c.hidden).css(_c.visible); + }; + + /** + * Returns the 'current CSS numeric value' for a CSS property - 0 if property does not exist + * + * @see Called by many methods + * @param {Array.<Object>} $E Must pass a jQuery object - first element is processed + * @param {string} prop The name of the CSS property, eg: top, width, etc. + * @return {(string|number)} Usually used to get an integer value for position (top, left) or size (height, width) + */ + var _cssNum = function ($E, prop) { + if (!$E.jquery) $E = $($E); + var CSS = _showInvisibly($E); + var val = parseInt($.curCSS($E[0], prop, true), 10) || 0; + $E.css( CSS ); // RESET + return val; + }; + + /** + * @param {!Object} E Can accept a 'pane' (east, west, etc) OR a DOM object OR a jQuery object + * @param {string} side Which border (top, left, etc.) is resized + * @return {number} Returns the borderWidth + */ + var _borderWidth = function (E, side) { + if (E.jquery) E = E[0]; + var b = "border"+ side.substr(0,1).toUpperCase() + side.substr(1); // left => Left + return $.curCSS(E, b+"Style", true) == "none" ? 0 : (parseInt($.curCSS(E, b+"Width", true), 10) || 0); + }; + + /** + * cssW / cssH / cssSize / cssMinDims + * + * Contains logic to check boxModel & browser, and return the correct width/height for the current browser/doctype + * + * @see initPanes(), sizeMidPanes(), initHandles(), sizeHandles() + * @param {(string|!Object)} el Can accept a 'pane' (east, west, etc) OR a DOM object OR a jQuery object + * @param {number=} outerWidth (optional) Can pass a width, allowing calculations BEFORE element is resized + * @return {number} Returns the innerWidth of el by subtracting padding and borders + */ + var cssW = function (el, outerWidth) { + var + str = isStr(el) + , $E = str ? $Ps[el] : $(el) + ; + if (isNaN(outerWidth)) // not specified + outerWidth = str ? getPaneSize(el) : $E.outerWidth(); + + // a 'calculated' outerHeight can be passed so borders and/or padding are removed if needed + if (outerWidth <= 0) return 0; + + if (!state.browser.boxModel) return outerWidth; + + // strip border and padding from outerWidth to get CSS Width + var W = outerWidth + - _borderWidth($E, "Left") + - _borderWidth($E, "Right") + - _cssNum($E, "paddingLeft") + - _cssNum($E, "paddingRight") + ; + + return max(0,W); + }; + + /** + * @param {(string|!Object)} el Can accept a 'pane' (east, west, etc) OR a DOM object OR a jQuery object + * @param {number=} outerHeight (optional) Can pass a width, allowing calculations BEFORE element is resized + * @return {number} Returns the innerHeight el by subtracting padding and borders + */ + var cssH = function (el, outerHeight) { + var + str = isStr(el) + , $E = str ? $Ps[el] : $(el) + ; + if (isNaN(outerHeight)) // not specified + outerHeight = str ? getPaneSize(el) : $E.outerHeight(); + + // a 'calculated' outerHeight can be passed so borders and/or padding are removed if needed + if (outerHeight <= 0) return 0; + + if (!state.browser.boxModel) return outerHeight; + + // strip border and padding from outerHeight to get CSS Height + var H = outerHeight + - _borderWidth($E, "Top") + - _borderWidth($E, "Bottom") + - _cssNum($E, "paddingTop") + - _cssNum($E, "paddingBottom") + ; + + return max(0,H); + }; + + /** + * @param {string} pane Can accept ONLY a 'pane' (east, west, etc) + * @param {number=} outerSize (optional) Can pass a width, allowing calculations BEFORE element is resized + * @return {number} Returns the innerHeight/Width of el by subtracting padding and borders + */ + var cssSize = function (pane, outerSize) { + if (_c[pane].dir=="horz") // pane = north or south + return cssH(pane, outerSize); + else // pane = east or west + return cssW(pane, outerSize); + }; + + /** + * @param {string} pane Can accept ONLY a 'pane' (east, west, etc) + * @return {Object} Returns hash of minWidth & minHeight + */ + var cssMinDims = function (pane) { + // minWidth/Height means CSS width/height = 1px + var + dir = _c[pane].dir + , d = { + minWidth: 1001 - cssW(pane, 1000) + , minHeight: 1001 - cssH(pane, 1000) + } + ; + if (dir == "horz") d.minSize = d.minHeight; + if (dir == "vert") d.minSize = d.minWidth; + return d; + }; + + // TODO: see if these methods can be made more useful... + // TODO: *maybe* return cssW/H from these so caller can use this info + + /** + * @param {(string|!Object)} el + * @param {number=} outerWidth + * @param {boolean=} autoHide + */ + var setOuterWidth = function (el, outerWidth, autoHide) { + var $E = el, w; + if (isStr(el)) $E = $Ps[el]; // west + else if (!el.jquery) $E = $(el); + w = cssW($E, outerWidth); + $E.css({ width: w }); + if (w > 0) { + if (autoHide && $E.data('autoHidden') && $E.innerHeight() > 0) { + $E.show().data('autoHidden', false); + if (!state.browser.mozilla) // FireFox refreshes iframes - IE doesn't + // make hidden, then visible to 'refresh' display after animation + $E.css(_c.hidden).css(_c.visible); + } + } + else if (autoHide && !$E.data('autoHidden')) + $E.hide().data('autoHidden', true); + }; + + /** + * @param {(string|!Object)} el + * @param {number=} outerHeight + * @param {boolean=} autoHide + */ + var setOuterHeight = function (el, outerHeight, autoHide) { + var $E = el, h; + if (isStr(el)) $E = $Ps[el]; // west + else if (!el.jquery) $E = $(el); + h = cssH($E, outerHeight); + $E.css({ height: h, visibility: "visible" }); // may have been 'hidden' by sizeContent + if (h > 0 && $E.innerWidth() > 0) { + if (autoHide && $E.data('autoHidden')) { + $E.show().data('autoHidden', false); + if (!state.browser.mozilla) // FireFox refreshes iframes - IE doesn't + $E.css(_c.hidden).css(_c.visible); + } + } + else if (autoHide && !$E.data('autoHidden')) + $E.hide().data('autoHidden', true); + }; + + /** + * @param {(string|!Object)} el + * @param {number=} outerSize + * @param {boolean=} autoHide + */ + var setOuterSize = function (el, outerSize, autoHide) { + if (_c[pane].dir=="horz") // pane = north or south + setOuterHeight(el, outerSize, autoHide); + else // pane = east or west + setOuterWidth(el, outerSize, autoHide); + }; + + + /** + * Converts any 'size' params to a pixel/integer size, if not already + * If 'auto' or a decimal/percentage is passed as 'size', a pixel-size is calculated + * + /** + * @param {string} pane + * @param {(string|number)=} size + * @param {string=} dir + * @return {number} + */ + var _parseSize = function (pane, size, dir) { + if (!dir) dir = _c[pane].dir; + + if (isStr(size) && size.match(/%/)) + size = parseInt(size, 10) / 100; // convert % to decimal + + if (size === 0) + return 0; + else if (size >= 1) + return parseInt(size, 10); + else if (size > 0) { // percentage, eg: .25 + var o = options, avail; + if (dir=="horz") // north or south or center.minHeight + avail = sC.innerHeight - ($Ps.north ? o.north.spacing_open : 0) - ($Ps.south ? o.south.spacing_open : 0); + else if (dir=="vert") // east or west or center.minWidth + avail = sC.innerWidth - ($Ps.west ? o.west.spacing_open : 0) - ($Ps.east ? o.east.spacing_open : 0); + return Math.floor(avail * size); + } + else if (pane=="center") + return 0; + else { // size < 0 || size=='auto' || size==Missing || size==Invalid + // auto-size the pane + var + $P = $Ps[pane] + , dim = (dir == "horz" ? "height" : "width") + , vis = _showInvisibly($P) // show pane invisibly if hidden + , s = $P.css(dim); // SAVE current size + ; + $P.css(dim, "auto"); + size = (dim == "height") ? $P.outerHeight() : $P.outerWidth(); // MEASURE + $P.css(dim, s).css(vis); // RESET size & visibility + return size; + } + }; + + /** + * Calculates current 'size' (outer-width or outer-height) of a border-pane - optionally with 'pane-spacing' added + * + * @param {(string|!Object)} pane + * @param {boolean=} inclSpace + * @return {number} Returns EITHER Width for east/west panes OR Height for north/south panes - adjusted for boxModel & browser + */ + var getPaneSize = function (pane, inclSpace) { + var + $P = $Ps[pane] + , o = options[pane] + , s = state[pane] + , oSp = (inclSpace ? o.spacing_open : 0) + , cSp = (inclSpace ? o.spacing_closed : 0) + ; + if (!$P || s.isHidden) + return 0; + else if (s.isClosed || (s.isSliding && inclSpace)) + return cSp; + else if (_c[pane].dir == "horz") + return $P.outerHeight() + oSp; + else // dir == "vert" + return $P.outerWidth() + oSp; + }; + + /** + * Calculate min/max pane dimensions and limits for resizing + * + * @param {string} pane + * @param {boolean=} slide + */ + var setSizeLimits = function (pane, slide) { + var + o = options[pane] + , s = state[pane] + , c = _c[pane] + , dir = c.dir + , side = c.side.toLowerCase() + , type = c.sizeType.toLowerCase() + , isSliding = (slide != undefined ? slide : s.isSliding) // only open() passes 'slide' param + , $P = $Ps[pane] + , paneSpacing = o.spacing_open + // measure the pane on the *opposite side* from this pane + , altPane = _c.altSide[pane] + , altS = state[altPane] + , $altP = $Ps[altPane] + , altPaneSize = (!$altP || altS.isVisible===false || altS.isSliding ? 0 : (dir=="horz" ? $altP.outerHeight() : $altP.outerWidth())) + , altPaneSpacing = ((!$altP || altS.isHidden ? 0 : options[altPane][ altS.isClosed !== false ? "spacing_closed" : "spacing_open" ]) || 0) + // limitSize prevents this pane from 'overlapping' opposite pane + , containerSize = (dir=="horz" ? sC.innerHeight : sC.innerWidth) + , minCenterDims = cssMinDims("center") + , minCenterSize = dir=="horz" ? max(options.center.minHeight, minCenterDims.minHeight) : max(options.center.minWidth, minCenterDims.minWidth) + // if pane is 'sliding', then ignore center and alt-pane sizes - because 'overlays' them + , limitSize = (containerSize - paneSpacing - (isSliding ? 0 : (_parseSize("center", minCenterSize, dir) + altPaneSize + altPaneSpacing))) + , minSize = s.minSize = max( _parseSize(pane, o.minSize), cssMinDims(pane).minSize ) + , maxSize = s.maxSize = min( (o.maxSize ? _parseSize(pane, o.maxSize) : 100000), limitSize ) + , r = s.resizerPosition = {} // used to set resizing limits + , top = sC.insetTop + , left = sC.insetLeft + , W = sC.innerWidth + , H = sC.innerHeight + , rW = o.spacing_open // subtract resizer-width to get top/left position for south/east + ; + switch (pane) { + case "north": r.min = top + minSize; + r.max = top + maxSize; + break; + case "west": r.min = left + minSize; + r.max = left + maxSize; + break; + case "south": r.min = top + H - maxSize - rW; + r.max = top + H - minSize - rW; + break; + case "east": r.min = left + W - maxSize - rW; + r.max = left + W - minSize - rW; + break; + }; + }; + + /** + * Returns data for setting the size/position of center pane. Also used to set Height for east/west panes + * + * @return JSON Returns a hash of all dimensions: top, bottom, left, right, (outer) width and (outer) height + */ + var calcNewCenterPaneDims = function () { + var d = { + top: getPaneSize("north", true) // true = include 'spacing' value for pane + , bottom: getPaneSize("south", true) + , left: getPaneSize("west", true) + , right: getPaneSize("east", true) + , width: 0 + , height: 0 + }; + + // NOTE: sC = state.container + // calc center-pane's outer dimensions + d.width = sC.innerWidth - d.left - d.right; // outerWidth + d.height = sC.innerHeight - d.bottom - d.top; // outerHeight + // add the 'container border/padding' to get final positions relative to the container + d.top += sC.insetTop; + d.bottom += sC.insetBottom; + d.left += sC.insetLeft; + d.right += sC.insetRight; + + return d; + }; + + + /** + * Returns data for setting size of an element (container or a pane). + * + * @see _create(), onWindowResize() for container, plus others for pane + * @return JSON Returns a hash of all dimensions: top, bottom, left, right, outerWidth, innerHeight, etc + */ + var getElemDims = function ($E) { + var + d = {} // dimensions hash + , x = d.css = {} // CSS hash + , i = {} // TEMP insets + , b, p // TEMP border, padding + , off = $E.offset() + ; + d.offsetLeft = off.left; + d.offsetTop = off.top; + + $.each("Left,Right,Top,Bottom".split(","), function (idx, e) { + b = x["border" + e] = _borderWidth($E, e); + p = x["padding"+ e] = _cssNum($E, "padding"+e); + i[e] = b + p; // total offset of content from outer side + d["inset"+ e] = p; + /* WRONG ??? + // if BOX MODEL, then 'position' = PADDING (ignore borderWidth) + if ($E == $Container) + d["inset"+ e] = (state.browser.boxModel ? p : 0); + */ + }); + + d.offsetWidth = $E.innerWidth(); // true=include Padding + d.offsetHeight = $E.innerHeight(); + d.outerWidth = $E.outerWidth(); + d.outerHeight = $E.outerHeight(); + d.innerWidth = d.outerWidth - i.Left - i.Right; + d.innerHeight = d.outerHeight - i.Top - i.Bottom; + + // TESTING + x.width = $E.width(); + x.height = $E.height(); + + return d; + }; + + var getElemCSS = function ($E, list) { + var + CSS = {} + , style = $E[0].style + , props = list.split(",") + , sides = "Top,Bottom,Left,Right".split(",") + , attrs = "Color,Style,Width".split(",") + , p, s, a, i, j, k + ; + for (i=0; i < props.length; i++) { + p = props[i]; + if (p.match(/(border|padding|margin)$/)) + for (j=0; j < 4; j++) { + s = sides[j]; + if (p == "border") + for (k=0; k < 3; k++) { + a = attrs[k]; + CSS[p+s+a] = style[p+s+a]; + } + else + CSS[p+s] = style[p+s]; + } + else + CSS[p] = style[p]; + }; + return CSS + }; + + + /** + * @param {!Object} el + * @param {boolean=} allStates + */ + var getHoverClasses = function (el, allStates) { + var + $El = $(el) + , type = $El.data("layoutRole") + , pane = $El.data("layoutEdge") + , o = options[pane] + , root = o[type +"Class"] + , _pane = "-"+ pane // eg: "-west" + , _open = "-open" + , _closed = "-closed" + , _slide = "-sliding" + , _hover = "-hover " // NOTE the trailing space + , _state = $El.hasClass(root+_closed) ? _closed : _open + , _alt = _state == _closed ? _open : _closed + , classes = (root+_hover) + (root+_pane+_hover) + (root+_state+_hover) + (root+_pane+_state+_hover) + ; + if (allStates) // when 'removing' classes, also remove alternate-state classes + classes += (root+_alt+_hover) + (root+_pane+_alt+_hover); + + if (type=="resizer" && $El.hasClass(root+_slide)) + classes += (root+_slide+_hover) + (root+_pane+_slide+_hover); + + return $.trim(classes); + }; + var addHover = function (evt, el) { + var $E = $(el || this); + if (evt && $E.data("layoutRole") == "toggler") + evt.stopPropagation(); // prevent triggering 'slide' on Resizer-bar + $E.addClass( getHoverClasses($E) ); + }; + var removeHover = function (evt, el) { + var $E = $(el || this); + $E.removeClass( getHoverClasses($E, true) ); + }; + + var onResizerEnter = function (evt) { + $('body').disableSelection(); + addHover(evt, this); + }; + var onResizerLeave = function (evt, el) { + var + e = el || this // el is only passed when called by the timer + , pane = $(e).data("layoutEdge") + , name = pane +"ResizerLeave" + ; + timer.clear(pane+"_openSlider"); // cancel slideOpen timer, if set + timer.clear(name); // cancel enableSelection timer - may re/set below + if (!el) { // 1st call - mouseleave event + removeHover(evt, this); // do this on initial call + // this method calls itself on a timer because it needs to allow + // enough time for dragging to kick-in and set the isResizing flag + // dragging has a 100ms delay set, so this delay must be higher + timer.set(name, function(){ onResizerLeave(evt, e); }, 200); + } + // if user is resizing, then dragStop will enableSelection() when done + else if (!state[pane].isResizing) // 2nd call - by timer + $('body').enableSelection(); + }; + +/* + * ########################### + * INITIALIZATION METHODS + * ########################### + */ + + /** + * Initialize the layout - called automatically whenever an instance of layout is created + * + * @see none - triggered onInit + * @return An object pointer to the instance created + */ + var _create = function () { + // initialize config/options + initOptions(); + var o = options; + + // onload will CANCEL resizing if returns false + if (false === _execCallback(null, o.onload_start)) return false; + + // a center pane is required, so make sure it exists + if (!getPane('center').length) { + alert( lang.errCenterPaneMissing ); + return null; + } + + // update options with saved state, if option enabled + if (o.useStateCookie && o.cookie.autoLoad) + loadCookie(); // Update options from state-cookie + + // set environment - can update code here if $.browser is phased out + state.browser = { + mozilla: $.browser.mozilla + , webkit: $.browser.webkit || $.browser.safari + , msie: $.browser.msie + , isIE6: $.browser.msie && $.browser.version == 6 + , boxModel: $.support.boxModel + //, version: $.browser.version - not used + }; + + // initialize all layout elements + initContainer(); // set CSS as needed and init state.container dimensions + initPanes(); // size & position panes - calls initHandles() - which calls initResizable() + sizeContent(); // AFTER panes & handles have been initialized, size 'content' divs + + if (o.scrollToBookmarkOnLoad) { + var l = self.location; + if (l.hash) l.replace( l.hash ); // scrollTo Bookmark + } + + // bind hotkey function - keyDown - if required + initHotkeys(); + + // search for and bind custom-buttons + if (o.autoBindCustomButtons) initButtons(); + + // bind resizeAll() for 'this layout instance' to window.resize event + if (o.resizeWithWindow && !$Container.data("layoutRole")) // skip if 'nested' inside a pane + $(window).bind("resize."+ sID, windowResize); + + // bind window.onunload + $(window).bind("unload."+ sID, unload); + + state.initialized = true; + + _execCallback(null, o.onload_end || o.onload); + }; + + var windowResize = function () { + var delay = Number(options.resizeWithWindowDelay) || 100; // there MUST be some delay! + if (delay > 0) { + // resizing uses a delay-loop because the resize event fires repeatly - except in FF, but delay anyway + timer.clear("winResize"); // if already running + timer.set("winResize", function(){ timer.clear("winResize"); timer.clear("winResizeRepeater"); resizeAll(); }, delay); + // ALSO set fixed-delay timer, if not already running + if (!timer.data["winResizeRepeater"]) setWindowResizeRepeater(); + } + }; + + var setWindowResizeRepeater = function () { + var delay = Number(options.resizeWithWindowMaxDelay); + if (delay > 0) + timer.set("winResizeRepeater", function(){ setWindowResizeRepeater(); resizeAll(); }, delay); + }; + + var unload = function () { + var o = options; + state.cookie = getState(); // save state in case onunload has custom state-management + _execCallback(null, o.onunload_start); + if (o.useStateCookie && o.cookie.autoSave) saveCookie(); + _execCallback(null, o.onunload_end || o.onunload); + }; + + /** + * Validate and initialize container CSS and events + * + * @see _create() + */ + var initContainer = function () { + var + $C = $Container // alias + , tag = sC.tagName = $C.attr("tagName") + , fullPage= (tag == "BODY") + , props = "position,margin,padding,border" + , CSS = {} + ; + sC.selector = $C.selector.split(".slice")[0]; + sC.ref = tag +"/"+ sC.selector; // used in messages + + $C .data("layout", Instance) + .data("layoutContainer", sID) // unique identifier for internal use + .addClass(options.containerClass) + ; + + // SAVE original container CSS for use in destroy() + if (!$C.data("layoutCSS")) { + // handle props like overflow different for BODY & HTML - has 'system default' values + if (fullPage) { + CSS = $.extend( getElemCSS($C, props), { + height: $C.css("height") + , overflow: $C.css("overflow") + , overflowX: $C.css("overflowX") + , overflowY: $C.css("overflowY") + }); + // ALSO SAVE <HTML> CSS + var $H = $("html"); + $H.data("layoutCSS", { + height: "auto" // FF would return a fixed px-size! + , overflow: $H.css("overflow") + , overflowX: $H.css("overflowX") + , overflowY: $H.css("overflowY") + }); + } + else // handle props normally for non-body elements + CSS = getElemCSS($C, props+",top,bottom,left,right,width,height,overflow,overflowX,overflowY"); + + $C.data("layoutCSS", CSS); + } + + try { // format html/body if this is a full page layout + if (fullPage) { + $("html").css({ + height: "100%" + , overflow: "hidden" + , overflowX: "hidden" + , overflowY: "hidden" + }); + $("body").css({ + position: "relative" + , height: "100%" + , overflow: "hidden" + , overflowX: "hidden" + , overflowY: "hidden" + , margin: 0 + , padding: 0 // TODO: test whether body-padding could be handled? + , border: "none" // a body-border creates problems because it cannot be measured! + }); + } + else { // set required CSS for overflow and position + CSS = { overflow: "hidden" } // make sure container will not 'scroll' + var + p = $C.css("position") + , h = $C.css("height") + ; + // if this is a NESTED layout, then container/outer-pane ALREADY has position and height + if (!$C.data("layoutRole")) { + if (!p || !p.match(/fixed|absolute|relative/)) + CSS.position = "relative"; // container MUST have a 'position' + /* + if (!h || h=="auto") + CSS.height = "100%"; // container MUST have a 'height' + */ + } + $C.css( CSS ); + + if ($C.is(":visible") && $C.innerHeight() < 2) + alert( lang.errContainerHeight.replace(/CONTAINER/, sC.ref) ); + } + } catch (ex) {} + + // set current layout-container dimensions + $.extend(state.container, getElemDims( $C )); + }; + + /** + * Bind layout hotkeys - if options enabled + * + * @see _create() and addPane() + * @param {string=} panes The edge(s) to process, blank = all + */ + var initHotkeys = function (panes) { + if (!panes || panes == "all") panes = _c.borderPanes; + // bind keyDown to capture hotkeys, if option enabled for ANY pane + $.each(panes.split(","), function (i, pane) { + var o = options[pane]; + if (o.enableCursorHotkey || o.customHotkey) { + $(document).bind("keydown."+ sID, keyDown); // only need to bind this ONCE + return false; // BREAK - binding was done + } + }); + }; + + /** + * Build final OPTIONS data + * + * @see _create() + */ + var initOptions = function () { + // simplify logic by making sure passed 'opts' var has basic keys + opts = _transformData( opts ); + + // TODO: create a compatibility add-on for new UI widget that will transform old option syntax + var newOpts = { + applyDefaultStyles: "applyDemoStyles" + }; + renameOpts(opts.defaults); + $.each(_c.allPanes.split(","), function (i, pane) { + renameOpts(opts[pane]); + }); + + // update default effects, if case user passed key + if (opts.effects) { + $.extend( effects, opts.effects ); + delete opts.effects; + } + $.extend( options.cookie, opts.cookie ); + + // see if any 'global options' were specified + var globals = "name,containerClass,zIndex,scrollToBookmarkOnLoad,resizeWithWindow,resizeWithWindowDelay,resizeWithWindowMaxDelay,"+ + "onresizeall,onresizeall_start,onresizeall_end,onload,onload_start,onload_end,onunload,onunload_start,onunload_end,autoBindCustomButtons,useStateCookie"; + $.each(globals.split(","), function (i, key) { + if (opts[key] !== undefined) + options[key] = opts[key]; + else if (opts.defaults[key] !== undefined) { + options[key] = opts.defaults[key]; + delete opts.defaults[key]; + } + }); + + // remove any 'defaults' that MUST be set 'per-pane' + $.each("paneSelector,resizerCursor,customHotkey".split(","), + function (i, key) { delete opts.defaults[key]; } // is OK if key does not exist + ); + + // now update options.defaults + $.extend( true, options.defaults, opts.defaults ); + + // merge config for 'center-pane' - border-panes handled in the loop below + _c.center = $.extend( true, {}, _c.panes, _c.center ); + // update config.zIndex values if zIndex option specified + var z = options.zIndex; + if (z === 0 || z > 0) { + _c.zIndex.pane_normal = z; + _c.zIndex.resizer_normal = z+1; + _c.zIndex.iframe_mask = z+1; + } + + // merge options for 'center-pane' - border-panes handled in the loop below + $.extend( options.center, opts.center ); + // Most 'default options' do not apply to 'center', so add only those that DO + var o_Center = $.extend( true, {}, options.defaults, opts.defaults, options.center ); // TEMP data + var optionsCenter = ("paneClass,contentSelector,applyDemoStyles,triggerEventsOnLoad,showOverflowOnHover," + + "onresize,onresize_start,onresize_end,resizeNestedLayout,resizeContentWhileDragging," + + "onsizecontent,onsizecontent_start,onsizecontent_end").split(","); + $.each(optionsCenter, + function (i, key) { options.center[key] = o_Center[key]; } + ); + + var o, defs = options.defaults; + + // create a COMPLETE set of options for EACH border-pane + $.each(_c.borderPanes.split(","), function (i, pane) { + + // apply 'pane-defaults' to CONFIG.[PANE] + _c[pane] = $.extend( true, {}, _c.panes, _c[pane] ); + + // apply 'pane-defaults' + user-options to OPTIONS.PANE + o = options[pane] = $.extend( true, {}, options.defaults, options[pane], opts.defaults, opts[pane] ); + + // make sure we have base-classes + if (!o.paneClass) o.paneClass = "ui-layout-pane"; + if (!o.resizerClass) o.resizerClass = "ui-layout-resizer"; + if (!o.togglerClass) o.togglerClass = "ui-layout-toggler"; + + // create FINAL fx options for each pane, ie: options.PANE.fxName/fxSpeed/fxSettings[_open|_close] + $.each(["_open","_close",""], function (i,n) { + var + sName = "fxName"+n + , sSpeed = "fxSpeed"+n + , sSettings = "fxSettings"+n + ; + // recalculate fxName according to specificity rules + o[sName] = + opts[pane][sName] // opts.west.fxName_open + || opts[pane].fxName // opts.west.fxName + || opts.defaults[sName] // opts.defaults.fxName_open + || opts.defaults.fxName // opts.defaults.fxName + || o[sName] // options.west.fxName_open + || o.fxName // options.west.fxName + || defs[sName] // options.defaults.fxName_open + || defs.fxName // options.defaults.fxName + || "none" + ; + // validate fxName to be sure is a valid effect + var fxName = o[sName]; + if (fxName == "none" || !$.effects || !$.effects[fxName] || (!effects[fxName] && !o[sSettings] && !o.fxSettings)) + fxName = o[sName] = "none"; // effect not loaded, OR undefined FX AND fxSettings not passed + // set vars for effects subkeys to simplify logic + var + fx = effects[fxName] || {} // effects.slide + , fx_all = fx.all || {} // effects.slide.all + , fx_pane = fx[pane] || {} // effects.slide.west + ; + // RECREATE the fxSettings[_open|_close] keys using specificity rules + o[sSettings] = $.extend( + {} + , fx_all // effects.slide.all + , fx_pane // effects.slide.west + , defs.fxSettings || {} // options.defaults.fxSettings + , defs[sSettings] || {} // options.defaults.fxSettings_open + , o.fxSettings // options.west.fxSettings + , o[sSettings] // options.west.fxSettings_open + , opts.defaults.fxSettings // opts.defaults.fxSettings + , opts.defaults[sSettings] || {} // opts.defaults.fxSettings_open + , opts[pane].fxSettings // opts.west.fxSettings + , opts[pane][sSettings] || {} // opts.west.fxSettings_open + ); + // recalculate fxSpeed according to specificity rules + o[sSpeed] = + opts[pane][sSpeed] // opts.west.fxSpeed_open + || opts[pane].fxSpeed // opts.west.fxSpeed (pane-default) + || opts.defaults[sSpeed] // opts.defaults.fxSpeed_open + || opts.defaults.fxSpeed // opts.defaults.fxSpeed + || o[sSpeed] // options.west.fxSpeed_open + || o[sSettings].duration // options.west.fxSettings_open.duration + || o.fxSpeed // options.west.fxSpeed + || o.fxSettings.duration // options.west.fxSettings.duration + || defs.fxSpeed // options.defaults.fxSpeed + || defs.fxSettings.duration// options.defaults.fxSettings.duration + || fx_pane.duration // effects.slide.west.duration + || fx_all.duration // effects.slide.all.duration + || "normal" // DEFAULT + ; + }); + + }); + + function renameOpts (O) { + for (var key in newOpts) { + if (O[key] != undefined) { + O[newOpts[key]] = O[key]; + delete O[key]; + } + } + } + }; + + /** + * Initialize module objects, styling, size and position for all panes + * + * @see _create() + * @param {string} pane The pane to process + */ + var getPane = function (pane) { + var sel = options[pane].paneSelector + if (sel.substr(0,1)==="#") // ID selector + // NOTE: elements selected 'by ID' DO NOT have to be 'children' + return $Container.find(sel).eq(0); + else { // class or other selector + var $P = $Container.children(sel).eq(0); + // look for the pane nested inside a 'form' element + return $P.length ? $P : $Container.children("form:first").children(sel).eq(0); + } + }; + var initPanes = function () { + // NOTE: do north & south FIRST so we can measure their height - do center LAST + $.each(_c.allPanes.split(","), function (idx, pane) { + addPane( pane ); + }); + + // init the pane-handles NOW in case we have to hide or close the pane below + initHandles(); + + // now that all panes have been initialized and initially-sized, + // make sure there is really enough space available for each pane + $.each(_c.borderPanes.split(","), function (i, pane) { + if ($Ps[pane] && state[pane].isVisible) { // pane is OPEN + setSizeLimits(pane); + makePaneFit(pane); // pane may be Closed, Hidden or Resized by makePaneFit() + } + }); + // size center-pane AGAIN in case we 'closed' a border-pane in loop above + sizeMidPanes("center"); + + // trigger onResize callbacks for all panes with triggerEventsOnLoad = true + $.each(_c.allPanes.split(","), function (i, pane) { + var o = options[pane]; + if ($Ps[pane] && state[pane].isVisible) { // pane is OPEN + if (o.triggerEventsOnLoad) + _execCallback(pane, o.onresize_end || o.onresize); + resizeNestedLayout(pane); + } + }); + + if ($Container.innerHeight() < 2) + alert( lang.errContainerHeight.replace(/CONTAINER/, sC.ref) ); + }; + + /** + * Remove a pane from the layout - subroutine of destroy() + * + * @see initPanes() + * @param {string} pane The pane to process + */ + var addPane = function (pane) { + var + o = options[pane] + , s = state[pane] + , c = _c[pane] + , fx = s.fx + , dir = c.dir + , spacing = o.spacing_open || 0 + , isCenter = (pane == "center") + , CSS = {} + , $P = $Ps[pane] + , size, minSize, maxSize + ; + + // if pane-pointer already exists, remove the old one first + if ($P) + removePane( pane ); + else + $Cs[pane] = false; // init + + $P = $Ps[pane] = getPane(pane); + if (!$P.length) { + $Ps[pane] = false; // logic + return; + } + + // SAVE original Pane CSS + if (!$P.data("layoutCSS")) { + var props = "position,top,left,bottom,right,width,height,overflow,zIndex,display,backgroundColor,padding,margin,border"; + $P.data("layoutCSS", getElemCSS($P, props)); + } + + // add basic classes & attributes + $P + .data("parentLayout", Instance) + .data("layoutRole", "pane") + .data("layoutEdge", pane) + .css(c.cssReq).css("zIndex", _c.zIndex.pane_normal) + .css(o.applyDemoStyles ? c.cssDemo : {}) // demo styles + .addClass( o.paneClass +" "+ o.paneClass+"-"+pane ) // default = "ui-layout-pane ui-layout-pane-west" - may be a dupe of 'paneSelector' + .bind("mouseenter."+ sID, addHover ) + .bind("mouseleave."+ sID, removeHover ) + ; + + // see if this pane has a 'scrolling-content element' + initContent(pane, false); // false = do NOT sizeContent() - called later + + if (!isCenter) { + // call _parseSize AFTER applying pane classes & styles - but before making visible (if hidden) + // if o.size is auto or not valid, then MEASURE the pane and use that as it's 'size' + size = s.size = _parseSize(pane, o.size); + minSize = _parseSize(pane,o.minSize) || 1; + maxSize = _parseSize(pane,o.maxSize) || 100000; + if (size > 0) size = max(min(size, maxSize), minSize); + + // state for border-panes + s.isClosed = false; // true = pane is closed + s.isSliding = false; // true = pane is currently open by 'sliding' over adjacent panes + s.isResizing= false; // true = pane is in process of being resized + s.isHidden = false; // true = pane is hidden - no spacing, resizer or toggler is visible! + } + // state for all panes + s.tagName = $P.attr("tagName"); + s.edge = pane // useful if pane is (or about to be) 'swapped' - easy find out where it is (or is going) + s.noRoom = false; // true = pane 'automatically' hidden due to insufficient room - will unhide automatically + s.isVisible = true; // false = pane is invisible - closed OR hidden - simplify logic + + // set css-position to account for container borders & padding + switch (pane) { + case "north": CSS.top = sC.insetTop; + CSS.left = sC.insetLeft; + CSS.right = sC.insetRight; + break; + case "south": CSS.bottom = sC.insetBottom; + CSS.left = sC.insetLeft; + CSS.right = sC.insetRight; + break; + case "west": CSS.left = sC.insetLeft; // top, bottom & height set by sizeMidPanes() + break; + case "east": CSS.right = sC.insetRight; // ditto + break; + case "center": // top, left, width & height set by sizeMidPanes() + } + + if (dir == "horz") // north or south pane + CSS.height = max(1, cssH(pane, size)); + else if (dir == "vert") // east or west pane + CSS.width = max(1, cssW(pane, size)); + //else if (isCenter) {} + + $P.css(CSS); // apply size -- top, bottom & height will be set by sizeMidPanes + if (dir != "horz") sizeMidPanes(pane, true); // true = skipCallback + + // NOW make the pane visible - in case was initially hidden + if (!s.noRoom) + $P.css({ visibility: "visible", display: "block" }); + + // close or hide the pane if specified in settings + if (o.initClosed && o.closable) + close(pane, true, true); // true, true = force, noAnimation + else if (o.initHidden || o.initClosed) + hide(pane); // will be completely invisible - no resizer or spacing + // ELSE setAsOpen() - called later by initHandles() + + // check option for auto-handling of pop-ups & drop-downs + if (o.showOverflowOnHover) + $P.hover( allowOverflow, resetOverflow ); + + // if adding a pane AFTER initialization, then... + if (state.initialized) { + initHandles( pane ); + initHotkeys( pane ); + resizeAll(); // will sizeContent if pane is visible + if (s.isVisible) { // pane is OPEN + if (o.triggerEventsOnLoad) + _execCallback(pane, o.onresize_end || o.onresize); + resizeNestedLayout(pane); + } + } + }; + + /** + * Initialize module objects, styling, size and position for all resize bars and toggler buttons + * + * @see _create() + * @param {string=} panes The edge(s) to process, blank = all + */ + var initHandles = function (panes) { + if (!panes || panes == "all") panes = _c.borderPanes; + + // create toggler DIVs for each pane, and set object pointers for them, eg: $R.north = north toggler DIV + $.each(panes.split(","), function (i, pane) { + var $P = $Ps[pane]; + $Rs[pane] = false; // INIT + $Ts[pane] = false; + if (!$P) return; // pane does not exist - skip + + var + o = options[pane] + , s = state[pane] + , c = _c[pane] + , rClass = o.resizerClass + , tClass = o.togglerClass + , side = c.side.toLowerCase() + , spacing = (s.isVisible ? o.spacing_open : o.spacing_closed) + , _pane = "-"+ pane // used for classNames + , _state = (s.isVisible ? "-open" : "-closed") // used for classNames + // INIT RESIZER BAR + , $R = $Rs[pane] = $("<div></div>") + // INIT TOGGLER BUTTON + , $T = (o.closable ? $Ts[pane] = $("<div></div>") : false) + ; + + //if (s.isVisible && o.resizable) ... handled by initResizable + if (!s.isVisible && o.slidable) + $R.attr("title", o.sliderTip).css("cursor", o.sliderCursor); + + $R + // if paneSelector is an ID, then create a matching ID for the resizer, eg: "#paneLeft" => "paneLeft-resizer" + .attr("id", (o.paneSelector.substr(0,1)=="#" ? o.paneSelector.substr(1) + "-resizer" : "")) + .data("parentLayout", Instance) + .data("layoutRole", "resizer") + .data("layoutEdge", pane) + .css(_c.resizers.cssReq).css("zIndex", _c.zIndex.resizer_normal) + .css(o.applyDemoStyles ? _c.resizers.cssDemo : {}) // add demo styles + .addClass(rClass +" "+ rClass+_pane) + .appendTo($Container) // append DIV to container + ; + + if ($T) { + $T + // if paneSelector is an ID, then create a matching ID for the resizer, eg: "#paneLeft" => "#paneLeft-toggler" + .attr("id", (o.paneSelector.substr(0,1)=="#" ? o.paneSelector.substr(1) + "-toggler" : "")) + .data("parentLayout", Instance) + .data("layoutRole", "toggler") + .data("layoutEdge", pane) + .css(_c.togglers.cssReq) // add base/required styles + .css(o.applyDemoStyles ? _c.togglers.cssDemo : {}) // add demo styles + .addClass(tClass +" "+ tClass+_pane) + .appendTo($R) // append SPAN to resizer DIV + ; + // ADD INNER-SPANS TO TOGGLER + if (o.togglerContent_open) // ui-layout-open + $("<span>"+ o.togglerContent_open +"</span>") + .data("layoutRole", "togglerContent") + .data("layoutEdge", pane) + .addClass("content content-open") + .css("display","none") + .appendTo( $T ) + //.hover( addHover, removeHover ) // use ui-layout-toggler-west-hover .content-open instead! + ; + if (o.togglerContent_closed) // ui-layout-closed + $("<span>"+ o.togglerContent_closed +"</span>") + .data("layoutRole", "togglerContent") + .data("layoutEdge", pane) + .addClass("content content-closed") + .css("display","none") + .appendTo( $T ) + //.hover( addHover, removeHover ) // use ui-layout-toggler-west-hover .content-closed instead! + ; + // ADD TOGGLER.click/.hover + enableClosable(pane); + } + + // add Draggable events + initResizable(pane); + + // ADD CLASSNAMES & SLIDE-BINDINGS - eg: class="resizer resizer-west resizer-open" + if (s.isVisible) + setAsOpen(pane); // onOpen will be called, but NOT onResize + else { + setAsClosed(pane); // onClose will be called + bindStartSlidingEvent(pane, true); // will enable events IF option is set + } + + }); + + // SET ALL HANDLE DIMENSIONS + sizeHandles("all"); + }; + + + /** + * Initialize scrolling ui-layout-content div - if exists + * + * @see initPane() - or externally after an Ajax injection + * @param {string} pane The pane to process + * @param {boolean=} resize Size content after init, default = true + */ + var initContent = function (pane, resize) { + var + o = options[pane] + , sel = o.contentSelector + , $P = $Ps[pane] + , $C + ; + if (sel) $C = $Cs[pane] = (o.findNestedContent) + ? $P.find(sel).eq(0) // match 1-element only + : $P.children(sel).eq(0) + ; + if ($C && $C.length) { + // SAVE original Pane CSS + if (!$C.data("layoutCSS")) + $C.data("layoutCSS", getElemCSS($C, "height")); + $C.css( _c.content.cssReq ); + if (o.applyDemoStyles) { + $C.css( _c.content.cssDemo ); // add padding & overflow: auto to content-div + $P.css( _c.content.cssDemoPane ); // REMOVE padding/scrolling from pane + } + state[pane].content = {}; // init content state + if (resize !== false) sizeContent(pane); + // sizeContent() is called AFTER init of all elements + } + else + $Cs[pane] = false; + }; + + + /** + * Searches for .ui-layout-button-xxx elements and auto-binds them as layout-buttons + * + * @see _create() + */ + var initButtons = function () { + var pre = "ui-layout-button-", name; + $.each("toggle,open,close,pin,toggle-slide,open-slide".split(","), function (i, action) { + $.each(_c.borderPanes.split(","), function (ii, pane) { + $("."+pre+action+"-"+pane).each(function(){ + // if button was previously 'bound', data.layoutName was set, but is blank if layout has no 'name' + name = $(this).data("layoutName") || $(this).attr("layoutName"); + if (name == undefined || name == options.name) + bindButton(this, action, pane); + }); + }); + }); + }; + + /** + * Add resize-bars to all panes that specify it in options + * -dependancy: $.fn.resizable - will skip if not found + * + * @see _create() + * @param {string=} panes The edge(s) to process, blank = all + */ + var initResizable = function (panes) { + var + draggingAvailable = (typeof $.fn.draggable == "function") + , $Frames, side // set in start() + ; + if (!panes || panes == "all") panes = _c.borderPanes; + + $.each(panes.split(","), function (idx, pane) { + var + o = options[pane] + , s = state[pane] + , c = _c[pane] + , side = (c.dir=="horz" ? "top" : "left") + , r, live // set in start because may change + ; + if (!draggingAvailable || !$Ps[pane] || !o.resizable) { + o.resizable = false; + return true; // skip to next + } + + var + $P = $Ps[pane] + , $R = $Rs[pane] + , base = o.resizerClass + // 'drag' classes are applied to the ORIGINAL resizer-bar while dragging is in process + , resizerClass = base+"-drag" // resizer-drag + , resizerPaneClass = base+"-"+pane+"-drag" // resizer-north-drag + // 'helper' class is applied to the CLONED resizer-bar while it is being dragged + , helperClass = base+"-dragging" // resizer-dragging + , helperPaneClass = base+"-"+pane+"-dragging" // resizer-north-dragging + , helperLimitClass = base+"-dragging-limit" // resizer-drag + , helperPaneLimitClass = base+"-"+pane+"-dragging-limit" // resizer-north-drag + , helperClassesSet = false // logic var + ; + + if (!s.isClosed) + $R + .attr("title", o.resizerTip) + .css("cursor", o.resizerCursor) // n-resize, s-resize, etc + ; + + $R.bind("mouseenter."+ sID, onResizerEnter) + .bind("mouseleave."+ sID, onResizerLeave); + + $R.draggable({ + containment: $Container[0] // limit resizing to layout container + , axis: (c.dir=="horz" ? "y" : "x") // limit resizing to horz or vert axis + , delay: 0 + , distance: 1 + // basic format for helper - style it using class: .ui-draggable-dragging + , helper: "clone" + , opacity: o.resizerDragOpacity + , addClasses: false // avoid ui-state-disabled class when disabled + //, iframeFix: o.draggableIframeFix // TODO: consider using when bug is fixed + , zIndex: _c.zIndex.resizer_drag + + , start: function (e, ui) { + // REFRESH options & state pointers in case we used swapPanes + o = options[pane]; + s = state[pane]; + // re-read options + live = o.resizeWhileDragging; + + // ondrag_start callback - will CANCEL hide if returns false + // TODO: dragging CANNOT be cancelled like this, so see if there is a way? + if (false === _execCallback(pane, o.ondrag_start)) return false; + + _c.isLayoutBusy = true; // used by sizePane() logic during a liveResize + s.isResizing = true; // prevent pane from closing while resizing + timer.clear(pane+"_closeSlider"); // just in case already triggered + + // SET RESIZER LIMITS - used in drag() + setSizeLimits(pane); // update pane/resizer state + r = s.resizerPosition; + + $R.addClass( resizerClass +" "+ resizerPaneClass ); // add drag classes + helperClassesSet = false; // reset logic var - see drag() + + // MASK PANES WITH IFRAMES OR OTHER TROUBLESOME ELEMENTS + $Frames = $(o.maskIframesOnResize === true ? "iframe" : o.maskIframesOnResize).filter(":visible"); + var id, i=0; // ID incrementer - used when 'resizing' masks during dynamic resizing + $Frames.each(function() { + id = "ui-layout-mask-"+ (++i); + $(this).data("layoutMaskID", id); // tag iframe with corresponding maskID + $('<div id="'+ id +'" class="ui-layout-mask ui-layout-mask-'+ pane +'"/>') + .css({ + background: "#fff" + , opacity: "0.001" + , zIndex: _c.zIndex.iframe_mask + , position: "absolute" + , width: this.offsetWidth+"px" + , height: this.offsetHeight+"px" + }) + .css($(this).position()) // top & left -- changed from offset() + .appendTo(this.parentNode) // put mask-div INSIDE pane to avoid zIndex issues + ; + }); + + // DISABLE TEXT SELECTION (probably already done by resizer.mouseOver) + $('body').disableSelection(); + } + + , drag: function (e, ui) { + if (!helperClassesSet) { // can only add classes after clone has been added to the DOM + //$(".ui-draggable-dragging") + ui.helper + .addClass( helperClass +" "+ helperPaneClass ) // add helper classes + .css({ right: "auto", bottom: "auto" }) // fix dir="rtl" issue + .children().css("visibility","hidden") // hide toggler inside dragged resizer-bar + ; + helperClassesSet = true; + // draggable bug!? RE-SET zIndex to prevent E/W resize-bar showing through N/S pane! + if (s.isSliding) $Ps[pane].css("zIndex", _c.zIndex.pane_sliding); + } + // CONTAIN RESIZER-BAR TO RESIZING LIMITS + var limit = 0; + if (ui.position[side] < r.min) { + ui.position[side] = r.min; + limit = -1; + } + else if (ui.position[side] > r.max) { + ui.position[side] = r.max; + limit = 1; + } + // ADD/REMOVE dragging-limit CLASS + if (limit) { + ui.helper.addClass( helperLimitClass +" "+ helperPaneLimitClass ); // at dragging-limit + window.defaultStatus = "Panel has reached its " + + ((limit>0 && pane.match(/north|west/)) || (limit<0 && pane.match(/south|east/)) ? "maximum" : "minimum") +" size"; + } + else { + ui.helper.removeClass( helperLimitClass +" "+ helperPaneLimitClass ); // not at dragging-limit + window.defaultStatus = ""; + } + // DYNAMICALLY RESIZE PANES IF OPTION ENABLED + if (live) resizePanes(e, ui, pane); + } + + , stop: function (e, ui) { + $('body').enableSelection(); // RE-ENABLE TEXT SELECTION + window.defaultStatus = ""; // clear 'resizing limit' message from statusbar + $R.removeClass( resizerClass +" "+ resizerPaneClass ); // remove drag classes from Resizer + s.isResizing = false; + _c.isLayoutBusy = false; // set BEFORE resizePanes so other logic can pick it up + resizePanes(e, ui, pane, true); // true = resizingDone + } + + }); + + /** + * resizePanes + * + * Sub-routine called from stop() and optionally drag() + * + * @param {!Object} evt + * @param {!Object} ui + * @param {string} pane + * @param {boolean=} resizingDone + */ + var resizePanes = function (evt, ui, pane, resizingDone) { + var + dragPos = ui.position + , c = _c[pane] + , resizerPos, newSize + , i = 0 // ID incrementer + ; + switch (pane) { + case "north": resizerPos = dragPos.top; break; + case "west": resizerPos = dragPos.left; break; + case "south": resizerPos = sC.offsetHeight - dragPos.top - o.spacing_open; break; + case "east": resizerPos = sC.offsetWidth - dragPos.left - o.spacing_open; break; + }; + + if (resizingDone) { + // Remove OR Resize MASK(S) created in drag.start + $("div.ui-layout-mask").each(function() { this.parentNode.removeChild(this); }); + //$("div.ui-layout-mask").remove(); // TODO: Is this less efficient? + + // ondrag_start callback - will CANCEL hide if returns false + if (false === _execCallback(pane, o.ondrag_end || o.ondrag)) return false; + } + else + $Frames.each(function() { + $("#"+ $(this).data("layoutMaskID")) // get corresponding mask by ID + .css($(this).position()) // update top & left + .css({ // update width & height + width: this.offsetWidth +"px" + , height: this.offsetHeight+"px" + }) + ; + }); + + // remove container margin from resizer position to get the pane size + newSize = resizerPos - sC["inset"+ c.side]; + manualSizePane(pane, newSize); + } + }); + }; + + + /** + * Destroy this layout and reset all elements + */ + var destroy = function () { + // UNBIND layout events and remove global object + $(window).unbind("."+ sID); + $(document).unbind("."+ sID); + + // loop all panes to remove layout classes, attributes and bindings + $.each(_c.allPanes.split(","), function (i, pane) { + removePane( pane, false, true ); // true = skipResize + }); + + // reset layout-container + var $C = $Container + .removeData("layout") + .removeData("layoutContainer") + .removeClass(options.containerClass) + ; + + // do NOT reset container CSS if is a 'pane' in an outer-layout - ie, THIS layout is 'nested' + if (!$C.data("layoutEdge") && $C.data("layoutCSS")) // RESET CSS + $C.css( $C.data("layoutCSS") ).removeData("layoutCSS"); + + // for full-page layouts, also reset the <HTML> CSS + if (sC.tagName == "BODY" && ($C = $("html")).data("layoutCSS")) // RESET <HTML> CSS + $C.css( $C.data("layoutCSS") ).removeData("layoutCSS"); + + // trigger state-management and onunload callback + unload(); + }; + + /** + * Remove a pane from the layout - subroutine of destroy() + * + * @see destroy() + * @param {string} pane The pane to process + * @param {boolean=} remove Remove the DOM element? default = false + * @param {boolean=} skipResize Skip calling resizeAll()? default = false + */ + var removePane = function (pane, remove, skipResize) { + if (!$Ps[pane]) return; // NO SUCH PANE + var + $P = $Ps[pane] + , $C = $Cs[pane] + , $R = $Rs[pane] + , $T = $Ts[pane] + // create list of ALL pane-classes that need to be removed + , _open = "-open" + , _sliding= "-sliding" + , _closed = "-closed" + , root = options[pane].paneClass // default="ui-layout-pane" + , pRoot = root +"-"+ pane // eg: "ui-layout-pane-west" + , classes = [ root, root+_open, root+_closed, root+_sliding, // generic classes + pRoot, pRoot+_open, pRoot+_closed, pRoot+_sliding ] // pane-specific classes + ; + $.merge(classes, getHoverClasses($P, true)); // ADD hover-classes + + if (!$P || !$P.length) { + } // pane has already been deleted! + else if (remove && !$P.data("layoutContainer") && (!$C || !$C.length || !$C.data("layoutContainer"))) + $P.remove(); + else { + $P .removeClass( classes.join(" ") ) // remove ALL pane-classes + .removeData("layoutParent") + .removeData("layoutRole") + .removeData("layoutEdge") + .removeData("autoHidden") // in case set + .unbind("."+ sID) // remove ALL Layout events + // TODO: remove these extra unbind commands when jQuery is fixed + //.unbind("mouseenter"+ sID) + //.unbind("mouseleave"+ sID) + ; + // do NOT reset CSS if this pane is STILL the container of a nested layout! + // the nested layout will reset its 'container' when/if it is destroyed + if (!$P.data("layoutContainer")) + $P.css( $P.data("layoutCSS") ).removeData("layoutCSS"); + // DITTO for the Content elem + if ($C && $C.length && !$C.data("layoutContainer")) + $C.css( $C.data("layoutCSS") ).removeData("layoutCSS"); + } + + // REMOVE pane's resizer and toggler elements + if ($T && $T.length) $T.remove(); + if ($R && $R.length) $R.remove(); + + // CLEAR all pointers and data + $Ps[pane] = $Cs[pane] = $Rs[pane] = $Ts[pane] = false; + + // skip resize & state-clear when called from destroy() + if (!skipResize) { + resizeAll(); + state[pane] = {}; + } + }; + + +/* + * ########################### + * ACTION METHODS + * ########################### + */ + + /** + * Completely 'hides' a pane, including its spacing - as if it does not exist + * The pane is not actually 'removed' from the source, so can use 'show' to un-hide it + * + * @param {string} pane The pane being hidden, ie: north, south, east, or west + * @param {boolean=} noAnimation + */ + var hide = function (pane, noAnimation) { + var + o = options[pane] + , s = state[pane] + , $P = $Ps[pane] + , $R = $Rs[pane] + ; + if (!$P || s.isHidden) return; // pane does not exist OR is already hidden + + // onhide_start callback - will CANCEL hide if returns false + if (state.initialized && false === _execCallback(pane, o.onhide_start)) return; + + s.isSliding = false; // just in case + + // now hide the elements + if ($R) $R.hide(); // hide resizer-bar + if (!state.initialized || s.isClosed) { + s.isClosed = true; // to trigger open-animation on show() + s.isHidden = true; + s.isVisible = false; + $P.hide(); // no animation when loading page + sizeMidPanes(_c[pane].dir == "horz" ? "all" : "center"); + if (state.initialized || o.triggerEventsOnLoad) + _execCallback(pane, o.onhide_end || o.onhide); + } + else { + s.isHiding = true; // used by onclose + close(pane, false, noAnimation); // adjust all panes to fit + } + }; + + /** + * Show a hidden pane - show as 'closed' by default unless openPane = true + * + * @param {string} pane The pane being opened, ie: north, south, east, or west + * @param {boolean=} openPane + * @param {boolean=} noAnimation + * @param {boolean=} noAlert + */ + var show = function (pane, openPane, noAnimation, noAlert) { + var + o = options[pane] + , s = state[pane] + , $P = $Ps[pane] + , $R = $Rs[pane] + ; + if (!$P || !s.isHidden) return; // pane does not exist OR is not hidden + + // onshow_start callback - will CANCEL show if returns false + if (false === _execCallback(pane, o.onshow_start)) return; + + s.isSliding = false; // just in case + s.isShowing = true; // used by onopen/onclose + //s.isHidden = false; - will be set by open/close - if not cancelled + + // now show the elements + //if ($R) $R.show(); - will be shown by open/close + if (openPane === false) + close(pane, true); // true = force + else + open(pane, false, noAnimation, noAlert); // adjust all panes to fit + }; + + + /** + * Toggles a pane open/closed by calling either open or close + * + * @param {string} pane The pane being toggled, ie: north, south, east, or west + * @param {boolean=} slide + */ + var toggle = function (pane, slide) { + if (!isStr(pane)) { + pane.stopImmediatePropagation(); // pane = event + pane = $(this).data("layoutEdge"); // bound to $R.dblclick + } + var s = state[str(pane)]; + if (s.isHidden) + show(pane); // will call 'open' after unhiding it + else if (s.isClosed) + open(pane, !!slide); + else + close(pane); + }; + + + /** + * Utility method used during init or other auto-processes + * + * @param {string} pane The pane being closed + * @param {boolean=} setHandles + */ + var _closePane = function (pane, setHandles) { + var + $P = $Ps[pane] + , s = state[pane] + ; + $P.hide(); + s.isClosed = true; + s.isVisible = false; + // UNUSED: if (setHandles) setAsClosed(pane, true); // true = force + }; + + /** + * Close the specified pane (animation optional), and resize all other panes as needed + * + * @param {string} pane The pane being closed, ie: north, south, east, or west + * @param {boolean=} force + * @param {boolean=} noAnimation + * @param {boolean=} skipCallback + */ + var close = function (pane, force, noAnimation, skipCallback) { + if (!state.initialized) { + _closePane(pane) + return; + } + var + $P = $Ps[pane] + , $R = $Rs[pane] + , $T = $Ts[pane] + , o = options[pane] + , s = state[pane] + , doFX = !noAnimation && !s.isClosed && (o.fxName_close != "none") + // transfer logic vars to temp vars + , isShowing = s.isShowing + , isHiding = s.isHiding + , wasSliding = s.isSliding + ; + // now clear the logic vars + delete s.isShowing; + delete s.isHiding; + + if (!$P || (!o.closable && !isShowing && !isHiding)) return; // invalid request // (!o.resizable && !o.closable) ??? + else if (!force && s.isClosed && !isShowing) return; // already closed + + if (_c.isLayoutBusy) { // layout is 'busy' - probably with an animation + _queue("close", pane, force); // set a callback for this action, if possible + return; // ABORT + } + + // onclose_start callback - will CANCEL hide if returns false + // SKIP if just 'showing' a hidden pane as 'closed' + if (!isShowing && false === _execCallback(pane, o.onclose_start)) return; + + // SET flow-control flags + _c[pane].isMoving = true; + _c.isLayoutBusy = true; + + s.isClosed = true; + s.isVisible = false; + // update isHidden BEFORE sizing panes + if (isHiding) s.isHidden = true; + else if (isShowing) s.isHidden = false; + + if (s.isSliding) // pane is being closed, so UNBIND trigger events + bindStopSlidingEvents(pane, false); // will set isSliding=false + else // resize panes adjacent to this one + sizeMidPanes(_c[pane].dir == "horz" ? "all" : "center", false); // false = NOT skipCallback + + // if this pane has a resizer bar, move it NOW - before animation + setAsClosed(pane); + + // CLOSE THE PANE + if (doFX) { // animate the close + lockPaneForFX(pane, true); // need to set left/top so animation will work + $P.hide( o.fxName_close, o.fxSettings_close, o.fxSpeed_close, function () { + lockPaneForFX(pane, false); // undo + close_2(); + }); + } + else { // hide the pane without animation + $P.hide(); + close_2(); + }; + + // SUBROUTINE + function close_2 () { + if (s.isClosed) { // make sure pane was not 'reopened' before animation finished! + + bindStartSlidingEvent(pane, true); // will enable if o.slidable = true + + // if opposite-pane was autoClosed, see if it can be autoOpened now + var altPane = _c.altSide[pane]; + if (state[ altPane ].noRoom) { + setSizeLimits( altPane ); + makePaneFit( altPane ); + } + + if (!skipCallback && (state.initialized || o.triggerEventsOnLoad)) { + // onclose callback - UNLESS just 'showing' a hidden pane as 'closed' + if (!isShowing) _execCallback(pane, o.onclose_end || o.onclose); + // onhide OR onshow callback + if (isShowing) _execCallback(pane, o.onshow_end || o.onshow); + if (isHiding) _execCallback(pane, o.onhide_end || o.onhide); + } + } + // execute internal flow-control callback + _dequeue(pane); + } + }; + + /** + * @param {string} pane The pane just closed, ie: north, south, east, or west + */ + var setAsClosed = function (pane) { + var + $P = $Ps[pane] + , $R = $Rs[pane] + , $T = $Ts[pane] + , o = options[pane] + , s = state[pane] + , side = _c[pane].side.toLowerCase() + , inset = "inset"+ _c[pane].side + , rClass = o.resizerClass + , tClass = o.togglerClass + , _pane = "-"+ pane // used for classNames + , _open = "-open" + , _sliding= "-sliding" + , _closed = "-closed" + ; + $R + .css(side, sC[inset]) // move the resizer + .removeClass( rClass+_open +" "+ rClass+_pane+_open ) + .removeClass( rClass+_sliding +" "+ rClass+_pane+_sliding ) + .addClass( rClass+_closed +" "+ rClass+_pane+_closed ) + .unbind("dblclick."+ sID) + ; + // DISABLE 'resizing' when closed - do this BEFORE bindStartSlidingEvent? + if (o.resizable && typeof $.fn.draggable == "function") + $R + .draggable("disable") + .removeClass("ui-state-disabled") // do NOT apply disabled styling - not suitable here + .css("cursor", "default") + .attr("title","") + ; + + // if pane has a toggler button, adjust that too + if ($T) { + $T + .removeClass( tClass+_open +" "+ tClass+_pane+_open ) + .addClass( tClass+_closed +" "+ tClass+_pane+_closed ) + .attr("title", o.togglerTip_closed) // may be blank + ; + // toggler-content - if exists + $T.children(".content-open").hide(); + $T.children(".content-closed").css("display","block"); + } + + // sync any 'pin buttons' + syncPinBtns(pane, false); + + if (state.initialized) { + // resize 'length' and position togglers for adjacent panes + sizeHandles("all"); + } + }; + + /** + * Open the specified pane (animation optional), and resize all other panes as needed + * + * @param {string} pane The pane being opened, ie: north, south, east, or west + * @param {boolean=} slide + * @param {boolean=} noAnimation + * @param {boolean=} noAlert + */ + var open = function (pane, slide, noAnimation, noAlert) { + var + $P = $Ps[pane] + , $R = $Rs[pane] + , $T = $Ts[pane] + , o = options[pane] + , s = state[pane] + , doFX = !noAnimation && s.isClosed && (o.fxName_open != "none") + // transfer logic var to temp var + , isShowing = s.isShowing + ; + // now clear the logic var + delete s.isShowing; + + if (!$P || (!o.resizable && !o.closable && !isShowing)) return; // invalid request + else if (s.isVisible && !s.isSliding) return; // already open + + // pane can ALSO be unhidden by just calling show(), so handle this scenario + if (s.isHidden && !isShowing) { + show(pane, true); + return; + } + + if (_c.isLayoutBusy) { // layout is 'busy' - probably with an animation + _queue("open", pane, slide); // set a callback for this action, if possible + return; // ABORT + } + + setSizeLimits(pane, slide); // update pane-state + + // onopen_start callback - will CANCEL hide if returns false + if (false === _execCallback(pane, o.onopen_start)) return; + + // make sure there is enough space available to open the pane + if (s.minSize > s.maxSize) { // INSUFFICIENT ROOM FOR PANE TO OPEN! + syncPinBtns(pane, false); // make sure pin-buttons are reset + if (!noAlert && o.noRoomToOpenTip) alert(o.noRoomToOpenTip); + return; // ABORT + } + + // SET flow-control flags + _c[pane].isMoving = true; + _c.isLayoutBusy = true; + + if (slide) // START Sliding - will set isSliding=true + bindStopSlidingEvents(pane, true); // BIND trigger events to close sliding-pane + else if (s.isSliding) // PIN PANE (stop sliding) - open pane 'normally' instead + bindStopSlidingEvents(pane, false); // UNBIND trigger events - will set isSliding=false + else if (o.slidable) + bindStartSlidingEvent(pane, false); // UNBIND trigger events + + s.noRoom = false; // will be reset by makePaneFit if 'noRoom' + makePaneFit(pane); + + s.isVisible = true; + s.isClosed = false; + // update isHidden BEFORE sizing panes - WHY??? Old? + if (isShowing) s.isHidden = false; + + if (doFX) { // ANIMATE + lockPaneForFX(pane, true); // need to set left/top so animation will work + $P.show( o.fxName_open, o.fxSettings_open, o.fxSpeed_open, function() { + lockPaneForFX(pane, false); // undo + open_2(); // continue + }); + } + else {// no animation + $P.show(); // just show pane and... + open_2(); // continue + }; + + // SUBROUTINE + function open_2 () { + if (s.isVisible) { // make sure pane was not closed or hidden before animation finished! + + // cure iframe display issues + _fixIframe(pane); + + // NOTE: if isSliding, then other panes are NOT 'resized' + if (!s.isSliding) // resize all panes adjacent to this one + sizeMidPanes(_c[pane].dir=="vert" ? "center" : "all", false); // false = NOT skipCallback + + // set classes, position handles and execute callbacks... + setAsOpen(pane); + } + + // internal flow-control callback + _dequeue(pane); + }; + + }; + + /** + * @param {string} pane The pane just opened, ie: north, south, east, or west + * @param {boolean=} skipCallback + */ + var setAsOpen = function (pane, skipCallback) { + var + $P = $Ps[pane] + , $R = $Rs[pane] + , $T = $Ts[pane] + , o = options[pane] + , s = state[pane] + , side = _c[pane].side.toLowerCase() + , inset = "inset"+ _c[pane].side + , rClass = o.resizerClass + , tClass = o.togglerClass + , _pane = "-"+ pane // used for classNames + , _open = "-open" + , _closed = "-closed" + , _sliding= "-sliding" + ; + $R + .css(side, sC[inset] + getPaneSize(pane)) // move the resizer + .removeClass( rClass+_closed +" "+ rClass+_pane+_closed ) + .addClass( rClass+_open +" "+ rClass+_pane+_open ) + ; + if (s.isSliding) + $R.addClass( rClass+_sliding +" "+ rClass+_pane+_sliding ) + else // in case 'was sliding' + $R.removeClass( rClass+_sliding +" "+ rClass+_pane+_sliding ) + + if (o.resizerDblClickToggle) + $R.bind("dblclick", toggle ); + removeHover( 0, $R ); // remove hover classes + if (o.resizable && typeof $.fn.draggable == "function") + $R + .draggable("enable") + .css("cursor", o.resizerCursor) + .attr("title", o.resizerTip) + ; + else if (!s.isSliding) + $R.css("cursor", "default"); // n-resize, s-resize, etc + + // if pane also has a toggler button, adjust that too + if ($T) { + $T + .removeClass( tClass+_closed +" "+ tClass+_pane+_closed ) + .addClass( tClass+_open +" "+ tClass+_pane+_open ) + .attr("title", o.togglerTip_open) // may be blank + ; + removeHover( 0, $T ); // remove hover classes + // toggler-content - if exists + $T.children(".content-closed").hide(); + $T.children(".content-open").css("display","block"); + } + + // sync any 'pin buttons' + syncPinBtns(pane, !s.isSliding); + + // update pane-state dimensions - BEFORE resizing content + $.extend(s, getElemDims($P)); + + if (state.initialized) { + // resize resizer & toggler sizes for all panes + sizeHandles("all"); + // resize content every time pane opens - to be sure + sizeContent(pane, true); // true = remeasure headers/footers, even if 'isLayoutBusy' + } + + if (!skipCallback && (state.initialized || o.triggerEventsOnLoad) && $P.is(":visible")) { + // onopen callback + _execCallback(pane, o.onopen_end || o.onopen); + // onshow callback - TODO: should this be here? + if (s.isShowing) _execCallback(pane, o.onshow_end || o.onshow); + // ALSO call onresize because layout-size *may* have changed while pane was closed + if (state.initialized) { + _execCallback(pane, o.onresize_end || o.onresize); + resizeNestedLayout(pane); + } + } + }; + + + /** + * slideOpen / slideClose / slideToggle + * + * Pass-though methods for sliding + */ + var slideOpen = function (evt_or_pane) { + var + evt = isStr(evt_or_pane) ? null : evt_or_pane + , pane = evt ? $(this).data("layoutEdge") : evt_or_pane + , s = state[pane] + , delay = options[pane].slideDelay_open + ; + // prevent event from triggering on NEW resizer binding created below + if (evt) evt.stopImmediatePropagation(); + + if (s.isClosed && evt && evt.type == "mouseenter" && delay > 0) + // trigger = mouseenter - use a delay + timer.set(pane+"_openSlider", open_NOW, delay); + else + open_NOW(); // will unbind events if is already open + + /** + * SUBROUTINE for timed open + */ + function open_NOW (evt) { + if (!s.isClosed) // skip if no longer closed! + bindStopSlidingEvents(pane, true); // BIND trigger events to close sliding-pane + else if (!_c[pane].isMoving) + open(pane, true); // true = slide - open() will handle binding + }; + }; + + var slideClose = function (evt_or_pane) { + var + evt = isStr(evt_or_pane) ? null : evt_or_pane + , pane = evt ? $(this).data("layoutEdge") : evt_or_pane + , o = options[pane] + , s = state[pane] + , delay = _c[pane].isMoving ? 1000 : 300 // MINIMUM delay - option may override + ; + + if (s.isClosed || s.isResizing) + return; // skip if already closed OR in process of resizing + else if (o.slideTrigger_close == "click") + close_NOW(); // close immediately onClick + else if (o.preventQuickSlideClose && _c.isLayoutBusy) + return; // handle Chrome quick-close on slide-open + else if (o.preventPrematureSlideClose && evt && $.layout.isMouseOverElem(evt, $Ps[pane])) + return; // handle incorrect mouseleave trigger, like when over a SELECT-list in IE + else if (evt) // trigger = mouseleave - use a delay + // 1 sec delay if 'opening', else .3 sec + timer.set(pane+"_closeSlider", close_NOW, max(o.slideDelay_close, delay)); + else // called programically + close_NOW(); + + /** + * SUBROUTINE for timed close + */ + function close_NOW () { + if (s.isClosed) // skip 'close' if already closed! + bindStopSlidingEvents(pane, false); // UNBIND trigger events - TODO: is this needed here? + else if (!_c[pane].isMoving) + close(pane); // close will handle unbinding + }; + }; + + var slideToggle = function (pane) { toggle(pane, true); }; + + + /** + * Must set left/top on East/South panes so animation will work properly + * + * @param {string} pane The pane to lock, 'east' or 'south' - any other is ignored! + * @param {boolean} doLock true = set left/top, false = remove + */ + var lockPaneForFX = function (pane, doLock) { + var $P = $Ps[pane]; + if (doLock) { + $P.css({ zIndex: _c.zIndex.pane_animate }); // overlay all elements during animation + if (pane=="south") + $P.css({ top: sC.insetTop + sC.innerHeight - $P.outerHeight() }); + else if (pane=="east") + $P.css({ left: sC.insetLeft + sC.innerWidth - $P.outerWidth() }); + } + else { // animation DONE - RESET CSS + // TODO: see if this can be deleted. It causes a quick-close when sliding in Chrome + $P.css({ zIndex: (state[pane].isSliding ? _c.zIndex.pane_sliding : _c.zIndex.pane_normal) }); + if (pane=="south") + $P.css({ top: "auto" }); + else if (pane=="east") + $P.css({ left: "auto" }); + // fix anti-aliasing in IE - only needed for animations that change opacity + var o = options[pane]; + if (state.browser.msie && o.fxOpacityFix && o.fxName_open != "slide" && $P.css("filter") && $P.css("opacity") == 1) + $P[0].style.removeAttribute('filter'); + } + }; + + + /** + * Toggle sliding functionality of a specific pane on/off by adding removing 'slide open' trigger + * + * @see open(), close() + * @param {string} pane The pane to enable/disable, 'north', 'south', etc. + * @param {boolean} enable Enable or Disable sliding? + */ + var bindStartSlidingEvent = function (pane, enable) { + var + o = options[pane] + , $P = $Ps[pane] + , $R = $Rs[pane] + , trigger = o.slideTrigger_open.toLowerCase() + ; + if (!$R || (enable && !o.slidable)) return; + + // make sure we have a valid event + if (trigger.match(/mouseover/)) + trigger = o.slideTrigger_open = "mouseenter"; + else if (!trigger.match(/click|dblclick|mouseenter/)) + trigger = o.slideTrigger_open = "click"; + + $R + // add or remove trigger event + [enable ? "bind" : "unbind"](trigger +'.'+ sID, slideOpen) + // set the appropriate cursor & title/tip + .css("cursor", enable ? o.sliderCursor : "default") + .attr("title", enable ? o.sliderTip : "") + ; + }; + + /** + * Add or remove 'mouseleave' events to 'slide close' when pane is 'sliding' open or closed + * Also increases zIndex when pane is sliding open + * See bindStartSlidingEvent for code to control 'slide open' + * + * @see slideOpen(), slideClose() + * @param {string} pane The pane to process, 'north', 'south', etc. + * @param {boolean} enable Enable or Disable events? + */ + var bindStopSlidingEvents = function (pane, enable) { + var + o = options[pane] + , s = state[pane] + , z = _c.zIndex + , trigger = o.slideTrigger_close.toLowerCase() + , action = (enable ? "bind" : "unbind") + , $P = $Ps[pane] + , $R = $Rs[pane] + ; + s.isSliding = enable; // logic + timer.clear(pane+"_closeSlider"); // just in case + + // remove 'slideOpen' trigger event from resizer + // ALSO will raise the zIndex of the pane & resizer + if (enable) bindStartSlidingEvent(pane, false); + + // RE/SET zIndex - increases when pane is sliding-open, resets to normal when not + $P.css("zIndex", enable ? z.pane_sliding : z.pane_normal); + $R.css("zIndex", enable ? z.pane_sliding : z.resizer_normal); + + // make sure we have a valid event + if (!trigger.match(/click|mouseleave/)) + trigger = o.slideTrigger_close = "mouseleave"; // also catches 'mouseout' + + // add/remove slide triggers + $R[action](trigger, slideClose); // base event on resize + // need extra events for mouseleave + if (trigger == "mouseleave") { + // also close on pane.mouseleave + $P[action]("mouseleave."+ sID, slideClose); + // cancel timer when mouse moves between 'pane' and 'resizer' + $R[action]("mouseenter."+ sID, cancelMouseOut); + $P[action]("mouseenter."+ sID, cancelMouseOut); + } + + if (!enable) + timer.clear(pane+"_closeSlider"); + else if (trigger == "click" && !o.resizable) { + // IF pane is not resizable (which already has a cursor and tip) + // then set the a cursor & title/tip on resizer when sliding + $R.css("cursor", enable ? o.sliderCursor : "default"); + $R.attr("title", enable ? o.togglerTip_open : ""); // use Toggler-tip, eg: "Close Pane" + } + + // SUBROUTINE for mouseleave timer clearing + function cancelMouseOut (evt) { + timer.clear(pane+"_closeSlider"); + evt.stopPropagation(); + } + }; + + + /** + * Hides/closes a pane if there is insufficient room - reverses this when there is room again + * MUST have already called setSizeLimits() before calling this method + * + * @param {string} pane The pane being resized + * @param {boolean=} isOpening Called from onOpen? + * @param {boolean=} skipCallback Should the onresize callback be run? + * @param {boolean=} force + */ + var makePaneFit = function (pane, isOpening, skipCallback, force) { + var + o = options[pane] + , s = state[pane] + , c = _c[pane] + , $P = $Ps[pane] + , $R = $Rs[pane] + , isSidePane = c.dir=="vert" + , hasRoom = false + ; + + // special handling for center & east/west panes + if (pane == "center" || (isSidePane && s.noVerticalRoom)) { + // see if there is enough room to display the pane + // ERROR: hasRoom = s.minHeight <= s.maxHeight && (isSidePane || s.minWidth <= s.maxWidth); + hasRoom = (s.maxHeight > 0); + if (hasRoom && s.noRoom) { // previously hidden due to noRoom, so show now + $P.show(); + if ($R) $R.show(); + s.isVisible = true; + s.noRoom = false; + if (isSidePane) s.noVerticalRoom = false; + _fixIframe(pane); + } + else if (!hasRoom && !s.noRoom) { // not currently hidden, so hide now + $P.hide(); + if ($R) $R.hide(); + s.isVisible = false; + s.noRoom = true; + } + } + + // see if there is enough room to fit the border-pane + if (pane == "center") { + // ignore center in this block + } + else if (s.minSize <= s.maxSize) { // pane CAN fit + hasRoom = true; + if (s.size > s.maxSize) // pane is too big - shrink it + sizePane(pane, s.maxSize, skipCallback, force); + else if (s.size < s.minSize) // pane is too small - enlarge it + sizePane(pane, s.minSize, skipCallback, force); + else if ($R && $P.is(":visible")) { + // make sure resizer-bar is positioned correctly + // handles situation where nested layout was 'hidden' when initialized + var + side = c.side.toLowerCase() + , pos = s.size + sC["inset"+ c.side] + ; + if (_cssNum($R, side) != pos) $R.css( side, pos ); + } + + // if was previously hidden due to noRoom, then RESET because NOW there is room + if (s.noRoom) { + // s.noRoom state will be set by open or show + if (s.wasOpen && o.closable) { + if (o.autoReopen) + open(pane, false, true, true); // true = noAnimation, true = noAlert + else // leave the pane closed, so just update state + s.noRoom = false; + } + else + show(pane, s.wasOpen, true, true); // true = noAnimation, true = noAlert + } + } + else { // !hasRoom - pane CANNOT fit + if (!s.noRoom) { // pane not set as noRoom yet, so hide or close it now... + s.noRoom = true; // update state + s.wasOpen = !s.isClosed && !s.isSliding; + if (s.isClosed){} // SKIP + else if (o.closable) // 'close' if possible + close(pane, true, true); // true = force, true = noAnimation + else // 'hide' pane if cannot just be closed + hide(pane, true); // true = noAnimation + } + } + }; + + + /** + * sizePane / manualSizePane + * sizePane is called only by internal methods whenever a pane needs to be resized + * manualSizePane is an exposed flow-through method allowing extra code when pane is 'manually resized' + * + * @param {string} pane The pane being resized + * @param {number} size The *desired* new size for this pane - will be validated + * @param {boolean=} skipCallback Should the onresize callback be run? + */ + var manualSizePane = function (pane, size, skipCallback) { + // ANY call to sizePane will disabled autoResize + var + o = options[pane] + // if resizing callbacks have been delayed and resizing is now DONE, force resizing to complete... + , forceResize = o.resizeWhileDragging && !_c.isLayoutBusy // && !o.triggerEventsWhileDragging + ; + o.autoResize = false; + // flow-through... + sizePane(pane, size, skipCallback, forceResize); + } + + /** + * @param {string} pane The pane being resized + * @param {number} size The *desired* new size for this pane - will be validated + * @param {boolean=} skipCallback Should the onresize callback be run? + * @param {boolean=} force Force resizing even if does not seem necessary + */ + var sizePane = function (pane, size, skipCallback, force) { + var + o = options[pane] + , s = state[pane] + , $P = $Ps[pane] + , $R = $Rs[pane] + , side = _c[pane].side.toLowerCase() + , inset = "inset"+ _c[pane].side + , skipResizeWhileDragging = _c.isLayoutBusy && !o.triggerEventsWhileDragging + , oldSize + ; + // calculate 'current' min/max sizes + setSizeLimits(pane); // update pane-state + oldSize = s.size; + + size = _parseSize(pane, size); // handle percentages & auto + size = max(size, _parseSize(pane, o.minSize)); + size = min(size, s.maxSize); + if (size < s.minSize) { // not enough room for pane! + makePaneFit(pane, false, skipCallback); // will hide or close pane + return; + } + + // IF newSize is same as oldSize, then nothing to do - abort + if (!force && size == oldSize) return; + + // onresize_start callback CANNOT cancel resizing because this would break the layout! + if (!skipCallback && state.initialized && s.isVisible) + _execCallback(pane, o.onresize_start); + + // resize the pane, and make sure its visible + $P.css( _c[pane].sizeType.toLowerCase(), max(1, cssSize(pane, size)) ); + + // update pane-state dimensions + s.size = size; + $.extend(s, getElemDims($P)); + + // reposition the resizer-bar + if ($R && $P.is(":visible")) $R.css( side, size + sC[inset] ); + + sizeContent(pane); + + if (!skipCallback && !skipResizeWhileDragging && state.initialized && s.isVisible) { + _execCallback(pane, o.onresize_end || o.onresize); + resizeNestedLayout(pane); + } + + // resize all the adjacent panes, and adjust their toggler buttons + // when skipCallback passed, it means the controlling method will handle 'other panes' + if (!skipCallback) { + // also no callback if live-resize is in progress and NOT triggerEventsWhileDragging + if (!s.isSliding) sizeMidPanes(_c[pane].dir=="horz" ? "all" : "center", skipResizeWhileDragging, force); + sizeHandles("all"); + } + + // if opposite-pane was autoClosed, see if it can be autoOpened now + var altPane = _c.altSide[pane]; + if (size < oldSize && state[ altPane ].noRoom) { + setSizeLimits( altPane ); + makePaneFit( altPane, false, skipCallback ); + } + }; + + /** + * @see initPanes(), sizePane(), resizeAll(), open(), close(), hide() + * @param {string} panes The pane(s) being resized, comma-delmited string + * @param {boolean=} skipCallback Should the onresize callback be run? + * @param {boolean=} force + */ + var sizeMidPanes = function (panes, skipCallback, force) { + if (!panes || panes == "all") panes = "east,west,center"; + + $.each(panes.split(","), function (i, pane) { + if (!$Ps[pane]) return; // NO PANE - skip + var + o = options[pane] + , s = state[pane] + , $P = $Ps[pane] + , $R = $Rs[pane] + , isCenter= (pane=="center") + , hasRoom = true + , CSS = {} + , d = calcNewCenterPaneDims() + ; + // update pane-state dimensions + $.extend(s, getElemDims($P)); + + if (pane == "center") { + if (!force && s.isVisible && d.width == s.outerWidth && d.height == s.outerHeight) + return true; // SKIP - pane already the correct size + // set state for makePaneFit() logic + $.extend(s, cssMinDims(pane), { + maxWidth: d.width + , maxHeight: d.height + }); + CSS = d; + // convert OUTER width/height to CSS width/height + CSS.width = cssW(pane, d.width); + CSS.height = cssH(pane, d.height); + hasRoom = CSS.width > 0 && CSS.height > 0; + + // during layout init, try to shrink east/west panes to make room for center + if (!hasRoom && !state.initialized && o.minWidth > 0) { + var + reqPx = o.minWidth - s.outerWidth + , minE = options.east.minSize || 0 + , minW = options.west.minSize || 0 + , sizeE = state.east.size + , sizeW = state.west.size + , newE = sizeE + , newW = sizeW + ; + if (reqPx > 0 && state.east.isVisible && sizeE > minE) { + newE = max( sizeE-minE, sizeE-reqPx ); + reqPx -= sizeE-newE; + } + if (reqPx > 0 && state.west.isVisible && sizeW > minW) { + newW = max( sizeW-minW, sizeW-reqPx ); + reqPx -= sizeW-newW; + } + // IF we found enough extra space, then resize the border panes as calculated + if (reqPx == 0) { + if (sizeE != minE) + sizePane('east', newE, true); // true = skipCallback - initPanes will handle when done + if (sizeW != minW) + sizePane('west', newW, true); + // now start over! + sizeMidPanes('center', skipCallback, force); + return; // abort this loop + } + } + } + else { // for east and west, set only the height, which is same as center height + // set state.min/maxWidth/Height for makePaneFit() logic + if (s.isVisible && !s.noVerticalRoom) + $.extend(s, getElemDims($P), cssMinDims(pane)) + if (!force && !s.noVerticalRoom && d.height == s.outerHeight) + return true; // SKIP - pane already the correct size + CSS.top = d.top; + CSS.bottom = d.bottom; + CSS.height = cssH(pane, d.height); + s.maxHeight = max(0, CSS.height); + hasRoom = (s.maxHeight > 0); + if (!hasRoom) s.noVerticalRoom = true; // makePaneFit() logic + } + + if (hasRoom) { + // resizeAll passes skipCallback because it triggers callbacks after ALL panes are resized + if (!skipCallback && state.initialized) + _execCallback(pane, o.onresize_start); + + $P.css(CSS); // apply the CSS to pane + if (s.noRoom && !s.isClosed && !s.isHidden) + makePaneFit(pane); // will re-open/show auto-closed/hidden pane + if (s.isVisible) { + $.extend(s, getElemDims($P)); // update pane dimensions + if (state.initialized) sizeContent(pane); // also resize the contents, if exists + } + } + else if (!s.noRoom && s.isVisible) // no room for pane + makePaneFit(pane); // will hide or close pane + + if (!s.isVisible) + return true; // DONE - next pane + + /* + * Extra CSS for IE6 or IE7 in Quirks-mode - add 'width' to NORTH/SOUTH panes + * Normally these panes have only 'left' & 'right' positions so pane auto-sizes + * ALSO required when pane is an IFRAME because will NOT default to 'full width' + */ + if (pane == "center") { // finished processing midPanes + var b = state.browser; + var fix = b.isIE6 || (b.msie && !b.boxModel); + if ($Ps.north && (fix || state.north.tagName=="IFRAME")) + $Ps.north.css("width", cssW($Ps.north, sC.innerWidth)); + if ($Ps.south && (fix || state.south.tagName=="IFRAME")) + $Ps.south.css("width", cssW($Ps.south, sC.innerWidth)); + } + + // resizeAll passes skipCallback because it triggers callbacks after ALL panes are resized + if (!skipCallback && state.initialized) { + _execCallback(pane, o.onresize_end || o.onresize); + resizeNestedLayout(pane); + } + }); + }; + + + /** + * @see window.onresize(), callbacks or custom code + */ + var resizeAll = function () { + var + oldW = sC.innerWidth + , oldH = sC.innerHeight + ; + $.extend( state.container, getElemDims( $Container ) ); // UPDATE container dimensions + if (!sC.outerHeight) return; // cannot size layout when 'container' is hidden or collapsed + + // onresizeall_start will CANCEL resizing if returns false + // state.container has already been set, so user can access this info for calcuations + if (false === _execCallback(null, options.onresizeall_start)) return false; + + var + // see if container is now 'smaller' than before + shrunkH = (sC.innerHeight < oldH) + , shrunkW = (sC.innerWidth < oldW) + , $P, o, s, dir + ; + // NOTE special order for sizing: S-N-E-W + $.each(["south","north","east","west"], function (i, pane) { + if (!$Ps[pane]) return; // no pane - SKIP + s = state[pane]; + o = options[pane]; + dir = _c[pane].dir; + + if (o.autoResize && s.size != o.size) // resize pane to original size set in options + sizePane(pane, o.size, true, true); // true=skipCallback, true=forceResize + else { + setSizeLimits(pane); + makePaneFit(pane, false, true, true); // true=skipCallback, true=forceResize + } + }); + + sizeMidPanes("all", true, true); // true=skipCallback, true=forceResize + sizeHandles("all"); // reposition the toggler elements + + // trigger all individual pane callbacks AFTER layout has finished resizing + o = options; // reuse alias + $.each(_c.allPanes.split(","), function (i, pane) { + $P = $Ps[pane]; + if (!$P) return; // SKIP + if (state[pane].isVisible) { // undefined for non-existent panes + _execCallback(pane, o[pane].onresize_end || o[pane].onresize); // callback - if exists + resizeNestedLayout(pane); + } + }); + + _execCallback(null, o.onresizeall_end || o.onresizeall); // onresizeall callback, if exists + }; + + + /** + * Whenever a pane resizes or opens that has a nested layout, trigger resizeAll + * + * @param {string} pane The pane just resized or opened + */ + var resizeNestedLayout = function (pane) { + var + $P = $Ps[pane] + , $C = $Cs[pane] + , d = "layoutContainer" + ; + if (options[pane].resizeNestedLayout) { + if ($P.data( d )) + $P.layout().resizeAll(); + else if ($C && $C.data( d )) + $C.layout().resizeAll(); + } + }; + + + /** + * IF pane has a content-div, then resize all elements inside pane to fit pane-height + * + * @param {string=} panes The pane(s) being resized + * @param {boolean=} remeasure Should the content (header/footer) be remeasured? + */ + var sizeContent = function (panes, remeasure) { + if (!panes || panes == "all") panes = _c.allPanes; + $.each(panes.split(","), function (idx, pane) { + var + $P = $Ps[pane] + , $C = $Cs[pane] + , o = options[pane] + , s = state[pane] + , m = s.content // m = measurements + ; + if (!$P || !$C || !$P.is(":visible")) return true; // NOT VISIBLE - skip + + // onsizecontent_start will CANCEL resizing if returns false + if (false === _execCallback(null, o.onsizecontent_start)) return; + + // skip re-measuring offsets if live-resizing + if (!_c.isLayoutBusy || m.top == undefined || remeasure || o.resizeContentWhileDragging) { + _measure(); + // if any footers are below pane-bottom, they may not measure correctly, + // so allow pane overflow and re-measure + if (m.hiddenFooters > 0 && $P.css("overflow") == "hidden") { + $P.css("overflow", "visible"); + _measure(); // remeasure while overflowing + $P.css("overflow", "hidden"); + } + } + // NOTE: spaceAbove/Below *includes* the pane's paddingTop/Bottom, but not pane.borders + var newH = s.innerHeight - (m.spaceAbove - s.css.paddingTop) - (m.spaceBelow - s.css.paddingBottom); + if (!$C.is(":visible") || m.height != newH) { + // size the Content element to fit new pane-size - will autoHide if not enough room + setOuterHeight($C, newH, true); // true=autoHide + m.height = newH; // save new height + }; + + if (state.initialized) { + _execCallback(pane, o.onsizecontent_end || o.onsizecontent); + resizeNestedLayout(pane); + } + + + function _below ($E) { + return max(s.css.paddingBottom, (parseInt($E.css("marginBottom"), 10) || 0)); + }; + + function _measure () { + var + ignore = options[pane].contentIgnoreSelector + , $Fs = $C.nextAll().not(ignore || ':lt(0)') // not :lt(0) = ALL + , $Fs_vis = $Fs.filter(':visible') + , $F = $Fs_vis.filter(':last') + ; + m = { + top: $C[0].offsetTop + , height: $C.outerHeight() + , numFooters: $Fs.length + , hiddenFooters: $Fs.length - $Fs_vis.length + , spaceBelow: 0 // correct if no content footer ($E) + } + m.spaceAbove = m.top; // just for state - not used in calc + m.bottom = m.top + m.height; + if ($F.length) + //spaceBelow = (LastFooter.top + LastFooter.height) [footerBottom] - Content.bottom + max(LastFooter.marginBottom, pane.paddingBotom) + m.spaceBelow = ($F[0].offsetTop + $F.outerHeight()) - m.bottom + _below($F); + else // no footer - check marginBottom on Content element itself + m.spaceBelow = _below($C); + }; + }); + }; + + + /** + * Called every time a pane is opened, closed, or resized to slide the togglers to 'center' and adjust their length if necessary + * + * @see initHandles(), open(), close(), resizeAll() + * @param {string=} panes The pane(s) being resized + */ + var sizeHandles = function (panes) { + if (!panes || panes == "all") panes = _c.borderPanes; + + $.each(panes.split(","), function (i, pane) { + var + o = options[pane] + , s = state[pane] + , $P = $Ps[pane] + , $R = $Rs[pane] + , $T = $Ts[pane] + , $TC + ; + if (!$P || !$R) return; + + var + dir = _c[pane].dir + , _state = (s.isClosed ? "_closed" : "_open") + , spacing = o["spacing"+ _state] + , togAlign = o["togglerAlign"+ _state] + , togLen = o["togglerLength"+ _state] + , paneLen + , offset + , CSS = {} + ; + + if (spacing == 0) { + $R.hide(); + return; + } + else if (!s.noRoom && !s.isHidden) // skip if resizer was hidden for any reason + $R.show(); // in case was previously hidden + + // Resizer Bar is ALWAYS same width/height of pane it is attached to + if (dir == "horz") { // north/south + paneLen = $P.outerWidth(); // s.outerWidth || + s.resizerLength = paneLen; + $R.css({ + width: max(1, cssW($R, paneLen)) // account for borders & padding + , height: max(0, cssH($R, spacing)) // ditto + , left: _cssNum($P, "left") + }); + } + else { // east/west + paneLen = $P.outerHeight(); // s.outerHeight || + s.resizerLength = paneLen; + $R.css({ + height: max(1, cssH($R, paneLen)) // account for borders & padding + , width: max(0, cssW($R, spacing)) // ditto + , top: sC.insetTop + getPaneSize("north", true) // TODO: what if no North pane? + //, top: _cssNum($Ps["center"], "top") + }); + } + + // remove hover classes + removeHover( o, $R ); + + if ($T) { + if (togLen == 0 || (s.isSliding && o.hideTogglerOnSlide)) { + $T.hide(); // always HIDE the toggler when 'sliding' + return; + } + else + $T.show(); // in case was previously hidden + + if (!(togLen > 0) || togLen == "100%" || togLen > paneLen) { + togLen = paneLen; + offset = 0; + } + else { // calculate 'offset' based on options.PANE.togglerAlign_open/closed + if (isStr(togAlign)) { + switch (togAlign) { + case "top": + case "left": offset = 0; + break; + case "bottom": + case "right": offset = paneLen - togLen; + break; + case "middle": + case "center": + default: offset = Math.floor((paneLen - togLen) / 2); // 'default' catches typos + } + } + else { // togAlign = number + var x = parseInt(togAlign, 10); // + if (togAlign >= 0) offset = x; + else offset = paneLen - togLen + x; // NOTE: x is negative! + } + } + + if (dir == "horz") { // north/south + var width = cssW($T, togLen); + $T.css({ + width: max(0, width) // account for borders & padding + , height: max(1, cssH($T, spacing)) // ditto + , left: offset // TODO: VERIFY that toggler positions correctly for ALL values + , top: 0 + }); + // CENTER the toggler content SPAN + $T.children(".content").each(function(){ + $TC = $(this); + $TC.css("marginLeft", Math.floor((width-$TC.outerWidth())/2)); // could be negative + }); + } + else { // east/west + var height = cssH($T, togLen); + $T.css({ + height: max(0, height) // account for borders & padding + , width: max(1, cssW($T, spacing)) // ditto + , top: offset // POSITION the toggler + , left: 0 + }); + // CENTER the toggler content SPAN + $T.children(".content").each(function(){ + $TC = $(this); + $TC.css("marginTop", Math.floor((height-$TC.outerHeight())/2)); // could be negative + }); + } + + // remove ALL hover classes + removeHover( 0, $T ); + } + + // DONE measuring and sizing this resizer/toggler, so can be 'hidden' now + if (!state.initialized && (o.initHidden || s.noRoom)) { + $R.hide(); + if ($T) $T.hide(); + } + }); + }; + + + var enableClosable = function (pane) { + var $T = $Ts[pane], o = options[pane]; + if (!$T) return; + o.closable = true; + $T .bind("click."+ sID, function(evt){ evt.stopPropagation(); toggle(pane); }) + .bind("mouseenter."+ sID, addHover) + .bind("mouseleave."+ sID, removeHover) + .css("visibility", "visible") + .css("cursor", "pointer") + .attr("title", state[pane].isClosed ? o.togglerTip_closed : o.togglerTip_open) // may be blank + .show() + ; + }; + + var disableClosable = function (pane, hide) { + var $T = $Ts[pane]; + if (!$T) return; + options[pane].closable = false; + // is closable is disable, then pane MUST be open! + if (state[pane].isClosed) open(pane, false, true); + $T .unbind("."+ sID) + .css("visibility", hide ? "hidden" : "visible") // instead of hide(), which creates logic issues + .css("cursor", "default") + .attr("title", "") + ; + }; + + + var enableSlidable = function (pane) { + var $R = $Rs[pane], o = options[pane]; + if (!$R || !$R.data('draggable')) return; + options[pane].slidable = true; + if (s.isClosed) + bindStartSlidingEvent(pane, true); + }; + + var disableSlidable = function (pane) { + var $R = $Rs[pane]; + if (!$R) return; + options[pane].slidable = false; + if (state[pane].isSliding) + close(pane, false, true); + else { + bindStartSlidingEvent(pane, false); + $R .css("cursor", "default") + .attr("title", "") + ; + removeHover(null, $R[0]); // in case currently hovered + } + }; + + + var enableResizable = function (pane) { + var $R = $Rs[pane], o = options[pane]; + if (!$R || !$R.data('draggable')) return; + o.resizable = true; + $R .draggable("enable") + .bind("mouseenter."+ sID, onResizerEnter) + .bind("mouseleave."+ sID, onResizerLeave) + ; + if (!state[pane].isClosed) + $R .css("cursor", o.resizerCursor) + .attr("title", o.resizerTip) + ; + }; + + var disableResizable = function (pane) { + var $R = $Rs[pane]; + if (!$R || !$R.data('draggable')) return; + options[pane].resizable = false; + $R .draggable("disable") + .unbind("."+ sID) + .css("cursor", "default") + .attr("title", "") + ; + removeHover(null, $R[0]); // in case currently hovered + }; + + + /** + * Move a pane from source-side (eg, west) to target-side (eg, east) + * If pane exists on target-side, move that to source-side, ie, 'swap' the panes + * + * @param {string} pane1 The pane/edge being swapped + * @param {string} pane2 ditto + */ + var swapPanes = function (pane1, pane2) { + // change state.edge NOW so callbacks can know where pane is headed... + state[pane1].edge = pane2; + state[pane2].edge = pane1; + // run these even if NOT state.initialized + var cancelled = false; + if (false === _execCallback(pane1, options[pane1].onswap_start)) cancelled = true; + if (!cancelled && false === _execCallback(pane2, options[pane2].onswap_start)) cancelled = true; + if (cancelled) { + state[pane1].edge = pane1; // reset + state[pane2].edge = pane2; + return; + } + + var + oPane1 = copy( pane1 ) + , oPane2 = copy( pane2 ) + , sizes = {} + ; + sizes[pane1] = oPane1 ? oPane1.state.size : 0; + sizes[pane2] = oPane2 ? oPane2.state.size : 0; + + // clear pointers & state + $Ps[pane1] = false; + $Ps[pane2] = false; + state[pane1] = {}; + state[pane2] = {}; + + // ALWAYS remove the resizer & toggler elements + if ($Ts[pane1]) $Ts[pane1].remove(); + if ($Ts[pane2]) $Ts[pane2].remove(); + if ($Rs[pane1]) $Rs[pane1].remove(); + if ($Rs[pane2]) $Rs[pane2].remove(); + $Rs[pane1] = $Rs[pane2] = $Ts[pane1] = $Ts[pane2] = false; + + // transfer element pointers and data to NEW Layout keys + move( oPane1, pane2 ); + move( oPane2, pane1 ); + + // cleanup objects + oPane1 = oPane2 = sizes = null; + + // make panes 'visible' again + if ($Ps[pane1]) $Ps[pane1].css(_c.visible); + if ($Ps[pane2]) $Ps[pane2].css(_c.visible); + + // fix any size discrepancies caused by swap + resizeAll(); + + // run these even if NOT state.initialized + _execCallback(pane1, options[pane1].onswap_end || options[pane1].onswap); + _execCallback(pane2, options[pane2].onswap_end || options[pane2].onswap); + + return; + + function copy (n) { // n = pane + var + $P = $Ps[n] + , $C = $Cs[n] + ; + return !$P ? false : { + pane: n + , P: $P ? $P[0] : false + , C: $C ? $C[0] : false + , state: $.extend({}, state[n]) + , options: $.extend({}, options[n]) + } + }; + + function move (oPane, pane) { + if (!oPane) return; + var + P = oPane.P + , C = oPane.C + , oldPane = oPane.pane + , c = _c[pane] + , side = c.side.toLowerCase() + , inset = "inset"+ c.side + // save pane-options that should be retained + , s = $.extend({}, state[pane]) + , o = options[pane] + // RETAIN side-specific FX Settings - more below + , fx = { resizerCursor: o.resizerCursor } + , re, size, pos + ; + $.each("fxName,fxSpeed,fxSettings".split(","), function (i, k) { + fx[k] = o[k]; + fx[k +"_open"] = o[k +"_open"]; + fx[k +"_close"] = o[k +"_close"]; + }); + + // update object pointers and attributes + $Ps[pane] = $(P) + .data("layoutEdge", pane) + .css(_c.hidden) + .css(c.cssReq) + ; + $Cs[pane] = C ? $(C) : false; + + // set options and state + options[pane] = $.extend({}, oPane.options, fx); + state[pane] = $.extend({}, oPane.state); + + // change classNames on the pane, eg: ui-layout-pane-east ==> ui-layout-pane-west + re = new RegExp(o.paneClass +"-"+ oldPane, "g"); + P.className = P.className.replace(re, o.paneClass +"-"+ pane); + + // ALWAYS regenerate the resizer & toggler elements + initHandles(pane); // create the required resizer & toggler + + // if moving to different orientation, then keep 'target' pane size + if (c.dir != _c[oldPane].dir) { + size = sizes[pane] || 0; + setSizeLimits(pane); // update pane-state + size = max(size, state[pane].minSize); + // use manualSizePane to disable autoResize - not useful after panes are swapped + manualSizePane(pane, size, true); // true = skipCallback + } + else // move the resizer here + $Rs[pane].css(side, sC[inset] + (state[pane].isVisible ? getPaneSize(pane) : 0)); + + + // ADD CLASSNAMES & SLIDE-BINDINGS + if (oPane.state.isVisible && !s.isVisible) + setAsOpen(pane, true); // true = skipCallback + else { + setAsClosed(pane); + bindStartSlidingEvent(pane, true); // will enable events IF option is set + } + + // DESTROY the object + oPane = null; + }; + }; + + + /** + * Capture keys when enableCursorHotkey - toggle pane if hotkey pressed + * + * @see document.keydown() + */ + function keyDown (evt) { + if (!evt) return true; + var code = evt.keyCode; + if (code < 33) return true; // ignore special keys: ENTER, TAB, etc + + var + PANE = { + 38: "north" // Up Cursor - $.ui.keyCode.UP + , 40: "south" // Down Cursor - $.ui.keyCode.DOWN + , 37: "west" // Left Cursor - $.ui.keyCode.LEFT + , 39: "east" // Right Cursor - $.ui.keyCode.RIGHT + } + , ALT = evt.altKey // no worky! + , SHIFT = evt.shiftKey + , CTRL = evt.ctrlKey + , CURSOR = (CTRL && code >= 37 && code <= 40) + , o, k, m, pane + ; + + if (CURSOR && options[PANE[code]].enableCursorHotkey) // valid cursor-hotkey + pane = PANE[code]; + else if (CTRL || SHIFT) // check to see if this matches a custom-hotkey + $.each(_c.borderPanes.split(","), function (i, p) { // loop each pane to check its hotkey + o = options[p]; + k = o.customHotkey; + m = o.customHotkeyModifier; // if missing or invalid, treated as "CTRL+SHIFT" + if ((SHIFT && m=="SHIFT") || (CTRL && m=="CTRL") || (CTRL && SHIFT)) { // Modifier matches + if (k && code == (isNaN(k) || k <= 9 ? k.toUpperCase().charCodeAt(0) : k)) { // Key matches + pane = p; + return false; // BREAK + } + } + }); + + // validate pane + if (!pane || !$Ps[pane] || !options[pane].closable || state[pane].isHidden) + return true; + + toggle(pane); + + evt.stopPropagation(); + evt.returnValue = false; // CANCEL key + return false; + }; + + +/* + * ###################################### + * UTILITY METHODS + * called externally or by initButtons + * ###################################### + */ + + /** + * Change/reset a pane's overflow setting & zIndex to allow popups/drop-downs to work + * + * @param {Object=} el (optional) Can also be 'bound' to a click, mouseOver, or other event + */ + function allowOverflow (el) { + if (this && this.tagName) el = this; // BOUND to element + var $P; + if (isStr(el)) + $P = $Ps[el]; + else if ($(el).data("layoutRole")) + $P = $(el); + else + $(el).parents().each(function(){ + if ($(this).data("layoutRole")) { + $P = $(this); + return false; // BREAK + } + }); + if (!$P || !$P.length) return; // INVALID + + var + pane = $P.data("layoutEdge") + , s = state[pane] + ; + + // if pane is already raised, then reset it before doing it again! + // this would happen if allowOverflow is attached to BOTH the pane and an element + if (s.cssSaved) + resetOverflow(pane); // reset previous CSS before continuing + + // if pane is raised by sliding or resizing, or it's closed, then abort + if (s.isSliding || s.isResizing || s.isClosed) { + s.cssSaved = false; + return; + } + + var + newCSS = { zIndex: (_c.zIndex.pane_normal + 2) } + , curCSS = {} + , of = $P.css("overflow") + , ofX = $P.css("overflowX") + , ofY = $P.css("overflowY") + ; + // determine which, if any, overflow settings need to be changed + if (of != "visible") { + curCSS.overflow = of; + newCSS.overflow = "visible"; + } + if (ofX && !ofX.match(/visible|auto/)) { + curCSS.overflowX = ofX; + newCSS.overflowX = "visible"; + } + if (ofY && !ofY.match(/visible|auto/)) { + curCSS.overflowY = ofX; + newCSS.overflowY = "visible"; + } + + // save the current overflow settings - even if blank! + s.cssSaved = curCSS; + + // apply new CSS to raise zIndex and, if necessary, make overflow 'visible' + $P.css( newCSS ); + + // make sure the zIndex of all other panes is normal + $.each(_c.allPanes.split(","), function(i, p) { + if (p != pane) resetOverflow(p); + }); + + }; + + function resetOverflow (el) { + if (this && this.tagName) el = this; // BOUND to element + var $P; + if (isStr(el)) + $P = $Ps[el]; + else if ($(el).data("layoutRole")) + $P = $(el); + else + $(el).parents().each(function(){ + if ($(this).data("layoutRole")) { + $P = $(this); + return false; // BREAK + } + }); + if (!$P || !$P.length) return; // INVALID + + var + pane = $P.data("layoutEdge") + , s = state[pane] + , CSS = s.cssSaved || {} + ; + // reset the zIndex + if (!s.isSliding && !s.isResizing) + $P.css("zIndex", _c.zIndex.pane_normal); + + // reset Overflow - if necessary + $P.css( CSS ); + + // clear var + s.cssSaved = false; + }; + + + /** + * Helper function to validate params received by addButton utilities + * + * Two classes are added to the element, based on the buttonClass... + * The type of button is appended to create the 2nd className: + * - ui-layout-button-pin + * - ui-layout-pane-button-toggle + * - ui-layout-pane-button-open + * - ui-layout-pane-button-close + * + * @param {(string|!Object)} selector jQuery selector (or element) for button, eg: ".ui-layout-north .toggle-button" + * @param {string} pane Name of the pane the button is for: 'north', 'south', etc. + * @return {Array.<Object>} If both params valid, the element matching 'selector' in a jQuery wrapper - otherwise returns null + */ + function getBtn (selector, pane, action) { + var $E = $(selector); + if (!$E.length) // element not found + alert(lang.errButton + lang.selector +": "+ selector); + else if (_c.borderPanes.indexOf(pane) == -1) // invalid 'pane' sepecified + alert(lang.errButton + lang.Pane.toLowerCase() +": "+ pane); + else { // VALID + var btn = options[pane].buttonClass +"-"+ action; + $E + .addClass( btn +" "+ btn +"-"+ pane ) + .data("layoutName", options.name) // add layout identifier - even if blank! + ; + return $E; + } + return null; // INVALID + }; + + + /** + * NEW syntax for binding layout-buttons - will eventually replace addToggleBtn, addOpenBtn, etc. + * + * @param {(string|!Object)} selector jQuery selector (or element) for button, eg: ".ui-layout-north .toggle-button" + * @param {string} action + * @param {string} pane + */ + function bindButton (selector, action, pane) { + switch (action.toLowerCase()) { + case "toggle": addToggleBtn(selector, pane); break; + case "open": addOpenBtn(selector, pane); break; + case "close": addCloseBtn(selector, pane); break; + case "pin": addPinBtn(selector, pane); break; + case "toggle-slide": addToggleBtn(selector, pane, true); break; + case "open-slide": addOpenBtn(selector, pane, true); break; + } + }; + + /** + * Add a custom Toggler button for a pane + * + * @param {(string|!Object)} selector jQuery selector (or element) for button, eg: ".ui-layout-north .toggle-button" + * @param {string} pane Name of the pane the button is for: 'north', 'south', etc. + * @param {boolean=} slide true = slide-open, false = pin-open + */ + function addToggleBtn (selector, pane, slide) { + var $E = getBtn(selector, pane, "toggle"); + if ($E) + $E.click(function (evt) { + toggle(pane, !!slide); + evt.stopPropagation(); + }); + }; + + /** + * Add a custom Open button for a pane + * + * @param {(string|!Object)} selector jQuery selector (or element) for button, eg: ".ui-layout-north .toggle-button" + * @param {string} pane Name of the pane the button is for: 'north', 'south', etc. + * @param {boolean=} slide true = slide-open, false = pin-open + */ + function addOpenBtn (selector, pane, slide) { + var $E = getBtn(selector, pane, "open"); + if ($E) + $E + .attr("title", lang.Open) + .click(function (evt) { + open(pane, !!slide); + evt.stopPropagation(); + }) + ; + }; + + /** + * Add a custom Close button for a pane + * + * @param {(string|!Object)} selector jQuery selector (or element) for button, eg: ".ui-layout-north .toggle-button" + * @param {string} pane Name of the pane the button is for: 'north', 'south', etc. + */ + function addCloseBtn (selector, pane) { + var $E = getBtn(selector, pane, "close"); + if ($E) + $E + .attr("title", lang.Close) + .click(function (evt) { + close(pane); + evt.stopPropagation(); + }) + ; + }; + + /** + * addPinBtn + * + * Add a custom Pin button for a pane + * + * Four classes are added to the element, based on the paneClass for the associated pane... + * Assuming the default paneClass and the pin is 'up', these classes are added for a west-pane pin: + * - ui-layout-pane-pin + * - ui-layout-pane-west-pin + * - ui-layout-pane-pin-up + * - ui-layout-pane-west-pin-up + * + * @param {(string|!Object)} selector jQuery selector (or element) for button, eg: ".ui-layout-north .toggle-button" + * @param {string} pane Name of the pane the pin is for: 'north', 'south', etc. + */ + function addPinBtn (selector, pane) { + var $E = getBtn(selector, pane, "pin"); + if ($E) { + var s = state[pane]; + $E.click(function (evt) { + setPinState($(this), pane, (s.isSliding || s.isClosed)); + if (s.isSliding || s.isClosed) open( pane ); // change from sliding to open + else close( pane ); // slide-closed + evt.stopPropagation(); + }); + // add up/down pin attributes and classes + setPinState($E, pane, (!s.isClosed && !s.isSliding)); + // add this pin to the pane data so we can 'sync it' automatically + // PANE.pins key is an array so we can store multiple pins for each pane + _c[pane].pins.push( selector ); // just save the selector string + } + }; + + /** + * INTERNAL function to sync 'pin buttons' when pane is opened or closed + * Unpinned means the pane is 'sliding' - ie, over-top of the adjacent panes + * + * @see open(), close() + * @param {string} pane These are the params returned to callbacks by layout() + * @param {boolean} doPin True means set the pin 'down', False means 'up' + */ + function syncPinBtns (pane, doPin) { + $.each(_c[pane].pins, function (i, selector) { + setPinState($(selector), pane, doPin); + }); + }; + + /** + * Change the class of the pin button to make it look 'up' or 'down' + * + * @see addPinBtn(), syncPinBtns() + * @param {Array.<Object>} $Pin The pin-span element in a jQuery wrapper + * @param {string} pane These are the params returned to callbacks by layout() + * @param {boolean} doPin true = set the pin 'down', false = set it 'up' + */ + function setPinState ($Pin, pane, doPin) { + var updown = $Pin.attr("pin"); + if (updown && doPin == (updown=="down")) return; // already in correct state + var + pin = options[pane].buttonClass +"-pin" + , side = pin +"-"+ pane + , UP = pin +"-up "+ side +"-up" + , DN = pin +"-down "+side +"-down" + ; + $Pin + .attr("pin", doPin ? "down" : "up") // logic + .attr("title", doPin ? lang.Unpin : lang.Pin) + .removeClass( doPin ? UP : DN ) + .addClass( doPin ? DN : UP ) + ; + }; + + + /* + * LAYOUT STATE MANAGEMENT + * + * @example .layout({ cookie: { name: "myLayout", keys: "west.isClosed,east.isClosed" } }) + * @example .layout({ cookie__name: "myLayout", cookie__keys: "west.isClosed,east.isClosed" }) + * @example myLayout.getState( "west.isClosed,north.size,south.isHidden" ); + * @example myLayout.saveCookie( "west.isClosed,north.size,south.isHidden", {expires: 7} ); + * @example myLayout.deleteCookie(); + * @example myLayout.loadCookie(); + * @example var hSaved = myLayout.state.cookie; + */ + + function isCookiesEnabled () { + // TODO: is the cookieEnabled property common enough to be useful??? + return (navigator.cookieEnabled != 0); + }; + + /** + * Read & return data from the cookie - as JSON + * + * @param {Object=} opts + */ + function getCookie (opts) { + var + o = $.extend( {}, options.cookie, opts || {} ) + , name = o.name || options.name || "Layout" + , c = document.cookie + , cs = c ? c.split(';') : [] + , pair // loop var + ; + for (var i=0, n=cs.length; i < n; i++) { + pair = $.trim(cs[i]).split('='); // name=value pair + if (pair[0] == name) // found the layout cookie + // convert cookie string back to a hash + return decodeJSON( decodeURIComponent(pair[1]) ); + } + return ""; + }; + + /** + * Get the current layout state and save it to a cookie + * + * @param {(string|Array)=} keys + * @param {Object=} opts + */ + function saveCookie (keys, opts) { + var + o = $.extend( {}, options.cookie, opts || {} ) + , name = o.name || options.name || "Layout" + , params = '' + , date = '' + , clear = false + ; + if (o.expires.toUTCString) + date = o.expires; + else if (typeof o.expires == 'number') { + date = new Date(); + if (o.expires > 0) + date.setDate(date.getDate() + o.expires); + else { + date.setYear(1970); + clear = true; + } + } + if (date) params += ';expires='+ date.toUTCString(); + if (o.path) params += ';path='+ o.path; + if (o.domain) params += ';domain='+ o.domain; + if (o.secure) params += ';secure'; + + if (clear) { + state.cookie = {}; // clear data + document.cookie = name +'='+ params; // expire the cookie + } + else { + state.cookie = getState(keys || o.keys); // read current panes-state + document.cookie = name +'='+ encodeURIComponent( encodeJSON(state.cookie) ) + params; // write cookie + } + + return $.extend({}, state.cookie); // return COPY of state.cookie + }; + + /** + * Remove the state cookie + */ + function deleteCookie () { + saveCookie('', { expires: -1 }); + }; + + /** + * Get data from the cookie and USE IT to loadState + * + * @param {Object=} opts + */ + function loadCookie (opts) { + var o = getCookie(opts); // READ the cookie + if (o) { + state.cookie = $.extend({}, o); // SET state.cookie + loadState(o); // LOAD the retrieved state + } + return o; + }; + + /** + * Update layout options from the cookie, if one exists + * + * @param {Object=} opts + * @param {boolean=} animate + */ + function loadState (opts, animate) { + $.extend( true, options, opts ); // update layout options + // if layout has already been initialized, then UPDATE layout state + if (state.initialized) { + var pane, o, v, a = !animate; + $.each(_c.allPanes.split(","), function (idx, pane) { + o = opts[ pane ]; + if (typeof o != 'object') return; // no key, continue + v = o.initHidden; + if (v === true) hide(pane, a); + if (v === false) show(pane, false, a); + v = o.size; + if (v > 0) sizePane(pane, v); + v = o.initClosed; + if (v === true) close(pane, false, a); + if (v === false) open(pane, false, a ); + }); + } + }; + + /** + * Get the *current layout state* and return it as a hash + * + * @param {(string|Array)=} keys + */ + function getState (keys) { + var + data = {} + , alt = { isClosed: 'initClosed', isHidden: 'initHidden' } + , pair, pane, key, val + ; + if (!keys) keys = options.cookie.keys; // if called by user + if ($.isArray(keys)) keys = keys.join(","); + // convert keys to an array and change delimiters from '__' to '.' + keys = keys.replace(/__/g, ".").split(','); + // loop keys and create a data hash + for (var i=0,n=keys.length; i < n; i++) { + pair = keys[i].split("."); + pane = pair[0]; + key = pair[1]; + if (_c.allPanes.indexOf(pane) < 0) continue; // bad pane! + val = state[ pane ][ key ]; + if (val == undefined) continue; + if (key=="isClosed" && state[pane]["isSliding"]) + val = true; // if sliding, then *really* isClosed + ( data[pane] || (data[pane]={}) )[ alt[key] ? alt[key] : key ] = val; + } + return data; + }; + + /** + * Stringify a JSON hash so can save in a cookie or db-field + */ + function encodeJSON (JSON) { + return parse( JSON ); + function parse (h) { + var D=[], i=0, k, v, t; // k = key, v = value + for (k in h) { + v = h[k]; + t = typeof v; + if (t == 'string') // STRING - add quotes + v = '"'+ v +'"'; + else if (t == 'object') // SUB-KEY - recurse into it + v = parse(v); + D[i++] = '"'+ k +'":'+ v; + } + return "{"+ D.join(",") +"}"; + }; + }; + + /** + * Convert stringified JSON back to a hash object + */ + function decodeJSON (str) { + try { return window["eval"]("("+ str +")") || {}; } + catch (e) { return {}; } + }; + + +/* + * ##################### + * CREATE/RETURN LAYOUT + * ##################### + */ + + // validate that container exists + var $Container = $(this).eq(0); // FIRST matching Container element + if (!$Container.length) { + //alert( lang.errContainerMissing ); + return null; + }; + // Users retreive Instance of a layout with: $Container.layout() OR $Container.data("layout") + // return the Instance-pointer if layout has already been initialized + if ($Container.data("layoutContainer") && $Container.data("layout")) + return $Container.data("layout"); // cached pointer + + // init global vars + var + $Ps = {} // Panes x5 - set in initPanes() + , $Cs = {} // Content x5 - set in initPanes() + , $Rs = {} // Resizers x4 - set in initHandles() + , $Ts = {} // Togglers x4 - set in initHandles() + // aliases for code brevity + , sC = state.container // alias for easy access to 'container dimensions' + , sID = state.id // alias for unique layout ID/namespace - eg: "layout435" + ; + + // create Instance object to expose data & option Properties, and primary action Methods + var Instance = { + options: options // property - options hash + , state: state // property - dimensions hash + , container: $Container // property - object pointers for layout container + , panes: $Ps // property - object pointers for ALL Panes: panes.north, panes.center + , contents: $Cs // property - object pointers for ALL Content: content.north, content.center + , resizers: $Rs // property - object pointers for ALL Resizers, eg: resizers.north + , togglers: $Ts // property - object pointers for ALL Togglers, eg: togglers.north + , toggle: toggle // method - pass a 'pane' ("north", "west", etc) + , hide: hide // method - ditto + , show: show // method - ditto + , open: open // method - ditto + , close: close // method - ditto + , slideOpen: slideOpen // method - ditto + , slideClose: slideClose // method - ditto + , slideToggle: slideToggle // method - ditto + , initContent: initContent // method - ditto + , sizeContent: sizeContent // method - pass a 'pane' + , sizePane: manualSizePane // method - pass a 'pane' AND an 'outer-size' in pixels or percent, or 'auto' + , swapPanes: swapPanes // method - pass TWO 'panes' - will swap them + , resizeAll: resizeAll // method - no parameters + , destroy: destroy // method - no parameters + , addPane: addPane // method - pass a 'pane' + , removePane: removePane // method - pass a 'pane' to remove from layout, add 'true' to delete the pane-elem + , setSizeLimits: setSizeLimits // method - pass a 'pane' - update state min/max data + , bindButton: bindButton // utility - pass element selector, 'action' and 'pane' (E, "toggle", "west") + , addToggleBtn: addToggleBtn // utility - pass element selector and 'pane' (E, "west") + , addOpenBtn: addOpenBtn // utility - ditto + , addCloseBtn: addCloseBtn // utility - ditto + , addPinBtn: addPinBtn // utility - ditto + , allowOverflow: allowOverflow // utility - pass calling element (this) + , resetOverflow: resetOverflow // utility - ditto + , encodeJSON: encodeJSON // method - pass a JSON object + , decodeJSON: decodeJSON // method - pass a string of encoded JSON + , getState: getState // method - returns hash of current layout-state + , getCookie: getCookie // method - update options from cookie - returns hash of cookie data + , saveCookie: saveCookie // method - optionally pass keys-list and cookie-options (hash) + , deleteCookie: deleteCookie // method + , loadCookie: loadCookie // method - update options from cookie - returns hash of cookie data + , loadState: loadState // method - pass a hash of state to use to update options + , cssWidth: cssW // utility - pass element and target outerWidth + , cssHeight: cssH // utility - ditto + , enableClosable: enableClosable + , disableClosable: disableClosable + , enableSlidable: enableSlidable + , disableSlidable: disableSlidable + , enableResizable: enableResizable + , disableResizable: disableResizable + }; + // create the border layout NOW + _create(); + + // return the Instance object + return Instance; + +} +})( jQuery );
@@ -0,0 +1,121 @@++/*+ * Superfish v1.4.8 - jQuery menu widget+ * Copyright (c) 2008 Joel Birch+ *+ * Dual licensed under the MIT and GPL licenses:+ * http://www.opensource.org/licenses/mit-license.php+ * http://www.gnu.org/licenses/gpl.html+ *+ * CHANGELOG: http://users.tpg.com.au/j_birch/plugins/superfish/changelog.txt+ */++;(function($){+ $.fn.superfish = function(op){++ var sf = $.fn.superfish,+ c = sf.c,+ $arrow = $(['<span class="',c.arrowClass,'"> »</span>'].join('')),+ over = function(){+ var $$ = $(this), menu = getMenu($$);+ clearTimeout(menu.sfTimer);+ $$.showSuperfishUl().siblings().hideSuperfishUl();+ },+ out = function(){+ var $$ = $(this), menu = getMenu($$), o = sf.op;+ clearTimeout(menu.sfTimer);+ menu.sfTimer=setTimeout(function(){+ o.retainPath=($.inArray($$[0],o.$path)>-1);+ $$.hideSuperfishUl();+ if (o.$path.length && $$.parents(['li.',o.hoverClass].join('')).length<1){over.call(o.$path);}+ },o.delay); + },+ getMenu = function($menu){+ var menu = $menu.parents(['ul.',c.menuClass,':first'].join(''))[0];+ sf.op = sf.o[menu.serial];+ return menu;+ },+ addArrow = function($a){ $a.addClass(c.anchorClass).append($arrow.clone()); };+ + return this.each(function() {+ var s = this.serial = sf.o.length;+ var o = $.extend({},sf.defaults,op);+ o.$path = $('li.'+o.pathClass,this).slice(0,o.pathLevels).each(function(){+ $(this).addClass([o.hoverClass,c.bcClass].join(' '))+ .filter('li:has(ul)').removeClass(o.pathClass);+ });+ sf.o[s] = sf.op = o;+ + $('li:has(ul)',this)[($.fn.hoverIntent && !o.disableHI) ? 'hoverIntent' : 'hover'](over,out).each(function() {+ if (o.autoArrows) addArrow( $('>a:first-child',this) );+ })+ .not('.'+c.bcClass)+ .hideSuperfishUl();+ + var $a = $('a',this);+ $a.each(function(i){+ var $li = $a.eq(i).parents('li');+ $a.eq(i).focus(function(){over.call($li);}).blur(function(){out.call($li);});+ });+ o.onInit.call(this);+ + }).each(function() {+ var menuClasses = [c.menuClass];+ if (sf.op.dropShadows && !($.browser.msie && $.browser.version < 7)) menuClasses.push(c.shadowClass);+ $(this).addClass(menuClasses.join(' '));+ });+ };++ var sf = $.fn.superfish;+ sf.o = [];+ sf.op = {};+ sf.IE7fix = function(){+ var o = sf.op;+ if ($.browser.msie && $.browser.version > 6 && o.dropShadows && o.animation.opacity!=undefined)+ this.toggleClass(sf.c.shadowClass+'-off');+ };+ sf.c = {+ bcClass : 'sf-breadcrumb',+ menuClass : 'sf-js-enabled',+ anchorClass : 'sf-with-ul',+ arrowClass : 'sf-sub-indicator',+ shadowClass : 'sf-shadow'+ };+ sf.defaults = {+ hoverClass : 'sfHover',+ pathClass : 'overideThisToUse',+ pathLevels : 1,+ delay : 800,+ animation : {opacity:'show'},+ speed : 'normal',+ autoArrows : true,+ dropShadows : true,+ disableHI : false, // true disables hoverIntent detection+ onInit : function(){}, // callback functions+ onBeforeShow: function(){},+ onShow : function(){},+ onHide : function(){}+ };+ $.fn.extend({+ hideSuperfishUl : function(){+ var o = sf.op,+ not = (o.retainPath===true) ? o.$path : '';+ o.retainPath = false;+ var $ul = $(['li.',o.hoverClass].join(''),this).add(this).not(not).removeClass(o.hoverClass)+ .find('>ul').hide().css('visibility','hidden');+ o.onHide.call($ul);+ return this;+ },+ showSuperfishUl : function(){+ var o = sf.op,+ sh = sf.c.shadowClass+'-off',+ $ul = this.addClass(o.hoverClass)+ .find('>ul:hidden').css('visibility','visible');+ sf.IE7fix.call($ul);+ o.onBeforeShow.call($ul);+ $ul.animate(o.animation,o.speed,function(){ sf.IE7fix.call($ul); o.onShow.call($ul); });+ return this;+ }+ });++})(jQuery);
@@ -0,0 +1,783 @@+/*!+ * jQuery UI 1.8.11+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI+ */+(function(c,j){function k(a){return!c(a).parents().andSelf().filter(function(){return c.curCSS(this,"visibility")==="hidden"||c.expr.filters.hidden(this)}).length}c.ui=c.ui||{};if(!c.ui.version){c.extend(c.ui,{version:"1.8.11",keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,+NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}});c.fn.extend({_focus:c.fn.focus,focus:function(a,b){return typeof a==="number"?this.each(function(){var d=this;setTimeout(function(){c(d).focus();b&&b.call(d)},a)}):this._focus.apply(this,arguments)},scrollParent:function(){var a;a=c.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(c.curCSS(this,+"position",1))&&/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0);return/fixed/.test(this.css("position"))||!a.length?c(document):a},zIndex:function(a){if(a!==j)return this.css("zIndex",a);if(this.length){a=c(this[0]);for(var b;a.length&&a[0]!==document;){b=a.css("position");+if(b==="absolute"||b==="relative"||b==="fixed"){b=parseInt(a.css("zIndex"),10);if(!isNaN(b)&&b!==0)return b}a=a.parent()}}return 0},disableSelection:function(){return this.bind((c.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}});c.each(["Width","Height"],function(a,b){function d(f,g,l,m){c.each(e,function(){g-=parseFloat(c.curCSS(f,"padding"+this,true))||0;if(l)g-=parseFloat(c.curCSS(f,+"border"+this+"Width",true))||0;if(m)g-=parseFloat(c.curCSS(f,"margin"+this,true))||0});return g}var e=b==="Width"?["Left","Right"]:["Top","Bottom"],h=b.toLowerCase(),i={innerWidth:c.fn.innerWidth,innerHeight:c.fn.innerHeight,outerWidth:c.fn.outerWidth,outerHeight:c.fn.outerHeight};c.fn["inner"+b]=function(f){if(f===j)return i["inner"+b].call(this);return this.each(function(){c(this).css(h,d(this,f)+"px")})};c.fn["outer"+b]=function(f,g){if(typeof f!=="number")return i["outer"+b].call(this,f);return this.each(function(){c(this).css(h,+d(this,f,true,g)+"px")})}});c.extend(c.expr[":"],{data:function(a,b,d){return!!c.data(a,d[3])},focusable:function(a){var b=a.nodeName.toLowerCase(),d=c.attr(a,"tabindex");if("area"===b){b=a.parentNode;d=b.name;if(!a.href||!d||b.nodeName.toLowerCase()!=="map")return false;a=c("img[usemap=#"+d+"]")[0];return!!a&&k(a)}return(/input|select|textarea|button|object/.test(b)?!a.disabled:"a"==b?a.href||!isNaN(d):!isNaN(d))&&k(a)},tabbable:function(a){var b=c.attr(a,"tabindex");return(isNaN(b)||b>=0)&&c(a).is(":focusable")}});+c(function(){var a=document.body,b=a.appendChild(b=document.createElement("div"));c.extend(b.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0});c.support.minHeight=b.offsetHeight===100;c.support.selectstart="onselectstart"in b;a.removeChild(b).style.display="none"});c.extend(c.ui,{plugin:{add:function(a,b,d){a=c.ui[a].prototype;for(var e in d){a.plugins[e]=a.plugins[e]||[];a.plugins[e].push([b,d[e]])}},call:function(a,b,d){if((b=a.plugins[b])&&a.element[0].parentNode)for(var e=0;e<b.length;e++)a.options[b[e][0]]&&+b[e][1].apply(a.element,d)}},contains:function(a,b){return document.compareDocumentPosition?a.compareDocumentPosition(b)&16:a!==b&&a.contains(b)},hasScroll:function(a,b){if(c(a).css("overflow")==="hidden")return false;b=b&&b==="left"?"scrollLeft":"scrollTop";var d=false;if(a[b]>0)return true;a[b]=1;d=a[b]>0;a[b]=0;return d},isOverAxis:function(a,b,d){return a>b&&a<b+d},isOver:function(a,b,d,e,h,i){return c.ui.isOverAxis(a,d,h)&&c.ui.isOverAxis(b,e,i)}})}})(jQuery);+;/*!+ * jQuery UI Widget 1.8.11+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Widget+ */+(function(b,j){if(b.cleanData){var k=b.cleanData;b.cleanData=function(a){for(var c=0,d;(d=a[c])!=null;c++)b(d).triggerHandler("remove");k(a)}}else{var l=b.fn.remove;b.fn.remove=function(a,c){return this.each(function(){if(!c)if(!a||b.filter(a,[this]).length)b("*",this).add([this]).each(function(){b(this).triggerHandler("remove")});return l.call(b(this),a,c)})}}b.widget=function(a,c,d){var e=a.split(".")[0],f;a=a.split(".")[1];f=e+"-"+a;if(!d){d=c;c=b.Widget}b.expr[":"][f]=function(h){return!!b.data(h,+a)};b[e]=b[e]||{};b[e][a]=function(h,g){arguments.length&&this._createWidget(h,g)};c=new c;c.options=b.extend(true,{},c.options);b[e][a].prototype=b.extend(true,c,{namespace:e,widgetName:a,widgetEventPrefix:b[e][a].prototype.widgetEventPrefix||a,widgetBaseClass:f},d);b.widget.bridge(a,b[e][a])};b.widget.bridge=function(a,c){b.fn[a]=function(d){var e=typeof d==="string",f=Array.prototype.slice.call(arguments,1),h=this;d=!e&&f.length?b.extend.apply(null,[true,d].concat(f)):d;if(e&&d.charAt(0)==="_")return h;+e?this.each(function(){var g=b.data(this,a),i=g&&b.isFunction(g[d])?g[d].apply(g,f):g;if(i!==g&&i!==j){h=i;return false}}):this.each(function(){var g=b.data(this,a);g?g.option(d||{})._init():b.data(this,a,new c(d,this))});return h}};b.Widget=function(a,c){arguments.length&&this._createWidget(a,c)};b.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",options:{disabled:false},_createWidget:function(a,c){b.data(c,this.widgetName,this);this.element=b(c);this.options=b.extend(true,{},this.options,+this._getCreateOptions(),a);var d=this;this.element.bind("remove."+this.widgetName,function(){d.destroy()});this._create();this._trigger("create");this._init()},_getCreateOptions:function(){return b.metadata&&b.metadata.get(this.element[0])[this.widgetName]},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName);this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+"-disabled ui-state-disabled")},+widget:function(){return this.element},option:function(a,c){var d=a;if(arguments.length===0)return b.extend({},this.options);if(typeof a==="string"){if(c===j)return this.options[a];d={};d[a]=c}this._setOptions(d);return this},_setOptions:function(a){var c=this;b.each(a,function(d,e){c._setOption(d,e)});return this},_setOption:function(a,c){this.options[a]=c;if(a==="disabled")this.widget()[c?"addClass":"removeClass"](this.widgetBaseClass+"-disabled ui-state-disabled").attr("aria-disabled",c);return this},+enable:function(){return this._setOption("disabled",false)},disable:function(){return this._setOption("disabled",true)},_trigger:function(a,c,d){var e=this.options[a];c=b.Event(c);c.type=(a===this.widgetEventPrefix?a:this.widgetEventPrefix+a).toLowerCase();d=d||{};if(c.originalEvent){a=b.event.props.length;for(var f;a;){f=b.event.props[--a];c[f]=c.originalEvent[f]}}this.element.trigger(c,d);return!(b.isFunction(e)&&e.call(this.element[0],c,d)===false||c.isDefaultPrevented())}}})(jQuery);+;/*!+ * jQuery UI Mouse 1.8.11+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Mouse+ *+ * Depends:+ * jquery.ui.widget.js+ */+(function(b){b.widget("ui.mouse",{options:{cancel:":input,option",distance:1,delay:0},_mouseInit:function(){var a=this;this.element.bind("mousedown."+this.widgetName,function(c){return a._mouseDown(c)}).bind("click."+this.widgetName,function(c){if(true===b.data(c.target,a.widgetName+".preventClickEvent")){b.removeData(c.target,a.widgetName+".preventClickEvent");c.stopImmediatePropagation();return false}});this.started=false},_mouseDestroy:function(){this.element.unbind("."+this.widgetName)},_mouseDown:function(a){a.originalEvent=+a.originalEvent||{};if(!a.originalEvent.mouseHandled){this._mouseStarted&&this._mouseUp(a);this._mouseDownEvent=a;var c=this,e=a.which==1,f=typeof this.options.cancel=="string"?b(a.target).parents().add(a.target).filter(this.options.cancel).length:false;if(!e||f||!this._mouseCapture(a))return true;this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet)this._mouseDelayTimer=setTimeout(function(){c.mouseDelayMet=true},this.options.delay);if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a)){this._mouseStarted=+this._mouseStart(a)!==false;if(!this._mouseStarted){a.preventDefault();return true}}true===b.data(a.target,this.widgetName+".preventClickEvent")&&b.removeData(a.target,this.widgetName+".preventClickEvent");this._mouseMoveDelegate=function(d){return c._mouseMove(d)};this._mouseUpDelegate=function(d){return c._mouseUp(d)};b(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate);a.preventDefault();return a.originalEvent.mouseHandled=+true}},_mouseMove:function(a){if(b.browser.msie&&!(document.documentMode>=9)&&!a.button)return this._mouseUp(a);if(this._mouseStarted){this._mouseDrag(a);return a.preventDefault()}if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a))(this._mouseStarted=this._mouseStart(this._mouseDownEvent,a)!==false)?this._mouseDrag(a):this._mouseUp(a);return!this._mouseStarted},_mouseUp:function(a){b(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);+if(this._mouseStarted){this._mouseStarted=false;a.target==this._mouseDownEvent.target&&b.data(a.target,this.widgetName+".preventClickEvent",true);this._mouseStop(a)}return false},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return true}})})(jQuery);+;/*+ * jQuery UI Position 1.8.11+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Position+ */+(function(c){c.ui=c.ui||{};var n=/left|center|right/,o=/top|center|bottom/,t=c.fn.position,u=c.fn.offset;c.fn.position=function(b){if(!b||!b.of)return t.apply(this,arguments);b=c.extend({},b);var a=c(b.of),d=a[0],g=(b.collision||"flip").split(" "),e=b.offset?b.offset.split(" "):[0,0],h,k,j;if(d.nodeType===9){h=a.width();k=a.height();j={top:0,left:0}}else if(d.setTimeout){h=a.width();k=a.height();j={top:a.scrollTop(),left:a.scrollLeft()}}else if(d.preventDefault){b.at="left top";h=k=0;j={top:b.of.pageY,+left:b.of.pageX}}else{h=a.outerWidth();k=a.outerHeight();j=a.offset()}c.each(["my","at"],function(){var f=(b[this]||"").split(" ");if(f.length===1)f=n.test(f[0])?f.concat(["center"]):o.test(f[0])?["center"].concat(f):["center","center"];f[0]=n.test(f[0])?f[0]:"center";f[1]=o.test(f[1])?f[1]:"center";b[this]=f});if(g.length===1)g[1]=g[0];e[0]=parseInt(e[0],10)||0;if(e.length===1)e[1]=e[0];e[1]=parseInt(e[1],10)||0;if(b.at[0]==="right")j.left+=h;else if(b.at[0]==="center")j.left+=h/2;if(b.at[1]==="bottom")j.top+=+k;else if(b.at[1]==="center")j.top+=k/2;j.left+=e[0];j.top+=e[1];return this.each(function(){var f=c(this),l=f.outerWidth(),m=f.outerHeight(),p=parseInt(c.curCSS(this,"marginLeft",true))||0,q=parseInt(c.curCSS(this,"marginTop",true))||0,v=l+p+(parseInt(c.curCSS(this,"marginRight",true))||0),w=m+q+(parseInt(c.curCSS(this,"marginBottom",true))||0),i=c.extend({},j),r;if(b.my[0]==="right")i.left-=l;else if(b.my[0]==="center")i.left-=l/2;if(b.my[1]==="bottom")i.top-=m;else if(b.my[1]==="center")i.top-=+m/2;i.left=Math.round(i.left);i.top=Math.round(i.top);r={left:i.left-p,top:i.top-q};c.each(["left","top"],function(s,x){c.ui.position[g[s]]&&c.ui.position[g[s]][x](i,{targetWidth:h,targetHeight:k,elemWidth:l,elemHeight:m,collisionPosition:r,collisionWidth:v,collisionHeight:w,offset:e,my:b.my,at:b.at})});c.fn.bgiframe&&f.bgiframe();f.offset(c.extend(i,{using:b.using}))})};c.ui.position={fit:{left:function(b,a){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();b.left=+d>0?b.left-d:Math.max(b.left-a.collisionPosition.left,b.left)},top:function(b,a){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();b.top=d>0?b.top-d:Math.max(b.top-a.collisionPosition.top,b.top)}},flip:{left:function(b,a){if(a.at[0]!=="center"){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();var g=a.my[0]==="left"?-a.elemWidth:a.my[0]==="right"?a.elemWidth:0,e=a.at[0]==="left"?a.targetWidth:-a.targetWidth,h=-2*a.offset[0];b.left+=+a.collisionPosition.left<0?g+e+h:d>0?g+e+h:0}},top:function(b,a){if(a.at[1]!=="center"){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();var g=a.my[1]==="top"?-a.elemHeight:a.my[1]==="bottom"?a.elemHeight:0,e=a.at[1]==="top"?a.targetHeight:-a.targetHeight,h=-2*a.offset[1];b.top+=a.collisionPosition.top<0?g+e+h:d>0?g+e+h:0}}}};if(!c.offset.setOffset){c.offset.setOffset=function(b,a){if(/static/.test(c.curCSS(b,"position")))b.style.position="relative";var d=c(b),+g=d.offset(),e=parseInt(c.curCSS(b,"top",true),10)||0,h=parseInt(c.curCSS(b,"left",true),10)||0;g={top:a.top-g.top+e,left:a.left-g.left+h};"using"in a?a.using.call(b,g):d.css(g)};c.fn.offset=function(b){var a=this[0];if(!a||!a.ownerDocument)return null;if(b)return this.each(function(){c.offset.setOffset(this,b)});return u.call(this)}}})(jQuery);+;/*+ * jQuery UI Draggable 1.8.11+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Draggables+ *+ * Depends:+ * jquery.ui.core.js+ * jquery.ui.mouse.js+ * jquery.ui.widget.js+ */+(function(d){d.widget("ui.draggable",d.ui.mouse,{widgetEventPrefix:"drag",options:{addClasses:true,appendTo:"parent",axis:false,connectToSortable:false,containment:false,cursor:"auto",cursorAt:false,grid:false,handle:false,helper:"original",iframeFix:false,opacity:false,refreshPositions:false,revert:false,revertDuration:500,scope:"default",scroll:true,scrollSensitivity:20,scrollSpeed:20,snap:false,snapMode:"both",snapTolerance:20,stack:false,zIndex:false},_create:function(){if(this.options.helper==+"original"&&!/^(?:r|a|f)/.test(this.element.css("position")))this.element[0].style.position="relative";this.options.addClasses&&this.element.addClass("ui-draggable");this.options.disabled&&this.element.addClass("ui-draggable-disabled");this._mouseInit()},destroy:function(){if(this.element.data("draggable")){this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled");this._mouseDestroy();return this}},_mouseCapture:function(a){var b=+this.options;if(this.helper||b.disabled||d(a.target).is(".ui-resizable-handle"))return false;this.handle=this._getHandle(a);if(!this.handle)return false;return true},_mouseStart:function(a){var b=this.options;this.helper=this._createHelper(a);this._cacheHelperProportions();if(d.ui.ddmanager)d.ui.ddmanager.current=this;this._cacheMargins();this.cssPosition=this.helper.css("position");this.scrollParent=this.helper.scrollParent();this.offset=this.positionAbs=this.element.offset();this.offset={top:this.offset.top-+this.margins.top,left:this.offset.left-this.margins.left};d.extend(this.offset,{click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this.position=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);b.containment&&this._setContainment();if(this._trigger("start",a)===false){this._clear();return false}this._cacheHelperProportions();+d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.helper.addClass("ui-draggable-dragging");this._mouseDrag(a,true);return true},_mouseDrag:function(a,b){this.position=this._generatePosition(a);this.positionAbs=this._convertPositionTo("absolute");if(!b){b=this._uiHash();if(this._trigger("drag",a,b)===false){this._mouseUp({});return false}this.position=b.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||+this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);return false},_mouseStop:function(a){var b=false;if(d.ui.ddmanager&&!this.options.dropBehaviour)b=d.ui.ddmanager.drop(this,a);if(this.dropped){b=this.dropped;this.dropped=false}if((!this.element[0]||!this.element[0].parentNode)&&this.options.helper=="original")return false;if(this.options.revert=="invalid"&&!b||this.options.revert=="valid"&&b||this.options.revert===true||d.isFunction(this.options.revert)&&+this.options.revert.call(this.element,b)){var c=this;d(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){c._trigger("stop",a)!==false&&c._clear()})}else this._trigger("stop",a)!==false&&this._clear();return false},cancel:function(){this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear();return this},_getHandle:function(a){var b=!this.options.handle||!d(this.options.handle,this.element).length?true:false;d(this.options.handle,this.element).find("*").andSelf().each(function(){if(this==+a.target)b=true});return b},_createHelper:function(a){var b=this.options;a=d.isFunction(b.helper)?d(b.helper.apply(this.element[0],[a])):b.helper=="clone"?this.element.clone():this.element;a.parents("body").length||a.appendTo(b.appendTo=="parent"?this.element[0].parentNode:b.appendTo);a[0]!=this.element[0]&&!/(fixed|absolute)/.test(a.css("position"))&&a.css("position","absolute");return a},_adjustOffsetFromHelper:function(a){if(typeof a=="string")a=a.split(" ");if(d.isArray(a))a={left:+a[0],top:+a[1]||+0};if("left"in a)this.offset.click.left=a.left+this.margins.left;if("right"in a)this.offset.click.left=this.helperProportions.width-a.right+this.margins.left;if("top"in a)this.offset.click.top=a.top+this.margins.top;if("bottom"in a)this.offset.click.top=this.helperProportions.height-a.bottom+this.margins.top},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var a=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],+this.offsetParent[0])){a.left+=this.scrollParent.scrollLeft();a.top+=this.scrollParent.scrollTop()}if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&d.browser.msie)a={top:0,left:0};return{top:a.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:a.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.element.position();return{top:a.top-+(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),+height:this.helper.outerHeight()}},_setContainment:function(){var a=this.options;if(a.containment=="parent")a.containment=this.helper[0].parentNode;if(a.containment=="document"||a.containment=="window")this.containment=[(a.containment=="document"?0:d(window).scrollLeft())-this.offset.relative.left-this.offset.parent.left,(a.containment=="document"?0:d(window).scrollTop())-this.offset.relative.top-this.offset.parent.top,(a.containment=="document"?0:d(window).scrollLeft())+d(a.containment=="document"?+document:window).width()-this.helperProportions.width-this.margins.left,(a.containment=="document"?0:d(window).scrollTop())+(d(a.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(a.containment)&&a.containment.constructor!=Array){var b=d(a.containment)[0];if(b){a=d(a.containment).offset();var c=d(b).css("overflow")!="hidden";this.containment=[a.left+(parseInt(d(b).css("borderLeftWidth"),+10)||0)+(parseInt(d(b).css("paddingLeft"),10)||0),a.top+(parseInt(d(b).css("borderTopWidth"),10)||0)+(parseInt(d(b).css("paddingTop"),10)||0),a.left+(c?Math.max(b.scrollWidth,b.offsetWidth):b.offsetWidth)-(parseInt(d(b).css("borderLeftWidth"),10)||0)-(parseInt(d(b).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,a.top+(c?Math.max(b.scrollHeight,b.offsetHeight):b.offsetHeight)-(parseInt(d(b).css("borderTopWidth"),10)||0)-(parseInt(d(b).css("paddingBottom"),+10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom]}}else if(a.containment.constructor==Array)this.containment=a.containment},_convertPositionTo:function(a,b){if(!b)b=this.position;a=a=="absolute"?1:-1;var c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName);return{top:b.top+this.offset.relative.top*a+this.offset.parent.top*a-(d.browser.safari&&+d.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():f?0:c.scrollTop())*a),left:b.left+this.offset.relative.left*a+this.offset.parent.left*a-(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():f?0:c.scrollLeft())*a)}},_generatePosition:function(a){var b=this.options,c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],+this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName),e=a.pageX,g=a.pageY;if(this.originalPosition){if(this.containment){if(a.pageX-this.offset.click.left<this.containment[0])e=this.containment[0]+this.offset.click.left;if(a.pageY-this.offset.click.top<this.containment[1])g=this.containment[1]+this.offset.click.top;if(a.pageX-this.offset.click.left>this.containment[2])e=this.containment[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>this.containment[3])g=+this.containment[3]+this.offset.click.top}if(b.grid){g=this.originalPageY+Math.round((g-this.originalPageY)/b.grid[1])*b.grid[1];g=this.containment?!(g-this.offset.click.top<this.containment[1]||g-this.offset.click.top>this.containment[3])?g:!(g-this.offset.click.top<this.containment[1])?g-b.grid[1]:g+b.grid[1]:g;e=this.originalPageX+Math.round((e-this.originalPageX)/b.grid[0])*b.grid[0];e=this.containment?!(e-this.offset.click.left<this.containment[0]||e-this.offset.click.left>this.containment[2])?+e:!(e-this.offset.click.left<this.containment[0])?e-b.grid[0]:e+b.grid[0]:e}}return{top:g-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():f?0:c.scrollTop()),left:e-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():+f?0:c.scrollLeft())}},_clear:function(){this.helper.removeClass("ui-draggable-dragging");this.helper[0]!=this.element[0]&&!this.cancelHelperRemoval&&this.helper.remove();this.helper=null;this.cancelHelperRemoval=false},_trigger:function(a,b,c){c=c||this._uiHash();d.ui.plugin.call(this,a,[b,c]);if(a=="drag")this.positionAbs=this._convertPositionTo("absolute");return d.Widget.prototype._trigger.call(this,a,b,c)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,+offset:this.positionAbs}}});d.extend(d.ui.draggable,{version:"1.8.11"});d.ui.plugin.add("draggable","connectToSortable",{start:function(a,b){var c=d(this).data("draggable"),f=c.options,e=d.extend({},b,{item:c.element});c.sortables=[];d(f.connectToSortable).each(function(){var g=d.data(this,"sortable");if(g&&!g.options.disabled){c.sortables.push({instance:g,shouldRevert:g.options.revert});g.refreshPositions();g._trigger("activate",a,e)}})},stop:function(a,b){var c=d(this).data("draggable"),f=d.extend({},+b,{item:c.element});d.each(c.sortables,function(){if(this.instance.isOver){this.instance.isOver=0;c.cancelHelperRemoval=true;this.instance.cancelHelperRemoval=false;if(this.shouldRevert)this.instance.options.revert=true;this.instance._mouseStop(a);this.instance.options.helper=this.instance.options._helper;c.options.helper=="original"&&this.instance.currentItem.css({top:"auto",left:"auto"})}else{this.instance.cancelHelperRemoval=false;this.instance._trigger("deactivate",a,f)}})},drag:function(a,b){var c=+d(this).data("draggable"),f=this;d.each(c.sortables,function(){this.instance.positionAbs=c.positionAbs;this.instance.helperProportions=c.helperProportions;this.instance.offset.click=c.offset.click;if(this.instance._intersectsWith(this.instance.containerCache)){if(!this.instance.isOver){this.instance.isOver=1;this.instance.currentItem=d(f).clone().appendTo(this.instance.element).data("sortable-item",true);this.instance.options._helper=this.instance.options.helper;this.instance.options.helper=function(){return b.helper[0]};+a.target=this.instance.currentItem[0];this.instance._mouseCapture(a,true);this.instance._mouseStart(a,true,true);this.instance.offset.click.top=c.offset.click.top;this.instance.offset.click.left=c.offset.click.left;this.instance.offset.parent.left-=c.offset.parent.left-this.instance.offset.parent.left;this.instance.offset.parent.top-=c.offset.parent.top-this.instance.offset.parent.top;c._trigger("toSortable",a);c.dropped=this.instance.element;c.currentItem=c.element;this.instance.fromOutside=c}this.instance.currentItem&&+this.instance._mouseDrag(a)}else if(this.instance.isOver){this.instance.isOver=0;this.instance.cancelHelperRemoval=true;this.instance.options.revert=false;this.instance._trigger("out",a,this.instance._uiHash(this.instance));this.instance._mouseStop(a,true);this.instance.options.helper=this.instance.options._helper;this.instance.currentItem.remove();this.instance.placeholder&&this.instance.placeholder.remove();c._trigger("fromSortable",a);c.dropped=false}})}});d.ui.plugin.add("draggable","cursor",+{start:function(){var a=d("body"),b=d(this).data("draggable").options;if(a.css("cursor"))b._cursor=a.css("cursor");a.css("cursor",b.cursor)},stop:function(){var a=d(this).data("draggable").options;a._cursor&&d("body").css("cursor",a._cursor)}});d.ui.plugin.add("draggable","iframeFix",{start:function(){var a=d(this).data("draggable").options;d(a.iframeFix===true?"iframe":a.iframeFix).each(function(){d('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>').css({width:this.offsetWidth++"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1E3}).css(d(this).offset()).appendTo("body")})},stop:function(){d("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)})}});d.ui.plugin.add("draggable","opacity",{start:function(a,b){a=d(b.helper);b=d(this).data("draggable").options;if(a.css("opacity"))b._opacity=a.css("opacity");a.css("opacity",b.opacity)},stop:function(a,b){a=d(this).data("draggable").options;a._opacity&&d(b.helper).css("opacity",+a._opacity)}});d.ui.plugin.add("draggable","scroll",{start:function(){var a=d(this).data("draggable");if(a.scrollParent[0]!=document&&a.scrollParent[0].tagName!="HTML")a.overflowOffset=a.scrollParent.offset()},drag:function(a){var b=d(this).data("draggable"),c=b.options,f=false;if(b.scrollParent[0]!=document&&b.scrollParent[0].tagName!="HTML"){if(!c.axis||c.axis!="x")if(b.overflowOffset.top+b.scrollParent[0].offsetHeight-a.pageY<c.scrollSensitivity)b.scrollParent[0].scrollTop=f=b.scrollParent[0].scrollTop++c.scrollSpeed;else if(a.pageY-b.overflowOffset.top<c.scrollSensitivity)b.scrollParent[0].scrollTop=f=b.scrollParent[0].scrollTop-c.scrollSpeed;if(!c.axis||c.axis!="y")if(b.overflowOffset.left+b.scrollParent[0].offsetWidth-a.pageX<c.scrollSensitivity)b.scrollParent[0].scrollLeft=f=b.scrollParent[0].scrollLeft+c.scrollSpeed;else if(a.pageX-b.overflowOffset.left<c.scrollSensitivity)b.scrollParent[0].scrollLeft=f=b.scrollParent[0].scrollLeft-c.scrollSpeed}else{if(!c.axis||c.axis!="x")if(a.pageY-d(document).scrollTop()<+c.scrollSensitivity)f=d(document).scrollTop(d(document).scrollTop()-c.scrollSpeed);else if(d(window).height()-(a.pageY-d(document).scrollTop())<c.scrollSensitivity)f=d(document).scrollTop(d(document).scrollTop()+c.scrollSpeed);if(!c.axis||c.axis!="y")if(a.pageX-d(document).scrollLeft()<c.scrollSensitivity)f=d(document).scrollLeft(d(document).scrollLeft()-c.scrollSpeed);else if(d(window).width()-(a.pageX-d(document).scrollLeft())<c.scrollSensitivity)f=d(document).scrollLeft(d(document).scrollLeft()++c.scrollSpeed)}f!==false&&d.ui.ddmanager&&!c.dropBehaviour&&d.ui.ddmanager.prepareOffsets(b,a)}});d.ui.plugin.add("draggable","snap",{start:function(){var a=d(this).data("draggable"),b=a.options;a.snapElements=[];d(b.snap.constructor!=String?b.snap.items||":data(draggable)":b.snap).each(function(){var c=d(this),f=c.offset();this!=a.element[0]&&a.snapElements.push({item:this,width:c.outerWidth(),height:c.outerHeight(),top:f.top,left:f.left})})},drag:function(a,b){for(var c=d(this).data("draggable"),+f=c.options,e=f.snapTolerance,g=b.offset.left,n=g+c.helperProportions.width,m=b.offset.top,o=m+c.helperProportions.height,h=c.snapElements.length-1;h>=0;h--){var i=c.snapElements[h].left,k=i+c.snapElements[h].width,j=c.snapElements[h].top,l=j+c.snapElements[h].height;if(i-e<g&&g<k+e&&j-e<m&&m<l+e||i-e<g&&g<k+e&&j-e<o&&o<l+e||i-e<n&&n<k+e&&j-e<m&&m<l+e||i-e<n&&n<k+e&&j-e<o&&o<l+e){if(f.snapMode!="inner"){var p=Math.abs(j-o)<=e,q=Math.abs(l-m)<=e,r=Math.abs(i-n)<=e,s=Math.abs(k-g)<=e;if(p)b.position.top=+c._convertPositionTo("relative",{top:j-c.helperProportions.height,left:0}).top-c.margins.top;if(q)b.position.top=c._convertPositionTo("relative",{top:l,left:0}).top-c.margins.top;if(r)b.position.left=c._convertPositionTo("relative",{top:0,left:i-c.helperProportions.width}).left-c.margins.left;if(s)b.position.left=c._convertPositionTo("relative",{top:0,left:k}).left-c.margins.left}var t=p||q||r||s;if(f.snapMode!="outer"){p=Math.abs(j-m)<=e;q=Math.abs(l-o)<=e;r=Math.abs(i-g)<=e;s=Math.abs(k-n)<=e;if(p)b.position.top=+c._convertPositionTo("relative",{top:j,left:0}).top-c.margins.top;if(q)b.position.top=c._convertPositionTo("relative",{top:l-c.helperProportions.height,left:0}).top-c.margins.top;if(r)b.position.left=c._convertPositionTo("relative",{top:0,left:i}).left-c.margins.left;if(s)b.position.left=c._convertPositionTo("relative",{top:0,left:k-c.helperProportions.width}).left-c.margins.left}if(!c.snapElements[h].snapping&&(p||q||r||s||t))c.options.snap.snap&&c.options.snap.snap.call(c.element,a,d.extend(c._uiHash(),+{snapItem:c.snapElements[h].item}));c.snapElements[h].snapping=p||q||r||s||t}else{c.snapElements[h].snapping&&c.options.snap.release&&c.options.snap.release.call(c.element,a,d.extend(c._uiHash(),{snapItem:c.snapElements[h].item}));c.snapElements[h].snapping=false}}}});d.ui.plugin.add("draggable","stack",{start:function(){var a=d(this).data("draggable").options;a=d.makeArray(d(a.stack)).sort(function(c,f){return(parseInt(d(c).css("zIndex"),10)||0)-(parseInt(d(f).css("zIndex"),10)||0)});if(a.length){var b=+parseInt(a[0].style.zIndex)||0;d(a).each(function(c){this.style.zIndex=b+c});this[0].style.zIndex=b+a.length}}});d.ui.plugin.add("draggable","zIndex",{start:function(a,b){a=d(b.helper);b=d(this).data("draggable").options;if(a.css("zIndex"))b._zIndex=a.css("zIndex");a.css("zIndex",b.zIndex)},stop:function(a,b){a=d(this).data("draggable").options;a._zIndex&&d(b.helper).css("zIndex",a._zIndex)}})})(jQuery);+;/*+ * jQuery UI Droppable 1.8.11+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Droppables+ *+ * Depends:+ * jquery.ui.core.js+ * jquery.ui.widget.js+ * jquery.ui.mouse.js+ * jquery.ui.draggable.js+ */+(function(d){d.widget("ui.droppable",{widgetEventPrefix:"drop",options:{accept:"*",activeClass:false,addClasses:true,greedy:false,hoverClass:false,scope:"default",tolerance:"intersect"},_create:function(){var a=this.options,b=a.accept;this.isover=0;this.isout=1;this.accept=d.isFunction(b)?b:function(c){return c.is(b)};this.proportions={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight};d.ui.ddmanager.droppables[a.scope]=d.ui.ddmanager.droppables[a.scope]||[];d.ui.ddmanager.droppables[a.scope].push(this);+a.addClasses&&this.element.addClass("ui-droppable")},destroy:function(){for(var a=d.ui.ddmanager.droppables[this.options.scope],b=0;b<a.length;b++)a[b]==this&&a.splice(b,1);this.element.removeClass("ui-droppable ui-droppable-disabled").removeData("droppable").unbind(".droppable");return this},_setOption:function(a,b){if(a=="accept")this.accept=d.isFunction(b)?b:function(c){return c.is(b)};d.Widget.prototype._setOption.apply(this,arguments)},_activate:function(a){var b=d.ui.ddmanager.current;this.options.activeClass&&+this.element.addClass(this.options.activeClass);b&&this._trigger("activate",a,this.ui(b))},_deactivate:function(a){var b=d.ui.ddmanager.current;this.options.activeClass&&this.element.removeClass(this.options.activeClass);b&&this._trigger("deactivate",a,this.ui(b))},_over:function(a){var b=d.ui.ddmanager.current;if(!(!b||(b.currentItem||b.element)[0]==this.element[0]))if(this.accept.call(this.element[0],b.currentItem||b.element)){this.options.hoverClass&&this.element.addClass(this.options.hoverClass);+this._trigger("over",a,this.ui(b))}},_out:function(a){var b=d.ui.ddmanager.current;if(!(!b||(b.currentItem||b.element)[0]==this.element[0]))if(this.accept.call(this.element[0],b.currentItem||b.element)){this.options.hoverClass&&this.element.removeClass(this.options.hoverClass);this._trigger("out",a,this.ui(b))}},_drop:function(a,b){var c=b||d.ui.ddmanager.current;if(!c||(c.currentItem||c.element)[0]==this.element[0])return false;var e=false;this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function(){var g=+d.data(this,"droppable");if(g.options.greedy&&!g.options.disabled&&g.options.scope==c.options.scope&&g.accept.call(g.element[0],c.currentItem||c.element)&&d.ui.intersect(c,d.extend(g,{offset:g.element.offset()}),g.options.tolerance)){e=true;return false}});if(e)return false;if(this.accept.call(this.element[0],c.currentItem||c.element)){this.options.activeClass&&this.element.removeClass(this.options.activeClass);this.options.hoverClass&&this.element.removeClass(this.options.hoverClass);this._trigger("drop",+a,this.ui(c));return this.element}return false},ui:function(a){return{draggable:a.currentItem||a.element,helper:a.helper,position:a.position,offset:a.positionAbs}}});d.extend(d.ui.droppable,{version:"1.8.11"});d.ui.intersect=function(a,b,c){if(!b.offset)return false;var e=(a.positionAbs||a.position.absolute).left,g=e+a.helperProportions.width,f=(a.positionAbs||a.position.absolute).top,h=f+a.helperProportions.height,i=b.offset.left,k=i+b.proportions.width,j=b.offset.top,l=j+b.proportions.height;+switch(c){case "fit":return i<=e&&g<=k&&j<=f&&h<=l;case "intersect":return i<e+a.helperProportions.width/2&&g-a.helperProportions.width/2<k&&j<f+a.helperProportions.height/2&&h-a.helperProportions.height/2<l;case "pointer":return d.ui.isOver((a.positionAbs||a.position.absolute).top+(a.clickOffset||a.offset.click).top,(a.positionAbs||a.position.absolute).left+(a.clickOffset||a.offset.click).left,j,i,b.proportions.height,b.proportions.width);case "touch":return(f>=j&&f<=l||h>=j&&h<=l||f<j&&h>l)&&(e>=+i&&e<=k||g>=i&&g<=k||e<i&&g>k);default:return false}};d.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(a,b){var c=d.ui.ddmanager.droppables[a.options.scope]||[],e=b?b.type:null,g=(a.currentItem||a.element).find(":data(droppable)").andSelf(),f=0;a:for(;f<c.length;f++)if(!(c[f].options.disabled||a&&!c[f].accept.call(c[f].element[0],a.currentItem||a.element))){for(var h=0;h<g.length;h++)if(g[h]==c[f].element[0]){c[f].proportions.height=0;continue a}c[f].visible=c[f].element.css("display")!=+"none";if(c[f].visible){e=="mousedown"&&c[f]._activate.call(c[f],b);c[f].offset=c[f].element.offset();c[f].proportions={width:c[f].element[0].offsetWidth,height:c[f].element[0].offsetHeight}}}},drop:function(a,b){var c=false;d.each(d.ui.ddmanager.droppables[a.options.scope]||[],function(){if(this.options){if(!this.options.disabled&&this.visible&&d.ui.intersect(a,this,this.options.tolerance))c=c||this._drop.call(this,b);if(!this.options.disabled&&this.visible&&this.accept.call(this.element[0],a.currentItem||+a.element)){this.isout=1;this.isover=0;this._deactivate.call(this,b)}}});return c},drag:function(a,b){a.options.refreshPositions&&d.ui.ddmanager.prepareOffsets(a,b);d.each(d.ui.ddmanager.droppables[a.options.scope]||[],function(){if(!(this.options.disabled||this.greedyChild||!this.visible)){var c=d.ui.intersect(a,this,this.options.tolerance);if(c=!c&&this.isover==1?"isout":c&&this.isover==0?"isover":null){var e;if(this.options.greedy){var g=this.element.parents(":data(droppable):eq(0)");if(g.length){e=+d.data(g[0],"droppable");e.greedyChild=c=="isover"?1:0}}if(e&&c=="isover"){e.isover=0;e.isout=1;e._out.call(e,b)}this[c]=1;this[c=="isout"?"isover":"isout"]=0;this[c=="isover"?"_over":"_out"].call(this,b);if(e&&c=="isout"){e.isout=0;e.isover=1;e._over.call(e,b)}}}})}}})(jQuery);+;/*+ * jQuery UI Resizable 1.8.11+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Resizables+ *+ * Depends:+ * jquery.ui.core.js+ * jquery.ui.mouse.js+ * jquery.ui.widget.js+ */+(function(e){e.widget("ui.resizable",e.ui.mouse,{widgetEventPrefix:"resize",options:{alsoResize:false,animate:false,animateDuration:"slow",animateEasing:"swing",aspectRatio:false,autoHide:false,containment:false,ghost:false,grid:false,handles:"e,s,se",helper:false,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1E3},_create:function(){var b=this,a=this.options;this.element.addClass("ui-resizable");e.extend(this,{_aspectRatio:!!a.aspectRatio,aspectRatio:a.aspectRatio,originalElement:this.element,+_proportionallyResizeElements:[],_helper:a.helper||a.ghost||a.animate?a.helper||"ui-resizable-helper":null});if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)){/relative/.test(this.element.css("position"))&&e.browser.opera&&this.element.css({position:"relative",top:"auto",left:"auto"});this.element.wrap(e('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),+top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle=+this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=a.handles||(!e(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",+nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all")this.handles="n,e,s,w,se,sw,ne,nw";var c=this.handles.split(",");this.handles={};for(var d=0;d<c.length;d++){var f=e.trim(c[d]),g=e('<div class="ui-resizable-handle '+("ui-resizable-"+f)+'"></div>');/sw|se|ne|nw/.test(f)&&g.css({zIndex:++a.zIndex});"se"==f&&g.addClass("ui-icon ui-icon-gripsmall-diagonal-se");this.handles[f]=".ui-resizable-"+f;this.element.append(g)}}this._renderAxis=function(h){h=h||this.element;for(var i in this.handles){if(this.handles[i].constructor==+String)this.handles[i]=e(this.handles[i],this.element).show();if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var j=e(this.handles[i],this.element),k=0;k=/sw|ne|nw|se|n|s/.test(i)?j.outerHeight():j.outerWidth();j=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join("");h.css(j,k);this._proportionallyResize()}e(this.handles[i])}};this._renderAxis(this.element);this._handles=e(".ui-resizable-handle",this.element).disableSelection();+this._handles.mouseover(function(){if(!b.resizing){if(this.className)var h=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);b.axis=h&&h[1]?h[1]:"se"}});if(a.autoHide){this._handles.hide();e(this.element).addClass("ui-resizable-autohide").hover(function(){e(this).removeClass("ui-resizable-autohide");b._handles.show()},function(){if(!b.resizing){e(this).addClass("ui-resizable-autohide");b._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy();var b=function(c){e(c).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};+if(this.elementIsWrapper){b(this.element);var a=this.element;a.after(this.originalElement.css({position:a.css("position"),width:a.outerWidth(),height:a.outerHeight(),top:a.css("top"),left:a.css("left")})).remove()}this.originalElement.css("resize",this.originalResizeStyle);b(this.originalElement);return this},_mouseCapture:function(b){var a=false;for(var c in this.handles)if(e(this.handles[c])[0]==b.target)a=true;return!this.options.disabled&&a},_mouseStart:function(b){var a=this.options,c=this.element.position(),+d=this.element;this.resizing=true;this.documentScroll={top:e(document).scrollTop(),left:e(document).scrollLeft()};if(d.is(".ui-draggable")||/absolute/.test(d.css("position")))d.css({position:"absolute",top:c.top,left:c.left});e.browser.opera&&/relative/.test(d.css("position"))&&d.css({position:"relative",top:"auto",left:"auto"});this._renderProxy();c=m(this.helper.css("left"));var f=m(this.helper.css("top"));if(a.containment){c+=e(a.containment).scrollLeft()||0;f+=e(a.containment).scrollTop()||0}this.offset=+this.helper.offset();this.position={left:c,top:f};this.size=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalSize=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalPosition={left:c,top:f};this.sizeDiff={width:d.outerWidth()-d.width(),height:d.outerHeight()-d.height()};this.originalMousePosition={left:b.pageX,top:b.pageY};this.aspectRatio=typeof a.aspectRatio=="number"?a.aspectRatio:+this.originalSize.width/this.originalSize.height||1;a=e(".ui-resizable-"+this.axis).css("cursor");e("body").css("cursor",a=="auto"?this.axis+"-resize":a);d.addClass("ui-resizable-resizing");this._propagate("start",b);return true},_mouseDrag:function(b){var a=this.helper,c=this.originalMousePosition,d=this._change[this.axis];if(!d)return false;c=d.apply(this,[b,b.pageX-c.left||0,b.pageY-c.top||0]);if(this._aspectRatio||b.shiftKey)c=this._updateRatio(c,b);c=this._respectSize(c,b);this._propagate("resize",+b);a.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize();this._updateCache(c);this._trigger("resize",b,this.ui());return false},_mouseStop:function(b){this.resizing=false;var a=this.options,c=this;if(this._helper){var d=this._proportionallyResizeElements,f=d.length&&/textarea/i.test(d[0].nodeName);d=f&&e.ui.hasScroll(d[0],"left")?0:c.sizeDiff.height;+f=f?0:c.sizeDiff.width;f={width:c.helper.width()-f,height:c.helper.height()-d};d=parseInt(c.element.css("left"),10)+(c.position.left-c.originalPosition.left)||null;var g=parseInt(c.element.css("top"),10)+(c.position.top-c.originalPosition.top)||null;a.animate||this.element.css(e.extend(f,{top:g,left:d}));c.helper.height(c.size.height);c.helper.width(c.size.width);this._helper&&!a.animate&&this._proportionallyResize()}e("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");+this._propagate("stop",b);this._helper&&this.helper.remove();return false},_updateCache:function(b){this.offset=this.helper.offset();if(l(b.left))this.position.left=b.left;if(l(b.top))this.position.top=b.top;if(l(b.height))this.size.height=b.height;if(l(b.width))this.size.width=b.width},_updateRatio:function(b){var a=this.position,c=this.size,d=this.axis;if(b.height)b.width=c.height*this.aspectRatio;else if(b.width)b.height=c.width/this.aspectRatio;if(d=="sw"){b.left=a.left+(c.width-b.width);b.top=+null}if(d=="nw"){b.top=a.top+(c.height-b.height);b.left=a.left+(c.width-b.width)}return b},_respectSize:function(b){var a=this.options,c=this.axis,d=l(b.width)&&a.maxWidth&&a.maxWidth<b.width,f=l(b.height)&&a.maxHeight&&a.maxHeight<b.height,g=l(b.width)&&a.minWidth&&a.minWidth>b.width,h=l(b.height)&&a.minHeight&&a.minHeight>b.height;if(g)b.width=a.minWidth;if(h)b.height=a.minHeight;if(d)b.width=a.maxWidth;if(f)b.height=a.maxHeight;var i=this.originalPosition.left+this.originalSize.width,j=this.position.top++this.size.height,k=/sw|nw|w/.test(c);c=/nw|ne|n/.test(c);if(g&&k)b.left=i-a.minWidth;if(d&&k)b.left=i-a.maxWidth;if(h&&c)b.top=j-a.minHeight;if(f&&c)b.top=j-a.maxHeight;if((a=!b.width&&!b.height)&&!b.left&&b.top)b.top=null;else if(a&&!b.top&&b.left)b.left=null;return b},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var b=this.helper||this.element,a=0;a<this._proportionallyResizeElements.length;a++){var c=this._proportionallyResizeElements[a];if(!this.borderDif){var d=+[c.css("borderTopWidth"),c.css("borderRightWidth"),c.css("borderBottomWidth"),c.css("borderLeftWidth")],f=[c.css("paddingTop"),c.css("paddingRight"),c.css("paddingBottom"),c.css("paddingLeft")];this.borderDif=e.map(d,function(g,h){g=parseInt(g,10)||0;h=parseInt(f[h],10)||0;return g+h})}e.browser.msie&&(e(b).is(":hidden")||e(b).parents(":hidden").length)||c.css({height:b.height()-this.borderDif[0]-this.borderDif[2]||0,width:b.width()-this.borderDif[1]-this.borderDif[3]||0})}},_renderProxy:function(){var b=+this.options;this.elementOffset=this.element.offset();if(this._helper){this.helper=this.helper||e('<div style="overflow:hidden;"></div>');var a=e.browser.msie&&e.browser.version<7,c=a?1:0;a=a?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+a,height:this.element.outerHeight()+a,position:"absolute",left:this.elementOffset.left-c+"px",top:this.elementOffset.top-c+"px",zIndex:++b.zIndex});this.helper.appendTo("body").disableSelection()}else this.helper=this.element},_change:{e:function(b,+a){return{width:this.originalSize.width+a}},w:function(b,a){return{left:this.originalPosition.left+a,width:this.originalSize.width-a}},n:function(b,a,c){return{top:this.originalPosition.top+c,height:this.originalSize.height-c}},s:function(b,a,c){return{height:this.originalSize.height+c}},se:function(b,a,c){return e.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[b,a,c]))},sw:function(b,a,c){return e.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[b,a,+c]))},ne:function(b,a,c){return e.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[b,a,c]))},nw:function(b,a,c){return e.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[b,a,c]))}},_propagate:function(b,a){e.ui.plugin.call(this,b,[a,this.ui()]);b!="resize"&&this._trigger(b,a,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,+originalPosition:this.originalPosition}}});e.extend(e.ui.resizable,{version:"1.8.11"});e.ui.plugin.add("resizable","alsoResize",{start:function(){var b=e(this).data("resizable").options,a=function(c){e(c).each(function(){var d=e(this);d.data("resizable-alsoresize",{width:parseInt(d.width(),10),height:parseInt(d.height(),10),left:parseInt(d.css("left"),10),top:parseInt(d.css("top"),10),position:d.css("position")})})};if(typeof b.alsoResize=="object"&&!b.alsoResize.parentNode)if(b.alsoResize.length){b.alsoResize=+b.alsoResize[0];a(b.alsoResize)}else e.each(b.alsoResize,function(c){a(c)});else a(b.alsoResize)},resize:function(b,a){var c=e(this).data("resizable");b=c.options;var d=c.originalSize,f=c.originalPosition,g={height:c.size.height-d.height||0,width:c.size.width-d.width||0,top:c.position.top-f.top||0,left:c.position.left-f.left||0},h=function(i,j){e(i).each(function(){var k=e(this),q=e(this).data("resizable-alsoresize"),p={},r=j&&j.length?j:k.parents(a.originalElement[0]).length?["width","height"]:["width",+"height","top","left"];e.each(r,function(n,o){if((n=(q[o]||0)+(g[o]||0))&&n>=0)p[o]=n||null});if(e.browser.opera&&/relative/.test(k.css("position"))){c._revertToRelativePosition=true;k.css({position:"absolute",top:"auto",left:"auto"})}k.css(p)})};typeof b.alsoResize=="object"&&!b.alsoResize.nodeType?e.each(b.alsoResize,function(i,j){h(i,j)}):h(b.alsoResize)},stop:function(){var b=e(this).data("resizable"),a=b.options,c=function(d){e(d).each(function(){var f=e(this);f.css({position:f.data("resizable-alsoresize").position})})};+if(b._revertToRelativePosition){b._revertToRelativePosition=false;typeof a.alsoResize=="object"&&!a.alsoResize.nodeType?e.each(a.alsoResize,function(d){c(d)}):c(a.alsoResize)}e(this).removeData("resizable-alsoresize")}});e.ui.plugin.add("resizable","animate",{stop:function(b){var a=e(this).data("resizable"),c=a.options,d=a._proportionallyResizeElements,f=d.length&&/textarea/i.test(d[0].nodeName),g=f&&e.ui.hasScroll(d[0],"left")?0:a.sizeDiff.height;f={width:a.size.width-(f?0:a.sizeDiff.width),height:a.size.height-+g};g=parseInt(a.element.css("left"),10)+(a.position.left-a.originalPosition.left)||null;var h=parseInt(a.element.css("top"),10)+(a.position.top-a.originalPosition.top)||null;a.element.animate(e.extend(f,h&&g?{top:h,left:g}:{}),{duration:c.animateDuration,easing:c.animateEasing,step:function(){var i={width:parseInt(a.element.css("width"),10),height:parseInt(a.element.css("height"),10),top:parseInt(a.element.css("top"),10),left:parseInt(a.element.css("left"),10)};d&&d.length&&e(d[0]).css({width:i.width,+height:i.height});a._updateCache(i);a._propagate("resize",b)}})}});e.ui.plugin.add("resizable","containment",{start:function(){var b=e(this).data("resizable"),a=b.element,c=b.options.containment;if(a=c instanceof e?c.get(0):/parent/.test(c)?a.parent().get(0):c){b.containerElement=e(a);if(/document/.test(c)||c==document){b.containerOffset={left:0,top:0};b.containerPosition={left:0,top:0};b.parentData={element:e(document),left:0,top:0,width:e(document).width(),height:e(document).height()||document.body.parentNode.scrollHeight}}else{var d=+e(a),f=[];e(["Top","Right","Left","Bottom"]).each(function(i,j){f[i]=m(d.css("padding"+j))});b.containerOffset=d.offset();b.containerPosition=d.position();b.containerSize={height:d.innerHeight()-f[3],width:d.innerWidth()-f[1]};c=b.containerOffset;var g=b.containerSize.height,h=b.containerSize.width;h=e.ui.hasScroll(a,"left")?a.scrollWidth:h;g=e.ui.hasScroll(a)?a.scrollHeight:g;b.parentData={element:a,left:c.left,top:c.top,width:h,height:g}}}},resize:function(b){var a=e(this).data("resizable"),c=a.options,+d=a.containerOffset,f=a.position;b=a._aspectRatio||b.shiftKey;var g={top:0,left:0},h=a.containerElement;if(h[0]!=document&&/static/.test(h.css("position")))g=d;if(f.left<(a._helper?d.left:0)){a.size.width+=a._helper?a.position.left-d.left:a.position.left-g.left;if(b)a.size.height=a.size.width/c.aspectRatio;a.position.left=c.helper?d.left:0}if(f.top<(a._helper?d.top:0)){a.size.height+=a._helper?a.position.top-d.top:a.position.top;if(b)a.size.width=a.size.height*c.aspectRatio;a.position.top=a._helper?+d.top:0}a.offset.left=a.parentData.left+a.position.left;a.offset.top=a.parentData.top+a.position.top;c=Math.abs((a._helper?a.offset.left-g.left:a.offset.left-g.left)+a.sizeDiff.width);d=Math.abs((a._helper?a.offset.top-g.top:a.offset.top-d.top)+a.sizeDiff.height);f=a.containerElement.get(0)==a.element.parent().get(0);g=/relative|absolute/.test(a.containerElement.css("position"));if(f&&g)c-=a.parentData.left;if(c+a.size.width>=a.parentData.width){a.size.width=a.parentData.width-c;if(b)a.size.height=+a.size.width/a.aspectRatio}if(d+a.size.height>=a.parentData.height){a.size.height=a.parentData.height-d;if(b)a.size.width=a.size.height*a.aspectRatio}},stop:function(){var b=e(this).data("resizable"),a=b.options,c=b.containerOffset,d=b.containerPosition,f=b.containerElement,g=e(b.helper),h=g.offset(),i=g.outerWidth()-b.sizeDiff.width;g=g.outerHeight()-b.sizeDiff.height;b._helper&&!a.animate&&/relative/.test(f.css("position"))&&e(this).css({left:h.left-d.left-c.left,width:i,height:g});b._helper&&!a.animate&&+/static/.test(f.css("position"))&&e(this).css({left:h.left-d.left-c.left,width:i,height:g})}});e.ui.plugin.add("resizable","ghost",{start:function(){var b=e(this).data("resizable"),a=b.options,c=b.size;b.ghost=b.originalElement.clone();b.ghost.css({opacity:0.25,display:"block",position:"relative",height:c.height,width:c.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof a.ghost=="string"?a.ghost:"");b.ghost.appendTo(b.helper)},resize:function(){var b=e(this).data("resizable");+b.ghost&&b.ghost.css({position:"relative",height:b.size.height,width:b.size.width})},stop:function(){var b=e(this).data("resizable");b.ghost&&b.helper&&b.helper.get(0).removeChild(b.ghost.get(0))}});e.ui.plugin.add("resizable","grid",{resize:function(){var b=e(this).data("resizable"),a=b.options,c=b.size,d=b.originalSize,f=b.originalPosition,g=b.axis;a.grid=typeof a.grid=="number"?[a.grid,a.grid]:a.grid;var h=Math.round((c.width-d.width)/(a.grid[0]||1))*(a.grid[0]||1);a=Math.round((c.height-d.height)/+(a.grid[1]||1))*(a.grid[1]||1);if(/^(se|s|e)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a}else if(/^(ne)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a;b.position.top=f.top-a}else{if(/^(sw)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a}else{b.size.width=d.width+h;b.size.height=d.height+a;b.position.top=f.top-a}b.position.left=f.left-h}}});var m=function(b){return parseInt(b,10)||0},l=function(b){return!isNaN(parseInt(b,10))}})(jQuery);+;/*+ * jQuery UI Selectable 1.8.11+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Selectables+ *+ * Depends:+ * jquery.ui.core.js+ * jquery.ui.mouse.js+ * jquery.ui.widget.js+ */+(function(e){e.widget("ui.selectable",e.ui.mouse,{options:{appendTo:"body",autoRefresh:true,distance:0,filter:"*",tolerance:"touch"},_create:function(){var c=this;this.element.addClass("ui-selectable");this.dragged=false;var f;this.refresh=function(){f=e(c.options.filter,c.element[0]);f.each(function(){var d=e(this),b=d.offset();e.data(this,"selectable-item",{element:this,$element:d,left:b.left,top:b.top,right:b.left+d.outerWidth(),bottom:b.top+d.outerHeight(),startselected:false,selected:d.hasClass("ui-selected"),+selecting:d.hasClass("ui-selecting"),unselecting:d.hasClass("ui-unselecting")})})};this.refresh();this.selectees=f.addClass("ui-selectee");this._mouseInit();this.helper=e("<div class='ui-selectable-helper'></div>")},destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item");this.element.removeClass("ui-selectable ui-selectable-disabled").removeData("selectable").unbind(".selectable");this._mouseDestroy();return this},_mouseStart:function(c){var f=this;this.opos=[c.pageX,+c.pageY];if(!this.options.disabled){var d=this.options;this.selectees=e(d.filter,this.element[0]);this._trigger("start",c);e(d.appendTo).append(this.helper);this.helper.css({left:c.clientX,top:c.clientY,width:0,height:0});d.autoRefresh&&this.refresh();this.selectees.filter(".ui-selected").each(function(){var b=e.data(this,"selectable-item");b.startselected=true;if(!c.metaKey){b.$element.removeClass("ui-selected");b.selected=false;b.$element.addClass("ui-unselecting");b.unselecting=true;f._trigger("unselecting",+c,{unselecting:b.element})}});e(c.target).parents().andSelf().each(function(){var b=e.data(this,"selectable-item");if(b){var g=!c.metaKey||!b.$element.hasClass("ui-selected");b.$element.removeClass(g?"ui-unselecting":"ui-selected").addClass(g?"ui-selecting":"ui-unselecting");b.unselecting=!g;b.selecting=g;(b.selected=g)?f._trigger("selecting",c,{selecting:b.element}):f._trigger("unselecting",c,{unselecting:b.element});return false}})}},_mouseDrag:function(c){var f=this;this.dragged=true;if(!this.options.disabled){var d=+this.options,b=this.opos[0],g=this.opos[1],h=c.pageX,i=c.pageY;if(b>h){var j=h;h=b;b=j}if(g>i){j=i;i=g;g=j}this.helper.css({left:b,top:g,width:h-b,height:i-g});this.selectees.each(function(){var a=e.data(this,"selectable-item");if(!(!a||a.element==f.element[0])){var k=false;if(d.tolerance=="touch")k=!(a.left>h||a.right<b||a.top>i||a.bottom<g);else if(d.tolerance=="fit")k=a.left>b&&a.right<h&&a.top>g&&a.bottom<i;if(k){if(a.selected){a.$element.removeClass("ui-selected");a.selected=false}if(a.unselecting){a.$element.removeClass("ui-unselecting");+a.unselecting=false}if(!a.selecting){a.$element.addClass("ui-selecting");a.selecting=true;f._trigger("selecting",c,{selecting:a.element})}}else{if(a.selecting)if(c.metaKey&&a.startselected){a.$element.removeClass("ui-selecting");a.selecting=false;a.$element.addClass("ui-selected");a.selected=true}else{a.$element.removeClass("ui-selecting");a.selecting=false;if(a.startselected){a.$element.addClass("ui-unselecting");a.unselecting=true}f._trigger("unselecting",c,{unselecting:a.element})}if(a.selected)if(!c.metaKey&&+!a.startselected){a.$element.removeClass("ui-selected");a.selected=false;a.$element.addClass("ui-unselecting");a.unselecting=true;f._trigger("unselecting",c,{unselecting:a.element})}}}});return false}},_mouseStop:function(c){var f=this;this.dragged=false;e(".ui-unselecting",this.element[0]).each(function(){var d=e.data(this,"selectable-item");d.$element.removeClass("ui-unselecting");d.unselecting=false;d.startselected=false;f._trigger("unselected",c,{unselected:d.element})});e(".ui-selecting",this.element[0]).each(function(){var d=+e.data(this,"selectable-item");d.$element.removeClass("ui-selecting").addClass("ui-selected");d.selecting=false;d.selected=true;d.startselected=true;f._trigger("selected",c,{selected:d.element})});this._trigger("stop",c);this.helper.remove();return false}});e.extend(e.ui.selectable,{version:"1.8.11"})})(jQuery);+;/*+ * jQuery UI Sortable 1.8.11+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Sortables+ *+ * Depends:+ * jquery.ui.core.js+ * jquery.ui.mouse.js+ * jquery.ui.widget.js+ */+(function(d){d.widget("ui.sortable",d.ui.mouse,{widgetEventPrefix:"sort",options:{appendTo:"parent",axis:false,connectWith:false,containment:false,cursor:"auto",cursorAt:false,dropOnEmpty:true,forcePlaceholderSize:false,forceHelperSize:false,grid:false,handle:false,helper:"original",items:"> *",opacity:false,placeholder:false,revert:false,scroll:true,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1E3},_create:function(){this.containerCache={};this.element.addClass("ui-sortable");+this.refresh();this.floating=this.items.length?/left|right/.test(this.items[0].item.css("float"))||/inline|table-cell/.test(this.items[0].item.css("display")):false;this.offset=this.element.offset();this._mouseInit()},destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled").removeData("sortable").unbind(".sortable");this._mouseDestroy();for(var a=this.items.length-1;a>=0;a--)this.items[a].item.removeData("sortable-item");return this},_setOption:function(a,b){if(a==="disabled"){this.options[a]=+b;this.widget()[b?"addClass":"removeClass"]("ui-sortable-disabled")}else d.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(a,b){if(this.reverting)return false;if(this.options.disabled||this.options.type=="static")return false;this._refreshItems(a);var c=null,e=this;d(a.target).parents().each(function(){if(d.data(this,"sortable-item")==e){c=d(this);return false}});if(d.data(a.target,"sortable-item")==e)c=d(a.target);if(!c)return false;if(this.options.handle&&!b){var f=false;+d(this.options.handle,c).find("*").andSelf().each(function(){if(this==a.target)f=true});if(!f)return false}this.currentItem=c;this._removeCurrentsFromItems();return true},_mouseStart:function(a,b,c){b=this.options;var e=this;this.currentContainer=this;this.refreshPositions();this.helper=this._createHelper(a);this._cacheHelperProportions();this._cacheMargins();this.scrollParent=this.helper.scrollParent();this.offset=this.currentItem.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-+this.margins.left};this.helper.css("position","absolute");this.cssPosition=this.helper.css("position");d.extend(this.offset,{click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]};+this.helper[0]!=this.currentItem[0]&&this.currentItem.hide();this._createPlaceholder();b.containment&&this._setContainment();if(b.cursor){if(d("body").css("cursor"))this._storedCursor=d("body").css("cursor");d("body").css("cursor",b.cursor)}if(b.opacity){if(this.helper.css("opacity"))this._storedOpacity=this.helper.css("opacity");this.helper.css("opacity",b.opacity)}if(b.zIndex){if(this.helper.css("zIndex"))this._storedZIndex=this.helper.css("zIndex");this.helper.css("zIndex",b.zIndex)}if(this.scrollParent[0]!=+document&&this.scrollParent[0].tagName!="HTML")this.overflowOffset=this.scrollParent.offset();this._trigger("start",a,this._uiHash());this._preserveHelperProportions||this._cacheHelperProportions();if(!c)for(c=this.containers.length-1;c>=0;c--)this.containers[c]._trigger("activate",a,e._uiHash(this));if(d.ui.ddmanager)d.ui.ddmanager.current=this;d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.dragging=true;this.helper.addClass("ui-sortable-helper");this._mouseDrag(a);+return true},_mouseDrag:function(a){this.position=this._generatePosition(a);this.positionAbs=this._convertPositionTo("absolute");if(!this.lastPositionAbs)this.lastPositionAbs=this.positionAbs;if(this.options.scroll){var b=this.options,c=false;if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"){if(this.overflowOffset.top+this.scrollParent[0].offsetHeight-a.pageY<b.scrollSensitivity)this.scrollParent[0].scrollTop=c=this.scrollParent[0].scrollTop+b.scrollSpeed;else if(a.pageY-this.overflowOffset.top<+b.scrollSensitivity)this.scrollParent[0].scrollTop=c=this.scrollParent[0].scrollTop-b.scrollSpeed;if(this.overflowOffset.left+this.scrollParent[0].offsetWidth-a.pageX<b.scrollSensitivity)this.scrollParent[0].scrollLeft=c=this.scrollParent[0].scrollLeft+b.scrollSpeed;else if(a.pageX-this.overflowOffset.left<b.scrollSensitivity)this.scrollParent[0].scrollLeft=c=this.scrollParent[0].scrollLeft-b.scrollSpeed}else{if(a.pageY-d(document).scrollTop()<b.scrollSensitivity)c=d(document).scrollTop(d(document).scrollTop()-+b.scrollSpeed);else if(d(window).height()-(a.pageY-d(document).scrollTop())<b.scrollSensitivity)c=d(document).scrollTop(d(document).scrollTop()+b.scrollSpeed);if(a.pageX-d(document).scrollLeft()<b.scrollSensitivity)c=d(document).scrollLeft(d(document).scrollLeft()-b.scrollSpeed);else if(d(window).width()-(a.pageX-d(document).scrollLeft())<b.scrollSensitivity)c=d(document).scrollLeft(d(document).scrollLeft()+b.scrollSpeed)}c!==false&&d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,+a)}this.positionAbs=this._convertPositionTo("absolute");if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";for(b=this.items.length-1;b>=0;b--){c=this.items[b];var e=c.item[0],f=this._intersectsWithPointer(c);if(f)if(e!=this.currentItem[0]&&this.placeholder[f==1?"next":"prev"]()[0]!=e&&!d.ui.contains(this.placeholder[0],e)&&(this.options.type=="semi-dynamic"?!d.ui.contains(this.element[0],+e):true)){this.direction=f==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(c))this._rearrange(a,c);else break;this._trigger("change",a,this._uiHash());break}}this._contactContainers(a);d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);this._trigger("sort",a,this._uiHash());this.lastPositionAbs=this.positionAbs;return false},_mouseStop:function(a,b){if(a){d.ui.ddmanager&&!this.options.dropBehaviour&&d.ui.ddmanager.drop(this,a);if(this.options.revert){var c=this;b=c.placeholder.offset();+c.reverting=true;d(this.helper).animate({left:b.left-this.offset.parent.left-c.margins.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft),top:b.top-this.offset.parent.top-c.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){c._clear(a)})}else this._clear(a,b);return false}},cancel:function(){var a=this;if(this.dragging){this._mouseUp({target:null});this.options.helper=="original"?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):+this.currentItem.show();for(var b=this.containers.length-1;b>=0;b--){this.containers[b]._trigger("deactivate",null,a._uiHash(this));if(this.containers[b].containerCache.over){this.containers[b]._trigger("out",null,a._uiHash(this));this.containers[b].containerCache.over=0}}}if(this.placeholder){this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]);this.options.helper!="original"&&this.helper&&this.helper[0].parentNode&&this.helper.remove();d.extend(this,{helper:null,+dragging:false,reverting:false,_noFinalSort:null});this.domPosition.prev?d(this.domPosition.prev).after(this.currentItem):d(this.domPosition.parent).prepend(this.currentItem)}return this},serialize:function(a){var b=this._getItemsAsjQuery(a&&a.connected),c=[];a=a||{};d(b).each(function(){var e=(d(a.item||this).attr(a.attribute||"id")||"").match(a.expression||/(.+)[-=_](.+)/);if(e)c.push((a.key||e[1]+"[]")+"="+(a.key&&a.expression?e[1]:e[2]))});!c.length&&a.key&&c.push(a.key+"=");return c.join("&")},+toArray:function(a){var b=this._getItemsAsjQuery(a&&a.connected),c=[];a=a||{};b.each(function(){c.push(d(a.item||this).attr(a.attribute||"id")||"")});return c},_intersectsWith:function(a){var b=this.positionAbs.left,c=b+this.helperProportions.width,e=this.positionAbs.top,f=e+this.helperProportions.height,g=a.left,h=g+a.width,i=a.top,k=i+a.height,j=this.offset.click.top,l=this.offset.click.left;j=e+j>i&&e+j<k&&b+l>g&&b+l<h;return this.options.tolerance=="pointer"||this.options.forcePointerForContainers||+this.options.tolerance!="pointer"&&this.helperProportions[this.floating?"width":"height"]>a[this.floating?"width":"height"]?j:g<b+this.helperProportions.width/2&&c-this.helperProportions.width/2<h&&i<e+this.helperProportions.height/2&&f-this.helperProportions.height/2<k},_intersectsWithPointer:function(a){var b=d.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,a.top,a.height);a=d.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,a.left,a.width);b=b&&a;a=this._getDragVerticalDirection();+var c=this._getDragHorizontalDirection();if(!b)return false;return this.floating?c&&c=="right"||a=="down"?2:1:a&&(a=="down"?2:1)},_intersectsWithSides:function(a){var b=d.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,a.top+a.height/2,a.height);a=d.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,a.left+a.width/2,a.width);var c=this._getDragVerticalDirection(),e=this._getDragHorizontalDirection();return this.floating&&e?e=="right"&&a||e=="left"&&!a:c&&(c=="down"&&b||c=="up"&&!b)},+_getDragVerticalDirection:function(){var a=this.positionAbs.top-this.lastPositionAbs.top;return a!=0&&(a>0?"down":"up")},_getDragHorizontalDirection:function(){var a=this.positionAbs.left-this.lastPositionAbs.left;return a!=0&&(a>0?"right":"left")},refresh:function(a){this._refreshItems(a);this.refreshPositions();return this},_connectWith:function(){var a=this.options;return a.connectWith.constructor==String?[a.connectWith]:a.connectWith},_getItemsAsjQuery:function(a){var b=[],c=[],e=this._connectWith();+if(e&&a)for(a=e.length-1;a>=0;a--)for(var f=d(e[a]),g=f.length-1;g>=0;g--){var h=d.data(f[g],"sortable");if(h&&h!=this&&!h.options.disabled)c.push([d.isFunction(h.options.items)?h.options.items.call(h.element):d(h.options.items,h.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),h])}c.push([d.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):d(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),+this]);for(a=c.length-1;a>=0;a--)c[a][0].each(function(){b.push(this)});return d(b)},_removeCurrentsFromItems:function(){for(var a=this.currentItem.find(":data(sortable-item)"),b=0;b<this.items.length;b++)for(var c=0;c<a.length;c++)a[c]==this.items[b].item[0]&&this.items.splice(b,1)},_refreshItems:function(a){this.items=[];this.containers=[this];var b=this.items,c=[[d.isFunction(this.options.items)?this.options.items.call(this.element[0],a,{item:this.currentItem}):d(this.options.items,this.element),+this]],e=this._connectWith();if(e)for(var f=e.length-1;f>=0;f--)for(var g=d(e[f]),h=g.length-1;h>=0;h--){var i=d.data(g[h],"sortable");if(i&&i!=this&&!i.options.disabled){c.push([d.isFunction(i.options.items)?i.options.items.call(i.element[0],a,{item:this.currentItem}):d(i.options.items,i.element),i]);this.containers.push(i)}}for(f=c.length-1;f>=0;f--){a=c[f][1];e=c[f][0];h=0;for(g=e.length;h<g;h++){i=d(e[h]);i.data("sortable-item",a);b.push({item:i,instance:a,width:0,height:0,left:0,top:0})}}},refreshPositions:function(a){if(this.offsetParent&&+this.helper)this.offset.parent=this._getParentOffset();for(var b=this.items.length-1;b>=0;b--){var c=this.items[b],e=this.options.toleranceElement?d(this.options.toleranceElement,c.item):c.item;if(!a){c.width=e.outerWidth();c.height=e.outerHeight()}e=e.offset();c.left=e.left;c.top=e.top}if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(b=this.containers.length-1;b>=0;b--){e=this.containers[b].element.offset();this.containers[b].containerCache.left=+e.left;this.containers[b].containerCache.top=e.top;this.containers[b].containerCache.width=this.containers[b].element.outerWidth();this.containers[b].containerCache.height=this.containers[b].element.outerHeight()}return this},_createPlaceholder:function(a){var b=a||this,c=b.options;if(!c.placeholder||c.placeholder.constructor==String){var e=c.placeholder;c.placeholder={element:function(){var f=d(document.createElement(b.currentItem[0].nodeName)).addClass(e||b.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];+if(!e)f.style.visibility="hidden";return f},update:function(f,g){if(!(e&&!c.forcePlaceholderSize)){g.height()||g.height(b.currentItem.innerHeight()-parseInt(b.currentItem.css("paddingTop")||0,10)-parseInt(b.currentItem.css("paddingBottom")||0,10));g.width()||g.width(b.currentItem.innerWidth()-parseInt(b.currentItem.css("paddingLeft")||0,10)-parseInt(b.currentItem.css("paddingRight")||0,10))}}}}b.placeholder=d(c.placeholder.element.call(b.element,b.currentItem));b.currentItem.after(b.placeholder);+c.placeholder.update(b,b.placeholder)},_contactContainers:function(a){for(var b=null,c=null,e=this.containers.length-1;e>=0;e--)if(!d.ui.contains(this.currentItem[0],this.containers[e].element[0]))if(this._intersectsWith(this.containers[e].containerCache)){if(!(b&&d.ui.contains(this.containers[e].element[0],b.element[0]))){b=this.containers[e];c=e}}else if(this.containers[e].containerCache.over){this.containers[e]._trigger("out",a,this._uiHash(this));this.containers[e].containerCache.over=0}if(b)if(this.containers.length===+1){this.containers[c]._trigger("over",a,this._uiHash(this));this.containers[c].containerCache.over=1}else if(this.currentContainer!=this.containers[c]){b=1E4;e=null;for(var f=this.positionAbs[this.containers[c].floating?"left":"top"],g=this.items.length-1;g>=0;g--)if(d.ui.contains(this.containers[c].element[0],this.items[g].item[0])){var h=this.items[g][this.containers[c].floating?"left":"top"];if(Math.abs(h-f)<b){b=Math.abs(h-f);e=this.items[g]}}if(e||this.options.dropOnEmpty){this.currentContainer=+this.containers[c];e?this._rearrange(a,e,null,true):this._rearrange(a,null,this.containers[c].element,true);this._trigger("change",a,this._uiHash());this.containers[c]._trigger("change",a,this._uiHash(this));this.options.placeholder.update(this.currentContainer,this.placeholder);this.containers[c]._trigger("over",a,this._uiHash(this));this.containers[c].containerCache.over=1}}},_createHelper:function(a){var b=this.options;a=d.isFunction(b.helper)?d(b.helper.apply(this.element[0],[a,this.currentItem])):+b.helper=="clone"?this.currentItem.clone():this.currentItem;a.parents("body").length||d(b.appendTo!="parent"?b.appendTo:this.currentItem[0].parentNode)[0].appendChild(a[0]);if(a[0]==this.currentItem[0])this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")};if(a[0].style.width==""||b.forceHelperSize)a.width(this.currentItem.width());if(a[0].style.height==+""||b.forceHelperSize)a.height(this.currentItem.height());return a},_adjustOffsetFromHelper:function(a){if(typeof a=="string")a=a.split(" ");if(d.isArray(a))a={left:+a[0],top:+a[1]||0};if("left"in a)this.offset.click.left=a.left+this.margins.left;if("right"in a)this.offset.click.left=this.helperProportions.width-a.right+this.margins.left;if("top"in a)this.offset.click.top=a.top+this.margins.top;if("bottom"in a)this.offset.click.top=this.helperProportions.height-a.bottom+this.margins.top},_getParentOffset:function(){this.offsetParent=+this.helper.offsetParent();var a=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0])){a.left+=this.scrollParent.scrollLeft();a.top+=this.scrollParent.scrollTop()}if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&d.browser.msie)a={top:0,left:0};return{top:a.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:a.left+(parseInt(this.offsetParent.css("borderLeftWidth"),+10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.currentItem.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions=+{width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var a=this.options;if(a.containment=="parent")a.containment=this.helper[0].parentNode;if(a.containment=="document"||a.containment=="window")this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,d(a.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(d(a.containment=="document"?document:window).height()||+document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(a.containment)){var b=d(a.containment)[0];a=d(a.containment).offset();var c=d(b).css("overflow")!="hidden";this.containment=[a.left+(parseInt(d(b).css("borderLeftWidth"),10)||0)+(parseInt(d(b).css("paddingLeft"),10)||0)-this.margins.left,a.top+(parseInt(d(b).css("borderTopWidth"),10)||0)+(parseInt(d(b).css("paddingTop"),10)||0)-this.margins.top,a.left+(c?Math.max(b.scrollWidth,+b.offsetWidth):b.offsetWidth)-(parseInt(d(b).css("borderLeftWidth"),10)||0)-(parseInt(d(b).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,a.top+(c?Math.max(b.scrollHeight,b.offsetHeight):b.offsetHeight)-(parseInt(d(b).css("borderTopWidth"),10)||0)-(parseInt(d(b).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}},_convertPositionTo:function(a,b){if(!b)b=this.position;a=a=="absolute"?1:-1;var c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=+document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(c[0].tagName);return{top:b.top+this.offset.relative.top*a+this.offset.parent.top*a-(d.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:c.scrollTop())*a),left:b.left+this.offset.relative.left*a+this.offset.parent.left*a-(d.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():+e?0:c.scrollLeft())*a)}},_generatePosition:function(a){var b=this.options,c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(c[0].tagName);if(this.cssPosition=="relative"&&!(this.scrollParent[0]!=document&&this.scrollParent[0]!=this.offsetParent[0]))this.offset.relative=this._getRelativeOffset();var f=a.pageX,g=a.pageY;if(this.originalPosition){if(this.containment){if(a.pageX-+this.offset.click.left<this.containment[0])f=this.containment[0]+this.offset.click.left;if(a.pageY-this.offset.click.top<this.containment[1])g=this.containment[1]+this.offset.click.top;if(a.pageX-this.offset.click.left>this.containment[2])f=this.containment[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>this.containment[3])g=this.containment[3]+this.offset.click.top}if(b.grid){g=this.originalPageY+Math.round((g-this.originalPageY)/b.grid[1])*b.grid[1];g=this.containment?!(g-this.offset.click.top<+this.containment[1]||g-this.offset.click.top>this.containment[3])?g:!(g-this.offset.click.top<this.containment[1])?g-b.grid[1]:g+b.grid[1]:g;f=this.originalPageX+Math.round((f-this.originalPageX)/b.grid[0])*b.grid[0];f=this.containment?!(f-this.offset.click.left<this.containment[0]||f-this.offset.click.left>this.containment[2])?f:!(f-this.offset.click.left<this.containment[0])?f-b.grid[0]:f+b.grid[0]:f}}return{top:g-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(d.browser.safari&&+this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:c.scrollTop()),left:f-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(d.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:c.scrollLeft())}},_rearrange:function(a,b,c,e){c?c[0].appendChild(this.placeholder[0]):b.item[0].parentNode.insertBefore(this.placeholder[0],this.direction=="down"?b.item[0]:b.item[0].nextSibling);this.counter=+this.counter?++this.counter:1;var f=this,g=this.counter;window.setTimeout(function(){g==f.counter&&f.refreshPositions(!e)},0)},_clear:function(a,b){this.reverting=false;var c=[];!this._noFinalSort&&this.currentItem[0].parentNode&&this.placeholder.before(this.currentItem);this._noFinalSort=null;if(this.helper[0]==this.currentItem[0]){for(var e in this._storedCSS)if(this._storedCSS[e]=="auto"||this._storedCSS[e]=="static")this._storedCSS[e]="";this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();+this.fromOutside&&!b&&c.push(function(f){this._trigger("receive",f,this._uiHash(this.fromOutside))});if((this.fromOutside||this.domPosition.prev!=this.currentItem.prev().not(".ui-sortable-helper")[0]||this.domPosition.parent!=this.currentItem.parent()[0])&&!b)c.push(function(f){this._trigger("update",f,this._uiHash())});if(!d.ui.contains(this.element[0],this.currentItem[0])){b||c.push(function(f){this._trigger("remove",f,this._uiHash())});for(e=this.containers.length-1;e>=0;e--)if(d.ui.contains(this.containers[e].element[0],+this.currentItem[0])&&!b){c.push(function(f){return function(g){f._trigger("receive",g,this._uiHash(this))}}.call(this,this.containers[e]));c.push(function(f){return function(g){f._trigger("update",g,this._uiHash(this))}}.call(this,this.containers[e]))}}for(e=this.containers.length-1;e>=0;e--){b||c.push(function(f){return function(g){f._trigger("deactivate",g,this._uiHash(this))}}.call(this,this.containers[e]));if(this.containers[e].containerCache.over){c.push(function(f){return function(g){f._trigger("out",+g,this._uiHash(this))}}.call(this,this.containers[e]));this.containers[e].containerCache.over=0}}this._storedCursor&&d("body").css("cursor",this._storedCursor);this._storedOpacity&&this.helper.css("opacity",this._storedOpacity);if(this._storedZIndex)this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex);this.dragging=false;if(this.cancelHelperRemoval){if(!b){this._trigger("beforeStop",a,this._uiHash());for(e=0;e<c.length;e++)c[e].call(this,a);this._trigger("stop",a,this._uiHash())}return false}b||+this._trigger("beforeStop",a,this._uiHash());this.placeholder[0].parentNode.removeChild(this.placeholder[0]);this.helper[0]!=this.currentItem[0]&&this.helper.remove();this.helper=null;if(!b){for(e=0;e<c.length;e++)c[e].call(this,a);this._trigger("stop",a,this._uiHash())}this.fromOutside=false;return true},_trigger:function(){d.Widget.prototype._trigger.apply(this,arguments)===false&&this.cancel()},_uiHash:function(a){var b=a||this;return{helper:b.helper,placeholder:b.placeholder||d([]),position:b.position,+originalPosition:b.originalPosition,offset:b.positionAbs,item:b.currentItem,sender:a?a.element:null}}});d.extend(d.ui.sortable,{version:"1.8.11"})})(jQuery);+;/*+ * jQuery UI Accordion 1.8.11+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Accordion+ *+ * Depends:+ * jquery.ui.core.js+ * jquery.ui.widget.js+ */+(function(c){c.widget("ui.accordion",{options:{active:0,animated:"slide",autoHeight:true,clearStyle:false,collapsible:false,event:"click",fillSpace:false,header:"> li > :first-child,> :not(li):even",icons:{header:"ui-icon-triangle-1-e",headerSelected:"ui-icon-triangle-1-s"},navigation:false,navigationFilter:function(){return this.href.toLowerCase()===location.href.toLowerCase()}},_create:function(){var a=this,b=a.options;a.running=0;a.element.addClass("ui-accordion ui-widget ui-helper-reset").children("li").addClass("ui-accordion-li-fix");+a.headers=a.element.find(b.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all").bind("mouseenter.accordion",function(){b.disabled||c(this).addClass("ui-state-hover")}).bind("mouseleave.accordion",function(){b.disabled||c(this).removeClass("ui-state-hover")}).bind("focus.accordion",function(){b.disabled||c(this).addClass("ui-state-focus")}).bind("blur.accordion",function(){b.disabled||c(this).removeClass("ui-state-focus")});a.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom");+if(b.navigation){var d=a.element.find("a").filter(b.navigationFilter).eq(0);if(d.length){var h=d.closest(".ui-accordion-header");a.active=h.length?h:d.closest(".ui-accordion-content").prev()}}a.active=a._findActive(a.active||b.active).addClass("ui-state-default ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top");a.active.next().addClass("ui-accordion-content-active");a._createIcons();a.resize();a.element.attr("role","tablist");a.headers.attr("role","tab").bind("keydown.accordion",+function(f){return a._keydown(f)}).next().attr("role","tabpanel");a.headers.not(a.active||"").attr({"aria-expanded":"false","aria-selected":"false",tabIndex:-1}).next().hide();a.active.length?a.active.attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}):a.headers.eq(0).attr("tabIndex",0);c.browser.safari||a.headers.find("a").attr("tabIndex",-1);b.event&&a.headers.bind(b.event.split(" ").join(".accordion ")+".accordion",function(f){a._clickHandler.call(a,f,this);f.preventDefault()})},_createIcons:function(){var a=+this.options;if(a.icons){c("<span></span>").addClass("ui-icon "+a.icons.header).prependTo(this.headers);this.active.children(".ui-icon").toggleClass(a.icons.header).toggleClass(a.icons.headerSelected);this.element.addClass("ui-accordion-icons")}},_destroyIcons:function(){this.headers.children(".ui-icon").remove();this.element.removeClass("ui-accordion-icons")},destroy:function(){var a=this.options;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role");this.headers.unbind(".accordion").removeClass("ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-selected").removeAttr("tabIndex");+this.headers.find("a").removeAttr("tabIndex");this._destroyIcons();var b=this.headers.next().css("display","").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled");if(a.autoHeight||a.fillHeight)b.css("height","");return c.Widget.prototype.destroy.call(this)},_setOption:function(a,b){c.Widget.prototype._setOption.apply(this,arguments);a=="active"&&this.activate(b);if(a=="icons"){this._destroyIcons();+b&&this._createIcons()}if(a=="disabled")this.headers.add(this.headers.next())[b?"addClass":"removeClass"]("ui-accordion-disabled ui-state-disabled")},_keydown:function(a){if(!(this.options.disabled||a.altKey||a.ctrlKey)){var b=c.ui.keyCode,d=this.headers.length,h=this.headers.index(a.target),f=false;switch(a.keyCode){case b.RIGHT:case b.DOWN:f=this.headers[(h+1)%d];break;case b.LEFT:case b.UP:f=this.headers[(h-1+d)%d];break;case b.SPACE:case b.ENTER:this._clickHandler({target:a.target},a.target);+a.preventDefault()}if(f){c(a.target).attr("tabIndex",-1);c(f).attr("tabIndex",0);f.focus();return false}return true}},resize:function(){var a=this.options,b;if(a.fillSpace){if(c.browser.msie){var d=this.element.parent().css("overflow");this.element.parent().css("overflow","hidden")}b=this.element.parent().height();c.browser.msie&&this.element.parent().css("overflow",d);this.headers.each(function(){b-=c(this).outerHeight(true)});this.headers.next().each(function(){c(this).height(Math.max(0,b-c(this).innerHeight()++c(this).height()))}).css("overflow","auto")}else if(a.autoHeight){b=0;this.headers.next().each(function(){b=Math.max(b,c(this).height("").height())}).height(b)}return this},activate:function(a){this.options.active=a;a=this._findActive(a)[0];this._clickHandler({target:a},a);return this},_findActive:function(a){return a?typeof a==="number"?this.headers.filter(":eq("+a+")"):this.headers.not(this.headers.not(a)):a===false?c([]):this.headers.filter(":eq(0)")},_clickHandler:function(a,b){var d=this.options;+if(!d.disabled)if(a.target){a=c(a.currentTarget||b);b=a[0]===this.active[0];d.active=d.collapsible&&b?false:this.headers.index(a);if(!(this.running||!d.collapsible&&b)){var h=this.active;j=a.next();g=this.active.next();e={options:d,newHeader:b&&d.collapsible?c([]):a,oldHeader:this.active,newContent:b&&d.collapsible?c([]):j,oldContent:g};var f=this.headers.index(this.active[0])>this.headers.index(a[0]);this.active=b?c([]):a;this._toggle(j,g,e,b,f);h.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header);+if(!b){a.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top").children(".ui-icon").removeClass(d.icons.header).addClass(d.icons.headerSelected);a.next().addClass("ui-accordion-content-active")}}}else if(d.collapsible){this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header);this.active.next().addClass("ui-accordion-content-active");var g=this.active.next(),+e={options:d,newHeader:c([]),oldHeader:d.active,newContent:c([]),oldContent:g},j=this.active=c([]);this._toggle(j,g,e)}},_toggle:function(a,b,d,h,f){var g=this,e=g.options;g.toShow=a;g.toHide=b;g.data=d;var j=function(){if(g)return g._completed.apply(g,arguments)};g._trigger("changestart",null,g.data);g.running=b.size()===0?a.size():b.size();if(e.animated){d={};d=e.collapsible&&h?{toShow:c([]),toHide:b,complete:j,down:f,autoHeight:e.autoHeight||e.fillSpace}:{toShow:a,toHide:b,complete:j,down:f,autoHeight:e.autoHeight||+e.fillSpace};if(!e.proxied)e.proxied=e.animated;if(!e.proxiedDuration)e.proxiedDuration=e.duration;e.animated=c.isFunction(e.proxied)?e.proxied(d):e.proxied;e.duration=c.isFunction(e.proxiedDuration)?e.proxiedDuration(d):e.proxiedDuration;h=c.ui.accordion.animations;var i=e.duration,k=e.animated;if(k&&!h[k]&&!c.easing[k])k="slide";h[k]||(h[k]=function(l){this.slide(l,{easing:k,duration:i||700})});h[k](d)}else{if(e.collapsible&&h)a.toggle();else{b.hide();a.show()}j(true)}b.prev().attr({"aria-expanded":"false",+"aria-selected":"false",tabIndex:-1}).blur();a.prev().attr({"aria-expanded":"true","aria-selected":"true",tabIndex:0}).focus()},_completed:function(a){this.running=a?0:--this.running;if(!this.running){this.options.clearStyle&&this.toShow.add(this.toHide).css({height:"",overflow:""});this.toHide.removeClass("ui-accordion-content-active");if(this.toHide.length)this.toHide.parent()[0].className=this.toHide.parent()[0].className;this._trigger("change",null,this.data)}}});c.extend(c.ui.accordion,{version:"1.8.11",+animations:{slide:function(a,b){a=c.extend({easing:"swing",duration:300},a,b);if(a.toHide.size())if(a.toShow.size()){var d=a.toShow.css("overflow"),h=0,f={},g={},e;b=a.toShow;e=b[0].style.width;b.width(parseInt(b.parent().width(),10)-parseInt(b.css("paddingLeft"),10)-parseInt(b.css("paddingRight"),10)-(parseInt(b.css("borderLeftWidth"),10)||0)-(parseInt(b.css("borderRightWidth"),10)||0));c.each(["height","paddingTop","paddingBottom"],function(j,i){g[i]="hide";j=(""+c.css(a.toShow[0],i)).match(/^([\d+-.]+)(.*)$/);+f[i]={value:j[1],unit:j[2]||"px"}});a.toShow.css({height:0,overflow:"hidden"}).show();a.toHide.filter(":hidden").each(a.complete).end().filter(":visible").animate(g,{step:function(j,i){if(i.prop=="height")h=i.end-i.start===0?0:(i.now-i.start)/(i.end-i.start);a.toShow[0].style[i.prop]=h*f[i.prop].value+f[i.prop].unit},duration:a.duration,easing:a.easing,complete:function(){a.autoHeight||a.toShow.css("height","");a.toShow.css({width:e,overflow:d});a.complete()}})}else a.toHide.animate({height:"hide",+paddingTop:"hide",paddingBottom:"hide"},a);else a.toShow.animate({height:"show",paddingTop:"show",paddingBottom:"show"},a)},bounceslide:function(a){this.slide(a,{easing:a.down?"easeOutBounce":"swing",duration:a.down?1E3:200})}}})})(jQuery);+;/*+ * jQuery UI Autocomplete 1.8.11+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Autocomplete+ *+ * Depends:+ * jquery.ui.core.js+ * jquery.ui.widget.js+ * jquery.ui.position.js+ */+(function(d){var e=0;d.widget("ui.autocomplete",{options:{appendTo:"body",autoFocus:false,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null},pending:0,_create:function(){var a=this,b=this.element[0].ownerDocument,g;this.element.addClass("ui-autocomplete-input").attr("autocomplete","off").attr({role:"textbox","aria-autocomplete":"list","aria-haspopup":"true"}).bind("keydown.autocomplete",function(c){if(!(a.options.disabled||a.element.attr("readonly"))){g=+false;var f=d.ui.keyCode;switch(c.keyCode){case f.PAGE_UP:a._move("previousPage",c);break;case f.PAGE_DOWN:a._move("nextPage",c);break;case f.UP:a._move("previous",c);c.preventDefault();break;case f.DOWN:a._move("next",c);c.preventDefault();break;case f.ENTER:case f.NUMPAD_ENTER:if(a.menu.active){g=true;c.preventDefault()}case f.TAB:if(!a.menu.active)return;a.menu.select(c);break;case f.ESCAPE:a.element.val(a.term);a.close(c);break;default:clearTimeout(a.searching);a.searching=setTimeout(function(){if(a.term!=+a.element.val()){a.selectedItem=null;a.search(null,c)}},a.options.delay);break}}}).bind("keypress.autocomplete",function(c){if(g){g=false;c.preventDefault()}}).bind("focus.autocomplete",function(){if(!a.options.disabled){a.selectedItem=null;a.previous=a.element.val()}}).bind("blur.autocomplete",function(c){if(!a.options.disabled){clearTimeout(a.searching);a.closing=setTimeout(function(){a.close(c);a._change(c)},150)}});this._initSource();this.response=function(){return a._response.apply(a,arguments)};+this.menu=d("<ul></ul>").addClass("ui-autocomplete").appendTo(d(this.options.appendTo||"body",b)[0]).mousedown(function(c){var f=a.menu.element[0];d(c.target).closest(".ui-menu-item").length||setTimeout(function(){d(document).one("mousedown",function(h){h.target!==a.element[0]&&h.target!==f&&!d.ui.contains(f,h.target)&&a.close()})},1);setTimeout(function(){clearTimeout(a.closing)},13)}).menu({focus:function(c,f){f=f.item.data("item.autocomplete");false!==a._trigger("focus",c,{item:f})&&/^key/.test(c.originalEvent.type)&&+a.element.val(f.value)},selected:function(c,f){var h=f.item.data("item.autocomplete"),i=a.previous;if(a.element[0]!==b.activeElement){a.element.focus();a.previous=i;setTimeout(function(){a.previous=i;a.selectedItem=h},1)}false!==a._trigger("select",c,{item:h})&&a.element.val(h.value);a.term=a.element.val();a.close(c);a.selectedItem=h},blur:function(){a.menu.element.is(":visible")&&a.element.val()!==a.term&&a.element.val(a.term)}}).zIndex(this.element.zIndex()+1).css({top:0,left:0}).hide().data("menu");+d.fn.bgiframe&&this.menu.element.bgiframe()},destroy:function(){this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete").removeAttr("role").removeAttr("aria-autocomplete").removeAttr("aria-haspopup");this.menu.element.remove();d.Widget.prototype.destroy.call(this)},_setOption:function(a,b){d.Widget.prototype._setOption.apply(this,arguments);a==="source"&&this._initSource();if(a==="appendTo")this.menu.element.appendTo(d(b||"body",this.element[0].ownerDocument)[0]);a==="disabled"&&+b&&this.xhr&&this.xhr.abort()},_initSource:function(){var a=this,b,g;if(d.isArray(this.options.source)){b=this.options.source;this.source=function(c,f){f(d.ui.autocomplete.filter(b,c.term))}}else if(typeof this.options.source==="string"){g=this.options.source;this.source=function(c,f){a.xhr&&a.xhr.abort();a.xhr=d.ajax({url:g,data:c,dataType:"json",autocompleteRequest:++e,success:function(h){this.autocompleteRequest===e&&f(h)},error:function(){this.autocompleteRequest===e&&f([])}})}}else this.source=+this.options.source},search:function(a,b){a=a!=null?a:this.element.val();this.term=this.element.val();if(a.length<this.options.minLength)return this.close(b);clearTimeout(this.closing);if(this._trigger("search",b)!==false)return this._search(a)},_search:function(a){this.pending++;this.element.addClass("ui-autocomplete-loading");this.source({term:a},this.response)},_response:function(a){if(!this.options.disabled&&a&&a.length){a=this._normalize(a);this._suggest(a);this._trigger("open")}else this.close();+this.pending--;this.pending||this.element.removeClass("ui-autocomplete-loading")},close:function(a){clearTimeout(this.closing);if(this.menu.element.is(":visible")){this.menu.element.hide();this.menu.deactivate();this._trigger("close",a)}},_change:function(a){this.previous!==this.element.val()&&this._trigger("change",a,{item:this.selectedItem})},_normalize:function(a){if(a.length&&a[0].label&&a[0].value)return a;return d.map(a,function(b){if(typeof b==="string")return{label:b,value:b};return d.extend({label:b.label||+b.value,value:b.value||b.label},b)})},_suggest:function(a){var b=this.menu.element.empty().zIndex(this.element.zIndex()+1);this._renderMenu(b,a);this.menu.deactivate();this.menu.refresh();b.show();this._resizeMenu();b.position(d.extend({of:this.element},this.options.position));this.options.autoFocus&&this.menu.next(new d.Event("mouseover"))},_resizeMenu:function(){var a=this.menu.element;a.outerWidth(Math.max(a.width("").outerWidth(),this.element.outerWidth()))},_renderMenu:function(a,b){var g=this;+d.each(b,function(c,f){g._renderItem(a,f)})},_renderItem:function(a,b){return d("<li></li>").data("item.autocomplete",b).append(d("<a></a>").text(b.label)).appendTo(a)},_move:function(a,b){if(this.menu.element.is(":visible"))if(this.menu.first()&&/^previous/.test(a)||this.menu.last()&&/^next/.test(a)){this.element.val(this.term);this.menu.deactivate()}else this.menu[a](b);else this.search(null,b)},widget:function(){return this.menu.element}});d.extend(d.ui.autocomplete,{escapeRegex:function(a){return a.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,+"\\$&")},filter:function(a,b){var g=new RegExp(d.ui.autocomplete.escapeRegex(b),"i");return d.grep(a,function(c){return g.test(c.label||c.value||c)})}})})(jQuery);+(function(d){d.widget("ui.menu",{_create:function(){var e=this;this.element.addClass("ui-menu ui-widget ui-widget-content ui-corner-all").attr({role:"listbox","aria-activedescendant":"ui-active-menuitem"}).click(function(a){if(d(a.target).closest(".ui-menu-item a").length){a.preventDefault();e.select(a)}});this.refresh()},refresh:function(){var e=this;this.element.children("li:not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","menuitem").children("a").addClass("ui-corner-all").attr("tabindex",+-1).mouseenter(function(a){e.activate(a,d(this).parent())}).mouseleave(function(){e.deactivate()})},activate:function(e,a){this.deactivate();if(this.hasScroll()){var b=a.offset().top-this.element.offset().top,g=this.element.attr("scrollTop"),c=this.element.height();if(b<0)this.element.attr("scrollTop",g+b);else b>=c&&this.element.attr("scrollTop",g+b-c+a.height())}this.active=a.eq(0).children("a").addClass("ui-state-hover").attr("id","ui-active-menuitem").end();this._trigger("focus",e,{item:a})},+deactivate:function(){if(this.active){this.active.children("a").removeClass("ui-state-hover").removeAttr("id");this._trigger("blur");this.active=null}},next:function(e){this.move("next",".ui-menu-item:first",e)},previous:function(e){this.move("prev",".ui-menu-item:last",e)},first:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},last:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},move:function(e,a,b){if(this.active){e=this.active[e+"All"](".ui-menu-item").eq(0);+e.length?this.activate(b,e):this.activate(b,this.element.children(a))}else this.activate(b,this.element.children(a))},nextPage:function(e){if(this.hasScroll())if(!this.active||this.last())this.activate(e,this.element.children(".ui-menu-item:first"));else{var a=this.active.offset().top,b=this.element.height(),g=this.element.children(".ui-menu-item").filter(function(){var c=d(this).offset().top-a-b+d(this).height();return c<10&&c>-10});g.length||(g=this.element.children(".ui-menu-item:last"));this.activate(e,+g)}else this.activate(e,this.element.children(".ui-menu-item").filter(!this.active||this.last()?":first":":last"))},previousPage:function(e){if(this.hasScroll())if(!this.active||this.first())this.activate(e,this.element.children(".ui-menu-item:last"));else{var a=this.active.offset().top,b=this.element.height();result=this.element.children(".ui-menu-item").filter(function(){var g=d(this).offset().top-a+b-d(this).height();return g<10&&g>-10});result.length||(result=this.element.children(".ui-menu-item:first"));+this.activate(e,result)}else this.activate(e,this.element.children(".ui-menu-item").filter(!this.active||this.first()?":last":":first"))},hasScroll:function(){return this.element.height()<this.element.attr("scrollHeight")},select:function(e){this._trigger("selected",e,{item:this.active})}})})(jQuery);+;/*+ * jQuery UI Button 1.8.11+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Button+ *+ * Depends:+ * jquery.ui.core.js+ * jquery.ui.widget.js+ */+(function(a){var g,i=function(b){a(":ui-button",b.target.form).each(function(){var c=a(this).data("button");setTimeout(function(){c.refresh()},1)})},h=function(b){var c=b.name,d=b.form,f=a([]);if(c)f=d?a(d).find("[name='"+c+"']"):a("[name='"+c+"']",b.ownerDocument).filter(function(){return!this.form});return f};a.widget("ui.button",{options:{disabled:null,text:true,label:null,icons:{primary:null,secondary:null}},_create:function(){this.element.closest("form").unbind("reset.button").bind("reset.button",+i);if(typeof this.options.disabled!=="boolean")this.options.disabled=this.element.attr("disabled");this._determineButtonType();this.hasTitle=!!this.buttonElement.attr("title");var b=this,c=this.options,d=this.type==="checkbox"||this.type==="radio",f="ui-state-hover"+(!d?" ui-state-active":"");if(c.label===null)c.label=this.buttonElement.html();if(this.element.is(":disabled"))c.disabled=true;this.buttonElement.addClass("ui-button ui-widget ui-state-default ui-corner-all").attr("role","button").bind("mouseenter.button",+function(){if(!c.disabled){a(this).addClass("ui-state-hover");this===g&&a(this).addClass("ui-state-active")}}).bind("mouseleave.button",function(){c.disabled||a(this).removeClass(f)}).bind("focus.button",function(){a(this).addClass("ui-state-focus")}).bind("blur.button",function(){a(this).removeClass("ui-state-focus")});d&&this.element.bind("change.button",function(){b.refresh()});if(this.type==="checkbox")this.buttonElement.bind("click.button",function(){if(c.disabled)return false;a(this).toggleClass("ui-state-active");+b.buttonElement.attr("aria-pressed",b.element[0].checked)});else if(this.type==="radio")this.buttonElement.bind("click.button",function(){if(c.disabled)return false;a(this).addClass("ui-state-active");b.buttonElement.attr("aria-pressed",true);var e=b.element[0];h(e).not(e).map(function(){return a(this).button("widget")[0]}).removeClass("ui-state-active").attr("aria-pressed",false)});else{this.buttonElement.bind("mousedown.button",function(){if(c.disabled)return false;a(this).addClass("ui-state-active");+g=this;a(document).one("mouseup",function(){g=null})}).bind("mouseup.button",function(){if(c.disabled)return false;a(this).removeClass("ui-state-active")}).bind("keydown.button",function(e){if(c.disabled)return false;if(e.keyCode==a.ui.keyCode.SPACE||e.keyCode==a.ui.keyCode.ENTER)a(this).addClass("ui-state-active")}).bind("keyup.button",function(){a(this).removeClass("ui-state-active")});this.buttonElement.is("a")&&this.buttonElement.keyup(function(e){e.keyCode===a.ui.keyCode.SPACE&&a(this).click()})}this._setOption("disabled",+c.disabled)},_determineButtonType:function(){this.type=this.element.is(":checkbox")?"checkbox":this.element.is(":radio")?"radio":this.element.is("input")?"input":"button";if(this.type==="checkbox"||this.type==="radio"){var b=this.element.parents().filter(":last"),c="label[for="+this.element.attr("id")+"]";this.buttonElement=b.find(c);if(!this.buttonElement.length){b=b.length?b.siblings():this.element.siblings();this.buttonElement=b.filter(c);if(!this.buttonElement.length)this.buttonElement=b.find(c)}this.element.addClass("ui-helper-hidden-accessible");+(b=this.element.is(":checked"))&&this.buttonElement.addClass("ui-state-active");this.buttonElement.attr("aria-pressed",b)}else this.buttonElement=this.element},widget:function(){return this.buttonElement},destroy:function(){this.element.removeClass("ui-helper-hidden-accessible");this.buttonElement.removeClass("ui-button ui-widget ui-state-default ui-corner-all ui-state-hover ui-state-active ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only").removeAttr("role").removeAttr("aria-pressed").html(this.buttonElement.find(".ui-button-text").html());+this.hasTitle||this.buttonElement.removeAttr("title");a.Widget.prototype.destroy.call(this)},_setOption:function(b,c){a.Widget.prototype._setOption.apply(this,arguments);if(b==="disabled")c?this.element.attr("disabled",true):this.element.removeAttr("disabled");this._resetButton()},refresh:function(){var b=this.element.is(":disabled");b!==this.options.disabled&&this._setOption("disabled",b);if(this.type==="radio")h(this.element[0]).each(function(){a(this).is(":checked")?a(this).button("widget").addClass("ui-state-active").attr("aria-pressed",+true):a(this).button("widget").removeClass("ui-state-active").attr("aria-pressed",false)});else if(this.type==="checkbox")this.element.is(":checked")?this.buttonElement.addClass("ui-state-active").attr("aria-pressed",true):this.buttonElement.removeClass("ui-state-active").attr("aria-pressed",false)},_resetButton:function(){if(this.type==="input")this.options.label&&this.element.val(this.options.label);else{var b=this.buttonElement.removeClass("ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only"),+c=a("<span></span>").addClass("ui-button-text").html(this.options.label).appendTo(b.empty()).text(),d=this.options.icons,f=d.primary&&d.secondary,e=[];if(d.primary||d.secondary){if(this.options.text)e.push("ui-button-text-icon"+(f?"s":d.primary?"-primary":"-secondary"));d.primary&&b.prepend("<span class='ui-button-icon-primary ui-icon "+d.primary+"'></span>");d.secondary&&b.append("<span class='ui-button-icon-secondary ui-icon "+d.secondary+"'></span>");if(!this.options.text){e.push(f?"ui-button-icons-only":+"ui-button-icon-only");this.hasTitle||b.attr("title",c)}}else e.push("ui-button-text-only");b.addClass(e.join(" "))}}});a.widget("ui.buttonset",{options:{items:":button, :submit, :reset, :checkbox, :radio, a, :data(button)"},_create:function(){this.element.addClass("ui-buttonset")},_init:function(){this.refresh()},_setOption:function(b,c){b==="disabled"&&this.buttons.button("option",b,c);a.Widget.prototype._setOption.apply(this,arguments)},refresh:function(){this.buttons=this.element.find(this.options.items).filter(":ui-button").button("refresh").end().not(":ui-button").button().end().map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":first").addClass("ui-corner-left").end().filter(":last").addClass("ui-corner-right").end().end()},+destroy:function(){this.element.removeClass("ui-buttonset");this.buttons.map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy");a.Widget.prototype.destroy.call(this)}})})(jQuery);+;/*+ * jQuery UI Dialog 1.8.11+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Dialog+ *+ * Depends:+ * jquery.ui.core.js+ * jquery.ui.widget.js+ * jquery.ui.button.js+ * jquery.ui.draggable.js+ * jquery.ui.mouse.js+ * jquery.ui.position.js+ * jquery.ui.resizable.js+ */+(function(c,j){var k={buttons:true,height:true,maxHeight:true,maxWidth:true,minHeight:true,minWidth:true,width:true},l={maxHeight:true,maxWidth:true,minHeight:true,minWidth:true};c.widget("ui.dialog",{options:{autoOpen:true,buttons:{},closeOnEscape:true,closeText:"close",dialogClass:"",draggable:true,hide:null,height:"auto",maxHeight:false,maxWidth:false,minHeight:150,minWidth:150,modal:false,position:{my:"center",at:"center",collision:"fit",using:function(a){var b=c(this).css(a).offset().top;b<0&&+c(this).css("top",a.top-b)}},resizable:true,show:null,stack:true,title:"",width:300,zIndex:1E3},_create:function(){this.originalTitle=this.element.attr("title");if(typeof this.originalTitle!=="string")this.originalTitle="";this.options.title=this.options.title||this.originalTitle;var a=this,b=a.options,d=b.title||" ",e=c.ui.dialog.getTitleId(a.element),g=(a.uiDialog=c("<div></div>")).appendTo(document.body).hide().addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+b.dialogClass).css({zIndex:b.zIndex}).attr("tabIndex",+-1).css("outline",0).keydown(function(i){if(b.closeOnEscape&&i.keyCode&&i.keyCode===c.ui.keyCode.ESCAPE){a.close(i);i.preventDefault()}}).attr({role:"dialog","aria-labelledby":e}).mousedown(function(i){a.moveToTop(false,i)});a.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(g);var f=(a.uiDialogTitlebar=c("<div></div>")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(g),h=c('<a href="#"></a>').addClass("ui-dialog-titlebar-close ui-corner-all").attr("role",+"button").hover(function(){h.addClass("ui-state-hover")},function(){h.removeClass("ui-state-hover")}).focus(function(){h.addClass("ui-state-focus")}).blur(function(){h.removeClass("ui-state-focus")}).click(function(i){a.close(i);return false}).appendTo(f);(a.uiDialogTitlebarCloseText=c("<span></span>")).addClass("ui-icon ui-icon-closethick").text(b.closeText).appendTo(h);c("<span></span>").addClass("ui-dialog-title").attr("id",e).html(d).prependTo(f);if(c.isFunction(b.beforeclose)&&!c.isFunction(b.beforeClose))b.beforeClose=+b.beforeclose;f.find("*").add(f).disableSelection();b.draggable&&c.fn.draggable&&a._makeDraggable();b.resizable&&c.fn.resizable&&a._makeResizable();a._createButtons(b.buttons);a._isOpen=false;c.fn.bgiframe&&g.bgiframe()},_init:function(){this.options.autoOpen&&this.open()},destroy:function(){var a=this;a.overlay&&a.overlay.destroy();a.uiDialog.hide();a.element.unbind(".dialog").removeData("dialog").removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body");a.uiDialog.remove();a.originalTitle&&+a.element.attr("title",a.originalTitle);return a},widget:function(){return this.uiDialog},close:function(a){var b=this,d,e;if(false!==b._trigger("beforeClose",a)){b.overlay&&b.overlay.destroy();b.uiDialog.unbind("keypress.ui-dialog");b._isOpen=false;if(b.options.hide)b.uiDialog.hide(b.options.hide,function(){b._trigger("close",a)});else{b.uiDialog.hide();b._trigger("close",a)}c.ui.dialog.overlay.resize();if(b.options.modal){d=0;c(".ui-dialog").each(function(){if(this!==b.uiDialog[0]){e=c(this).css("z-index");+isNaN(e)||(d=Math.max(d,e))}});c.ui.dialog.maxZ=d}return b}},isOpen:function(){return this._isOpen},moveToTop:function(a,b){var d=this,e=d.options;if(e.modal&&!a||!e.stack&&!e.modal)return d._trigger("focus",b);if(e.zIndex>c.ui.dialog.maxZ)c.ui.dialog.maxZ=e.zIndex;if(d.overlay){c.ui.dialog.maxZ+=1;d.overlay.$el.css("z-index",c.ui.dialog.overlay.maxZ=c.ui.dialog.maxZ)}a={scrollTop:d.element.attr("scrollTop"),scrollLeft:d.element.attr("scrollLeft")};c.ui.dialog.maxZ+=1;d.uiDialog.css("z-index",c.ui.dialog.maxZ);+d.element.attr(a);d._trigger("focus",b);return d},open:function(){if(!this._isOpen){var a=this,b=a.options,d=a.uiDialog;a.overlay=b.modal?new c.ui.dialog.overlay(a):null;a._size();a._position(b.position);d.show(b.show);a.moveToTop(true);b.modal&&d.bind("keypress.ui-dialog",function(e){if(e.keyCode===c.ui.keyCode.TAB){var g=c(":tabbable",this),f=g.filter(":first");g=g.filter(":last");if(e.target===g[0]&&!e.shiftKey){f.focus(1);return false}else if(e.target===f[0]&&e.shiftKey){g.focus(1);return false}}});+c(a.element.find(":tabbable").get().concat(d.find(".ui-dialog-buttonpane :tabbable").get().concat(d.get()))).eq(0).focus();a._isOpen=true;a._trigger("open");return a}},_createButtons:function(a){var b=this,d=false,e=c("<div></div>").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),g=c("<div></div>").addClass("ui-dialog-buttonset").appendTo(e);b.uiDialog.find(".ui-dialog-buttonpane").remove();typeof a==="object"&&a!==null&&c.each(a,function(){return!(d=true)});if(d){c.each(a,function(f,+h){h=c.isFunction(h)?{click:h,text:f}:h;f=c('<button type="button"></button>').attr(h,true).unbind("click").click(function(){h.click.apply(b.element[0],arguments)}).appendTo(g);c.fn.button&&f.button()});e.appendTo(b.uiDialog)}},_makeDraggable:function(){function a(f){return{position:f.position,offset:f.offset}}var b=this,d=b.options,e=c(document),g;b.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(f,h){g=+d.height==="auto"?"auto":c(this).height();c(this).height(c(this).height()).addClass("ui-dialog-dragging");b._trigger("dragStart",f,a(h))},drag:function(f,h){b._trigger("drag",f,a(h))},stop:function(f,h){d.position=[h.position.left-e.scrollLeft(),h.position.top-e.scrollTop()];c(this).removeClass("ui-dialog-dragging").height(g);b._trigger("dragStop",f,a(h));c.ui.dialog.overlay.resize()}})},_makeResizable:function(a){function b(f){return{originalPosition:f.originalPosition,originalSize:f.originalSize,+position:f.position,size:f.size}}a=a===j?this.options.resizable:a;var d=this,e=d.options,g=d.uiDialog.css("position");a=typeof a==="string"?a:"n,e,s,w,se,sw,ne,nw";d.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:d.element,maxWidth:e.maxWidth,maxHeight:e.maxHeight,minWidth:e.minWidth,minHeight:d._minHeight(),handles:a,start:function(f,h){c(this).addClass("ui-dialog-resizing");d._trigger("resizeStart",f,b(h))},resize:function(f,h){d._trigger("resize",f,b(h))},stop:function(f,+h){c(this).removeClass("ui-dialog-resizing");e.height=c(this).height();e.width=c(this).width();d._trigger("resizeStop",f,b(h));c.ui.dialog.overlay.resize()}}).css("position",g).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var a=this.options;return a.height==="auto"?a.minHeight:Math.min(a.minHeight,a.height)},_position:function(a){var b=[],d=[0,0],e;if(a){if(typeof a==="string"||typeof a==="object"&&"0"in a){b=a.split?a.split(" "):[a[0],a[1]];if(b.length===+1)b[1]=b[0];c.each(["left","top"],function(g,f){if(+b[g]===b[g]){d[g]=b[g];b[g]=f}});a={my:b.join(" "),at:b.join(" "),offset:d.join(" ")}}a=c.extend({},c.ui.dialog.prototype.options.position,a)}else a=c.ui.dialog.prototype.options.position;(e=this.uiDialog.is(":visible"))||this.uiDialog.show();this.uiDialog.css({top:0,left:0}).position(c.extend({of:window},a));e||this.uiDialog.hide()},_setOptions:function(a){var b=this,d={},e=false;c.each(a,function(g,f){b._setOption(g,f);if(g in k)e=true;if(g in+l)d[g]=f});e&&this._size();this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option",d)},_setOption:function(a,b){var d=this,e=d.uiDialog;switch(a){case "beforeclose":a="beforeClose";break;case "buttons":d._createButtons(b);break;case "closeText":d.uiDialogTitlebarCloseText.text(""+b);break;case "dialogClass":e.removeClass(d.options.dialogClass).addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+b);break;case "disabled":b?e.addClass("ui-dialog-disabled"):e.removeClass("ui-dialog-disabled");+break;case "draggable":var g=e.is(":data(draggable)");g&&!b&&e.draggable("destroy");!g&&b&&d._makeDraggable();break;case "position":d._position(b);break;case "resizable":(g=e.is(":data(resizable)"))&&!b&&e.resizable("destroy");g&&typeof b==="string"&&e.resizable("option","handles",b);!g&&b!==false&&d._makeResizable(b);break;case "title":c(".ui-dialog-title",d.uiDialogTitlebar).html(""+(b||" "));break}c.Widget.prototype._setOption.apply(d,arguments)},_size:function(){var a=this.options,b,d,e=+this.uiDialog.is(":visible");this.element.show().css({width:"auto",minHeight:0,height:0});if(a.minWidth>a.width)a.width=a.minWidth;b=this.uiDialog.css({height:"auto",width:a.width}).height();d=Math.max(0,a.minHeight-b);if(a.height==="auto")if(c.support.minHeight)this.element.css({minHeight:d,height:"auto"});else{this.uiDialog.show();a=this.element.css("height","auto").height();e||this.uiDialog.hide();this.element.height(Math.max(a,d))}else this.element.height(Math.max(a.height-b,0));this.uiDialog.is(":data(resizable)")&&+this.uiDialog.resizable("option","minHeight",this._minHeight())}});c.extend(c.ui.dialog,{version:"1.8.11",uuid:0,maxZ:0,getTitleId:function(a){a=a.attr("id");if(!a){this.uuid+=1;a=this.uuid}return"ui-dialog-title-"+a},overlay:function(a){this.$el=c.ui.dialog.overlay.create(a)}});c.extend(c.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:c.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(a){return a+".dialog-overlay"}).join(" "),create:function(a){if(this.instances.length===+0){setTimeout(function(){c.ui.dialog.overlay.instances.length&&c(document).bind(c.ui.dialog.overlay.events,function(d){if(c(d.target).zIndex()<c.ui.dialog.overlay.maxZ)return false})},1);c(document).bind("keydown.dialog-overlay",function(d){if(a.options.closeOnEscape&&d.keyCode&&d.keyCode===c.ui.keyCode.ESCAPE){a.close(d);d.preventDefault()}});c(window).bind("resize.dialog-overlay",c.ui.dialog.overlay.resize)}var b=(this.oldInstances.pop()||c("<div></div>").addClass("ui-widget-overlay")).appendTo(document.body).css({width:this.width(),+height:this.height()});c.fn.bgiframe&&b.bgiframe();this.instances.push(b);return b},destroy:function(a){var b=c.inArray(a,this.instances);b!=-1&&this.oldInstances.push(this.instances.splice(b,1)[0]);this.instances.length===0&&c([document,window]).unbind(".dialog-overlay");a.remove();var d=0;c.each(this.instances,function(){d=Math.max(d,this.css("z-index"))});this.maxZ=d},height:function(){var a,b;if(c.browser.msie&&c.browser.version<7){a=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight);+b=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight);return a<b?c(window).height()+"px":a+"px"}else return c(document).height()+"px"},width:function(){var a,b;if(c.browser.msie&&c.browser.version<7){a=Math.max(document.documentElement.scrollWidth,document.body.scrollWidth);b=Math.max(document.documentElement.offsetWidth,document.body.offsetWidth);return a<b?c(window).width()+"px":a+"px"}else return c(document).width()+"px"},resize:function(){var a=c([]);c.each(c.ui.dialog.overlay.instances,+function(){a=a.add(this)});a.css({width:0,height:0}).css({width:c.ui.dialog.overlay.width(),height:c.ui.dialog.overlay.height()})}});c.extend(c.ui.dialog.overlay.prototype,{destroy:function(){c.ui.dialog.overlay.destroy(this.$el)}})})(jQuery);+;/*+ * jQuery UI Slider 1.8.11+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Slider+ *+ * Depends:+ * jquery.ui.core.js+ * jquery.ui.mouse.js+ * jquery.ui.widget.js+ */+(function(d){d.widget("ui.slider",d.ui.mouse,{widgetEventPrefix:"slide",options:{animate:false,distance:0,max:100,min:0,orientation:"horizontal",range:false,step:1,value:0,values:null},_create:function(){var b=this,a=this.options;this._mouseSliding=this._keySliding=false;this._animateOff=true;this._handleIndex=null;this._detectOrientation();this._mouseInit();this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget ui-widget-content ui-corner-all");a.disabled&&this.element.addClass("ui-slider-disabled ui-disabled");+this.range=d([]);if(a.range){if(a.range===true){this.range=d("<div></div>");if(!a.values)a.values=[this._valueMin(),this._valueMin()];if(a.values.length&&a.values.length!==2)a.values=[a.values[0],a.values[0]]}else this.range=d("<div></div>");this.range.appendTo(this.element).addClass("ui-slider-range");if(a.range==="min"||a.range==="max")this.range.addClass("ui-slider-range-"+a.range);this.range.addClass("ui-widget-header")}d(".ui-slider-handle",this.element).length===0&&d("<a href='#'></a>").appendTo(this.element).addClass("ui-slider-handle");+if(a.values&&a.values.length)for(;d(".ui-slider-handle",this.element).length<a.values.length;)d("<a href='#'></a>").appendTo(this.element).addClass("ui-slider-handle");this.handles=d(".ui-slider-handle",this.element).addClass("ui-state-default ui-corner-all");this.handle=this.handles.eq(0);this.handles.add(this.range).filter("a").click(function(c){c.preventDefault()}).hover(function(){a.disabled||d(this).addClass("ui-state-hover")},function(){d(this).removeClass("ui-state-hover")}).focus(function(){if(a.disabled)d(this).blur();+else{d(".ui-slider .ui-state-focus").removeClass("ui-state-focus");d(this).addClass("ui-state-focus")}}).blur(function(){d(this).removeClass("ui-state-focus")});this.handles.each(function(c){d(this).data("index.ui-slider-handle",c)});this.handles.keydown(function(c){var e=true,f=d(this).data("index.ui-slider-handle"),h,g,i;if(!b.options.disabled){switch(c.keyCode){case d.ui.keyCode.HOME:case d.ui.keyCode.END:case d.ui.keyCode.PAGE_UP:case d.ui.keyCode.PAGE_DOWN:case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:e=+false;if(!b._keySliding){b._keySliding=true;d(this).addClass("ui-state-active");h=b._start(c,f);if(h===false)return}break}i=b.options.step;h=b.options.values&&b.options.values.length?(g=b.values(f)):(g=b.value());switch(c.keyCode){case d.ui.keyCode.HOME:g=b._valueMin();break;case d.ui.keyCode.END:g=b._valueMax();break;case d.ui.keyCode.PAGE_UP:g=b._trimAlignValue(h+(b._valueMax()-b._valueMin())/5);break;case d.ui.keyCode.PAGE_DOWN:g=b._trimAlignValue(h-(b._valueMax()-b._valueMin())/5);break;case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:if(h===+b._valueMax())return;g=b._trimAlignValue(h+i);break;case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:if(h===b._valueMin())return;g=b._trimAlignValue(h-i);break}b._slide(c,f,g);return e}}).keyup(function(c){var e=d(this).data("index.ui-slider-handle");if(b._keySliding){b._keySliding=false;b._stop(c,e);b._change(c,e);d(this).removeClass("ui-state-active")}});this._refreshValue();this._animateOff=false},destroy:function(){this.handles.remove();this.range.remove();this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider");+this._mouseDestroy();return this},_mouseCapture:function(b){var a=this.options,c,e,f,h,g;if(a.disabled)return false;this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()};this.elementOffset=this.element.offset();c=this._normValueFromMouse({x:b.pageX,y:b.pageY});e=this._valueMax()-this._valueMin()+1;h=this;this.handles.each(function(i){var j=Math.abs(c-h.values(i));if(e>j){e=j;f=d(this);g=i}});if(a.range===true&&this.values(1)===a.min){g+=1;f=d(this.handles[g])}if(this._start(b,+g)===false)return false;this._mouseSliding=true;h._handleIndex=g;f.addClass("ui-state-active").focus();a=f.offset();this._clickOffset=!d(b.target).parents().andSelf().is(".ui-slider-handle")?{left:0,top:0}:{left:b.pageX-a.left-f.width()/2,top:b.pageY-a.top-f.height()/2-(parseInt(f.css("borderTopWidth"),10)||0)-(parseInt(f.css("borderBottomWidth"),10)||0)+(parseInt(f.css("marginTop"),10)||0)};this.handles.hasClass("ui-state-hover")||this._slide(b,g,c);return this._animateOff=true},_mouseStart:function(){return true},+_mouseDrag:function(b){var a=this._normValueFromMouse({x:b.pageX,y:b.pageY});this._slide(b,this._handleIndex,a);return false},_mouseStop:function(b){this.handles.removeClass("ui-state-active");this._mouseSliding=false;this._stop(b,this._handleIndex);this._change(b,this._handleIndex);this._clickOffset=this._handleIndex=null;return this._animateOff=false},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(b){var a;+if(this.orientation==="horizontal"){a=this.elementSize.width;b=b.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)}else{a=this.elementSize.height;b=b.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)}a=b/a;if(a>1)a=1;if(a<0)a=0;if(this.orientation==="vertical")a=1-a;b=this._valueMax()-this._valueMin();return this._trimAlignValue(this._valueMin()+a*b)},_start:function(b,a){var c={handle:this.handles[a],value:this.value()};if(this.options.values&&this.options.values.length){c.value=+this.values(a);c.values=this.values()}return this._trigger("start",b,c)},_slide:function(b,a,c){var e;if(this.options.values&&this.options.values.length){e=this.values(a?0:1);if(this.options.values.length===2&&this.options.range===true&&(a===0&&c>e||a===1&&c<e))c=e;if(c!==this.values(a)){e=this.values();e[a]=c;b=this._trigger("slide",b,{handle:this.handles[a],value:c,values:e});this.values(a?0:1);b!==false&&this.values(a,c,true)}}else if(c!==this.value()){b=this._trigger("slide",b,{handle:this.handles[a],+value:c});b!==false&&this.value(c)}},_stop:function(b,a){var c={handle:this.handles[a],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(a);c.values=this.values()}this._trigger("stop",b,c)},_change:function(b,a){if(!this._keySliding&&!this._mouseSliding){var c={handle:this.handles[a],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(a);c.values=this.values()}this._trigger("change",b,c)}},value:function(b){if(arguments.length){this.options.value=+this._trimAlignValue(b);this._refreshValue();this._change(null,0)}return this._value()},values:function(b,a){var c,e,f;if(arguments.length>1){this.options.values[b]=this._trimAlignValue(a);this._refreshValue();this._change(null,b)}if(arguments.length)if(d.isArray(arguments[0])){c=this.options.values;e=arguments[0];for(f=0;f<c.length;f+=1){c[f]=this._trimAlignValue(e[f]);this._change(null,f)}this._refreshValue()}else return this.options.values&&this.options.values.length?this._values(b):this.value();+else return this._values()},_setOption:function(b,a){var c,e=0;if(d.isArray(this.options.values))e=this.options.values.length;d.Widget.prototype._setOption.apply(this,arguments);switch(b){case "disabled":if(a){this.handles.filter(".ui-state-focus").blur();this.handles.removeClass("ui-state-hover");this.handles.attr("disabled","disabled");this.element.addClass("ui-disabled")}else{this.handles.removeAttr("disabled");this.element.removeClass("ui-disabled")}break;case "orientation":this._detectOrientation();+this.element.removeClass("ui-slider-horizontal ui-slider-vertical").addClass("ui-slider-"+this.orientation);this._refreshValue();break;case "value":this._animateOff=true;this._refreshValue();this._change(null,0);this._animateOff=false;break;case "values":this._animateOff=true;this._refreshValue();for(c=0;c<e;c+=1)this._change(null,c);this._animateOff=false;break}},_value:function(){var b=this.options.value;return b=this._trimAlignValue(b)},_values:function(b){var a,c;if(arguments.length){a=this.options.values[b];+return a=this._trimAlignValue(a)}else{a=this.options.values.slice();for(c=0;c<a.length;c+=1)a[c]=this._trimAlignValue(a[c]);return a}},_trimAlignValue:function(b){if(b<=this._valueMin())return this._valueMin();if(b>=this._valueMax())return this._valueMax();var a=this.options.step>0?this.options.step:1,c=(b-this._valueMin())%a;alignValue=b-c;if(Math.abs(c)*2>=a)alignValue+=c>0?a:-a;return parseFloat(alignValue.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},+_refreshValue:function(){var b=this.options.range,a=this.options,c=this,e=!this._animateOff?a.animate:false,f,h={},g,i,j,l;if(this.options.values&&this.options.values.length)this.handles.each(function(k){f=(c.values(k)-c._valueMin())/(c._valueMax()-c._valueMin())*100;h[c.orientation==="horizontal"?"left":"bottom"]=f+"%";d(this).stop(1,1)[e?"animate":"css"](h,a.animate);if(c.options.range===true)if(c.orientation==="horizontal"){if(k===0)c.range.stop(1,1)[e?"animate":"css"]({left:f+"%"},a.animate);+if(k===1)c.range[e?"animate":"css"]({width:f-g+"%"},{queue:false,duration:a.animate})}else{if(k===0)c.range.stop(1,1)[e?"animate":"css"]({bottom:f+"%"},a.animate);if(k===1)c.range[e?"animate":"css"]({height:f-g+"%"},{queue:false,duration:a.animate})}g=f});else{i=this.value();j=this._valueMin();l=this._valueMax();f=l!==j?(i-j)/(l-j)*100:0;h[c.orientation==="horizontal"?"left":"bottom"]=f+"%";this.handle.stop(1,1)[e?"animate":"css"](h,a.animate);if(b==="min"&&this.orientation==="horizontal")this.range.stop(1,+1)[e?"animate":"css"]({width:f+"%"},a.animate);if(b==="max"&&this.orientation==="horizontal")this.range[e?"animate":"css"]({width:100-f+"%"},{queue:false,duration:a.animate});if(b==="min"&&this.orientation==="vertical")this.range.stop(1,1)[e?"animate":"css"]({height:f+"%"},a.animate);if(b==="max"&&this.orientation==="vertical")this.range[e?"animate":"css"]({height:100-f+"%"},{queue:false,duration:a.animate})}}});d.extend(d.ui.slider,{version:"1.8.11"})})(jQuery);+;/*+ * jQuery UI Tabs 1.8.11+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Tabs+ *+ * Depends:+ * jquery.ui.core.js+ * jquery.ui.widget.js+ */+(function(d,p){function u(){return++v}function w(){return++x}var v=0,x=0;d.widget("ui.tabs",{options:{add:null,ajaxOptions:null,cache:false,cookie:null,collapsible:false,disable:null,disabled:[],enable:null,event:"click",fx:null,idPrefix:"ui-tabs-",load:null,panelTemplate:"<div></div>",remove:null,select:null,show:null,spinner:"<em>Loading…</em>",tabTemplate:"<li><a href='#{href}'><span>#{label}</span></a></li>"},_create:function(){this._tabify(true)},_setOption:function(b,e){if(b=="selected")this.options.collapsible&&+e==this.options.selected||this.select(e);else{this.options[b]=e;this._tabify()}},_tabId:function(b){return b.title&&b.title.replace(/\s/g,"_").replace(/[^\w\u00c0-\uFFFF-]/g,"")||this.options.idPrefix+u()},_sanitizeSelector:function(b){return b.replace(/:/g,"\\:")},_cookie:function(){var b=this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+w());return d.cookie.apply(null,[b].concat(d.makeArray(arguments)))},_ui:function(b,e){return{tab:b,panel:e,index:this.anchors.index(b)}},_cleanup:function(){this.lis.filter(".ui-state-processing").removeClass("ui-state-processing").find("span:data(label.tabs)").each(function(){var b=+d(this);b.html(b.data("label.tabs")).removeData("label.tabs")})},_tabify:function(b){function e(g,f){g.css("display","");!d.support.opacity&&f.opacity&&g[0].style.removeAttribute("filter")}var a=this,c=this.options,h=/^#.+/;this.list=this.element.find("ol,ul").eq(0);this.lis=d(" > li:has(a[href])",this.list);this.anchors=this.lis.map(function(){return d("a",this)[0]});this.panels=d([]);this.anchors.each(function(g,f){var i=d(f).attr("href"),l=i.split("#")[0],q;if(l&&(l===location.toString().split("#")[0]||+(q=d("base")[0])&&l===q.href)){i=f.hash;f.href=i}if(h.test(i))a.panels=a.panels.add(a.element.find(a._sanitizeSelector(i)));else if(i&&i!=="#"){d.data(f,"href.tabs",i);d.data(f,"load.tabs",i.replace(/#.*$/,""));i=a._tabId(f);f.href="#"+i;f=a.element.find("#"+i);if(!f.length){f=d(c.panelTemplate).attr("id",i).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").insertAfter(a.panels[g-1]||a.list);f.data("destroy.tabs",true)}a.panels=a.panels.add(f)}else c.disabled.push(g)});if(b){this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all");+this.list.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.lis.addClass("ui-state-default ui-corner-top");this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom");if(c.selected===p){location.hash&&this.anchors.each(function(g,f){if(f.hash==location.hash){c.selected=g;return false}});if(typeof c.selected!=="number"&&c.cookie)c.selected=parseInt(a._cookie(),10);if(typeof c.selected!=="number"&&this.lis.filter(".ui-tabs-selected").length)c.selected=+this.lis.index(this.lis.filter(".ui-tabs-selected"));c.selected=c.selected||(this.lis.length?0:-1)}else if(c.selected===null)c.selected=-1;c.selected=c.selected>=0&&this.anchors[c.selected]||c.selected<0?c.selected:0;c.disabled=d.unique(c.disabled.concat(d.map(this.lis.filter(".ui-state-disabled"),function(g){return a.lis.index(g)}))).sort();d.inArray(c.selected,c.disabled)!=-1&&c.disabled.splice(d.inArray(c.selected,c.disabled),1);this.panels.addClass("ui-tabs-hide");this.lis.removeClass("ui-tabs-selected ui-state-active");+if(c.selected>=0&&this.anchors.length){a.element.find(a._sanitizeSelector(a.anchors[c.selected].hash)).removeClass("ui-tabs-hide");this.lis.eq(c.selected).addClass("ui-tabs-selected ui-state-active");a.element.queue("tabs",function(){a._trigger("show",null,a._ui(a.anchors[c.selected],a.element.find(a._sanitizeSelector(a.anchors[c.selected].hash))[0]))});this.load(c.selected)}d(window).bind("unload",function(){a.lis.add(a.anchors).unbind(".tabs");a.lis=a.anchors=a.panels=null})}else c.selected=this.lis.index(this.lis.filter(".ui-tabs-selected"));+this.element[c.collapsible?"addClass":"removeClass"]("ui-tabs-collapsible");c.cookie&&this._cookie(c.selected,c.cookie);b=0;for(var j;j=this.lis[b];b++)d(j)[d.inArray(b,c.disabled)!=-1&&!d(j).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled");c.cache===false&&this.anchors.removeData("cache.tabs");this.lis.add(this.anchors).unbind(".tabs");if(c.event!=="mouseover"){var k=function(g,f){f.is(":not(.ui-state-disabled)")&&f.addClass("ui-state-"+g)},n=function(g,f){f.removeClass("ui-state-"++g)};this.lis.bind("mouseover.tabs",function(){k("hover",d(this))});this.lis.bind("mouseout.tabs",function(){n("hover",d(this))});this.anchors.bind("focus.tabs",function(){k("focus",d(this).closest("li"))});this.anchors.bind("blur.tabs",function(){n("focus",d(this).closest("li"))})}var m,o;if(c.fx)if(d.isArray(c.fx)){m=c.fx[0];o=c.fx[1]}else m=o=c.fx;var r=o?function(g,f){d(g).closest("li").addClass("ui-tabs-selected ui-state-active");f.hide().removeClass("ui-tabs-hide").animate(o,o.duration||"normal",+function(){e(f,o);a._trigger("show",null,a._ui(g,f[0]))})}:function(g,f){d(g).closest("li").addClass("ui-tabs-selected ui-state-active");f.removeClass("ui-tabs-hide");a._trigger("show",null,a._ui(g,f[0]))},s=m?function(g,f){f.animate(m,m.duration||"normal",function(){a.lis.removeClass("ui-tabs-selected ui-state-active");f.addClass("ui-tabs-hide");e(f,m);a.element.dequeue("tabs")})}:function(g,f){a.lis.removeClass("ui-tabs-selected ui-state-active");f.addClass("ui-tabs-hide");a.element.dequeue("tabs")};+this.anchors.bind(c.event+".tabs",function(){var g=this,f=d(g).closest("li"),i=a.panels.filter(":not(.ui-tabs-hide)"),l=a.element.find(a._sanitizeSelector(g.hash));if(f.hasClass("ui-tabs-selected")&&!c.collapsible||f.hasClass("ui-state-disabled")||f.hasClass("ui-state-processing")||a.panels.filter(":animated").length||a._trigger("select",null,a._ui(this,l[0]))===false){this.blur();return false}c.selected=a.anchors.index(this);a.abort();if(c.collapsible)if(f.hasClass("ui-tabs-selected")){c.selected=+-1;c.cookie&&a._cookie(c.selected,c.cookie);a.element.queue("tabs",function(){s(g,i)}).dequeue("tabs");this.blur();return false}else if(!i.length){c.cookie&&a._cookie(c.selected,c.cookie);a.element.queue("tabs",function(){r(g,l)});a.load(a.anchors.index(this));this.blur();return false}c.cookie&&a._cookie(c.selected,c.cookie);if(l.length){i.length&&a.element.queue("tabs",function(){s(g,i)});a.element.queue("tabs",function(){r(g,l)});a.load(a.anchors.index(this))}else throw"jQuery UI Tabs: Mismatching fragment identifier.";+d.browser.msie&&this.blur()});this.anchors.bind("click.tabs",function(){return false})},_getIndex:function(b){if(typeof b=="string")b=this.anchors.index(this.anchors.filter("[href$="+b+"]"));return b},destroy:function(){var b=this.options;this.abort();this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs");this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.anchors.each(function(){var e=+d.data(this,"href.tabs");if(e)this.href=e;var a=d(this).unbind(".tabs");d.each(["href","load","cache"],function(c,h){a.removeData(h+".tabs")})});this.lis.unbind(".tabs").add(this.panels).each(function(){d.data(this,"destroy.tabs")?d(this).remove():d(this).removeClass("ui-state-default ui-corner-top ui-tabs-selected ui-state-active ui-state-hover ui-state-focus ui-state-disabled ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide")});b.cookie&&this._cookie(null,b.cookie);return this},add:function(b,+e,a){if(a===p)a=this.anchors.length;var c=this,h=this.options;e=d(h.tabTemplate.replace(/#\{href\}/g,b).replace(/#\{label\}/g,e));b=!b.indexOf("#")?b.replace("#",""):this._tabId(d("a",e)[0]);e.addClass("ui-state-default ui-corner-top").data("destroy.tabs",true);var j=c.element.find("#"+b);j.length||(j=d(h.panelTemplate).attr("id",b).data("destroy.tabs",true));j.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide");if(a>=this.lis.length){e.appendTo(this.list);j.appendTo(this.list[0].parentNode)}else{e.insertBefore(this.lis[a]);+j.insertBefore(this.panels[a])}h.disabled=d.map(h.disabled,function(k){return k>=a?++k:k});this._tabify();if(this.anchors.length==1){h.selected=0;e.addClass("ui-tabs-selected ui-state-active");j.removeClass("ui-tabs-hide");this.element.queue("tabs",function(){c._trigger("show",null,c._ui(c.anchors[0],c.panels[0]))});this.load(0)}this._trigger("add",null,this._ui(this.anchors[a],this.panels[a]));return this},remove:function(b){b=this._getIndex(b);var e=this.options,a=this.lis.eq(b).remove(),c=this.panels.eq(b).remove();+if(a.hasClass("ui-tabs-selected")&&this.anchors.length>1)this.select(b+(b+1<this.anchors.length?1:-1));e.disabled=d.map(d.grep(e.disabled,function(h){return h!=b}),function(h){return h>=b?--h:h});this._tabify();this._trigger("remove",null,this._ui(a.find("a")[0],c[0]));return this},enable:function(b){b=this._getIndex(b);var e=this.options;if(d.inArray(b,e.disabled)!=-1){this.lis.eq(b).removeClass("ui-state-disabled");e.disabled=d.grep(e.disabled,function(a){return a!=b});this._trigger("enable",null,+this._ui(this.anchors[b],this.panels[b]));return this}},disable:function(b){b=this._getIndex(b);var e=this.options;if(b!=e.selected){this.lis.eq(b).addClass("ui-state-disabled");e.disabled.push(b);e.disabled.sort();this._trigger("disable",null,this._ui(this.anchors[b],this.panels[b]))}return this},select:function(b){b=this._getIndex(b);if(b==-1)if(this.options.collapsible&&this.options.selected!=-1)b=this.options.selected;else return this;this.anchors.eq(b).trigger(this.options.event+".tabs");return this},+load:function(b){b=this._getIndex(b);var e=this,a=this.options,c=this.anchors.eq(b)[0],h=d.data(c,"load.tabs");this.abort();if(!h||this.element.queue("tabs").length!==0&&d.data(c,"cache.tabs"))this.element.dequeue("tabs");else{this.lis.eq(b).addClass("ui-state-processing");if(a.spinner){var j=d("span",c);j.data("label.tabs",j.html()).html(a.spinner)}this.xhr=d.ajax(d.extend({},a.ajaxOptions,{url:h,success:function(k,n){e.element.find(e._sanitizeSelector(c.hash)).html(k);e._cleanup();a.cache&&d.data(c,+"cache.tabs",true);e._trigger("load",null,e._ui(e.anchors[b],e.panels[b]));try{a.ajaxOptions.success(k,n)}catch(m){}},error:function(k,n){e._cleanup();e._trigger("load",null,e._ui(e.anchors[b],e.panels[b]));try{a.ajaxOptions.error(k,n,b,c)}catch(m){}}}));e.element.dequeue("tabs");return this}},abort:function(){this.element.queue([]);this.panels.stop(false,true);this.element.queue("tabs",this.element.queue("tabs").splice(-2,2));if(this.xhr){this.xhr.abort();delete this.xhr}this._cleanup();return this},+url:function(b,e){this.anchors.eq(b).removeData("cache.tabs").data("load.tabs",e);return this},length:function(){return this.anchors.length}});d.extend(d.ui.tabs,{version:"1.8.11"});d.extend(d.ui.tabs.prototype,{rotation:null,rotate:function(b,e){var a=this,c=this.options,h=a._rotate||(a._rotate=function(j){clearTimeout(a.rotation);a.rotation=setTimeout(function(){var k=c.selected;a.select(++k<a.anchors.length?k:0)},b);j&&j.stopPropagation()});e=a._unrotate||(a._unrotate=!e?function(j){j.clientX&&+a.rotate(null)}:function(){t=c.selected;h()});if(b){this.element.bind("tabsshow",h);this.anchors.bind(c.event+".tabs",e);h()}else{clearTimeout(a.rotation);this.element.unbind("tabsshow",h);this.anchors.unbind(c.event+".tabs",e);delete this._rotate;delete this._unrotate}return this}})})(jQuery);+;/*+ * jQuery UI Datepicker 1.8.11+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Datepicker+ *+ * Depends:+ * jquery.ui.core.js+ */+(function(d,A){function K(){this.debug=false;this._curInst=null;this._keyEvent=false;this._disabledInputs=[];this._inDialog=this._datepickerShowing=false;this._mainDivId="ui-datepicker-div";this._inlineClass="ui-datepicker-inline";this._appendClass="ui-datepicker-append";this._triggerClass="ui-datepicker-trigger";this._dialogClass="ui-datepicker-dialog";this._disableClass="ui-datepicker-disabled";this._unselectableClass="ui-datepicker-unselectable";this._currentClass="ui-datepicker-current-day";this._dayOverClass=+"ui-datepicker-days-cell-over";this.regional=[];this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su",+"Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:false,showMonthAfterYear:false,yearSuffix:""};this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:false,hideIfNoPrevNext:false,navigationAsDateFormat:false,gotoCurrent:false,changeMonth:false,changeYear:false,yearRange:"c-10:c+10",showOtherMonths:false,selectOtherMonths:false,showWeek:false,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",+minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:true,showButtonPanel:false,autoSize:false};d.extend(this._defaults,this.regional[""]);this.dpDiv=d('<div id="'+this._mainDivId+'" class="ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>')}function F(a,b){d.extend(a,b);for(var c in b)if(b[c]==+null||b[c]==A)a[c]=b[c];return a}d.extend(d.ui,{datepicker:{version:"1.8.11"}});var y=(new Date).getTime();d.extend(K.prototype,{markerClassName:"hasDatepicker",log:function(){this.debug&&console.log.apply("",arguments)},_widgetDatepicker:function(){return this.dpDiv},setDefaults:function(a){F(this._defaults,a||{});return this},_attachDatepicker:function(a,b){var c=null;for(var e in this._defaults){var f=a.getAttribute("date:"+e);if(f){c=c||{};try{c[e]=eval(f)}catch(h){c[e]=f}}}e=a.nodeName.toLowerCase();+f=e=="div"||e=="span";if(!a.id){this.uuid+=1;a.id="dp"+this.uuid}var i=this._newInst(d(a),f);i.settings=d.extend({},b||{},c||{});if(e=="input")this._connectDatepicker(a,i);else f&&this._inlineDatepicker(a,i)},_newInst:function(a,b){return{id:a[0].id.replace(/([^A-Za-z0-9_-])/g,"\\\\$1"),input:a,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:b,dpDiv:!b?this.dpDiv:d('<div class="'+this._inlineClass+' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>')}},+_connectDatepicker:function(a,b){var c=d(a);b.append=d([]);b.trigger=d([]);if(!c.hasClass(this.markerClassName)){this._attachments(c,b);c.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp).bind("setData.datepicker",function(e,f,h){b.settings[f]=h}).bind("getData.datepicker",function(e,f){return this._get(b,f)});this._autoSize(b);d.data(a,"datepicker",b)}},_attachments:function(a,b){var c=this._get(b,"appendText"),e=this._get(b,"isRTL");b.append&&+b.append.remove();if(c){b.append=d('<span class="'+this._appendClass+'">'+c+"</span>");a[e?"before":"after"](b.append)}a.unbind("focus",this._showDatepicker);b.trigger&&b.trigger.remove();c=this._get(b,"showOn");if(c=="focus"||c=="both")a.focus(this._showDatepicker);if(c=="button"||c=="both"){c=this._get(b,"buttonText");var f=this._get(b,"buttonImage");b.trigger=d(this._get(b,"buttonImageOnly")?d("<img/>").addClass(this._triggerClass).attr({src:f,alt:c,title:c}):d('<button type="button"></button>').addClass(this._triggerClass).html(f==+""?c:d("<img/>").attr({src:f,alt:c,title:c})));a[e?"before":"after"](b.trigger);b.trigger.click(function(){d.datepicker._datepickerShowing&&d.datepicker._lastInput==a[0]?d.datepicker._hideDatepicker():d.datepicker._showDatepicker(a[0]);return false})}},_autoSize:function(a){if(this._get(a,"autoSize")&&!a.inline){var b=new Date(2009,11,20),c=this._get(a,"dateFormat");if(c.match(/[DM]/)){var e=function(f){for(var h=0,i=0,g=0;g<f.length;g++)if(f[g].length>h){h=f[g].length;i=g}return i};b.setMonth(e(this._get(a,+c.match(/MM/)?"monthNames":"monthNamesShort")));b.setDate(e(this._get(a,c.match(/DD/)?"dayNames":"dayNamesShort"))+20-b.getDay())}a.input.attr("size",this._formatDate(a,b).length)}},_inlineDatepicker:function(a,b){var c=d(a);if(!c.hasClass(this.markerClassName)){c.addClass(this.markerClassName).append(b.dpDiv).bind("setData.datepicker",function(e,f,h){b.settings[f]=h}).bind("getData.datepicker",function(e,f){return this._get(b,f)});d.data(a,"datepicker",b);this._setDate(b,this._getDefaultDate(b),+true);this._updateDatepicker(b);this._updateAlternate(b);b.dpDiv.show()}},_dialogDatepicker:function(a,b,c,e,f){a=this._dialogInst;if(!a){this.uuid+=1;this._dialogInput=d('<input type="text" id="'+("dp"+this.uuid)+'" style="position: absolute; top: -100px; width: 0px; z-index: -10;"/>');this._dialogInput.keydown(this._doKeyDown);d("body").append(this._dialogInput);a=this._dialogInst=this._newInst(this._dialogInput,false);a.settings={};d.data(this._dialogInput[0],"datepicker",a)}F(a.settings,e||{});+b=b&&b.constructor==Date?this._formatDate(a,b):b;this._dialogInput.val(b);this._pos=f?f.length?f:[f.pageX,f.pageY]:null;if(!this._pos)this._pos=[document.documentElement.clientWidth/2-100+(document.documentElement.scrollLeft||document.body.scrollLeft),document.documentElement.clientHeight/2-150+(document.documentElement.scrollTop||document.body.scrollTop)];this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px");a.settings.onSelect=c;this._inDialog=true;this.dpDiv.addClass(this._dialogClass);+this._showDatepicker(this._dialogInput[0]);d.blockUI&&d.blockUI(this.dpDiv);d.data(this._dialogInput[0],"datepicker",a);return this},_destroyDatepicker:function(a){var b=d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();d.removeData(a,"datepicker");if(e=="input"){c.append.remove();c.trigger.remove();b.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",+this._doKeyUp)}else if(e=="div"||e=="span")b.removeClass(this.markerClassName).empty()}},_enableDatepicker:function(a){var b=d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();if(e=="input"){a.disabled=false;c.trigger.filter("button").each(function(){this.disabled=false}).end().filter("img").css({opacity:"1.0",cursor:""})}else if(e=="div"||e=="span")b.children("."+this._inlineClass).children().removeClass("ui-state-disabled");this._disabledInputs=d.map(this._disabledInputs,+function(f){return f==a?null:f})}},_disableDatepicker:function(a){var b=d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();if(e=="input"){a.disabled=true;c.trigger.filter("button").each(function(){this.disabled=true}).end().filter("img").css({opacity:"0.5",cursor:"default"})}else if(e=="div"||e=="span")b.children("."+this._inlineClass).children().addClass("ui-state-disabled");this._disabledInputs=d.map(this._disabledInputs,function(f){return f==a?null:+f});this._disabledInputs[this._disabledInputs.length]=a}},_isDisabledDatepicker:function(a){if(!a)return false;for(var b=0;b<this._disabledInputs.length;b++)if(this._disabledInputs[b]==a)return true;return false},_getInst:function(a){try{return d.data(a,"datepicker")}catch(b){throw"Missing instance data for this datepicker";}},_optionDatepicker:function(a,b,c){var e=this._getInst(a);if(arguments.length==2&&typeof b=="string")return b=="defaults"?d.extend({},d.datepicker._defaults):e?b=="all"?d.extend({},+e.settings):this._get(e,b):null;var f=b||{};if(typeof b=="string"){f={};f[b]=c}if(e){this._curInst==e&&this._hideDatepicker();var h=this._getDateDatepicker(a,true),i=this._getMinMaxDate(e,"min"),g=this._getMinMaxDate(e,"max");F(e.settings,f);if(i!==null&&f.dateFormat!==A&&f.minDate===A)e.settings.minDate=this._formatDate(e,i);if(g!==null&&f.dateFormat!==A&&f.maxDate===A)e.settings.maxDate=this._formatDate(e,g);this._attachments(d(a),e);this._autoSize(e);this._setDateDatepicker(a,h);this._updateDatepicker(e)}},+_changeDatepicker:function(a,b,c){this._optionDatepicker(a,b,c)},_refreshDatepicker:function(a){(a=this._getInst(a))&&this._updateDatepicker(a)},_setDateDatepicker:function(a,b){if(a=this._getInst(a)){this._setDate(a,b);this._updateDatepicker(a);this._updateAlternate(a)}},_getDateDatepicker:function(a,b){(a=this._getInst(a))&&!a.inline&&this._setDateFromField(a,b);return a?this._getDate(a):null},_doKeyDown:function(a){var b=d.datepicker._getInst(a.target),c=true,e=b.dpDiv.is(".ui-datepicker-rtl");+b._keyEvent=true;if(d.datepicker._datepickerShowing)switch(a.keyCode){case 9:d.datepicker._hideDatepicker();c=false;break;case 13:c=d("td."+d.datepicker._dayOverClass+":not(."+d.datepicker._currentClass+")",b.dpDiv);c[0]?d.datepicker._selectDay(a.target,b.selectedMonth,b.selectedYear,c[0]):d.datepicker._hideDatepicker();return false;case 27:d.datepicker._hideDatepicker();break;case 33:d.datepicker._adjustDate(a.target,a.ctrlKey?-d.datepicker._get(b,"stepBigMonths"):-d.datepicker._get(b,"stepMonths"),+"M");break;case 34:d.datepicker._adjustDate(a.target,a.ctrlKey?+d.datepicker._get(b,"stepBigMonths"):+d.datepicker._get(b,"stepMonths"),"M");break;case 35:if(a.ctrlKey||a.metaKey)d.datepicker._clearDate(a.target);c=a.ctrlKey||a.metaKey;break;case 36:if(a.ctrlKey||a.metaKey)d.datepicker._gotoToday(a.target);c=a.ctrlKey||a.metaKey;break;case 37:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,e?+1:-1,"D");c=a.ctrlKey||a.metaKey;if(a.originalEvent.altKey)d.datepicker._adjustDate(a.target,a.ctrlKey?+-d.datepicker._get(b,"stepBigMonths"):-d.datepicker._get(b,"stepMonths"),"M");break;case 38:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,-7,"D");c=a.ctrlKey||a.metaKey;break;case 39:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,e?-1:+1,"D");c=a.ctrlKey||a.metaKey;if(a.originalEvent.altKey)d.datepicker._adjustDate(a.target,a.ctrlKey?+d.datepicker._get(b,"stepBigMonths"):+d.datepicker._get(b,"stepMonths"),"M");break;case 40:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,++7,"D");c=a.ctrlKey||a.metaKey;break;default:c=false}else if(a.keyCode==36&&a.ctrlKey)d.datepicker._showDatepicker(this);else c=false;if(c){a.preventDefault();a.stopPropagation()}},_doKeyPress:function(a){var b=d.datepicker._getInst(a.target);if(d.datepicker._get(b,"constrainInput")){b=d.datepicker._possibleChars(d.datepicker._get(b,"dateFormat"));var c=String.fromCharCode(a.charCode==A?a.keyCode:a.charCode);return a.ctrlKey||a.metaKey||c<" "||!b||b.indexOf(c)>-1}},_doKeyUp:function(a){a=d.datepicker._getInst(a.target);+if(a.input.val()!=a.lastVal)try{if(d.datepicker.parseDate(d.datepicker._get(a,"dateFormat"),a.input?a.input.val():null,d.datepicker._getFormatConfig(a))){d.datepicker._setDateFromField(a);d.datepicker._updateAlternate(a);d.datepicker._updateDatepicker(a)}}catch(b){d.datepicker.log(b)}return true},_showDatepicker:function(a){a=a.target||a;if(a.nodeName.toLowerCase()!="input")a=d("input",a.parentNode)[0];if(!(d.datepicker._isDisabledDatepicker(a)||d.datepicker._lastInput==a)){var b=d.datepicker._getInst(a);+d.datepicker._curInst&&d.datepicker._curInst!=b&&d.datepicker._curInst.dpDiv.stop(true,true);var c=d.datepicker._get(b,"beforeShow");F(b.settings,c?c.apply(a,[a,b]):{});b.lastVal=null;d.datepicker._lastInput=a;d.datepicker._setDateFromField(b);if(d.datepicker._inDialog)a.value="";if(!d.datepicker._pos){d.datepicker._pos=d.datepicker._findPos(a);d.datepicker._pos[1]+=a.offsetHeight}var e=false;d(a).parents().each(function(){e|=d(this).css("position")=="fixed";return!e});if(e&&d.browser.opera){d.datepicker._pos[0]-=+document.documentElement.scrollLeft;d.datepicker._pos[1]-=document.documentElement.scrollTop}c={left:d.datepicker._pos[0],top:d.datepicker._pos[1]};d.datepicker._pos=null;b.dpDiv.empty();b.dpDiv.css({position:"absolute",display:"block",top:"-1000px"});d.datepicker._updateDatepicker(b);c=d.datepicker._checkOffset(b,c,e);b.dpDiv.css({position:d.datepicker._inDialog&&d.blockUI?"static":e?"fixed":"absolute",display:"none",left:c.left+"px",top:c.top+"px"});if(!b.inline){c=d.datepicker._get(b,"showAnim");+var f=d.datepicker._get(b,"duration"),h=function(){d.datepicker._datepickerShowing=true;var i=b.dpDiv.find("iframe.ui-datepicker-cover");if(i.length){var g=d.datepicker._getBorders(b.dpDiv);i.css({left:-g[0],top:-g[1],width:b.dpDiv.outerWidth(),height:b.dpDiv.outerHeight()})}};b.dpDiv.zIndex(d(a).zIndex()+1);d.effects&&d.effects[c]?b.dpDiv.show(c,d.datepicker._get(b,"showOptions"),f,h):b.dpDiv[c||"show"](c?f:null,h);if(!c||!f)h();b.input.is(":visible")&&!b.input.is(":disabled")&&b.input.focus();d.datepicker._curInst=+b}}},_updateDatepicker:function(a){var b=this,c=d.datepicker._getBorders(a.dpDiv);a.dpDiv.empty().append(this._generateHTML(a));var e=a.dpDiv.find("iframe.ui-datepicker-cover");e.length&&e.css({left:-c[0],top:-c[1],width:a.dpDiv.outerWidth(),height:a.dpDiv.outerHeight()});a.dpDiv.find("button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a").bind("mouseout",function(){d(this).removeClass("ui-state-hover");this.className.indexOf("ui-datepicker-prev")!=-1&&d(this).removeClass("ui-datepicker-prev-hover");+this.className.indexOf("ui-datepicker-next")!=-1&&d(this).removeClass("ui-datepicker-next-hover")}).bind("mouseover",function(){if(!b._isDisabledDatepicker(a.inline?a.dpDiv.parent()[0]:a.input[0])){d(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");d(this).addClass("ui-state-hover");this.className.indexOf("ui-datepicker-prev")!=-1&&d(this).addClass("ui-datepicker-prev-hover");this.className.indexOf("ui-datepicker-next")!=-1&&d(this).addClass("ui-datepicker-next-hover")}}).end().find("."++this._dayOverClass+" a").trigger("mouseover").end();c=this._getNumberOfMonths(a);e=c[1];e>1?a.dpDiv.addClass("ui-datepicker-multi-"+e).css("width",17*e+"em"):a.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");a.dpDiv[(c[0]!=1||c[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi");a.dpDiv[(this._get(a,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl");a==d.datepicker._curInst&&d.datepicker._datepickerShowing&&a.input&&a.input.is(":visible")&&!a.input.is(":disabled")&&+a.input[0]!=document.activeElement&&a.input.focus();if(a.yearshtml){var f=a.yearshtml;setTimeout(function(){f===a.yearshtml&&a.dpDiv.find("select.ui-datepicker-year:first").replaceWith(a.yearshtml);f=a.yearshtml=null},0)}},_getBorders:function(a){var b=function(c){return{thin:1,medium:2,thick:3}[c]||c};return[parseFloat(b(a.css("border-left-width"))),parseFloat(b(a.css("border-top-width")))]},_checkOffset:function(a,b,c){var e=a.dpDiv.outerWidth(),f=a.dpDiv.outerHeight(),h=a.input?a.input.outerWidth():+0,i=a.input?a.input.outerHeight():0,g=document.documentElement.clientWidth+d(document).scrollLeft(),j=document.documentElement.clientHeight+d(document).scrollTop();b.left-=this._get(a,"isRTL")?e-h:0;b.left-=c&&b.left==a.input.offset().left?d(document).scrollLeft():0;b.top-=c&&b.top==a.input.offset().top+i?d(document).scrollTop():0;b.left-=Math.min(b.left,b.left+e>g&&g>e?Math.abs(b.left+e-g):0);b.top-=Math.min(b.top,b.top+f>j&&j>f?Math.abs(f+i):0);return b},_findPos:function(a){for(var b=this._get(this._getInst(a),+"isRTL");a&&(a.type=="hidden"||a.nodeType!=1||d.expr.filters.hidden(a));)a=a[b?"previousSibling":"nextSibling"];a=d(a).offset();return[a.left,a.top]},_hideDatepicker:function(a){var b=this._curInst;if(!(!b||a&&b!=d.data(a,"datepicker")))if(this._datepickerShowing){a=this._get(b,"showAnim");var c=this._get(b,"duration"),e=function(){d.datepicker._tidyDialog(b);this._curInst=null};d.effects&&d.effects[a]?b.dpDiv.hide(a,d.datepicker._get(b,"showOptions"),c,e):b.dpDiv[a=="slideDown"?"slideUp":a=="fadeIn"?+"fadeOut":"hide"](a?c:null,e);a||e();if(a=this._get(b,"onClose"))a.apply(b.input?b.input[0]:null,[b.input?b.input.val():"",b]);this._datepickerShowing=false;this._lastInput=null;if(this._inDialog){this._dialogInput.css({position:"absolute",left:"0",top:"-100px"});if(d.blockUI){d.unblockUI();d("body").append(this.dpDiv)}}this._inDialog=false}},_tidyDialog:function(a){a.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(a){if(d.datepicker._curInst){a=+d(a.target);a[0].id!=d.datepicker._mainDivId&&a.parents("#"+d.datepicker._mainDivId).length==0&&!a.hasClass(d.datepicker.markerClassName)&&!a.hasClass(d.datepicker._triggerClass)&&d.datepicker._datepickerShowing&&!(d.datepicker._inDialog&&d.blockUI)&&d.datepicker._hideDatepicker()}},_adjustDate:function(a,b,c){a=d(a);var e=this._getInst(a[0]);if(!this._isDisabledDatepicker(a[0])){this._adjustInstDate(e,b+(c=="M"?this._get(e,"showCurrentAtPos"):0),c);this._updateDatepicker(e)}},_gotoToday:function(a){a=+d(a);var b=this._getInst(a[0]);if(this._get(b,"gotoCurrent")&&b.currentDay){b.selectedDay=b.currentDay;b.drawMonth=b.selectedMonth=b.currentMonth;b.drawYear=b.selectedYear=b.currentYear}else{var c=new Date;b.selectedDay=c.getDate();b.drawMonth=b.selectedMonth=c.getMonth();b.drawYear=b.selectedYear=c.getFullYear()}this._notifyChange(b);this._adjustDate(a)},_selectMonthYear:function(a,b,c){a=d(a);var e=this._getInst(a[0]);e._selectingMonthYear=false;e["selected"+(c=="M"?"Month":"Year")]=e["draw"+(c==+"M"?"Month":"Year")]=parseInt(b.options[b.selectedIndex].value,10);this._notifyChange(e);this._adjustDate(a)},_clickMonthYear:function(a){var b=this._getInst(d(a)[0]);b.input&&b._selectingMonthYear&&setTimeout(function(){b.input.focus()},0);b._selectingMonthYear=!b._selectingMonthYear},_selectDay:function(a,b,c,e){var f=d(a);if(!(d(e).hasClass(this._unselectableClass)||this._isDisabledDatepicker(f[0]))){f=this._getInst(f[0]);f.selectedDay=f.currentDay=d("a",e).html();f.selectedMonth=f.currentMonth=+b;f.selectedYear=f.currentYear=c;this._selectDate(a,this._formatDate(f,f.currentDay,f.currentMonth,f.currentYear))}},_clearDate:function(a){a=d(a);this._getInst(a[0]);this._selectDate(a,"")},_selectDate:function(a,b){a=this._getInst(d(a)[0]);b=b!=null?b:this._formatDate(a);a.input&&a.input.val(b);this._updateAlternate(a);var c=this._get(a,"onSelect");if(c)c.apply(a.input?a.input[0]:null,[b,a]);else a.input&&a.input.trigger("change");if(a.inline)this._updateDatepicker(a);else{this._hideDatepicker();+this._lastInput=a.input[0];typeof a.input[0]!="object"&&a.input.focus();this._lastInput=null}},_updateAlternate:function(a){var b=this._get(a,"altField");if(b){var c=this._get(a,"altFormat")||this._get(a,"dateFormat"),e=this._getDate(a),f=this.formatDate(c,e,this._getFormatConfig(a));d(b).each(function(){d(this).val(f)})}},noWeekends:function(a){a=a.getDay();return[a>0&&a<6,""]},iso8601Week:function(a){a=new Date(a.getTime());a.setDate(a.getDate()+4-(a.getDay()||7));var b=a.getTime();a.setMonth(0);+a.setDate(1);return Math.floor(Math.round((b-a)/864E5)/7)+1},parseDate:function(a,b,c){if(a==null||b==null)throw"Invalid arguments";b=typeof b=="object"?b.toString():b+"";if(b=="")return null;var e=(c?c.shortYearCutoff:null)||this._defaults.shortYearCutoff;e=typeof e!="string"?e:(new Date).getFullYear()%100+parseInt(e,10);for(var f=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,h=(c?c.dayNames:null)||this._defaults.dayNames,i=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,g=(c?+c.monthNames:null)||this._defaults.monthNames,j=c=-1,l=-1,u=-1,k=false,o=function(p){(p=z+1<a.length&&a.charAt(z+1)==p)&&z++;return p},m=function(p){var v=o(p);p=new RegExp("^\\d{1,"+(p=="@"?14:p=="!"?20:p=="y"&&v?4:p=="o"?3:2)+"}");p=b.substring(s).match(p);if(!p)throw"Missing number at position "+s;s+=p[0].length;return parseInt(p[0],10)},n=function(p,v,H){p=o(p)?H:v;for(v=0;v<p.length;v++)if(b.substr(s,p[v].length).toLowerCase()==p[v].toLowerCase()){s+=p[v].length;return v+1}throw"Unknown name at position "++s;},r=function(){if(b.charAt(s)!=a.charAt(z))throw"Unexpected literal at position "+s;s++},s=0,z=0;z<a.length;z++)if(k)if(a.charAt(z)=="'"&&!o("'"))k=false;else r();else switch(a.charAt(z)){case "d":l=m("d");break;case "D":n("D",f,h);break;case "o":u=m("o");break;case "m":j=m("m");break;case "M":j=n("M",i,g);break;case "y":c=m("y");break;case "@":var w=new Date(m("@"));c=w.getFullYear();j=w.getMonth()+1;l=w.getDate();break;case "!":w=new Date((m("!")-this._ticksTo1970)/1E4);c=w.getFullYear();j=w.getMonth()++1;l=w.getDate();break;case "'":if(o("'"))r();else k=true;break;default:r()}if(c==-1)c=(new Date).getFullYear();else if(c<100)c+=(new Date).getFullYear()-(new Date).getFullYear()%100+(c<=e?0:-100);if(u>-1){j=1;l=u;do{e=this._getDaysInMonth(c,j-1);if(l<=e)break;j++;l-=e}while(1)}w=this._daylightSavingAdjust(new Date(c,j-1,l));if(w.getFullYear()!=c||w.getMonth()+1!=j||w.getDate()!=l)throw"Invalid date";return w},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",+RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925))*24*60*60*1E7,formatDate:function(a,b,c){if(!b)return"";var e=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,f=(c?c.dayNames:null)||this._defaults.dayNames,h=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort;c=(c?c.monthNames:null)||this._defaults.monthNames;var i=function(o){(o=k+1<a.length&&+a.charAt(k+1)==o)&&k++;return o},g=function(o,m,n){m=""+m;if(i(o))for(;m.length<n;)m="0"+m;return m},j=function(o,m,n,r){return i(o)?r[m]:n[m]},l="",u=false;if(b)for(var k=0;k<a.length;k++)if(u)if(a.charAt(k)=="'"&&!i("'"))u=false;else l+=a.charAt(k);else switch(a.charAt(k)){case "d":l+=g("d",b.getDate(),2);break;case "D":l+=j("D",b.getDay(),e,f);break;case "o":l+=g("o",(b.getTime()-(new Date(b.getFullYear(),0,0)).getTime())/864E5,3);break;case "m":l+=g("m",b.getMonth()+1,2);break;case "M":l+=j("M",+b.getMonth(),h,c);break;case "y":l+=i("y")?b.getFullYear():(b.getYear()%100<10?"0":"")+b.getYear()%100;break;case "@":l+=b.getTime();break;case "!":l+=b.getTime()*1E4+this._ticksTo1970;break;case "'":if(i("'"))l+="'";else u=true;break;default:l+=a.charAt(k)}return l},_possibleChars:function(a){for(var b="",c=false,e=function(h){(h=f+1<a.length&&a.charAt(f+1)==h)&&f++;return h},f=0;f<a.length;f++)if(c)if(a.charAt(f)=="'"&&!e("'"))c=false;else b+=a.charAt(f);else switch(a.charAt(f)){case "d":case "m":case "y":case "@":b+=+"0123456789";break;case "D":case "M":return null;case "'":if(e("'"))b+="'";else c=true;break;default:b+=a.charAt(f)}return b},_get:function(a,b){return a.settings[b]!==A?a.settings[b]:this._defaults[b]},_setDateFromField:function(a,b){if(a.input.val()!=a.lastVal){var c=this._get(a,"dateFormat"),e=a.lastVal=a.input?a.input.val():null,f,h;f=h=this._getDefaultDate(a);var i=this._getFormatConfig(a);try{f=this.parseDate(c,e,i)||h}catch(g){this.log(g);e=b?"":e}a.selectedDay=f.getDate();a.drawMonth=a.selectedMonth=+f.getMonth();a.drawYear=a.selectedYear=f.getFullYear();a.currentDay=e?f.getDate():0;a.currentMonth=e?f.getMonth():0;a.currentYear=e?f.getFullYear():0;this._adjustInstDate(a)}},_getDefaultDate:function(a){return this._restrictMinMax(a,this._determineDate(a,this._get(a,"defaultDate"),new Date))},_determineDate:function(a,b,c){var e=function(h){var i=new Date;i.setDate(i.getDate()+h);return i},f=function(h){try{return d.datepicker.parseDate(d.datepicker._get(a,"dateFormat"),h,d.datepicker._getFormatConfig(a))}catch(i){}var g=+(h.toLowerCase().match(/^c/)?d.datepicker._getDate(a):null)||new Date,j=g.getFullYear(),l=g.getMonth();g=g.getDate();for(var u=/([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,k=u.exec(h);k;){switch(k[2]||"d"){case "d":case "D":g+=parseInt(k[1],10);break;case "w":case "W":g+=parseInt(k[1],10)*7;break;case "m":case "M":l+=parseInt(k[1],10);g=Math.min(g,d.datepicker._getDaysInMonth(j,l));break;case "y":case "Y":j+=parseInt(k[1],10);g=Math.min(g,d.datepicker._getDaysInMonth(j,l));break}k=u.exec(h)}return new Date(j,+l,g)};if(b=(b=b==null||b===""?c:typeof b=="string"?f(b):typeof b=="number"?isNaN(b)?c:e(b):new Date(b.getTime()))&&b.toString()=="Invalid Date"?c:b){b.setHours(0);b.setMinutes(0);b.setSeconds(0);b.setMilliseconds(0)}return this._daylightSavingAdjust(b)},_daylightSavingAdjust:function(a){if(!a)return null;a.setHours(a.getHours()>12?a.getHours()+2:0);return a},_setDate:function(a,b,c){var e=!b,f=a.selectedMonth,h=a.selectedYear;b=this._restrictMinMax(a,this._determineDate(a,b,new Date));a.selectedDay=+a.currentDay=b.getDate();a.drawMonth=a.selectedMonth=a.currentMonth=b.getMonth();a.drawYear=a.selectedYear=a.currentYear=b.getFullYear();if((f!=a.selectedMonth||h!=a.selectedYear)&&!c)this._notifyChange(a);this._adjustInstDate(a);if(a.input)a.input.val(e?"":this._formatDate(a))},_getDate:function(a){return!a.currentYear||a.input&&a.input.val()==""?null:this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay))},_generateHTML:function(a){var b=new Date;b=this._daylightSavingAdjust(new Date(b.getFullYear(),+b.getMonth(),b.getDate()));var c=this._get(a,"isRTL"),e=this._get(a,"showButtonPanel"),f=this._get(a,"hideIfNoPrevNext"),h=this._get(a,"navigationAsDateFormat"),i=this._getNumberOfMonths(a),g=this._get(a,"showCurrentAtPos"),j=this._get(a,"stepMonths"),l=i[0]!=1||i[1]!=1,u=this._daylightSavingAdjust(!a.currentDay?new Date(9999,9,9):new Date(a.currentYear,a.currentMonth,a.currentDay)),k=this._getMinMaxDate(a,"min"),o=this._getMinMaxDate(a,"max");g=a.drawMonth-g;var m=a.drawYear;if(g<0){g+=12;m--}if(o){var n=+this._daylightSavingAdjust(new Date(o.getFullYear(),o.getMonth()-i[0]*i[1]+1,o.getDate()));for(n=k&&n<k?k:n;this._daylightSavingAdjust(new Date(m,g,1))>n;){g--;if(g<0){g=11;m--}}}a.drawMonth=g;a.drawYear=m;n=this._get(a,"prevText");n=!h?n:this.formatDate(n,this._daylightSavingAdjust(new Date(m,g-j,1)),this._getFormatConfig(a));n=this._canAdjustMonth(a,-1,m,g)?'<a class="ui-datepicker-prev ui-corner-all" onclick="DP_jQuery_'+y+".datepicker._adjustDate('#"+a.id+"', -"+j+", 'M');\" title=\""+n+'"><span class="ui-icon ui-icon-circle-triangle-'++(c?"e":"w")+'">'+n+"</span></a>":f?"":'<a class="ui-datepicker-prev ui-corner-all ui-state-disabled" title="'+n+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"e":"w")+'">'+n+"</span></a>";var r=this._get(a,"nextText");r=!h?r:this.formatDate(r,this._daylightSavingAdjust(new Date(m,g+j,1)),this._getFormatConfig(a));f=this._canAdjustMonth(a,+1,m,g)?'<a class="ui-datepicker-next ui-corner-all" onclick="DP_jQuery_'+y+".datepicker._adjustDate('#"+a.id+"', +"+j+", 'M');\" title=\""+r+'"><span class="ui-icon ui-icon-circle-triangle-'++(c?"w":"e")+'">'+r+"</span></a>":f?"":'<a class="ui-datepicker-next ui-corner-all ui-state-disabled" title="'+r+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"w":"e")+'">'+r+"</span></a>";j=this._get(a,"currentText");r=this._get(a,"gotoCurrent")&&a.currentDay?u:b;j=!h?j:this.formatDate(j,r,this._getFormatConfig(a));h=!a.inline?'<button type="button" class="ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all" onclick="DP_jQuery_'+y+'.datepicker._hideDatepicker();">'+this._get(a,+"closeText")+"</button>":"";e=e?'<div class="ui-datepicker-buttonpane ui-widget-content">'+(c?h:"")+(this._isInRange(a,r)?'<button type="button" class="ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all" onclick="DP_jQuery_'+y+".datepicker._gotoToday('#"+a.id+"');\">"+j+"</button>":"")+(c?"":h)+"</div>":"";h=parseInt(this._get(a,"firstDay"),10);h=isNaN(h)?0:h;j=this._get(a,"showWeek");r=this._get(a,"dayNames");this._get(a,"dayNamesShort");var s=this._get(a,"dayNamesMin"),z=+this._get(a,"monthNames"),w=this._get(a,"monthNamesShort"),p=this._get(a,"beforeShowDay"),v=this._get(a,"showOtherMonths"),H=this._get(a,"selectOtherMonths");this._get(a,"calculateWeek");for(var L=this._getDefaultDate(a),I="",D=0;D<i[0];D++){for(var M="",E=0;E<i[1];E++){var N=this._daylightSavingAdjust(new Date(m,g,a.selectedDay)),t=" ui-corner-all",x="";if(l){x+='<div class="ui-datepicker-group';if(i[1]>1)switch(E){case 0:x+=" ui-datepicker-group-first";t=" ui-corner-"+(c?"right":"left");break;case i[1]-+1:x+=" ui-datepicker-group-last";t=" ui-corner-"+(c?"left":"right");break;default:x+=" ui-datepicker-group-middle";t="";break}x+='">'}x+='<div class="ui-datepicker-header ui-widget-header ui-helper-clearfix'+t+'">'+(/all|left/.test(t)&&D==0?c?f:n:"")+(/all|right/.test(t)&&D==0?c?n:f:"")+this._generateMonthYearHeader(a,g,m,k,o,D>0||E>0,z,w)+'</div><table class="ui-datepicker-calendar"><thead><tr>';var B=j?'<th class="ui-datepicker-week-col">'+this._get(a,"weekHeader")+"</th>":"";for(t=0;t<7;t++){var q=+(t+h)%7;B+="<th"+((t+h+6)%7>=5?' class="ui-datepicker-week-end"':"")+'><span title="'+r[q]+'">'+s[q]+"</span></th>"}x+=B+"</tr></thead><tbody>";B=this._getDaysInMonth(m,g);if(m==a.selectedYear&&g==a.selectedMonth)a.selectedDay=Math.min(a.selectedDay,B);t=(this._getFirstDayOfMonth(m,g)-h+7)%7;B=l?6:Math.ceil((t+B)/7);q=this._daylightSavingAdjust(new Date(m,g,1-t));for(var O=0;O<B;O++){x+="<tr>";var P=!j?"":'<td class="ui-datepicker-week-col">'+this._get(a,"calculateWeek")(q)+"</td>";for(t=0;t<7;t++){var G=+p?p.apply(a.input?a.input[0]:null,[q]):[true,""],C=q.getMonth()!=g,J=C&&!H||!G[0]||k&&q<k||o&&q>o;P+='<td class="'+((t+h+6)%7>=5?" ui-datepicker-week-end":"")+(C?" ui-datepicker-other-month":"")+(q.getTime()==N.getTime()&&g==a.selectedMonth&&a._keyEvent||L.getTime()==q.getTime()&&L.getTime()==N.getTime()?" "+this._dayOverClass:"")+(J?" "+this._unselectableClass+" ui-state-disabled":"")+(C&&!v?"":" "+G[1]+(q.getTime()==u.getTime()?" "+this._currentClass:"")+(q.getTime()==b.getTime()?" ui-datepicker-today":+""))+'"'+((!C||v)&&G[2]?' title="'+G[2]+'"':"")+(J?"":' onclick="DP_jQuery_'+y+".datepicker._selectDay('#"+a.id+"',"+q.getMonth()+","+q.getFullYear()+', this);return false;"')+">"+(C&&!v?" ":J?'<span class="ui-state-default">'+q.getDate()+"</span>":'<a class="ui-state-default'+(q.getTime()==b.getTime()?" ui-state-highlight":"")+(q.getTime()==u.getTime()?" ui-state-active":"")+(C?" ui-priority-secondary":"")+'" href="#">'+q.getDate()+"</a>")+"</td>";q.setDate(q.getDate()+1);q=this._daylightSavingAdjust(q)}x+=+P+"</tr>"}g++;if(g>11){g=0;m++}x+="</tbody></table>"+(l?"</div>"+(i[0]>0&&E==i[1]-1?'<div class="ui-datepicker-row-break"></div>':""):"");M+=x}I+=M}I+=e+(d.browser.msie&&parseInt(d.browser.version,10)<7&&!a.inline?'<iframe src="javascript:false;" class="ui-datepicker-cover" frameborder="0"></iframe>':"");a._keyEvent=false;return I},_generateMonthYearHeader:function(a,b,c,e,f,h,i,g){var j=this._get(a,"changeMonth"),l=this._get(a,"changeYear"),u=this._get(a,"showMonthAfterYear"),k='<div class="ui-datepicker-title">',+o="";if(h||!j)o+='<span class="ui-datepicker-month">'+i[b]+"</span>";else{i=e&&e.getFullYear()==c;var m=f&&f.getFullYear()==c;o+='<select class="ui-datepicker-month" onchange="DP_jQuery_'+y+".datepicker._selectMonthYear('#"+a.id+"', this, 'M');\" onclick=\"DP_jQuery_"+y+".datepicker._clickMonthYear('#"+a.id+"');\">";for(var n=0;n<12;n++)if((!i||n>=e.getMonth())&&(!m||n<=f.getMonth()))o+='<option value="'+n+'"'+(n==b?' selected="selected"':"")+">"+g[n]+"</option>";o+="</select>"}u||(k+=o+(h||!(j&&+l)?" ":""));a.yearshtml="";if(h||!l)k+='<span class="ui-datepicker-year">'+c+"</span>";else{g=this._get(a,"yearRange").split(":");var r=(new Date).getFullYear();i=function(s){s=s.match(/c[+-].*/)?c+parseInt(s.substring(1),10):s.match(/[+-].*/)?r+parseInt(s,10):parseInt(s,10);return isNaN(s)?r:s};b=i(g[0]);g=Math.max(b,i(g[1]||""));b=e?Math.max(b,e.getFullYear()):b;g=f?Math.min(g,f.getFullYear()):g;for(a.yearshtml+='<select class="ui-datepicker-year" onchange="DP_jQuery_'+y+".datepicker._selectMonthYear('#"++a.id+"', this, 'Y');\" onclick=\"DP_jQuery_"+y+".datepicker._clickMonthYear('#"+a.id+"');\">";b<=g;b++)a.yearshtml+='<option value="'+b+'"'+(b==c?' selected="selected"':"")+">"+b+"</option>";a.yearshtml+="</select>";if(d.browser.mozilla)k+='<select class="ui-datepicker-year"><option value="'+c+'" selected="selected">'+c+"</option></select>";else{k+=a.yearshtml;a.yearshtml=null}}k+=this._get(a,"yearSuffix");if(u)k+=(h||!(j&&l)?" ":"")+o;k+="</div>";return k},_adjustInstDate:function(a,b,c){var e=+a.drawYear+(c=="Y"?b:0),f=a.drawMonth+(c=="M"?b:0);b=Math.min(a.selectedDay,this._getDaysInMonth(e,f))+(c=="D"?b:0);e=this._restrictMinMax(a,this._daylightSavingAdjust(new Date(e,f,b)));a.selectedDay=e.getDate();a.drawMonth=a.selectedMonth=e.getMonth();a.drawYear=a.selectedYear=e.getFullYear();if(c=="M"||c=="Y")this._notifyChange(a)},_restrictMinMax:function(a,b){var c=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");b=c&&b<c?c:b;return b=a&&b>a?a:b},_notifyChange:function(a){var b=this._get(a,+"onChangeMonthYear");if(b)b.apply(a.input?a.input[0]:null,[a.selectedYear,a.selectedMonth+1,a])},_getNumberOfMonths:function(a){a=this._get(a,"numberOfMonths");return a==null?[1,1]:typeof a=="number"?[1,a]:a},_getMinMaxDate:function(a,b){return this._determineDate(a,this._get(a,b+"Date"),null)},_getDaysInMonth:function(a,b){return 32-this._daylightSavingAdjust(new Date(a,b,32)).getDate()},_getFirstDayOfMonth:function(a,b){return(new Date(a,b,1)).getDay()},_canAdjustMonth:function(a,b,c,e){var f=this._getNumberOfMonths(a);+c=this._daylightSavingAdjust(new Date(c,e+(b<0?b:f[0]*f[1]),1));b<0&&c.setDate(this._getDaysInMonth(c.getFullYear(),c.getMonth()));return this._isInRange(a,c)},_isInRange:function(a,b){var c=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");return(!c||b.getTime()>=c.getTime())&&(!a||b.getTime()<=a.getTime())},_getFormatConfig:function(a){var b=this._get(a,"shortYearCutoff");b=typeof b!="string"?b:(new Date).getFullYear()%100+parseInt(b,10);return{shortYearCutoff:b,dayNamesShort:this._get(a,+"dayNamesShort"),dayNames:this._get(a,"dayNames"),monthNamesShort:this._get(a,"monthNamesShort"),monthNames:this._get(a,"monthNames")}},_formatDate:function(a,b,c,e){if(!b){a.currentDay=a.selectedDay;a.currentMonth=a.selectedMonth;a.currentYear=a.selectedYear}b=b?typeof b=="object"?b:this._daylightSavingAdjust(new Date(e,c,b)):this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return this.formatDate(this._get(a,"dateFormat"),b,this._getFormatConfig(a))}});d.fn.datepicker=+function(a){if(!this.length)return this;if(!d.datepicker.initialized){d(document).mousedown(d.datepicker._checkExternalClick).find("body").append(d.datepicker.dpDiv);d.datepicker.initialized=true}var b=Array.prototype.slice.call(arguments,1);if(typeof a=="string"&&(a=="isDisabled"||a=="getDate"||a=="widget"))return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));if(a=="option"&&arguments.length==2&&typeof arguments[1]=="string")return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,+[this[0]].concat(b));return this.each(function(){typeof a=="string"?d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this].concat(b)):d.datepicker._attachDatepicker(this,a)})};d.datepicker=new K;d.datepicker.initialized=false;d.datepicker.uuid=(new Date).getTime();d.datepicker.version="1.8.11";window["DP_jQuery_"+y]=d})(jQuery);+;/*+ * jQuery UI Progressbar 1.8.11+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Progressbar+ *+ * Depends:+ * jquery.ui.core.js+ * jquery.ui.widget.js+ */+(function(b,d){b.widget("ui.progressbar",{options:{value:0,max:100},min:0,_create:function(){this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min,"aria-valuemax":this.options.max,"aria-valuenow":this._value()});this.valueDiv=b("<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>").appendTo(this.element);this.oldValue=this._value();this._refreshValue()},destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow");+this.valueDiv.remove();b.Widget.prototype.destroy.apply(this,arguments)},value:function(a){if(a===d)return this._value();this._setOption("value",a);return this},_setOption:function(a,c){if(a==="value"){this.options.value=c;this._refreshValue();this._value()===this.options.max&&this._trigger("complete")}b.Widget.prototype._setOption.apply(this,arguments)},_value:function(){var a=this.options.value;if(typeof a!=="number")a=0;return Math.min(this.options.max,Math.max(this.min,a))},_percentage:function(){return 100*+this._value()/this.options.max},_refreshValue:function(){var a=this.value(),c=this._percentage();if(this.oldValue!==a){this.oldValue=a;this._trigger("change")}this.valueDiv.toggleClass("ui-corner-right",a===this.options.max).width(c.toFixed(0)+"%");this.element.attr("aria-valuenow",a)}});b.extend(b.ui.progressbar,{version:"1.8.11"})})(jQuery);+;/*+ * jQuery UI Effects 1.8.11+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Effects/+ */+jQuery.effects||function(f,j){function n(c){var a;if(c&&c.constructor==Array&&c.length==3)return c;if(a=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(c))return[parseInt(a[1],10),parseInt(a[2],10),parseInt(a[3],10)];if(a=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(c))return[parseFloat(a[1])*2.55,parseFloat(a[2])*2.55,parseFloat(a[3])*2.55];if(a=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(c))return[parseInt(a[1],+16),parseInt(a[2],16),parseInt(a[3],16)];if(a=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(c))return[parseInt(a[1]+a[1],16),parseInt(a[2]+a[2],16),parseInt(a[3]+a[3],16)];if(/rgba\(0, 0, 0, 0\)/.exec(c))return o.transparent;return o[f.trim(c).toLowerCase()]}function s(c,a){var b;do{b=f.curCSS(c,a);if(b!=""&&b!="transparent"||f.nodeName(c,"body"))break;a="backgroundColor"}while(c=c.parentNode);return n(b)}function p(){var c=document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle,+a={},b,d;if(c&&c.length&&c[0]&&c[c[0]])for(var e=c.length;e--;){b=c[e];if(typeof c[b]=="string"){d=b.replace(/\-(\w)/g,function(g,h){return h.toUpperCase()});a[d]=c[b]}}else for(b in c)if(typeof c[b]==="string")a[b]=c[b];return a}function q(c){var a,b;for(a in c){b=c[a];if(b==null||f.isFunction(b)||a in t||/scrollbar/.test(a)||!/color/i.test(a)&&isNaN(parseFloat(b)))delete c[a]}return c}function u(c,a){var b={_:0},d;for(d in a)if(c[d]!=a[d])b[d]=a[d];return b}function k(c,a,b,d){if(typeof c=="object"){d=+a;b=null;a=c;c=a.effect}if(f.isFunction(a)){d=a;b=null;a={}}if(typeof a=="number"||f.fx.speeds[a]){d=b;b=a;a={}}if(f.isFunction(b)){d=b;b=null}a=a||{};b=b||a.duration;b=f.fx.off?0:typeof b=="number"?b:b in f.fx.speeds?f.fx.speeds[b]:f.fx.speeds._default;d=d||a.complete;return[c,a,b,d]}function m(c){if(!c||typeof c==="number"||f.fx.speeds[c])return true;if(typeof c==="string"&&!f.effects[c])return true;return false}f.effects={};f.each(["backgroundColor","borderBottomColor","borderLeftColor","borderRightColor",+"borderTopColor","borderColor","color","outlineColor"],function(c,a){f.fx.step[a]=function(b){if(!b.colorInit){b.start=s(b.elem,a);b.end=n(b.end);b.colorInit=true}b.elem.style[a]="rgb("+Math.max(Math.min(parseInt(b.pos*(b.end[0]-b.start[0])+b.start[0],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[1]-b.start[1])+b.start[1],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[2]-b.start[2])+b.start[2],10),255),0)+")"}});var o={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,+0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,+211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]},r=["add","remove","toggle"],t={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};f.effects.animateClass=function(c,a,b,+d){if(f.isFunction(b)){d=b;b=null}return this.queue("fx",function(){var e=f(this),g=e.attr("style")||" ",h=q(p.call(this)),l,v=e.attr("className");f.each(r,function(w,i){c[i]&&e[i+"Class"](c[i])});l=q(p.call(this));e.attr("className",v);e.animate(u(h,l),a,b,function(){f.each(r,function(w,i){c[i]&&e[i+"Class"](c[i])});if(typeof e.attr("style")=="object"){e.attr("style").cssText="";e.attr("style").cssText=g}else e.attr("style",g);d&&d.apply(this,arguments)});h=f.queue(this);l=h.splice(h.length-1,1)[0];+h.splice(1,0,l);f.dequeue(this)})};f.fn.extend({_addClass:f.fn.addClass,addClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{add:c},a,b,d]):this._addClass(c)},_removeClass:f.fn.removeClass,removeClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{remove:c},a,b,d]):this._removeClass(c)},_toggleClass:f.fn.toggleClass,toggleClass:function(c,a,b,d,e){return typeof a=="boolean"||a===j?b?f.effects.animateClass.apply(this,[a?{add:c}:{remove:c},b,d,e]):this._toggleClass(c,+a):f.effects.animateClass.apply(this,[{toggle:c},a,b,d])},switchClass:function(c,a,b,d,e){return f.effects.animateClass.apply(this,[{add:a,remove:c},b,d,e])}});f.extend(f.effects,{version:"1.8.11",save:function(c,a){for(var b=0;b<a.length;b++)a[b]!==null&&c.data("ec.storage."+a[b],c[0].style[a[b]])},restore:function(c,a){for(var b=0;b<a.length;b++)a[b]!==null&&c.css(a[b],c.data("ec.storage."+a[b]))},setMode:function(c,a){if(a=="toggle")a=c.is(":hidden")?"show":"hide";return a},getBaseline:function(c,+a){var b;switch(c[0]){case "top":b=0;break;case "middle":b=0.5;break;case "bottom":b=1;break;default:b=c[0]/a.height}switch(c[1]){case "left":c=0;break;case "center":c=0.5;break;case "right":c=1;break;default:c=c[1]/a.width}return{x:c,y:b}},createWrapper:function(c){if(c.parent().is(".ui-effects-wrapper"))return c.parent();var a={width:c.outerWidth(true),height:c.outerHeight(true),"float":c.css("float")},b=f("<div></div>").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",+border:"none",margin:0,padding:0});c.wrap(b);b=c.parent();if(c.css("position")=="static"){b.css({position:"relative"});c.css({position:"relative"})}else{f.extend(a,{position:c.css("position"),zIndex:c.css("z-index")});f.each(["top","left","bottom","right"],function(d,e){a[e]=c.css(e);if(isNaN(parseInt(a[e],10)))a[e]="auto"});c.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})}return b.css(a).show()},removeWrapper:function(c){if(c.parent().is(".ui-effects-wrapper"))return c.parent().replaceWith(c);+return c},setTransition:function(c,a,b,d){d=d||{};f.each(a,function(e,g){unit=c.cssUnit(g);if(unit[0]>0)d[g]=unit[0]*b+unit[1]});return d}});f.fn.extend({effect:function(c){var a=k.apply(this,arguments),b={options:a[1],duration:a[2],callback:a[3]};a=b.options.mode;var d=f.effects[c];if(f.fx.off||!d)return a?this[a](b.duration,b.callback):this.each(function(){b.callback&&b.callback.call(this)});return d.call(this,b)},_show:f.fn.show,show:function(c){if(m(c))return this._show.apply(this,arguments);+else{var a=k.apply(this,arguments);a[1].mode="show";return this.effect.apply(this,a)}},_hide:f.fn.hide,hide:function(c){if(m(c))return this._hide.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="hide";return this.effect.apply(this,a)}},__toggle:f.fn.toggle,toggle:function(c){if(m(c)||typeof c==="boolean"||f.isFunction(c))return this.__toggle.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="toggle";return this.effect.apply(this,a)}},cssUnit:function(c){var a=this.css(c),+b=[];f.each(["em","px","%","pt"],function(d,e){if(a.indexOf(e)>0)b=[parseFloat(a),e]});return b}});f.easing.jswing=f.easing.swing;f.extend(f.easing,{def:"easeOutQuad",swing:function(c,a,b,d,e){return f.easing[f.easing.def](c,a,b,d,e)},easeInQuad:function(c,a,b,d,e){return d*(a/=e)*a+b},easeOutQuad:function(c,a,b,d,e){return-d*(a/=e)*(a-2)+b},easeInOutQuad:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a+b;return-d/2*(--a*(a-2)-1)+b},easeInCubic:function(c,a,b,d,e){return d*(a/=e)*a*a+b},easeOutCubic:function(c,+a,b,d,e){return d*((a=a/e-1)*a*a+1)+b},easeInOutCubic:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a+b;return d/2*((a-=2)*a*a+2)+b},easeInQuart:function(c,a,b,d,e){return d*(a/=e)*a*a*a+b},easeOutQuart:function(c,a,b,d,e){return-d*((a=a/e-1)*a*a*a-1)+b},easeInOutQuart:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a+b;return-d/2*((a-=2)*a*a*a-2)+b},easeInQuint:function(c,a,b,d,e){return d*(a/=e)*a*a*a*a+b},easeOutQuint:function(c,a,b,d,e){return d*((a=a/e-1)*a*a*a*a+1)+b},easeInOutQuint:function(c,+a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a*a+b;return d/2*((a-=2)*a*a*a*a+2)+b},easeInSine:function(c,a,b,d,e){return-d*Math.cos(a/e*(Math.PI/2))+d+b},easeOutSine:function(c,a,b,d,e){return d*Math.sin(a/e*(Math.PI/2))+b},easeInOutSine:function(c,a,b,d,e){return-d/2*(Math.cos(Math.PI*a/e)-1)+b},easeInExpo:function(c,a,b,d,e){return a==0?b:d*Math.pow(2,10*(a/e-1))+b},easeOutExpo:function(c,a,b,d,e){return a==e?b+d:d*(-Math.pow(2,-10*a/e)+1)+b},easeInOutExpo:function(c,a,b,d,e){if(a==0)return b;if(a==+e)return b+d;if((a/=e/2)<1)return d/2*Math.pow(2,10*(a-1))+b;return d/2*(-Math.pow(2,-10*--a)+2)+b},easeInCirc:function(c,a,b,d,e){return-d*(Math.sqrt(1-(a/=e)*a)-1)+b},easeOutCirc:function(c,a,b,d,e){return d*Math.sqrt(1-(a=a/e-1)*a)+b},easeInOutCirc:function(c,a,b,d,e){if((a/=e/2)<1)return-d/2*(Math.sqrt(1-a*a)-1)+b;return d/2*(Math.sqrt(1-(a-=2)*a)+1)+b},easeInElastic:function(c,a,b,d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e)==1)return b+d;g||(g=e*0.3);if(h<Math.abs(d)){h=d;c=g/4}else c=+g/(2*Math.PI)*Math.asin(d/h);return-(h*Math.pow(2,10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g))+b},easeOutElastic:function(c,a,b,d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e)==1)return b+d;g||(g=e*0.3);if(h<Math.abs(d)){h=d;c=g/4}else c=g/(2*Math.PI)*Math.asin(d/h);return h*Math.pow(2,-10*a)*Math.sin((a*e-c)*2*Math.PI/g)+d+b},easeInOutElastic:function(c,a,b,d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e/2)==2)return b+d;g||(g=e*0.3*1.5);if(h<Math.abs(d)){h=d;c=g/4}else c=g/(2*Math.PI)*Math.asin(d/+h);if(a<1)return-0.5*h*Math.pow(2,10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g)+b;return h*Math.pow(2,-10*(a-=1))*Math.sin((a*e-c)*2*Math.PI/g)*0.5+d+b},easeInBack:function(c,a,b,d,e,g){if(g==j)g=1.70158;return d*(a/=e)*a*((g+1)*a-g)+b},easeOutBack:function(c,a,b,d,e,g){if(g==j)g=1.70158;return d*((a=a/e-1)*a*((g+1)*a+g)+1)+b},easeInOutBack:function(c,a,b,d,e,g){if(g==j)g=1.70158;if((a/=e/2)<1)return d/2*a*a*(((g*=1.525)+1)*a-g)+b;return d/2*((a-=2)*a*(((g*=1.525)+1)*a+g)+2)+b},easeInBounce:function(c,+a,b,d,e){return d-f.easing.easeOutBounce(c,e-a,0,d,e)+b},easeOutBounce:function(c,a,b,d,e){return(a/=e)<1/2.75?d*7.5625*a*a+b:a<2/2.75?d*(7.5625*(a-=1.5/2.75)*a+0.75)+b:a<2.5/2.75?d*(7.5625*(a-=2.25/2.75)*a+0.9375)+b:d*(7.5625*(a-=2.625/2.75)*a+0.984375)+b},easeInOutBounce:function(c,a,b,d,e){if(a<e/2)return f.easing.easeInBounce(c,a*2,0,d,e)*0.5+b;return f.easing.easeOutBounce(c,a*2-e,0,d,e)*0.5+d*0.5+b}})}(jQuery);+;/*+ * jQuery UI Effects Blind 1.8.11+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Effects/Blind+ *+ * Depends:+ * jquery.effects.core.js+ */+(function(b){b.effects.blind=function(c){return this.queue(function(){var a=b(this),g=["position","top","bottom","left","right"],f=b.effects.setMode(a,c.options.mode||"hide"),d=c.options.direction||"vertical";b.effects.save(a,g);a.show();var e=b.effects.createWrapper(a).css({overflow:"hidden"}),h=d=="vertical"?"height":"width";d=d=="vertical"?e.height():e.width();f=="show"&&e.css(h,0);var i={};i[h]=f=="show"?d:0;e.animate(i,c.duration,c.options.easing,function(){f=="hide"&&a.hide();b.effects.restore(a,+g);b.effects.removeWrapper(a);c.callback&&c.callback.apply(a[0],arguments);a.dequeue()})})}})(jQuery);+;/*+ * jQuery UI Effects Bounce 1.8.11+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Effects/Bounce+ *+ * Depends:+ * jquery.effects.core.js+ */+(function(e){e.effects.bounce=function(b){return this.queue(function(){var a=e(this),l=["position","top","bottom","left","right"],h=e.effects.setMode(a,b.options.mode||"effect"),d=b.options.direction||"up",c=b.options.distance||20,m=b.options.times||5,i=b.duration||250;/show|hide/.test(h)&&l.push("opacity");e.effects.save(a,l);a.show();e.effects.createWrapper(a);var f=d=="up"||d=="down"?"top":"left";d=d=="up"||d=="left"?"pos":"neg";c=b.options.distance||(f=="top"?a.outerHeight({margin:true})/3:a.outerWidth({margin:true})/+3);if(h=="show")a.css("opacity",0).css(f,d=="pos"?-c:c);if(h=="hide")c/=m*2;h!="hide"&&m--;if(h=="show"){var g={opacity:1};g[f]=(d=="pos"?"+=":"-=")+c;a.animate(g,i/2,b.options.easing);c/=2;m--}for(g=0;g<m;g++){var j={},k={};j[f]=(d=="pos"?"-=":"+=")+c;k[f]=(d=="pos"?"+=":"-=")+c;a.animate(j,i/2,b.options.easing).animate(k,i/2,b.options.easing);c=h=="hide"?c*2:c/2}if(h=="hide"){g={opacity:0};g[f]=(d=="pos"?"-=":"+=")+c;a.animate(g,i/2,b.options.easing,function(){a.hide();e.effects.restore(a,l);e.effects.removeWrapper(a);+b.callback&&b.callback.apply(this,arguments)})}else{j={};k={};j[f]=(d=="pos"?"-=":"+=")+c;k[f]=(d=="pos"?"+=":"-=")+c;a.animate(j,i/2,b.options.easing).animate(k,i/2,b.options.easing,function(){e.effects.restore(a,l);e.effects.removeWrapper(a);b.callback&&b.callback.apply(this,arguments)})}a.queue("fx",function(){a.dequeue()});a.dequeue()})}})(jQuery);+;/*+ * jQuery UI Effects Clip 1.8.11+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Effects/Clip+ *+ * Depends:+ * jquery.effects.core.js+ */+(function(b){b.effects.clip=function(e){return this.queue(function(){var a=b(this),i=["position","top","bottom","left","right","height","width"],f=b.effects.setMode(a,e.options.mode||"hide"),c=e.options.direction||"vertical";b.effects.save(a,i);a.show();var d=b.effects.createWrapper(a).css({overflow:"hidden"});d=a[0].tagName=="IMG"?d:a;var g={size:c=="vertical"?"height":"width",position:c=="vertical"?"top":"left"};c=c=="vertical"?d.height():d.width();if(f=="show"){d.css(g.size,0);d.css(g.position,+c/2)}var h={};h[g.size]=f=="show"?c:0;h[g.position]=f=="show"?0:c/2;d.animate(h,{queue:false,duration:e.duration,easing:e.options.easing,complete:function(){f=="hide"&&a.hide();b.effects.restore(a,i);b.effects.removeWrapper(a);e.callback&&e.callback.apply(a[0],arguments);a.dequeue()}})})}})(jQuery);+;/*+ * jQuery UI Effects Drop 1.8.11+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Effects/Drop+ *+ * Depends:+ * jquery.effects.core.js+ */+(function(c){c.effects.drop=function(d){return this.queue(function(){var a=c(this),h=["position","top","bottom","left","right","opacity"],e=c.effects.setMode(a,d.options.mode||"hide"),b=d.options.direction||"left";c.effects.save(a,h);a.show();c.effects.createWrapper(a);var f=b=="up"||b=="down"?"top":"left";b=b=="up"||b=="left"?"pos":"neg";var g=d.options.distance||(f=="top"?a.outerHeight({margin:true})/2:a.outerWidth({margin:true})/2);if(e=="show")a.css("opacity",0).css(f,b=="pos"?-g:g);var i={opacity:e==+"show"?1:0};i[f]=(e=="show"?b=="pos"?"+=":"-=":b=="pos"?"-=":"+=")+g;a.animate(i,{queue:false,duration:d.duration,easing:d.options.easing,complete:function(){e=="hide"&&a.hide();c.effects.restore(a,h);c.effects.removeWrapper(a);d.callback&&d.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery);+;/*+ * jQuery UI Effects Explode 1.8.11+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Effects/Explode+ *+ * Depends:+ * jquery.effects.core.js+ */+(function(j){j.effects.explode=function(a){return this.queue(function(){var c=a.options.pieces?Math.round(Math.sqrt(a.options.pieces)):3,d=a.options.pieces?Math.round(Math.sqrt(a.options.pieces)):3;a.options.mode=a.options.mode=="toggle"?j(this).is(":visible")?"hide":"show":a.options.mode;var b=j(this).show().css("visibility","hidden"),g=b.offset();g.top-=parseInt(b.css("marginTop"),10)||0;g.left-=parseInt(b.css("marginLeft"),10)||0;for(var h=b.outerWidth(true),i=b.outerHeight(true),e=0;e<c;e++)for(var f=+0;f<d;f++)b.clone().appendTo("body").wrap("<div></div>").css({position:"absolute",visibility:"visible",left:-f*(h/d),top:-e*(i/c)}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:h/d,height:i/c,left:g.left+f*(h/d)+(a.options.mode=="show"?(f-Math.floor(d/2))*(h/d):0),top:g.top+e*(i/c)+(a.options.mode=="show"?(e-Math.floor(c/2))*(i/c):0),opacity:a.options.mode=="show"?0:1}).animate({left:g.left+f*(h/d)+(a.options.mode=="show"?0:(f-Math.floor(d/2))*(h/d)),top:g.top++e*(i/c)+(a.options.mode=="show"?0:(e-Math.floor(c/2))*(i/c)),opacity:a.options.mode=="show"?1:0},a.duration||500);setTimeout(function(){a.options.mode=="show"?b.css({visibility:"visible"}):b.css({visibility:"visible"}).hide();a.callback&&a.callback.apply(b[0]);b.dequeue();j("div.ui-effects-explode").remove()},a.duration||500)})}})(jQuery);+;/*+ * jQuery UI Effects Fade 1.8.11+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Effects/Fade+ *+ * Depends:+ * jquery.effects.core.js+ */+(function(b){b.effects.fade=function(a){return this.queue(function(){var c=b(this),d=b.effects.setMode(c,a.options.mode||"hide");c.animate({opacity:d},{queue:false,duration:a.duration,easing:a.options.easing,complete:function(){a.callback&&a.callback.apply(this,arguments);c.dequeue()}})})}})(jQuery);+;/*+ * jQuery UI Effects Fold 1.8.11+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Effects/Fold+ *+ * Depends:+ * jquery.effects.core.js+ */+(function(c){c.effects.fold=function(a){return this.queue(function(){var b=c(this),j=["position","top","bottom","left","right"],d=c.effects.setMode(b,a.options.mode||"hide"),g=a.options.size||15,h=!!a.options.horizFirst,k=a.duration?a.duration/2:c.fx.speeds._default/2;c.effects.save(b,j);b.show();var e=c.effects.createWrapper(b).css({overflow:"hidden"}),f=d=="show"!=h,l=f?["width","height"]:["height","width"];f=f?[e.width(),e.height()]:[e.height(),e.width()];var i=/([0-9]+)%/.exec(g);if(i)g=parseInt(i[1],+10)/100*f[d=="hide"?0:1];if(d=="show")e.css(h?{height:0,width:g}:{height:g,width:0});h={};i={};h[l[0]]=d=="show"?f[0]:g;i[l[1]]=d=="show"?f[1]:0;e.animate(h,k,a.options.easing).animate(i,k,a.options.easing,function(){d=="hide"&&b.hide();c.effects.restore(b,j);c.effects.removeWrapper(b);a.callback&&a.callback.apply(b[0],arguments);b.dequeue()})})}})(jQuery);+;/*+ * jQuery UI Effects Highlight 1.8.11+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Effects/Highlight+ *+ * Depends:+ * jquery.effects.core.js+ */+(function(b){b.effects.highlight=function(c){return this.queue(function(){var a=b(this),e=["backgroundImage","backgroundColor","opacity"],d=b.effects.setMode(a,c.options.mode||"show"),f={backgroundColor:a.css("backgroundColor")};if(d=="hide")f.opacity=0;b.effects.save(a,e);a.show().css({backgroundImage:"none",backgroundColor:c.options.color||"#ffff99"}).animate(f,{queue:false,duration:c.duration,easing:c.options.easing,complete:function(){d=="hide"&&a.hide();b.effects.restore(a,e);d=="show"&&!b.support.opacity&&+this.style.removeAttribute("filter");c.callback&&c.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery);+;/*+ * jQuery UI Effects Pulsate 1.8.11+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Effects/Pulsate+ *+ * Depends:+ * jquery.effects.core.js+ */+(function(d){d.effects.pulsate=function(a){return this.queue(function(){var b=d(this),c=d.effects.setMode(b,a.options.mode||"show");times=(a.options.times||5)*2-1;duration=a.duration?a.duration/2:d.fx.speeds._default/2;isVisible=b.is(":visible");animateTo=0;if(!isVisible){b.css("opacity",0).show();animateTo=1}if(c=="hide"&&isVisible||c=="show"&&!isVisible)times--;for(c=0;c<times;c++){b.animate({opacity:animateTo},duration,a.options.easing);animateTo=(animateTo+1)%2}b.animate({opacity:animateTo},duration,+a.options.easing,function(){animateTo==0&&b.hide();a.callback&&a.callback.apply(this,arguments)});b.queue("fx",function(){b.dequeue()}).dequeue()})}})(jQuery);+;/*+ * jQuery UI Effects Scale 1.8.11+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Effects/Scale+ *+ * Depends:+ * jquery.effects.core.js+ */+(function(c){c.effects.puff=function(b){return this.queue(function(){var a=c(this),e=c.effects.setMode(a,b.options.mode||"hide"),g=parseInt(b.options.percent,10)||150,h=g/100,i={height:a.height(),width:a.width()};c.extend(b.options,{fade:true,mode:e,percent:e=="hide"?g:100,from:e=="hide"?i:{height:i.height*h,width:i.width*h}});a.effect("scale",b.options,b.duration,b.callback);a.dequeue()})};c.effects.scale=function(b){return this.queue(function(){var a=c(this),e=c.extend(true,{},b.options),g=c.effects.setMode(a,+b.options.mode||"effect"),h=parseInt(b.options.percent,10)||(parseInt(b.options.percent,10)==0?0:g=="hide"?0:100),i=b.options.direction||"both",f=b.options.origin;if(g!="effect"){e.origin=f||["middle","center"];e.restore=true}f={height:a.height(),width:a.width()};a.from=b.options.from||(g=="show"?{height:0,width:0}:f);h={y:i!="horizontal"?h/100:1,x:i!="vertical"?h/100:1};a.to={height:f.height*h.y,width:f.width*h.x};if(b.options.fade){if(g=="show"){a.from.opacity=0;a.to.opacity=1}if(g=="hide"){a.from.opacity=+1;a.to.opacity=0}}e.from=a.from;e.to=a.to;e.mode=g;a.effect("size",e,b.duration,b.callback);a.dequeue()})};c.effects.size=function(b){return this.queue(function(){var a=c(this),e=["position","top","bottom","left","right","width","height","overflow","opacity"],g=["position","top","bottom","left","right","overflow","opacity"],h=["width","height","overflow"],i=["fontSize"],f=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],k=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"],+p=c.effects.setMode(a,b.options.mode||"effect"),n=b.options.restore||false,m=b.options.scale||"both",l=b.options.origin,j={height:a.height(),width:a.width()};a.from=b.options.from||j;a.to=b.options.to||j;if(l){l=c.effects.getBaseline(l,j);a.from.top=(j.height-a.from.height)*l.y;a.from.left=(j.width-a.from.width)*l.x;a.to.top=(j.height-a.to.height)*l.y;a.to.left=(j.width-a.to.width)*l.x}var d={from:{y:a.from.height/j.height,x:a.from.width/j.width},to:{y:a.to.height/j.height,x:a.to.width/j.width}};+if(m=="box"||m=="both"){if(d.from.y!=d.to.y){e=e.concat(f);a.from=c.effects.setTransition(a,f,d.from.y,a.from);a.to=c.effects.setTransition(a,f,d.to.y,a.to)}if(d.from.x!=d.to.x){e=e.concat(k);a.from=c.effects.setTransition(a,k,d.from.x,a.from);a.to=c.effects.setTransition(a,k,d.to.x,a.to)}}if(m=="content"||m=="both")if(d.from.y!=d.to.y){e=e.concat(i);a.from=c.effects.setTransition(a,i,d.from.y,a.from);a.to=c.effects.setTransition(a,i,d.to.y,a.to)}c.effects.save(a,n?e:g);a.show();c.effects.createWrapper(a);+a.css("overflow","hidden").css(a.from);if(m=="content"||m=="both"){f=f.concat(["marginTop","marginBottom"]).concat(i);k=k.concat(["marginLeft","marginRight"]);h=e.concat(f).concat(k);a.find("*[width]").each(function(){child=c(this);n&&c.effects.save(child,h);var o={height:child.height(),width:child.width()};child.from={height:o.height*d.from.y,width:o.width*d.from.x};child.to={height:o.height*d.to.y,width:o.width*d.to.x};if(d.from.y!=d.to.y){child.from=c.effects.setTransition(child,f,d.from.y,child.from);+child.to=c.effects.setTransition(child,f,d.to.y,child.to)}if(d.from.x!=d.to.x){child.from=c.effects.setTransition(child,k,d.from.x,child.from);child.to=c.effects.setTransition(child,k,d.to.x,child.to)}child.css(child.from);child.animate(child.to,b.duration,b.options.easing,function(){n&&c.effects.restore(child,h)})})}a.animate(a.to,{queue:false,duration:b.duration,easing:b.options.easing,complete:function(){a.to.opacity===0&&a.css("opacity",a.from.opacity);p=="hide"&&a.hide();c.effects.restore(a,+n?e:g);c.effects.removeWrapper(a);b.callback&&b.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery);+;/*+ * jQuery UI Effects Shake 1.8.11+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Effects/Shake+ *+ * Depends:+ * jquery.effects.core.js+ */+(function(d){d.effects.shake=function(a){return this.queue(function(){var b=d(this),j=["position","top","bottom","left","right"];d.effects.setMode(b,a.options.mode||"effect");var c=a.options.direction||"left",e=a.options.distance||20,l=a.options.times||3,f=a.duration||a.options.duration||140;d.effects.save(b,j);b.show();d.effects.createWrapper(b);var g=c=="up"||c=="down"?"top":"left",h=c=="up"||c=="left"?"pos":"neg";c={};var i={},k={};c[g]=(h=="pos"?"-=":"+=")+e;i[g]=(h=="pos"?"+=":"-=")+e*2;k[g]=+(h=="pos"?"-=":"+=")+e*2;b.animate(c,f,a.options.easing);for(e=1;e<l;e++)b.animate(i,f,a.options.easing).animate(k,f,a.options.easing);b.animate(i,f,a.options.easing).animate(c,f/2,a.options.easing,function(){d.effects.restore(b,j);d.effects.removeWrapper(b);a.callback&&a.callback.apply(this,arguments)});b.queue("fx",function(){b.dequeue()});b.dequeue()})}})(jQuery);+;/*+ * jQuery UI Effects Slide 1.8.11+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Effects/Slide+ *+ * Depends:+ * jquery.effects.core.js+ */+(function(c){c.effects.slide=function(d){return this.queue(function(){var a=c(this),h=["position","top","bottom","left","right"],f=c.effects.setMode(a,d.options.mode||"show"),b=d.options.direction||"left";c.effects.save(a,h);a.show();c.effects.createWrapper(a).css({overflow:"hidden"});var g=b=="up"||b=="down"?"top":"left";b=b=="up"||b=="left"?"pos":"neg";var e=d.options.distance||(g=="top"?a.outerHeight({margin:true}):a.outerWidth({margin:true}));if(f=="show")a.css(g,b=="pos"?isNaN(e)?"-"+e:-e:e);+var i={};i[g]=(f=="show"?b=="pos"?"+=":"-=":b=="pos"?"-=":"+=")+e;a.animate(i,{queue:false,duration:d.duration,easing:d.options.easing,complete:function(){f=="hide"&&a.hide();c.effects.restore(a,h);c.effects.removeWrapper(a);d.callback&&d.callback.apply(this,arguments);a.dequeue()}})})}})(jQuery);+;/*+ * jQuery UI Effects Transfer 1.8.11+ *+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * http://docs.jquery.com/UI/Effects/Transfer+ *+ * Depends:+ * jquery.effects.core.js+ */+(function(e){e.effects.transfer=function(a){return this.queue(function(){var b=e(this),c=e(a.options.to),d=c.offset();c={top:d.top,left:d.left,height:c.innerHeight(),width:c.innerWidth()};d=b.offset();var f=e('<div class="ui-effects-transfer"></div>').appendTo(document.body).addClass(a.options.className).css({top:d.top,left:d.left,height:b.innerHeight(),width:b.innerWidth(),position:"absolute"}).animate(c,a.duration,a.options.easing,function(){f.remove();a.callback&&a.callback.apply(b[0],arguments);+b.dequeue()})})}})(jQuery);+;
@@ -0,0 +1,16 @@+/*!+ * jQuery JavaScript Library v1.5.1+ * http://jquery.com/+ *+ * Copyright 2011, John Resig+ * Dual licensed under the MIT or GPL Version 2 licenses.+ * http://jquery.org/license+ *+ * Includes Sizzle.js+ * http://sizzlejs.com/+ * Copyright 2011, The Dojo Foundation+ * Released under the MIT, BSD, and GPL Licenses.+ *+ * Date: Wed Feb 23 13:55:29 2011 -0500+ */+(function(a,b){function cg(a){return d.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cd(a){if(!bZ[a]){var b=d("<"+a+">").appendTo("body"),c=b.css("display");b.remove();if(c==="none"||c==="")c="block";bZ[a]=c}return bZ[a]}function cc(a,b){var c={};d.each(cb.concat.apply([],cb.slice(0,b)),function(){c[this]=a});return c}function bY(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function bX(){try{return new a.XMLHttpRequest}catch(b){}}function bW(){d(a).unload(function(){for(var a in bU)bU[a](0,1)})}function bQ(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var e=a.dataTypes,f={},g,h,i=e.length,j,k=e[0],l,m,n,o,p;for(g=1;g<i;g++){if(g===1)for(h in a.converters)typeof h==="string"&&(f[h.toLowerCase()]=a.converters[h]);l=k,k=e[g];if(k==="*")k=l;else if(l!=="*"&&l!==k){m=l+" "+k,n=f[m]||f["* "+k];if(!n){p=b;for(o in f){j=o.split(" ");if(j[0]===l||j[0]==="*"){p=f[j[1]+" "+k];if(p){o=f[o],o===!0?n=p:p===!0&&(n=o);break}}}}!n&&!p&&d.error("No conversion from "+m.replace(" "," to ")),n!==!0&&(c=n?n(c):p(o(c)))}}return c}function bP(a,c,d){var e=a.contents,f=a.dataTypes,g=a.responseFields,h,i,j,k;for(i in g)i in d&&(c[g[i]]=d[i]);while(f[0]==="*")f.shift(),h===b&&(h=a.mimeType||c.getResponseHeader("content-type"));if(h)for(i in e)if(e[i]&&e[i].test(h)){f.unshift(i);break}if(f[0]in d)j=f[0];else{for(i in d){if(!f[0]||a.converters[i+" "+f[0]]){j=i;break}k||(k=i)}j=j||k}if(j){j!==f[0]&&f.unshift(j);return d[j]}}function bO(a,b,c,e){if(d.isArray(b)&&b.length)d.each(b,function(b,f){c||bq.test(a)?e(a,f):bO(a+"["+(typeof f==="object"||d.isArray(f)?b:"")+"]",f,c,e)});else if(c||b==null||typeof b!=="object")e(a,b);else if(d.isArray(b)||d.isEmptyObject(b))e(a,"");else for(var f in b)bO(a+"["+f+"]",b[f],c,e)}function bN(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h=a[f],i=0,j=h?h.length:0,k=a===bH,l;for(;i<j&&(k||!l);i++)l=h[i](c,d,e),typeof l==="string"&&(!k||g[l]?l=b:(c.dataTypes.unshift(l),l=bN(a,c,d,e,l,g)));(k||!l)&&!g["*"]&&(l=bN(a,c,d,e,"*",g));return l}function bM(a){return function(b,c){typeof b!=="string"&&(c=b,b="*");if(d.isFunction(c)){var e=b.toLowerCase().split(bB),f=0,g=e.length,h,i,j;for(;f<g;f++)h=e[f],j=/^\+/.test(h),j&&(h=h.substr(1)||"*"),i=a[h]=a[h]||[],i[j?"unshift":"push"](c)}}}function bo(a,b,c){var e=b==="width"?bi:bj,f=b==="width"?a.offsetWidth:a.offsetHeight;if(c==="border")return f;d.each(e,function(){c||(f-=parseFloat(d.css(a,"padding"+this))||0),c==="margin"?f+=parseFloat(d.css(a,"margin"+this))||0:f-=parseFloat(d.css(a,"border"+this+"Width"))||0});return f}function ba(a,b){b.src?d.ajax({url:b.src,async:!1,dataType:"script"}):d.globalEval(b.text||b.textContent||b.innerHTML||""),b.parentNode&&b.parentNode.removeChild(b)}function _(a){return"getElementsByTagName"in a?a.getElementsByTagName("*"):"querySelectorAll"in a?a.querySelectorAll("*"):[]}function $(a,b){if(b.nodeType===1){var c=b.nodeName.toLowerCase();b.clearAttributes(),b.mergeAttributes(a);if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(d.expando)}}function Z(a,b){if(b.nodeType===1&&d.hasData(a)){var c=d.expando,e=d.data(a),f=d.data(b,e);if(e=e[c]){var g=e.events;f=f[c]=d.extend({},e);if(g){delete f.handle,f.events={};for(var h in g)for(var i=0,j=g[h].length;i<j;i++)d.event.add(b,h+(g[h][i].namespace?".":"")+g[h][i].namespace,g[h][i],g[h][i].data)}}}}function Y(a,b){return d.nodeName(a,"table")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function O(a,b,c){if(d.isFunction(b))return d.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return d.grep(a,function(a,d){return a===b===c});if(typeof b==="string"){var e=d.grep(a,function(a){return a.nodeType===1});if(J.test(b))return d.filter(b,e,!c);b=d.filter(b,e)}return d.grep(a,function(a,e){return d.inArray(a,b)>=0===c})}function N(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function F(a,b){return(a&&a!=="*"?a+".":"")+b.replace(r,"`").replace(s,"&")}function E(a){var b,c,e,f,g,h,i,j,k,l,m,n,o,q=[],r=[],s=d._data(this,"events");if(a.liveFired!==this&&s&&s.live&&!a.target.disabled&&(!a.button||a.type!=="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var t=s.live.slice(0);for(i=0;i<t.length;i++)g=t[i],g.origType.replace(p,"")===a.type?r.push(g.selector):t.splice(i--,1);f=d(a.target).closest(r,a.currentTarget);for(j=0,k=f.length;j<k;j++){m=f[j];for(i=0;i<t.length;i++){g=t[i];if(m.selector===g.selector&&(!n||n.test(g.namespace))&&!m.elem.disabled){h=m.elem,e=null;if(g.preType==="mouseenter"||g.preType==="mouseleave")a.type=g.preType,e=d(a.relatedTarget).closest(g.selector)[0];(!e||e!==h)&&q.push({elem:h,handleObj:g,level:m.level})}}}for(j=0,k=q.length;j<k;j++){f=q[j];if(c&&f.level>c)break;a.currentTarget=f.elem,a.data=f.handleObj.data,a.handleObj=f.handleObj,o=f.handleObj.origHandler.apply(f.elem,arguments);if(o===!1||a.isPropagationStopped()){c=f.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function C(a,c,e){var f=d.extend({},e[0]);f.type=a,f.originalEvent={},f.liveFired=b,d.event.handle.call(c,f),f.isDefaultPrevented()&&e[0].preventDefault()}function w(){return!0}function v(){return!1}function g(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function f(a,c,f){if(f===b&&a.nodeType===1){f=a.getAttribute("data-"+c);if(typeof f==="string"){try{f=f==="true"?!0:f==="false"?!1:f==="null"?null:d.isNaN(f)?e.test(f)?d.parseJSON(f):f:parseFloat(f)}catch(g){}d.data(a,c,f)}else f=b}return f}var c=a.document,d=function(){function I(){if(!d.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(I,1);return}d.ready()}}var d=function(a,b){return new d.fn.init(a,b,g)},e=a.jQuery,f=a.$,g,h=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/,i=/\S/,j=/^\s+/,k=/\s+$/,l=/\d/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=navigator.userAgent,w,x=!1,y,z="then done fail isResolved isRejected promise".split(" "),A,B=Object.prototype.toString,C=Object.prototype.hasOwnProperty,D=Array.prototype.push,E=Array.prototype.slice,F=String.prototype.trim,G=Array.prototype.indexOf,H={};d.fn=d.prototype={constructor:d,init:function(a,e,f){var g,i,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!e&&c.body){this.context=c,this[0]=c.body,this.selector="body",this.length=1;return this}if(typeof a==="string"){g=h.exec(a);if(!g||!g[1]&&e)return!e||e.jquery?(e||f).find(a):this.constructor(e).find(a);if(g[1]){e=e instanceof d?e[0]:e,k=e?e.ownerDocument||e:c,j=m.exec(a),j?d.isPlainObject(e)?(a=[c.createElement(j[1])],d.fn.attr.call(a,e,!0)):a=[k.createElement(j[1])]:(j=d.buildFragment([g[1]],[k]),a=(j.cacheable?d.clone(j.fragment):j.fragment).childNodes);return d.merge(this,a)}i=c.getElementById(g[2]);if(i&&i.parentNode){if(i.id!==g[2])return f.find(a);this.length=1,this[0]=i}this.context=c,this.selector=a;return this}if(d.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return d.makeArray(a,this)},selector:"",jquery:"1.5.1",length:0,size:function(){return this.length},toArray:function(){return E.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var e=this.constructor();d.isArray(a)?D.apply(e,a):d.merge(e,a),e.prevObject=this,e.context=this.context,b==="find"?e.selector=this.selector+(this.selector?" ":"")+c:b&&(e.selector=this.selector+"."+b+"("+c+")");return e},each:function(a,b){return d.each(this,a,b)},ready:function(a){d.bindReady(),y.done(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(E.apply(this,arguments),"slice",E.call(arguments).join(","))},map:function(a){return this.pushStack(d.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:D,sort:[].sort,splice:[].splice},d.fn.init.prototype=d.fn,d.extend=d.fn.extend=function(){var a,c,e,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i==="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!=="object"&&!d.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j<k;j++)if((a=arguments[j])!=null)for(c in a){e=i[c],f=a[c];if(i===f)continue;l&&f&&(d.isPlainObject(f)||(g=d.isArray(f)))?(g?(g=!1,h=e&&d.isArray(e)?e:[]):h=e&&d.isPlainObject(e)?e:{},i[c]=d.extend(l,h,f)):f!==b&&(i[c]=f)}return i},d.extend({noConflict:function(b){a.$=f,b&&(a.jQuery=e);return d},isReady:!1,readyWait:1,ready:function(a){a===!0&&d.readyWait--;if(!d.readyWait||a!==!0&&!d.isReady){if(!c.body)return setTimeout(d.ready,1);d.isReady=!0;if(a!==!0&&--d.readyWait>0)return;y.resolveWith(c,[d]),d.fn.trigger&&d(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!x){x=!0;if(c.readyState==="complete")return setTimeout(d.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",A,!1),a.addEventListener("load",d.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",A),a.attachEvent("onload",d.ready);var b=!1;try{b=a.frameElement==null}catch(e){}c.documentElement.doScroll&&b&&I()}}},isFunction:function(a){return d.type(a)==="function"},isArray:Array.isArray||function(a){return d.type(a)==="array"},isWindow:function(a){return a&&typeof a==="object"&&"setInterval"in a},isNaN:function(a){return a==null||!l.test(a)||isNaN(a)},type:function(a){return a==null?String(a):H[B.call(a)]||"object"},isPlainObject:function(a){if(!a||d.type(a)!=="object"||a.nodeType||d.isWindow(a))return!1;if(a.constructor&&!C.call(a,"constructor")&&!C.call(a.constructor.prototype,"isPrototypeOf"))return!1;var c;for(c in a){}return c===b||C.call(a,c)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!=="string"||!b)return null;b=d.trim(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return a.JSON&&a.JSON.parse?a.JSON.parse(b):(new Function("return "+b))();d.error("Invalid JSON: "+b)},parseXML:function(b,c,e){a.DOMParser?(e=new DOMParser,c=e.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b)),e=c.documentElement,(!e||!e.nodeName||e.nodeName==="parsererror")&&d.error("Invalid XML: "+b);return c},noop:function(){},globalEval:function(a){if(a&&i.test(a)){var b=c.head||c.getElementsByTagName("head")[0]||c.documentElement,e=c.createElement("script");d.support.scriptEval()?e.appendChild(c.createTextNode(a)):e.text=a,b.insertBefore(e,b.firstChild),b.removeChild(e)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,e){var f,g=0,h=a.length,i=h===b||d.isFunction(a);if(e){if(i){for(f in a)if(c.apply(a[f],e)===!1)break}else for(;g<h;)if(c.apply(a[g++],e)===!1)break}else if(i){for(f in a)if(c.call(a[f],f,a[f])===!1)break}else for(var j=a[0];g<h&&c.call(j,g,j)!==!1;j=a[++g]){}return a},trim:F?function(a){return a==null?"":F.call(a)}:function(a){return a==null?"":(a+"").replace(j,"").replace(k,"")},makeArray:function(a,b){var c=b||[];if(a!=null){var e=d.type(a);a.length==null||e==="string"||e==="function"||e==="regexp"||d.isWindow(a)?D.call(c,a):d.merge(c,a)}return c},inArray:function(a,b){if(b.indexOf)return b.indexOf(a);for(var c=0,d=b.length;c<d;c++)if(b[c]===a)return c;return-1},merge:function(a,c){var d=a.length,e=0;if(typeof c.length==="number")for(var f=c.length;e<f;e++)a[d++]=c[e];else while(c[e]!==b)a[d++]=c[e++];a.length=d;return a},grep:function(a,b,c){var d=[],e;c=!!c;for(var f=0,g=a.length;f<g;f++)e=!!b(a[f],f),c!==e&&d.push(a[f]);return d},map:function(a,b,c){var d=[],e;for(var f=0,g=a.length;f<g;f++)e=b(a[f],f,c),e!=null&&(d[d.length]=e);return d.concat.apply([],d)},guid:1,proxy:function(a,c,e){arguments.length===2&&(typeof c==="string"?(e=a,a=e[c],c=b):c&&!d.isFunction(c)&&(e=c,c=b)),!c&&a&&(c=function(){return a.apply(e||this,arguments)}),a&&(c.guid=a.guid=a.guid||c.guid||d.guid++);return c},access:function(a,c,e,f,g,h){var i=a.length;if(typeof c==="object"){for(var j in c)d.access(a,j,c[j],f,g,e);return a}if(e!==b){f=!h&&f&&d.isFunction(e);for(var k=0;k<i;k++)g(a[k],c,f?e.call(a[k],k,g(a[k],c)):e,h);return a}return i?g(a[0],c):b},now:function(){return(new Date).getTime()},_Deferred:function(){var a=[],b,c,e,f={done:function(){if(!e){var c=arguments,g,h,i,j,k;b&&(k=b,b=0);for(g=0,h=c.length;g<h;g++)i=c[g],j=d.type(i),j==="array"?f.done.apply(f,i):j==="function"&&a.push(i);k&&f.resolveWith(k[0],k[1])}return this},resolveWith:function(d,f){if(!e&&!b&&!c){c=1;try{while(a[0])a.shift().apply(d,f)}catch(g){throw g}finally{b=[d,f],c=0}}return this},resolve:function(){f.resolveWith(d.isFunction(this.promise)?this.promise():this,arguments);return this},isResolved:function(){return c||b},cancel:function(){e=1,a=[];return this}};return f},Deferred:function(a){var b=d._Deferred(),c=d._Deferred(),e;d.extend(b,{then:function(a,c){b.done(a).fail(c);return this},fail:c.done,rejectWith:c.resolveWith,reject:c.resolve,isRejected:c.isResolved,promise:function(a){if(a==null){if(e)return e;e=a={}}var c=z.length;while(c--)a[z[c]]=b[z[c]];return a}}),b.done(c.cancel).fail(b.cancel),delete b.cancel,a&&a.call(b,b);return b},when:function(a){var b=arguments.length,c=b<=1&&a&&d.isFunction(a.promise)?a:d.Deferred(),e=c.promise();if(b>1){var f=E.call(arguments,0),g=b,h=function(a){return function(b){f[a]=arguments.length>1?E.call(arguments,0):b,--g||c.resolveWith(e,f)}};while(b--)a=f[b],a&&d.isFunction(a.promise)?a.promise().then(h(b),c.reject):--g;g||c.resolveWith(e,f)}else c!==a&&c.resolve(a);return e},uaMatch:function(a){a=a.toLowerCase();var b=r.exec(a)||s.exec(a)||t.exec(a)||a.indexOf("compatible")<0&&u.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},sub:function(){function a(b,c){return new a.fn.init(b,c)}d.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.subclass=this.subclass,a.fn.init=function b(b,c){c&&c instanceof d&&!(c instanceof a)&&(c=a(c));return d.fn.init.call(this,b,c,e)},a.fn.init.prototype=a.fn;var e=a(c);return a},browser:{}}),y=d._Deferred(),d.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){H["[object "+b+"]"]=b.toLowerCase()}),w=d.uaMatch(v),w.browser&&(d.browser[w.browser]=!0,d.browser.version=w.version),d.browser.webkit&&(d.browser.safari=!0),G&&(d.inArray=function(a,b){return G.call(b,a)}),i.test(" ")&&(j=/^[\s\xA0]+/,k=/[\s\xA0]+$/),g=d(c),c.addEventListener?A=function(){c.removeEventListener("DOMContentLoaded",A,!1),d.ready()}:c.attachEvent&&(A=function(){c.readyState==="complete"&&(c.detachEvent("onreadystatechange",A),d.ready())});return d}();(function(){d.support={};var b=c.createElement("div");b.style.display="none",b.innerHTML=" <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";var e=b.getElementsByTagName("*"),f=b.getElementsByTagName("a")[0],g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=b.getElementsByTagName("input")[0];if(e&&e.length&&f){d.support={leadingWhitespace:b.firstChild.nodeType===3,tbody:!b.getElementsByTagName("tbody").length,htmlSerialize:!!b.getElementsByTagName("link").length,style:/red/.test(f.getAttribute("style")),hrefNormalized:f.getAttribute("href")==="/a",opacity:/^0.55$/.test(f.style.opacity),cssFloat:!!f.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,deleteExpando:!0,optDisabled:!1,checkClone:!1,noCloneEvent:!0,noCloneChecked:!0,boxModel:null,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableHiddenOffsets:!0},i.checked=!0,d.support.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,d.support.optDisabled=!h.disabled;var j=null;d.support.scriptEval=function(){if(j===null){var b=c.documentElement,e=c.createElement("script"),f="script"+d.now();try{e.appendChild(c.createTextNode("window."+f+"=1;"))}catch(g){}b.insertBefore(e,b.firstChild),a[f]?(j=!0,delete a[f]):j=!1,b.removeChild(e),b=e=f=null}return j};try{delete b.test}catch(k){d.support.deleteExpando=!1}!b.addEventListener&&b.attachEvent&&b.fireEvent&&(b.attachEvent("onclick",function l(){d.support.noCloneEvent=!1,b.detachEvent("onclick",l)}),b.cloneNode(!0).fireEvent("onclick")),b=c.createElement("div"),b.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";var m=c.createDocumentFragment();m.appendChild(b.firstChild),d.support.checkClone=m.cloneNode(!0).cloneNode(!0).lastChild.checked,d(function(){var a=c.createElement("div"),b=c.getElementsByTagName("body")[0];if(b){a.style.width=a.style.paddingLeft="1px",b.appendChild(a),d.boxModel=d.support.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,d.support.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="<div style='width:4px;'></div>",d.support.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>";var e=a.getElementsByTagName("td");d.support.reliableHiddenOffsets=e[0].offsetHeight===0,e[0].style.display="",e[1].style.display="none",d.support.reliableHiddenOffsets=d.support.reliableHiddenOffsets&&e[0].offsetHeight===0,a.innerHTML="",b.removeChild(a).style.display="none",a=e=null}});var n=function(a){var b=c.createElement("div");a="on"+a;if(!b.attachEvent)return!0;var d=a in b;d||(b.setAttribute(a,"return;"),d=typeof b[a]==="function"),b=null;return d};d.support.submitBubbles=n("submit"),d.support.changeBubbles=n("change"),b=e=f=null}})();var e=/^(?:\{.*\}|\[.*\])$/;d.extend({cache:{},uuid:0,expando:"jQuery"+(d.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?d.cache[a[d.expando]]:a[d.expando];return!!a&&!g(a)},data:function(a,c,e,f){if(d.acceptData(a)){var g=d.expando,h=typeof c==="string",i,j=a.nodeType,k=j?d.cache:a,l=j?a[d.expando]:a[d.expando]&&d.expando;if((!l||f&&l&&!k[l][g])&&h&&e===b)return;l||(j?a[d.expando]=l=++d.uuid:l=d.expando),k[l]||(k[l]={},j||(k[l].toJSON=d.noop));if(typeof c==="object"||typeof c==="function")f?k[l][g]=d.extend(k[l][g],c):k[l]=d.extend(k[l],c);i=k[l],f&&(i[g]||(i[g]={}),i=i[g]),e!==b&&(i[c]=e);if(c==="events"&&!i[c])return i[g]&&i[g].events;return h?i[c]:i}},removeData:function(b,c,e){if(d.acceptData(b)){var f=d.expando,h=b.nodeType,i=h?d.cache:b,j=h?b[d.expando]:d.expando;if(!i[j])return;if(c){var k=e?i[j][f]:i[j];if(k){delete k[c];if(!g(k))return}}if(e){delete i[j][f];if(!g(i[j]))return}var l=i[j][f];d.support.deleteExpando||i!=a?delete i[j]:i[j]=null,l?(i[j]={},h||(i[j].toJSON=d.noop),i[j][f]=l):h&&(d.support.deleteExpando?delete b[d.expando]:b.removeAttribute?b.removeAttribute(d.expando):b[d.expando]=null)}},_data:function(a,b,c){return d.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=d.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),d.fn.extend({data:function(a,c){var e=null;if(typeof a==="undefined"){if(this.length){e=d.data(this[0]);if(this[0].nodeType===1){var g=this[0].attributes,h;for(var i=0,j=g.length;i<j;i++)h=g[i].name,h.indexOf("data-")===0&&(h=h.substr(5),f(this[0],h,e[h]))}}return e}if(typeof a==="object")return this.each(function(){d.data(this,a)});var k=a.split(".");k[1]=k[1]?"."+k[1]:"";if(c===b){e=this.triggerHandler("getData"+k[1]+"!",[k[0]]),e===b&&this.length&&(e=d.data(this[0],a),e=f(this[0],a,e));return e===b&&k[1]?this.data(k[0]):e}return this.each(function(){var b=d(this),e=[k[0],c];b.triggerHandler("setData"+k[1]+"!",e),d.data(this,a,c),b.triggerHandler("changeData"+k[1]+"!",e)})},removeData:function(a){return this.each(function(){d.removeData(this,a)})}}),d.extend({queue:function(a,b,c){if(a){b=(b||"fx")+"queue";var e=d._data(a,b);if(!c)return e||[];!e||d.isArray(c)?e=d._data(a,b,d.makeArray(c)):e.push(c);return e}},dequeue:function(a,b){b=b||"fx";var c=d.queue(a,b),e=c.shift();e==="inprogress"&&(e=c.shift()),e&&(b==="fx"&&c.unshift("inprogress"),e.call(a,function(){d.dequeue(a,b)})),c.length||d.removeData(a,b+"queue",!0)}}),d.fn.extend({queue:function(a,c){typeof a!=="string"&&(c=a,a="fx");if(c===b)return d.queue(this[0],a);return this.each(function(b){var e=d.queue(this,a,c);a==="fx"&&e[0]!=="inprogress"&&d.dequeue(this,a)})},dequeue:function(a){return this.each(function(){d.dequeue(this,a)})},delay:function(a,b){a=d.fx?d.fx.speeds[a]||a:a,b=b||"fx";return this.queue(b,function(){var c=this;setTimeout(function(){d.dequeue(c,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var h=/[\n\t\r]/g,i=/\s+/,j=/\r/g,k=/^(?:href|src|style)$/,l=/^(?:button|input)$/i,m=/^(?:button|input|object|select|textarea)$/i,n=/^a(?:rea)?$/i,o=/^(?:radio|checkbox)$/i;d.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"},d.fn.extend({attr:function(a,b){return d.access(this,a,b,!0,d.attr)},removeAttr:function(a,b){return this.each(function(){d.attr(this,a,""),this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(d.isFunction(a))return this.each(function(b){var c=d(this);c.addClass(a.call(this,b,c.attr("class")))});if(a&&typeof a==="string"){var b=(a||"").split(i);for(var c=0,e=this.length;c<e;c++){var f=this[c];if(f.nodeType===1)if(f.className){var g=" "+f.className+" ",h=f.className;for(var j=0,k=b.length;j<k;j++)g.indexOf(" "+b[j]+" ")<0&&(h+=" "+b[j]);f.className=d.trim(h)}else f.className=a}}return this},removeClass:function(a){if(d.isFunction(a))return this.each(function(b){var c=d(this);c.removeClass(a.call(this,b,c.attr("class")))});if(a&&typeof a==="string"||a===b){var c=(a||"").split(i);for(var e=0,f=this.length;e<f;e++){var g=this[e];if(g.nodeType===1&&g.className)if(a){var j=(" "+g.className+" ").replace(h," ");for(var k=0,l=c.length;k<l;k++)j=j.replace(" "+c[k]+" "," ");g.className=d.trim(j)}else g.className=""}}return this},toggleClass:function(a,b){var c=typeof a,e=typeof b==="boolean";if(d.isFunction(a))return this.each(function(c){var e=d(this);e.toggleClass(a.call(this,c,e.attr("class"),b),b)});return this.each(function(){if(c==="string"){var f,g=0,h=d(this),j=b,k=a.split(i);while(f=k[g++])j=e?j:!h.hasClass(f),h[j?"addClass":"removeClass"](f)}else if(c==="undefined"||c==="boolean")this.className&&d._data(this,"__className__",this.className),this.className=this.className||a===!1?"":d._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ";for(var c=0,d=this.length;c<d;c++)if((" "+this[c].className+" ").replace(h," ").indexOf(b)>-1)return!0;return!1},val:function(a){if(!arguments.length){var c=this[0];if(c){if(d.nodeName(c,"option")){var e=c.attributes.value;return!e||e.specified?c.value:c.text}if(d.nodeName(c,"select")){var f=c.selectedIndex,g=[],h=c.options,i=c.type==="select-one";if(f<0)return null;for(var k=i?f:0,l=i?f+1:h.length;k<l;k++){var m=h[k];if(m.selected&&(d.support.optDisabled?!m.disabled:m.getAttribute("disabled")===null)&&(!m.parentNode.disabled||!d.nodeName(m.parentNode,"optgroup"))){a=d(m).val();if(i)return a;g.push(a)}}if(i&&!g.length&&h.length)return d(h[f]).val();return g}if(o.test(c.type)&&!d.support.checkOn)return c.getAttribute("value")===null?"on":c.value;return(c.value||"").replace(j,"")}return b}var n=d.isFunction(a);return this.each(function(b){var c=d(this),e=a;if(this.nodeType===1){n&&(e=a.call(this,b,c.val())),e==null?e="":typeof e==="number"?e+="":d.isArray(e)&&(e=d.map(e,function(a){return a==null?"":a+""}));if(d.isArray(e)&&o.test(this.type))this.checked=d.inArray(c.val(),e)>=0;else if(d.nodeName(this,"select")){var f=d.makeArray(e);d("option",this).each(function(){this.selected=d.inArray(d(this).val(),f)>=0}),f.length||(this.selectedIndex=-1)}else this.value=e}})}}),d.extend({attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,e,f){if(!a||a.nodeType===3||a.nodeType===8||a.nodeType===2)return b;if(f&&c in d.attrFn)return d(a)[c](e);var g=a.nodeType!==1||!d.isXMLDoc(a),h=e!==b;c=g&&d.props[c]||c;if(a.nodeType===1){var i=k.test(c);if(c==="selected"&&!d.support.optSelected){var j=a.parentNode;j&&(j.selectedIndex,j.parentNode&&j.parentNode.selectedIndex)}if((c in a||a[c]!==b)&&g&&!i){h&&(c==="type"&&l.test(a.nodeName)&&a.parentNode&&d.error("type property can't be changed"),e===null?a.nodeType===1&&a.removeAttribute(c):a[c]=e);if(d.nodeName(a,"form")&&a.getAttributeNode(c))return a.getAttributeNode(c).nodeValue;if(c==="tabIndex"){var o=a.getAttributeNode("tabIndex");return o&&o.specified?o.value:m.test(a.nodeName)||n.test(a.nodeName)&&a.href?0:b}return a[c]}if(!d.support.style&&g&&c==="style"){h&&(a.style.cssText=""+e);return a.style.cssText}h&&a.setAttribute(c,""+e);if(!a.attributes[c]&&(a.hasAttribute&&!a.hasAttribute(c)))return b;var p=!d.support.hrefNormalized&&g&&i?a.getAttribute(c,2):a.getAttribute(c);return p===null?b:p}h&&(a[c]=e);return a[c]}});var p=/\.(.*)$/,q=/^(?:textarea|input|select)$/i,r=/\./g,s=/ /g,t=/[^\w\s.|`]/g,u=function(a){return a.replace(t,"\\$&")};d.event={add:function(c,e,f,g){if(c.nodeType!==3&&c.nodeType!==8){try{d.isWindow(c)&&(c!==a&&!c.frameElement)&&(c=a)}catch(h){}if(f===!1)f=v;else if(!f)return;var i,j;f.handler&&(i=f,f=i.handler),f.guid||(f.guid=d.guid++);var k=d._data(c);if(!k)return;var l=k.events,m=k.handle;l||(k.events=l={}),m||(k.handle=m=function(){return typeof d!=="undefined"&&!d.event.triggered?d.event.handle.apply(m.elem,arguments):b}),m.elem=c,e=e.split(" ");var n,o=0,p;while(n=e[o++]){j=i?d.extend({},i):{handler:f,data:g},n.indexOf(".")>-1?(p=n.split("."),n=p.shift(),j.namespace=p.slice(0).sort().join(".")):(p=[],j.namespace=""),j.type=n,j.guid||(j.guid=f.guid);var q=l[n],r=d.event.special[n]||{};if(!q){q=l[n]=[];if(!r.setup||r.setup.call(c,g,p,m)===!1)c.addEventListener?c.addEventListener(n,m,!1):c.attachEvent&&c.attachEvent("on"+n,m)}r.add&&(r.add.call(c,j),j.handler.guid||(j.handler.guid=f.guid)),q.push(j),d.event.global[n]=!0}c=null}},global:{},remove:function(a,c,e,f){if(a.nodeType!==3&&a.nodeType!==8){e===!1&&(e=v);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=d.hasData(a)&&d._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(e=c.handler,c=c.type);if(!c||typeof c==="string"&&c.charAt(0)==="."){c=c||"";for(h in t)d.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+d.map(m.slice(0).sort(),u).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=t[h];if(!p)continue;if(!e){for(j=0;j<p.length;j++){q=p[j];if(l||n.test(q.namespace))d.event.remove(a,r,q.handler,j),p.splice(j--,1)}continue}o=d.event.special[h]||{};for(j=f||0;j<p.length;j++){q=p[j];if(e.guid===q.guid){if(l||n.test(q.namespace))f==null&&p.splice(j--,1),o.remove&&o.remove.call(a,q);if(f!=null)break}}if(p.length===0||f!=null&&p.length===1)(!o.teardown||o.teardown.call(a,m)===!1)&&d.removeEvent(a,h,s.handle),g=null,delete t[h]}if(d.isEmptyObject(t)){var w=s.handle;w&&(w.elem=null),delete s.events,delete s.handle,d.isEmptyObject(s)&&d.removeData(a,b,!0)}}},trigger:function(a,c,e){var f=a.type||a,g=arguments[3];if(!g){a=typeof a==="object"?a[d.expando]?a:d.extend(d.Event(f),a):d.Event(f),f.indexOf("!")>=0&&(a.type=f=f.slice(0,-1),a.exclusive=!0),e||(a.stopPropagation(),d.event.global[f]&&d.each(d.cache,function(){var b=d.expando,e=this[b];e&&e.events&&e.events[f]&&d.event.trigger(a,c,e.handle.elem)}));if(!e||e.nodeType===3||e.nodeType===8)return b;a.result=b,a.target=e,c=d.makeArray(c),c.unshift(a)}a.currentTarget=e;var h=d._data(e,"handle");h&&h.apply(e,c);var i=e.parentNode||e.ownerDocument;try{e&&e.nodeName&&d.noData[e.nodeName.toLowerCase()]||e["on"+f]&&e["on"+f].apply(e,c)===!1&&(a.result=!1,a.preventDefault())}catch(j){}if(!a.isPropagationStopped()&&i)d.event.trigger(a,c,i,!0);else if(!a.isDefaultPrevented()){var k,l=a.target,m=f.replace(p,""),n=d.nodeName(l,"a")&&m==="click",o=d.event.special[m]||{};if((!o._default||o._default.call(e,a)===!1)&&!n&&!(l&&l.nodeName&&d.noData[l.nodeName.toLowerCase()])){try{l[m]&&(k=l["on"+m],k&&(l["on"+m]=null),d.event.triggered=!0,l[m]())}catch(q){}k&&(l["on"+m]=k),d.event.triggered=!1}}},handle:function(c){var e,f,g,h,i,j=[],k=d.makeArray(arguments);c=k[0]=d.event.fix(c||a.event),c.currentTarget=this,e=c.type.indexOf(".")<0&&!c.exclusive,e||(g=c.type.split("."),c.type=g.shift(),j=g.slice(0).sort(),h=new RegExp("(^|\\.)"+j.join("\\.(?:.*\\.)?")+"(\\.|$)")),c.namespace=c.namespace||j.join("."),i=d._data(this,"events"),f=(i||{})[c.type];if(i&&f){f=f.slice(0);for(var l=0,m=f.length;l<m;l++){var n=f[l];if(e||h.test(n.namespace)){c.handler=n.handler,c.data=n.data,c.handleObj=n;var o=n.handler.apply(this,k);o!==b&&(c.result=o,o===!1&&(c.preventDefault(),c.stopPropagation()));if(c.isImmediatePropagationStopped())break}}}return c.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(a){if(a[d.expando])return a;var e=a;a=d.Event(e);for(var f=this.props.length,g;f;)g=this.props[--f],a[g]=e[g];a.target||(a.target=a.srcElement||c),a.target.nodeType===3&&(a.target=a.target.parentNode),!a.relatedTarget&&a.fromElement&&(a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement);if(a.pageX==null&&a.clientX!=null){var h=c.documentElement,i=c.body;a.pageX=a.clientX+(h&&h.scrollLeft||i&&i.scrollLeft||0)-(h&&h.clientLeft||i&&i.clientLeft||0),a.pageY=a.clientY+(h&&h.scrollTop||i&&i.scrollTop||0)-(h&&h.clientTop||i&&i.clientTop||0)}a.which==null&&(a.charCode!=null||a.keyCode!=null)&&(a.which=a.charCode!=null?a.charCode:a.keyCode),!a.metaKey&&a.ctrlKey&&(a.metaKey=a.ctrlKey),!a.which&&a.button!==b&&(a.which=a.button&1?1:a.button&2?3:a.button&4?2:0);return a},guid:1e8,proxy:d.proxy,special:{ready:{setup:d.bindReady,teardown:d.noop},live:{add:function(a){d.event.add(this,F(a.origType,a.selector),d.extend({},a,{handler:E,guid:a.handler.guid}))},remove:function(a){d.event.remove(this,F(a.origType,a.selector),a)}},beforeunload:{setup:function(a,b,c){d.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}}},d.removeEvent=c.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){a.detachEvent&&a.detachEvent("on"+b,c)},d.Event=function(a){if(!this.preventDefault)return new d.Event(a);a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?w:v):this.type=a,this.timeStamp=d.now(),this[d.expando]=!0},d.Event.prototype={preventDefault:function(){this.isDefaultPrevented=w;var a=this.originalEvent;a&&(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){this.isPropagationStopped=w;var a=this.originalEvent;a&&(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=w,this.stopPropagation()},isDefaultPrevented:v,isPropagationStopped:v,isImmediatePropagationStopped:v};var x=function(a){var b=a.relatedTarget;try{if(b!==c&&!b.parentNode)return;while(b&&b!==this)b=b.parentNode;b!==this&&(a.type=a.data,d.event.handle.apply(this,arguments))}catch(e){}},y=function(a){a.type=a.data,d.event.handle.apply(this,arguments)};d.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){d.event.special[a]={setup:function(c){d.event.add(this,b,c&&c.selector?y:x,a)},teardown:function(a){d.event.remove(this,b,a&&a.selector?y:x)}}}),d.support.submitBubbles||(d.event.special.submit={setup:function(a,b){if(this.nodeName&&this.nodeName.toLowerCase()!=="form")d.event.add(this,"click.specialSubmit",function(a){var b=a.target,c=b.type;(c==="submit"||c==="image")&&d(b).closest("form").length&&C("submit",this,arguments)}),d.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,c=b.type;(c==="text"||c==="password")&&d(b).closest("form").length&&a.keyCode===13&&C("submit",this,arguments)});else return!1},teardown:function(a){d.event.remove(this,".specialSubmit")}});if(!d.support.changeBubbles){var z,A=function(a){var b=a.type,c=a.value;b==="radio"||b==="checkbox"?c=a.checked:b==="select-multiple"?c=a.selectedIndex>-1?d.map(a.options,function(a){return a.selected}).join("-"):"":a.nodeName.toLowerCase()==="select"&&(c=a.selectedIndex);return c},B=function B(a){var c=a.target,e,f;if(q.test(c.nodeName)&&!c.readOnly){e=d._data(c,"_change_data"),f=A(c),(a.type!=="focusout"||c.type!=="radio")&&d._data(c,"_change_data",f);if(e===b||f===e)return;if(e!=null||f)a.type="change",a.liveFired=b,d.event.trigger(a,arguments[1],c)}};d.event.special.change={filters:{focusout:B,beforedeactivate:B,click:function(a){var b=a.target,c=b.type;(c==="radio"||c==="checkbox"||b.nodeName.toLowerCase()==="select")&&B.call(this,a)},keydown:function(a){var b=a.target,c=b.type;(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&B.call(this,a)},beforeactivate:function(a){var b=a.target;d._data(b,"_change_data",A(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in z)d.event.add(this,c+".specialChange",z[c]);return q.test(this.nodeName)},teardown:function(a){d.event.remove(this,".specialChange");return q.test(this.nodeName)}},z=d.event.special.change.filters,z.focus=z.beforeactivate}c.addEventListener&&d.each({focus:"focusin",blur:"focusout"},function(a,b){function c(a){a=d.event.fix(a),a.type=b;return d.event.handle.call(this,a)}d.event.special[b]={setup:function(){this.addEventListener(a,c,!0)},teardown:function(){this.removeEventListener(a,c,!0)}}}),d.each(["bind","one"],function(a,c){d.fn[c]=function(a,e,f){if(typeof a==="object"){for(var g in a)this[c](g,e,a[g],f);return this}if(d.isFunction(e)||e===!1)f=e,e=b;var h=c==="one"?d.proxy(f,function(a){d(this).unbind(a,h);return f.apply(this,arguments)}):f;if(a==="unload"&&c!=="one")this.one(a,e,f);else for(var i=0,j=this.length;i<j;i++)d.event.add(this[i],a,h,e);return this}}),d.fn.extend({unbind:function(a,b){if(typeof a!=="object"||a.preventDefault)for(var e=0,f=this.length;e<f;e++)d.event.remove(this[e],a,b);else for(var c in a)this.unbind(c,a[c]);return this},delegate:function(a,b,c,d){return this.live(b,c,d,a)},undelegate:function(a,b,c){return arguments.length===0?this.unbind("live"):this.die(b,null,c,a)},trigger:function(a,b){return this.each(function(){d.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){var c=d.Event(a);c.preventDefault(),c.stopPropagation(),d.event.trigger(c,b,this[0]);return c.result}},toggle:function(a){var b=arguments,c=1;while(c<b.length)d.proxy(a,b[c++]);return this.click(d.proxy(a,function(e){var f=(d._data(this,"lastToggle"+a.guid)||0)%c;d._data(this,"lastToggle"+a.guid,f+1),e.preventDefault();return b[f].apply(this,arguments)||!1}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var D={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};d.each(["live","die"],function(a,c){d.fn[c]=function(a,e,f,g){var h,i=0,j,k,l,m=g||this.selector,n=g?this:d(this.context);if(typeof a==="object"&&!a.preventDefault){for(var o in a)n[c](o,e,a[o],m);return this}d.isFunction(e)&&(f=e,e=b),a=(a||"").split(" ");while((h=a[i++])!=null){j=p.exec(h),k="",j&&(k=j[0],h=h.replace(p,""));if(h==="hover"){a.push("mouseenter"+k,"mouseleave"+k);continue}l=h,h==="focus"||h==="blur"?(a.push(D[h]+k),h=h+k):h=(D[h]||h)+k;if(c==="live")for(var q=0,r=n.length;q<r;q++)d.event.add(n[q],"live."+F(h,m),{data:e,selector:m,handler:f,origType:h,origHandler:f,preType:l});else n.unbind("live."+F(h,m),f)}return this}}),d.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),function(a,b){d.fn[b]=function(a,c){c==null&&(c=a,a=null);return arguments.length>0?this.bind(b,a,c):this.trigger(b)},d.attrFn&&(d.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g<h;g++){var i=d[g];if(i){var j=!1;i=i[a];while(i){if(i.sizcache===c){j=d[i.sizset];break}if(i.nodeType===1){f||(i.sizcache=c,i.sizset=g);if(typeof b!=="string"){if(i===b){j=!0;break}}else if(k.filter(b,[i]).length>0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g<h;g++){var i=d[g];if(i){var j=!1;i=i[a];while(i){if(i.sizcache===c){j=d[i.sizset];break}i.nodeType===1&&!f&&(i.sizcache=c,i.sizset=g);if(i.nodeName.toLowerCase()===b){j=i;break}i=i[a]}d[g]=j}}}var a=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,e=0,f=Object.prototype.toString,g=!1,h=!0,i=/\\/g,j=/\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,e,g){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!=="string")return e;var i,j,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(""),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r="",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(f.call(n)==="[object Array]")if(u)if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&e.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&e.push(j[t]);else e.push.apply(e,n);else p(n,e);o&&(k(o,h,e,g),k.uniqueSort(e));return e};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b<a.length;b++)a[b]===a[b-1]&&a.splice(b--,1)}return a},k.matches=function(a,b){return k(a,null,null,b)},k.matchesSelector=function(a,b){return k(b,null,null,[a]).length>0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e<f;e++){var g,h=l.order[e];if(g=l.leftMatch[h].exec(a)){var j=g[1];g.splice(1,1);if(j.substr(j.length-1)!=="\\"){g[1]=(g[1]||"").replace(i,""),d=l.find[h](g,b,c);if(d!=null){a=a.replace(l.match[h],"");break}}}}d||(d=typeof b.getElementsByTagName!=="undefined"?b.getElementsByTagName("*"):[]);return{set:d,expr:a}},k.filter=function(a,c,d,e){var f,g,h=a,i=[],j=c,m=c&&c[0]&&k.isXML(c[0]);while(a&&c.length){for(var n in l.filter)if((f=l.leftMatch[n].exec(a))!=null&&f[2]){var o,p,q=l.filter[n],r=f[1];g=!1,f.splice(1,1);if(r.substr(r.length-1)==="\\")continue;j===i&&(i=[]);if(l.preFilter[n]){f=l.preFilter[n](f,j,d,i,e,m);if(f){if(f===!0)continue}else g=o=!0}if(f)for(var s=0;(p=j[s])!=null;s++)if(p){o=q(p,f,s,j);var t=e^!!o;d&&o!=null?t?g=!0:j[s]=!1:t&&(i.push(p),g=!0)}if(o!==b){d||(j=i),a=a.replace(l.match[n],"");if(!g)return[];break}}if(a===h)if(g==null)k.error(a);else break;h=a}return j},k.error=function(a){throw"Syntax error, unrecognized expression: "+a};var l=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(a){return a.getAttribute("href")},type:function(a){return a.getAttribute("type")}},relative:{"+":function(a,b){var c=typeof b==="string",d=c&&!j.test(b),e=c&&!d;d&&(b=b.toLowerCase());for(var f=0,g=a.length,h;f<g;f++)if(h=a[f]){while((h=h.previousSibling)&&h.nodeType!==1){}a[f]=e||h&&h.nodeName.toLowerCase()===b?h||!1:h===b}e&&k.filter(b,a,!0)},">":function(a,b){var c,d=typeof b==="string",e=0,f=a.length;if(d&&!j.test(b)){b=b.toLowerCase();for(;e<f;e++){c=a[e];if(c){var g=c.parentNode;a[e]=g.nodeName.toLowerCase()===b?g:!1}}}else{for(;e<f;e++)c=a[e],c&&(a[e]=d?c.parentNode:c.parentNode===b);d&&k.filter(b,a,!0)}},"":function(a,b,c){var d,f=e++,g=u;typeof b==="string"&&!j.test(b)&&(b=b.toLowerCase(),d=b,g=t),g("parentNode",b,f,a,d,c)},"~":function(a,b,c){var d,f=e++,g=u;typeof b==="string"&&!j.test(b)&&(b=b.toLowerCase(),d=b,g=t),g("previousSibling",b,f,a,d,c)}},find:{ID:function(a,b,c){if(typeof b.getElementById!=="undefined"&&!c){var d=b.getElementById(a[1]);return d&&d.parentNode?[d]:[]}},NAME:function(a,b){if(typeof b.getElementsByName!=="undefined"){var c=[],d=b.getElementsByName(a[1]);for(var e=0,f=d.length;e<f;e++)d[e].getAttribute("name")===a[1]&&c.push(d[e]);return c.length===0?null:c}},TAG:function(a,b){if(typeof b.getElementsByTagName!=="undefined")return b.getElementsByTagName(a[1])}},preFilter:{CLASS:function(a,b,c,d,e,f){a=" "+a[1].replace(i,"")+" ";if(f)return a;for(var g=0,h;(h=b[g])!=null;g++)h&&(e^(h.className&&(" "+h.className+" ").replace(/[\t\n\r]/g," ").indexOf(a)>=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(i,"")},TAG:function(a,b){return a[1].replace(i,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||k.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&k.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,"");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(i,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!k(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){return"text"===a.getAttribute("type")},radio:function(a){return"radio"===a.type},checkbox:function(a){return"checkbox"===a.type},file:function(a){return"file"===a.type},password:function(a){return"password"===a.type},submit:function(a){return"submit"===a.type},image:function(a){return"image"===a.type},reset:function(a){return"reset"===a.type},button:function(a){return"button"===a.type||a.nodeName.toLowerCase()==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return b<c[3]-0},gt:function(a,b,c){return b>c[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=l.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||k.getText([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h<i;h++)if(g[h]===a)return!1;return!0}k.error(e)},CHILD:function(a,b){var c=b[1],d=a;switch(c){case"only":case"first":while(d=d.previousSibling)if(d.nodeType===1)return!1;if(c==="first")return!0;d=a;case"last":while(d=d.nextSibling)if(d.nodeType===1)return!1;return!0;case"nth":var e=b[2],f=b[3];if(e===1&&f===0)return!0;var g=b[0],h=a.parentNode;if(h&&(h.sizcache!==g||!a.nodeIndex)){var i=0;for(d=h.firstChild;d;d=d.nextSibling)d.nodeType===1&&(d.nodeIndex=++i);h.sizcache=g}var j=a.nodeIndex-f;return e===0?j===0:j%e===0&&j/e>=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return"\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\[]*\])(?![^\(]*\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\r|\n)*?)/.source+l.match[o].source.replace(/\\(\d+)/g,n));var p=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(q){p=function(a,b){var c=0,d=b||[];if(f.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length==="number")for(var e=a.length;c<e;c++)d.push(a[c]);else for(;a[c];c++)d.push(a[c]);return d}}var r,s;c.documentElement.compareDocumentPosition?r=function(a,b){if(a===b){g=!0;return 0}if(!a.compareDocumentPosition||!b.compareDocumentPosition)return a.compareDocumentPosition?-1:1;return a.compareDocumentPosition(b)&4?-1:1}:(r=function(a,b){var c,d,e=[],f=[],h=a.parentNode,i=b.parentNode,j=h;if(a===b){g=!0;return 0}if(h===i)return s(a,b);if(!h)return-1;if(!i)return 1;while(j)e.unshift(j),j=j.parentNode;j=i;while(j)f.unshift(j),j=j.parentNode;c=e.length,d=f.length;for(var k=0;k<c&&k<d;k++)if(e[k]!==f[k])return s(e[k],f[k]);return k===c?s(a,f[k],-1):s(e[k],b,1)},s=function(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}),k.getText=function(a){var b="",c;for(var d=0;a[d];d++)c=a[d],c.nodeType===3||c.nodeType===4?b+=c.nodeValue:c.nodeType!==8&&(b+=k.getText(c.childNodes));return b},function(){var a=c.createElement("div"),d="script"+(new Date).getTime(),e=c.documentElement;a.innerHTML="<a name='"+d+"'/>",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(l.find.ID=function(a,c,d){if(typeof c.getElementById!=="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!=="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},l.filter.ID=function(a,b){var c=typeof a.getAttributeNode!=="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(l.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="<a href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!=="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(l.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement("div"),d="__sizzle__";b.innerHTML="<p class='TEST'></p>";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e,n=e.getAttribute("id"),o=n||d,q=e.parentNode,r=/^\s*[+~]/.test(b);n?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(s){}finally{n||m.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)k[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector,d=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(e){d=!0}b&&(k.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(a))try{if(d||!l.match.PSEUDO.test(c)&&!/!=/.test(c))return b.call(a,c)}catch(e){}return k(c,null,null,[a]).length>0})}(),function(){var a=c.createElement("div");a.innerHTML="<div class='test e'></div><div class='test'></div>";if(a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;l.order.splice(1,0,"CLASS"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!=="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var v=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,"");a=l.relative[a]?a+"*":a;for(var g=0,h=f.length;g<h;g++)k(a,f[g],d);return k.filter(e,d)};d.find=k,d.expr=k.selectors,d.expr[":"]=d.expr.filters,d.unique=k.uniqueSort,d.text=k.getText,d.isXMLDoc=k.isXML,d.contains=k.contains}();var G=/Until$/,H=/^(?:parents|prevUntil|prevAll)/,I=/,/,J=/^.[^:#\[\.,]*$/,K=Array.prototype.slice,L=d.expr.match.POS,M={children:!0,contents:!0,next:!0,prev:!0};d.fn.extend({find:function(a){var b=this.pushStack("","find",a),c=0;for(var e=0,f=this.length;e<f;e++){c=b.length,d.find(a,this[e],b);if(e>0)for(var g=c;g<b.length;g++)for(var h=0;h<c;h++)if(b[h]===b[g]){b.splice(g--,1);break}}return b},has:function(a){var b=d(a);return this.filter(function(){for(var a=0,c=b.length;a<c;a++)if(d.contains(this,b[a]))return!0})},not:function(a){return this.pushStack(O(this,a,!1),"not",a)},filter:function(a){return this.pushStack(O(this,a,!0),"filter",a)},is:function(a){return!!a&&d.filter(a,this).length>0},closest:function(a,b){var c=[],e,f,g=this[0];if(d.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(e=0,f=a.length;e<f;e++)i=a[e],j[i]||(j[i]=d.expr.match.POS.test(i)?d(i,b||this.context):i);while(g&&g.ownerDocument&&g!==b){for(i in j)h=j[i],(h.jquery?h.index(g)>-1:d(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=L.test(a)?d(a,b||this.context):null;for(e=0,f=this.length;e<f;e++){g=this[e];while(g){if(l?l.index(g)>-1:d.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b)break}}c=c.length>1?d.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a||typeof a==="string")return d.inArray(this[0],a?d(a):this.parent().children());return d.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a==="string"?d(a,b):d.makeArray(a),e=d.merge(this.get(),c);return this.pushStack(N(c[0])||N(e[0])?e:d.unique(e))},andSelf:function(){return this.add(this.prevObject)}}),d.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return d.dir(a,"parentNode")},parentsUntil:function(a,b,c){return d.dir(a,"parentNode",c)},next:function(a){return d.nth(a,2,"nextSibling")},prev:function(a){return d.nth(a,2,"previousSibling")},nextAll:function(a){return d.dir(a,"nextSibling")},prevAll:function(a){return d.dir(a,"previousSibling")},nextUntil:function(a,b,c){return d.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return d.dir(a,"previousSibling",c)},siblings:function(a){return d.sibling(a.parentNode.firstChild,a)},children:function(a){return d.sibling(a.firstChild)},contents:function(a){return d.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:d.makeArray(a.childNodes)}},function(a,b){d.fn[a]=function(c,e){var f=d.map(this,b,c),g=K.call(arguments);G.test(a)||(e=c),e&&typeof e==="string"&&(f=d.filter(e,f)),f=this.length>1&&!M[a]?d.unique(f):f,(this.length>1||I.test(e))&&H.test(a)&&(f=f.reverse());return this.pushStack(f,a,g.join(","))}}),d.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?d.find.matchesSelector(b[0],a)?[b[0]]:[]:d.find.matches(a,b)},dir:function(a,c,e){var f=[],g=a[c];while(g&&g.nodeType!==9&&(e===b||g.nodeType!==1||!d(g).is(e)))g.nodeType===1&&f.push(g),g=g[c];return f},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var P=/ jQuery\d+="(?:\d+|null)"/g,Q=/^\s+/,R=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,S=/<([\w:]+)/,T=/<tbody/i,U=/<|&#?\w+;/,V=/<(?:script|object|embed|option|style)/i,W=/checked\s*(?:[^=]|=\s*.checked.)/i,X={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};X.optgroup=X.option,X.tbody=X.tfoot=X.colgroup=X.caption=X.thead,X.th=X.td,d.support.htmlSerialize||(X._default=[1,"div<div>","</div>"]),d.fn.extend({text:function(a){if(d.isFunction(a))return this.each(function(b){var c=d(this);c.text(a.call(this,b,c.text()))});if(typeof a!=="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return d.text(this)},wrapAll:function(a){if(d.isFunction(a))return this.each(function(b){d(this).wrapAll(a.call(this,b))});if(this[0]){var b=d(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(d.isFunction(a))return this.each(function(b){d(this).wrapInner(a.call(this,b))});return this.each(function(){var b=d(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){d(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){d.nodeName(this,"body")||d(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=d(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,d(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,e;(e=this[c])!=null;c++)if(!a||d.filter(a,[e]).length)!b&&e.nodeType===1&&(d.cleanData(e.getElementsByTagName("*")),d.cleanData([e])),e.parentNode&&e.parentNode.removeChild(e);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&d.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return d.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(P,""):null;if(typeof a!=="string"||V.test(a)||!d.support.leadingWhitespace&&Q.test(a)||X[(S.exec(a)||["",""])[1].toLowerCase()])d.isFunction(a)?this.each(function(b){var c=d(this);c.html(a.call(this,b,c.html()))}):this.empty().append(a);else{a=a.replace(R,"<$1></$2>");try{for(var c=0,e=this.length;c<e;c++)this[c].nodeType===1&&(d.cleanData(this[c].getElementsByTagName("*")),this[c].innerHTML=a)}catch(f){this.empty().append(a)}}return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(d.isFunction(a))return this.each(function(b){var c=d(this),e=c.html();c.replaceWith(a.call(this,b,e))});typeof a!=="string"&&(a=d(a).detach());return this.each(function(){var b=this.nextSibling,c=this.parentNode;d(this).remove(),b?d(b).before(a):d(c).append(a)})}return this.pushStack(d(d.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,e){var f,g,h,i,j=a[0],k=[];if(!d.support.checkClone&&arguments.length===3&&typeof j==="string"&&W.test(j))return this.each(function(){d(this).domManip(a,c,e,!0)});if(d.isFunction(j))return this.each(function(f){var g=d(this);a[0]=j.call(this,f,c?g.html():b),g.domManip(a,c,e)});if(this[0]){i=j&&j.parentNode,d.support.parentNode&&i&&i.nodeType===11&&i.childNodes.length===this.length?f={fragment:i}:f=d.buildFragment(a,this,k),h=f.fragment,h.childNodes.length===1?g=h=h.firstChild:g=h.firstChild;if(g){c=c&&d.nodeName(g,"tr");for(var l=0,m=this.length,n=m-1;l<m;l++)e.call(c?Y(this[l],g):this[l],f.cacheable||m>1&&l<n?d.clone(h,!0,!0):h)}k.length&&d.each(k,ba)}return this}}),d.buildFragment=function(a,b,e){var f,g,h,i=b&&b[0]?b[0].ownerDocument||b[0]:c;a.length===1&&typeof a[0]==="string"&&a[0].length<512&&i===c&&a[0].charAt(0)==="<"&&!V.test(a[0])&&(d.support.checkClone||!W.test(a[0]))&&(g=!0,h=d.fragments[a[0]],h&&(h!==1&&(f=h))),f||(f=i.createDocumentFragment(),d.clean(a,i,f,e)),g&&(d.fragments[a[0]]=h?f:1);return{fragment:f,cacheable:g}},d.fragments={},d.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){d.fn[a]=function(c){var e=[],f=d(c),g=this.length===1&&this[0].parentNode;if(g&&g.nodeType===11&&g.childNodes.length===1&&f.length===1){f[b](this[0]);return this}for(var h=0,i=f.length;h<i;h++){var j=(h>0?this.clone(!0):this).get();d(f[h])[b](j),e=e.concat(j)}return this.pushStack(e,a,f.selector)}}),d.extend({clone:function(a,b,c){var e=a.cloneNode(!0),f,g,h;if((!d.support.noCloneEvent||!d.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!d.isXMLDoc(a)){$(a,e),f=_(a),g=_(e);for(h=0;f[h];++h)$(f[h],g[h])}if(b){Z(a,e);if(c){f=_(a),g=_(e);for(h=0;f[h];++h)Z(f[h],g[h])}}return e},clean:function(a,b,e,f){b=b||c,typeof b.createElement==="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var g=[];for(var h=0,i;(i=a[h])!=null;h++){typeof i==="number"&&(i+="");if(!i)continue;if(typeof i!=="string"||U.test(i)){if(typeof i==="string"){i=i.replace(R,"<$1></$2>");var j=(S.exec(i)||["",""])[1].toLowerCase(),k=X[j]||X._default,l=k[0],m=b.createElement("div");m.innerHTML=k[1]+i+k[2];while(l--)m=m.lastChild;if(!d.support.tbody){var n=T.test(i),o=j==="table"&&!n?m.firstChild&&m.firstChild.childNodes:k[1]==="<table>"&&!n?m.childNodes:[];for(var p=o.length-1;p>=0;--p)d.nodeName(o[p],"tbody")&&!o[p].childNodes.length&&o[p].parentNode.removeChild(o[p])}!d.support.leadingWhitespace&&Q.test(i)&&m.insertBefore(b.createTextNode(Q.exec(i)[0]),m.firstChild),i=m.childNodes}}else i=b.createTextNode(i);i.nodeType?g.push(i):g=d.merge(g,i)}if(e)for(h=0;g[h];h++)!f||!d.nodeName(g[h],"script")||g[h].type&&g[h].type.toLowerCase()!=="text/javascript"?(g[h].nodeType===1&&g.splice.apply(g,[h+1,0].concat(d.makeArray(g[h].getElementsByTagName("script")))),e.appendChild(g[h])):f.push(g[h].parentNode?g[h].parentNode.removeChild(g[h]):g[h]);return g},cleanData:function(a){var b,c,e=d.cache,f=d.expando,g=d.event.special,h=d.support.deleteExpando;for(var i=0,j;(j=a[i])!=null;i++){if(j.nodeName&&d.noData[j.nodeName.toLowerCase()])continue;c=j[d.expando];if(c){b=e[c]&&e[c][f];if(b&&b.events){for(var k in b.events)g[k]?d.event.remove(j,k):d.removeEvent(j,k,b.handle);b.handle&&(b.handle.elem=null)}h?delete j[d.expando]:j.removeAttribute&&j.removeAttribute(d.expando),delete e[c]}}}});var bb=/alpha\([^)]*\)/i,bc=/opacity=([^)]*)/,bd=/-([a-z])/ig,be=/([A-Z])/g,bf=/^-?\d+(?:px)?$/i,bg=/^-?\d/,bh={position:"absolute",visibility:"hidden",display:"block"},bi=["Left","Right"],bj=["Top","Bottom"],bk,bl,bm,bn=function(a,b){return b.toUpperCase()};d.fn.css=function(a,c){if(arguments.length===2&&c===b)return this;return d.access(this,a,c,!0,function(a,c,e){return e!==b?d.style(a,c,e):d.css(a,c)})},d.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bk(a,"opacity","opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{zIndex:!0,fontWeight:!0,opacity:!0,zoom:!0,lineHeight:!0},cssProps:{"float":d.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,e,f){if(a&&a.nodeType!==3&&a.nodeType!==8&&a.style){var g,h=d.camelCase(c),i=a.style,j=d.cssHooks[h];c=d.cssProps[h]||h;if(e===b){if(j&&"get"in j&&(g=j.get(a,!1,f))!==b)return g;return i[c]}if(typeof e==="number"&&isNaN(e)||e==null)return;typeof e==="number"&&!d.cssNumber[h]&&(e+="px");if(!j||!("set"in j)||(e=j.set(a,e))!==b)try{i[c]=e}catch(k){}}},css:function(a,c,e){var f,g=d.camelCase(c),h=d.cssHooks[g];c=d.cssProps[g]||g;if(h&&"get"in h&&(f=h.get(a,!0,e))!==b)return f;if(bk)return bk(a,c,g)},swap:function(a,b,c){var d={};for(var e in b)d[e]=a.style[e],a.style[e]=b[e];c.call(a);for(e in b)a.style[e]=d[e]},camelCase:function(a){return a.replace(bd,bn)}}),d.curCSS=d.css,d.each(["height","width"],function(a,b){d.cssHooks[b]={get:function(a,c,e){var f;if(c){a.offsetWidth!==0?f=bo(a,b,e):d.swap(a,bh,function(){f=bo(a,b,e)});if(f<=0){f=bk(a,b,b),f==="0px"&&bm&&(f=bm(a,b,b));if(f!=null)return f===""||f==="auto"?"0px":f}if(f<0||f==null){f=a.style[b];return f===""||f==="auto"?"0px":f}return typeof f==="string"?f:f+"px"}},set:function(a,b){if(!bf.test(b))return b;b=parseFloat(b);if(b>=0)return b+"px"}}}),d.support.opacity||(d.cssHooks.opacity={get:function(a,b){return bc.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style;c.zoom=1;var e=d.isNaN(b)?"":"alpha(opacity="+b*100+")",f=c.filter||"";c.filter=bb.test(f)?f.replace(bb,e):c.filter+" "+e}}),c.defaultView&&c.defaultView.getComputedStyle&&(bl=function(a,c,e){var f,g,h;e=e.replace(be,"-$1").toLowerCase();if(!(g=a.ownerDocument.defaultView))return b;if(h=g.getComputedStyle(a,null))f=h.getPropertyValue(e),f===""&&!d.contains(a.ownerDocument.documentElement,a)&&(f=d.style(a,e));return f}),c.documentElement.currentStyle&&(bm=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bf.test(d)&&bg.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bk=bl||bm,d.expr&&d.expr.filters&&(d.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!d.support.reliableHiddenOffsets&&(a.style.display||d.css(a,"display"))==="none"},d.expr.filters.visible=function(a){return!d.expr.filters.hidden(a)});var bp=/%20/g,bq=/\[\]$/,br=/\r?\n/g,bs=/#.*$/,bt=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bu=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bv=/(?:^file|^widget|\-extension):$/,bw=/^(?:GET|HEAD)$/,bx=/^\/\//,by=/\?/,bz=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,bA=/^(?:select|textarea)/i,bB=/\s+/,bC=/([?&])_=[^&]*/,bD=/(^|\-)([a-z])/g,bE=function(a,b,c){return b+c.toUpperCase()},bF=/^([\w\+\.\-]+:)\/\/([^\/?#:]*)(?::(\d+))?/,bG=d.fn.load,bH={},bI={},bJ,bK;try{bJ=c.location.href}catch(bL){bJ=c.createElement("a"),bJ.href="",bJ=bJ.href}bK=bF.exec(bJ.toLowerCase()),d.fn.extend({load:function(a,c,e){if(typeof a!=="string"&&bG)return bG.apply(this,arguments);if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var g=a.slice(f,a.length);a=a.slice(0,f)}var h="GET";c&&(d.isFunction(c)?(e=c,c=b):typeof c==="object"&&(c=d.param(c,d.ajaxSettings.traditional),h="POST"));var i=this;d.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?d("<div>").append(c.replace(bz,"")).find(g):c)),e&&i.each(e,[c,b,a])}});return this},serialize:function(){return d.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?d.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bA.test(this.nodeName)||bu.test(this.type))}).map(function(a,b){var c=d(this).val();return c==null?null:d.isArray(c)?d.map(c,function(a,c){return{name:b.name,value:a.replace(br,"\r\n")}}):{name:b.name,value:c.replace(br,"\r\n")}}).get()}}),d.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){d.fn[b]=function(a){return this.bind(b,a)}}),d.each(["get","post"],function(a,c){d[c]=function(a,e,f,g){d.isFunction(e)&&(g=g||f,f=e,e=b);return d.ajax({type:c,url:a,data:e,success:f,dataType:g})}}),d.extend({getScript:function(a,c){return d.get(a,b,c,"script")},getJSON:function(a,b,c){return d.get(a,b,c,"json")},ajaxSetup:function(a,b){b?d.extend(!0,a,d.ajaxSettings,b):(b=a,a=d.extend(!0,d.ajaxSettings,b));for(var c in {context:1,url:1})c in b?a[c]=b[c]:c in d.ajaxSettings&&(a[c]=d.ajaxSettings[c]);return a},ajaxSettings:{url:bJ,isLocal:bv.test(bK[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":"*/*"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":d.parseJSON,"text xml":d.parseXML}},ajaxPrefilter:bM(bH),ajaxTransport:bM(bI),ajax:function(a,c){function v(a,c,l,n){if(r!==2){r=2,p&&clearTimeout(p),o=b,m=n||"",u.readyState=a?4:0;var q,t,v,w=l?bP(e,u,l):b,x,y;if(a>=200&&a<300||a===304){if(e.ifModified){if(x=u.getResponseHeader("Last-Modified"))d.lastModified[k]=x;if(y=u.getResponseHeader("Etag"))d.etag[k]=y}if(a===304)c="notmodified",q=!0;else try{t=bQ(e,w),c="success",q=!0}catch(z){c="parsererror",v=z}}else{v=c;if(!c||a)c="error",a<0&&(a=0)}u.status=a,u.statusText=c,q?h.resolveWith(f,[t,c,u]):h.rejectWith(f,[u,c,v]),u.statusCode(j),j=b,s&&g.trigger("ajax"+(q?"Success":"Error"),[u,e,q?t:v]),i.resolveWith(f,[u,c]),s&&(g.trigger("ajaxComplete",[u,e]),--d.active||d.event.trigger("ajaxStop"))}}typeof a==="object"&&(c=a,a=b),c=c||{};var e=d.ajaxSetup({},c),f=e.context||e,g=f!==e&&(f.nodeType||f instanceof d)?d(f):d.event,h=d.Deferred(),i=d._Deferred(),j=e.statusCode||{},k,l={},m,n,o,p,q,r=0,s,t,u={readyState:0,setRequestHeader:function(a,b){r||(l[a.toLowerCase().replace(bD,bE)]=b);return this},getAllResponseHeaders:function(){return r===2?m:null},getResponseHeader:function(a){var c;if(r===2){if(!n){n={};while(c=bt.exec(m))n[c[1].toLowerCase()]=c[2]}c=n[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){r||(e.mimeType=a);return this},abort:function(a){a=a||"abort",o&&o.abort(a),v(0,a);return this}};h.promise(u),u.success=u.done,u.error=u.fail,u.complete=i.done,u.statusCode=function(a){if(a){var b;if(r<2)for(b in a)j[b]=[j[b],a[b]];else b=a[u.status],u.then(b,b)}return this},e.url=((a||e.url)+"").replace(bs,"").replace(bx,bK[1]+"//"),e.dataTypes=d.trim(e.dataType||"*").toLowerCase().split(bB),e.crossDomain||(q=bF.exec(e.url.toLowerCase()),e.crossDomain=q&&(q[1]!=bK[1]||q[2]!=bK[2]||(q[3]||(q[1]==="http:"?80:443))!=(bK[3]||(bK[1]==="http:"?80:443)))),e.data&&e.processData&&typeof e.data!=="string"&&(e.data=d.param(e.data,e.traditional)),bN(bH,e,c,u);if(r===2)return!1;s=e.global,e.type=e.type.toUpperCase(),e.hasContent=!bw.test(e.type),s&&d.active++===0&&d.event.trigger("ajaxStart");if(!e.hasContent){e.data&&(e.url+=(by.test(e.url)?"&":"?")+e.data),k=e.url;if(e.cache===!1){var w=d.now(),x=e.url.replace(bC,"$1_="+w);e.url=x+(x===e.url?(by.test(e.url)?"&":"?")+"_="+w:"")}}if(e.data&&e.hasContent&&e.contentType!==!1||c.contentType)l["Content-Type"]=e.contentType;e.ifModified&&(k=k||e.url,d.lastModified[k]&&(l["If-Modified-Since"]=d.lastModified[k]),d.etag[k]&&(l["If-None-Match"]=d.etag[k])),l.Accept=e.dataTypes[0]&&e.accepts[e.dataTypes[0]]?e.accepts[e.dataTypes[0]]+(e.dataTypes[0]!=="*"?", */*; q=0.01":""):e.accepts["*"];for(t in e.headers)u.setRequestHeader(t,e.headers[t]);if(e.beforeSend&&(e.beforeSend.call(f,u,e)===!1||r===2)){u.abort();return!1}for(t in {success:1,error:1,complete:1})u[t](e[t]);o=bN(bI,e,c,u);if(o){u.readyState=1,s&&g.trigger("ajaxSend",[u,e]),e.async&&e.timeout>0&&(p=setTimeout(function(){u.abort("timeout")},e.timeout));try{r=1,o.send(l,v)}catch(y){status<2?v(-1,y):d.error(y)}}else v(-1,"No Transport");return u},param:function(a,c){var e=[],f=function(a,b){b=d.isFunction(b)?b():b,e[e.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=d.ajaxSettings.traditional);if(d.isArray(a)||a.jquery&&!d.isPlainObject(a))d.each(a,function(){f(this.name,this.value)});else for(var g in a)bO(g,a[g],c,f);return e.join("&").replace(bp,"+")}}),d.extend({active:0,lastModified:{},etag:{}});var bR=d.now(),bS=/(\=)\?(&|$)|()\?\?()/i;d.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return d.expando+"_"+bR++}}),d.ajaxPrefilter("json jsonp",function(b,c,e){var f=typeof b.data==="string";if(b.dataTypes[0]==="jsonp"||c.jsonpCallback||c.jsonp!=null||b.jsonp!==!1&&(bS.test(b.url)||f&&bS.test(b.data))){var g,h=b.jsonpCallback=d.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2",m=function(){a[h]=i,g&&d.isFunction(i)&&a[h](g[0])};b.jsonp!==!1&&(j=j.replace(bS,l),b.url===j&&(f&&(k=k.replace(bS,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},e.then(m,m),b.converters["script json"]=function(){g||d.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),d.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){d.globalEval(a);return a}}}),d.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),d.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var bT=d.now(),bU,bV;d.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&bX()||bY()}:bX,bV=d.ajaxSettings.xhr(),d.support.ajax=!!bV,d.support.cors=bV&&"withCredentials"in bV,bV=b,d.support.ajax&&d.ajaxTransport(function(a){if(!a.crossDomain||d.support.cors){var c;return{send:function(e,f){var g=a.xhr(),h,i;a.username?g.open(a.type,a.url,a.async,a.username,a.password):g.open(a.type,a.url,a.async);if(a.xhrFields)for(i in a.xhrFields)g[i]=a.xhrFields[i];a.mimeType&&g.overrideMimeType&&g.overrideMimeType(a.mimeType),(!a.crossDomain||a.hasContent)&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(i in e)g.setRequestHeader(i,e[i])}catch(j){}g.send(a.hasContent&&a.data||null),c=function(e,i){var j,k,l,m,n;try{if(c&&(i||g.readyState===4)){c=b,h&&(g.onreadystatechange=d.noop,delete bU[h]);if(i)g.readyState!==4&&g.abort();else{j=g.status,l=g.getAllResponseHeaders(),m={},n=g.responseXML,n&&n.documentElement&&(m.xml=n),m.text=g.responseText;try{k=g.statusText}catch(o){k=""}j||!a.isLocal||a.crossDomain?j===1223&&(j=204):j=m.text?200:404}}}catch(p){i||f(-1,p)}m&&f(j,k,m,l)},a.async&&g.readyState!==4?(bU||(bU={},bW()),h=bT++,g.onreadystatechange=bU[h]=c):c()},abort:function(){c&&c(0,1)}}}});var bZ={},b$=/^(?:toggle|show|hide)$/,b_=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,ca,cb=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];d.fn.extend({show:function(a,b,c){var e,f;if(a||a===0)return this.animate(cc("show",3),a,b,c);for(var g=0,h=this.length;g<h;g++)e=this[g],f=e.style.display,!d._data(e,"olddisplay")&&f==="none"&&(f=e.style.display=""),f===""&&d.css(e,"display")==="none"&&d._data(e,"olddisplay",cd(e.nodeName));for(g=0;g<h;g++){e=this[g],f=e.style.display;if(f===""||f==="none")e.style.display=d._data(e,"olddisplay")||""}return this},hide:function(a,b,c){if(a||a===0)return this.animate(cc("hide",3),a,b,c);for(var e=0,f=this.length;e<f;e++){var g=d.css(this[e],"display");g!=="none"&&!d._data(this[e],"olddisplay")&&d._data(this[e],"olddisplay",g)}for(e=0;e<f;e++)this[e].style.display="none";return this},_toggle:d.fn.toggle,toggle:function(a,b,c){var e=typeof a==="boolean";d.isFunction(a)&&d.isFunction(b)?this._toggle.apply(this,arguments):a==null||e?this.each(function(){var b=e?a:d(this).is(":hidden");d(this)[b?"show":"hide"]()}):this.animate(cc("toggle",3),a,b,c);return this},fadeTo:function(a,b,c,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,e){var f=d.speed(b,c,e);if(d.isEmptyObject(a))return this.each(f.complete);return this[f.queue===!1?"each":"queue"](function(){var b=d.extend({},f),c,e=this.nodeType===1,g=e&&d(this).is(":hidden"),h=this;for(c in a){var i=d.camelCase(c);c!==i&&(a[i]=a[c],delete a[c],c=i);if(a[c]==="hide"&&g||a[c]==="show"&&!g)return b.complete.call(this);if(e&&(c==="height"||c==="width")){b.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY];if(d.css(this,"display")==="inline"&&d.css(this,"float")==="none")if(d.support.inlineBlockNeedsLayout){var j=cd(this.nodeName);j==="inline"?this.style.display="inline-block":(this.style.display="inline",this.style.zoom=1)}else this.style.display="inline-block"}d.isArray(a[c])&&((b.specialEasing=b.specialEasing||{})[c]=a[c][1],a[c]=a[c][0])}b.overflow!=null&&(this.style.overflow="hidden"),b.curAnim=d.extend({},a),d.each(a,function(c,e){var f=new d.fx(h,b,c);if(b$.test(e))f[e==="toggle"?g?"show":"hide":e](a);else{var i=b_.exec(e),j=f.cur();if(i){var k=parseFloat(i[2]),l=i[3]||(d.cssNumber[c]?"":"px");l!=="px"&&(d.style(h,c,(k||1)+l),j=(k||1)/f.cur()*j,d.style(h,c,j+l)),i[1]&&(k=(i[1]==="-="?-1:1)*k+j),f.custom(j,k,l)}else f.custom(j,e,"")}});return!0})},stop:function(a,b){var c=d.timers;a&&this.queue([]),this.each(function(){for(var a=c.length-1;a>=0;a--)c[a].elem===this&&(b&&c[a](!0),c.splice(a,1))}),b||this.dequeue();return this}}),d.each({slideDown:cc("show",1),slideUp:cc("hide",1),slideToggle:cc("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){d.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),d.extend({speed:function(a,b,c){var e=a&&typeof a==="object"?d.extend({},a):{complete:c||!c&&b||d.isFunction(a)&&a,duration:a,easing:c&&b||b&&!d.isFunction(b)&&b};e.duration=d.fx.off?0:typeof e.duration==="number"?e.duration:e.duration in d.fx.speeds?d.fx.speeds[e.duration]:d.fx.speeds._default,e.old=e.complete,e.complete=function(){e.queue!==!1&&d(this).dequeue(),d.isFunction(e.old)&&e.old.call(this)};return e},easing:{linear:function(a,b,c,d){return c+d*a},swing:function(a,b,c,d){return(-Math.cos(a*Math.PI)/2+.5)*d+c}},timers:[],fx:function(a,b,c){this.options=b,this.elem=a,this.prop=c,b.orig||(b.orig={})}}),d.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this),(d.fx.step[this.prop]||d.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a,b=d.css(this.elem,this.prop);return isNaN(a=parseFloat(b))?!b||b==="auto"?0:b:a},custom:function(a,b,c){function g(a){return e.step(a)}var e=this,f=d.fx;this.startTime=d.now(),this.start=a,this.end=b,this.unit=c||this.unit||(d.cssNumber[this.prop]?"":"px"),this.now=this.start,this.pos=this.state=0,g.elem=this.elem,g()&&d.timers.push(g)&&!ca&&(ca=setInterval(f.tick,f.interval))},show:function(){this.options.orig[this.prop]=d.style(this.elem,this.prop),this.options.show=!0,this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur()),d(this.elem).show()},hide:function(){this.options.orig[this.prop]=d.style(this.elem,this.prop),this.options.hide=!0,this.custom(this.cur(),0)},step:function(a){var b=d.now(),c=!0;if(a||b>=this.options.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),this.options.curAnim[this.prop]=!0;for(var e in this.options.curAnim)this.options.curAnim[e]!==!0&&(c=!1);if(c){if(this.options.overflow!=null&&!d.support.shrinkWrapBlocks){var f=this.elem,g=this.options;d.each(["","X","Y"],function(a,b){f.style["overflow"+b]=g.overflow[a]})}this.options.hide&&d(this.elem).hide();if(this.options.hide||this.options.show)for(var h in this.options.curAnim)d.style(this.elem,h,this.options.orig[h]);this.options.complete.call(this.elem)}return!1}var i=b-this.startTime;this.state=i/this.options.duration;var j=this.options.specialEasing&&this.options.specialEasing[this.prop],k=this.options.easing||(d.easing.swing?"swing":"linear");this.pos=d.easing[j||k](this.state,i,0,1,this.options.duration),this.now=this.start+(this.end-this.start)*this.pos,this.update();return!0}},d.extend(d.fx,{tick:function(){var a=d.timers;for(var b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||d.fx.stop()},interval:13,stop:function(){clearInterval(ca),ca=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){d.style(a.elem,"opacity",a.now)},_default:function(a){a.elem.style&&a.elem.style[a.prop]!=null?a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit:a.elem[a.prop]=a.now}}}),d.expr&&d.expr.filters&&(d.expr.filters.animated=function(a){return d.grep(d.timers,function(b){return a===b.elem}).length});var ce=/^t(?:able|d|h)$/i,cf=/^(?:body|html)$/i;"getBoundingClientRect"in c.documentElement?d.fn.offset=function(a){var b=this[0],c;if(a)return this.each(function(b){d.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return d.offset.bodyOffset(b);try{c=b.getBoundingClientRect()}catch(e){}var f=b.ownerDocument,g=f.documentElement;if(!c||!d.contains(g,b))return c?{top:c.top,left:c.left}:{top:0,left:0};var h=f.body,i=cg(f),j=g.clientTop||h.clientTop||0,k=g.clientLeft||h.clientLeft||0,l=i.pageYOffset||d.support.boxModel&&g.scrollTop||h.scrollTop,m=i.pageXOffset||d.support.boxModel&&g.scrollLeft||h.scrollLeft,n=c.top+l-j,o=c.left+m-k;return{top:n,left:o}}:d.fn.offset=function(a){var b=this[0];if(a)return this.each(function(b){d.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return d.offset.bodyOffset(b);d.offset.initialize();var c,e=b.offsetParent,f=b,g=b.ownerDocument,h=g.documentElement,i=g.body,j=g.defaultView,k=j?j.getComputedStyle(b,null):b.currentStyle,l=b.offsetTop,m=b.offsetLeft;while((b=b.parentNode)&&b!==i&&b!==h){if(d.offset.supportsFixedPosition&&k.position==="fixed")break;c=j?j.getComputedStyle(b,null):b.currentStyle,l-=b.scrollTop,m-=b.scrollLeft,b===e&&(l+=b.offsetTop,m+=b.offsetLeft,d.offset.doesNotAddBorder&&(!d.offset.doesAddBorderForTableAndCells||!ce.test(b.nodeName))&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),f=e,e=b.offsetParent),d.offset.subtractsBorderForOverflowNotVisible&&c.overflow!=="visible"&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),k=c}if(k.position==="relative"||k.position==="static")l+=i.offsetTop,m+=i.offsetLeft;d.offset.supportsFixedPosition&&k.position==="fixed"&&(l+=Math.max(h.scrollTop,i.scrollTop),m+=Math.max(h.scrollLeft,i.scrollLeft));return{top:l,left:m}},d.offset={initialize:function(){var a=c.body,b=c.createElement("div"),e,f,g,h,i=parseFloat(d.css(a,"marginTop"))||0,j="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";d.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"}),b.innerHTML=j,a.insertBefore(b,a.firstChild),e=b.firstChild,f=e.firstChild,h=e.nextSibling.firstChild.firstChild,this.doesNotAddBorder=f.offsetTop!==5,this.doesAddBorderForTableAndCells=h.offsetTop===5,f.style.position="fixed",f.style.top="20px",this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15,f.style.position=f.style.top="",e.style.overflow="hidden",e.style.position="relative",this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5,this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i,a.removeChild(b),a=b=e=f=g=h=null,d.offset.initialize=d.noop},bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;d.offset.initialize(),d.offset.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(d.css(a,"marginTop"))||0,c+=parseFloat(d.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var e=d.css(a,"position");e==="static"&&(a.style.position="relative");var f=d(a),g=f.offset(),h=d.css(a,"top"),i=d.css(a,"left"),j=e==="absolute"&&d.inArray("auto",[h,i])>-1,k={},l={},m,n;j&&(l=f.position()),m=j?l.top:parseInt(h,10)||0,n=j?l.left:parseInt(i,10)||0,d.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):f.css(k)}},d.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),e=cf.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(d.css(a,"marginTop"))||0,c.left-=parseFloat(d.css(a,"marginLeft"))||0,e.top+=parseFloat(d.css(b[0],"borderTopWidth"))||0,e.left+=parseFloat(d.css(b[0],"borderLeftWidth"))||0;return{top:c.top-e.top,left:c.left-e.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&(!cf.test(a.nodeName)&&d.css(a,"position")==="static"))a=a.offsetParent;return a})}}),d.each(["Left","Top"],function(a,c){var e="scroll"+c;d.fn[e]=function(c){var f=this[0],g;if(!f)return null;if(c!==b)return this.each(function(){g=cg(this),g?g.scrollTo(a?d(g).scrollLeft():c,a?c:d(g).scrollTop()):this[e]=c});g=cg(f);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:d.support.boxModel&&g.document.documentElement[e]||g.document.body[e]:f[e]}}),d.each(["Height","Width"],function(a,c){var e=c.toLowerCase();d.fn["inner"+c]=function(){return this[0]?parseFloat(d.css(this[0],e,"padding")):null},d.fn["outer"+c]=function(a){return this[0]?parseFloat(d.css(this[0],e,a?"margin":"border")):null},d.fn[e]=function(a){var f=this[0];if(!f)return a==null?null:this;if(d.isFunction(a))return this.each(function(b){var c=d(this);c[e](a.call(this,b,c[e]()))});if(d.isWindow(f)){var g=f.document.documentElement["client"+c];return f.document.compatMode==="CSS1Compat"&&g||f.document.body["client"+c]||g}if(f.nodeType===9)return Math.max(f.documentElement["client"+c],f.body["scroll"+c],f.documentElement["scroll"+c],f.body["offset"+c],f.documentElement["offset"+c]);if(a===b){var h=d.css(f,e),i=parseFloat(h);return d.isNaN(i)?h:i}return this.css(e,typeof a==="string"?a:a+"px")}}),a.jQuery=a.$=d})(window);
@@ -0,0 +1,747 @@+/**+ * Dh-proto-proof ui controller+ * @author Cedric Staub+ */++/*-----------------------------------------------------------*+ * Theory state *+ *-----------------------------------------------------------*/++var theory = {+ /**+ * Convert a relative path into an absolute one.+ * @param section Section/display, for example main or debug.+ * @param path The relative path.+ * @return The absolute path.+ */+ absolutePath: function(section, path) {+ return "/thy/" + this.idx + "/" + section + "/" + path;+ }+}++/*-----------------------------------------------------------*+ * Backend/server communication *+ *-----------------------------------------------------------*/++var server = {+ /**+ * Perform an ASR (asynchronous request) to the server.+ * @param path The path to request (absolute!).+ * @param dataType The data to request (xml, html, json).+ * @param cache Should we cache? True/false.+ * @param success The callback function on success.+ * @param error The callback function on error.+ */+ performASR: function(path, dataType, cache, success, error) {+ loadingScreen.show(path);++ $.ajax({+ url: path,+ dataType: dataType,+ cache: cache,+ success: function(data, textStatus) {+ loadingScreen.reset();+ success(data, textStatus);+ },+ error: function(data, textStatus, err) {+ loadingScreen.reset();+ error(data, textStatus, err);+ }+ });+ },++ /**+ * Process JSON response from server.+ * @param path The path that was loaded.+ * @param data The data that was received.+ * @param html Callback for html data.+ */+ handleJson: function(data, html) {+ // Parse resulting json+ if(data.redirect) {+ // Server wants redirect+ loadingScreen.show(data.redirect);+ window.location.href = data.redirect;+ } else if(data.alert) {+ // Server requested alert box+ ui.showDialog(data.alert);+ } else {+ // It must be a html response.+ html(data.title, data.html);+ }+ },+}++/*-----------------------------------------------------------*+ * Loading screen *+ *-----------------------------------------------------------*/++var loadingScreen = {+ /**+ * Cancel a request by sending a kill request to the server.+ * @param path The original request path.+ */+ cancel: function(path) {+ server.performASR(+ "/kill?path=" + encodeURIComponent(path),+ "text",+ false,+ // Success callback+ function(data, textStatus) {+ ui.showDialog(data);+ },+ // Error callback+ function(data, textStatus, err) {+ ui.showDisplay("Unable to cancel request! Is server down?");+ });+ },++ /**+ * Show the loading notification in the main view.+ * @param path The target of the link which is loading.+ */+ show: function(path) {+ // Display loading screen+ var display = $("p.loading");+ display.hide().fadeIn(1000);+ + // Install cancel click handler+ display.children("a#cancel").unbind('click').click(function() {+ loadingScreen.cancel(path);+ });+ },++ /**+ * Reset the loading display.+ */+ reset: function() {+ var display = $("p.loading");+ display.stop(true, true);+ display.hide();+ }+}++/*-----------------------------------------------------------*+ * User interface *+ *-----------------------------------------------------------*/++var ui = {+ /**+ * Initialize various aspects of the user interface.+ */+ init: function() {+ // Load display settings+ this.loadSettings();++ // Navigation drop-down menus+ $("ul#navigation").superfish();++ // Add keyboard shortcuts+ var shortcuts = {+ 74 : function() { proofScript.jump('next/smart', null); },+ 75 : function() { proofScript.jump('prev/smart', null); },+ 106 : function() { proofScript.jump('next/normal', null); },+ 107 : function() { proofScript.jump('prev/normal', null); }+ }++ for(i = 1; i < 10; i++) {+ shortcuts[i + 48] = function(key) {+ mainDisplay.applyProofMethod(key - 48);+ };+ }++ this.add_shortcuts(shortcuts);++ // Initialize dialog box+ $("div#dialog").dialog({+ autoOpen: false,+ title: 'Message',+ width: '30em',+ buttons: {+ "Ok": function() {+ $(this).dialog("close");+ }+ }+ });++ // Enable context menu+ $("#proof a.proof-step").contextMenu(+ { menu: "contextMenu" },+ function(action, el, pos) {+ mainDisplay.loadTarget(+ action,+ $(el).attr("href"),+ function() {+ var path = $(el).attr("href");+ $.cookie("last-target", path, { path: "/" });+ $.cookie("jump-to-target", true, { path: "/" });+ });+ });++ // Click handler for save link+ events.installAbsoluteClickHandler("a.save-link", server.handleJson);++ // Click handler for edit link(s)+ events.installAbsoluteClickHandler(+ "a.edit-link",+ function(data, textStatus) {+ server.handleJson(data, mainDisplay.setContent);+ events.installFormHandler();+ });++ // Click handler for debug pane toggle+ var debug_toggle = $("a#debug-toggle");+ debug_toggle.click(function(ev) {+ ev.preventDefault();+ layout.toggle("east");+ mainDisplay.toggleOption(debug_toggle);+ });+ + // Click handler for graph toggle+ var graph_toggle = $('a#graph-toggle');+ graph_toggle.click(function(ev) {+ ev.preventDefault();+ if($.cookie("uncompact-graphs")) {+ $.cookie("uncompact-graphs", null, { path: '/' });+ } else {+ $.cookie("uncompact-graphs", true, { path: '/' });+ }+ $("a.active-link").click();+ mainDisplay.toggleOption(graph_toggle);+ });+ + // Click handler for sequent compression toggle+ var sequent_toggle = $('a#seqnt-toggle');+ sequent_toggle.click(function(ev) {+ ev.preventDefault();+ if($.cookie("uncompress-sequents")) {+ $.cookie("uncompress-sequents", null, { path: '/' });+ } else {+ $.cookie("uncompress-sequents", true, { path: '/' });+ }+ $("a.active-link").click();+ mainDisplay.toggleOption(sequent_toggle);+ });++ // Install event handlers+ events.installScrollHandler(+ "west",+ "div.ui-layout-west div.scroll-wrapper");+ + // Install handlers on plain internal links+ events.installRelativeClickHandler(+ "div#proof a.internal-link",+ "main",+ null);+ + // Install handlers on edit links (lemma)+ events.installRelativeClickHandler(+ "div#proof a.internal-link.edit-link",+ "edit/path",+ function(el) {+ events.installFormHandler();+ });+ + // Install handlers on delete links+ events.installRelativeClickHandler(+ "div#proof a.internal-link.delete-link",+ "del/path",+ null);+ + // Install handlers on proof-step links+ events.installRelativeClickHandler(+ "div#proof a.internal-link.proof-step",+ "main",+ function(el) {+ var path = $(el).attr("href");+ $.cookie("last-target", path, { path: "/" });+ $.cookie("jump-next-open-goal", true, { path: "/" });+ });+ + // Install handlers on removal links+ events.installRelativeClickHandler(+ "div#proof a.internal-link.remove-step",+ "del/path",+ function(el) {+ var path = $(el).attr("href");+ $.cookie("last-target", path, { path: "/" });+ $.cookie("jump-to-target", true, { path: "/" });+ });+ },++ /**+ * Load viewing settings from cookie.+ */+ loadSettings: function() {+ if($.cookie("east-size")) {+ layout.sizePane("east", $.cookie("east-size"));+ }+ + if($.cookie("east-open")) {+ layout.open("east");+ $("a#debug-toggle").addClass("active-option");+ } else {+ layout.close("east");+ $("a#debug-toggle").addClass("inactive-option");+ }+ + if($.cookie("west-size")) {+ layout.sizePane("west", $.cookie("west-size"));+ } else {+ layout.sizePane("west", 475);+ }+ + if($.cookie("west-position")) {+ var pos = $.cookie("west-position");+ $("div.ui-layout-west div.scroll-wrapper").scrollTop(pos);+ }+ + if($.cookie("uncompress-sequents")) {+ $("a#seqnt-toggle").addClass("inactive-option");+ } else {+ $("a#seqnt-toggle").addClass("active-option");+ }+ + if($.cookie("uncompact-graphs")) {+ $("a#graph-toggle").addClass("inactive-option");+ } else {+ $("a#graph-toggle").addClass("active-option");+ }+ },++ /**+ * Add keyboard shortcut(s) from map.+ * @param map Map of { key : callback } pairs.+ */+ add_shortcuts: function(map) {+ $("html").keypress(function(ev) {+ var key = ev.which;+ var tag = ev.target.tagName.toLowerCase();++ // Don't trigger on input/textarea+ if(tag == 'input' || tag == 'textarea') return;++ // If key is in map, call the given+ // callback function and pass keycode+ if(map[key]) {+ // Hide context menu+ $("ul#contextMenu").hide();+ // Call callback+ var callback = map[key];+ callback(key);+ }+ });+ },++ /**+ * Show dialog+ * @param msg The message.+ */+ showDialog: function(msg) {+ var dialog = $("div#dialog");+ dialog.html(msg.replace("\n","<br>"));+ dialog.dialog('open');+ }+}+++/*-----------------------------------------------------------*+ * Event handlers and callback functions *+ *-----------------------------------------------------------*/++var events = {+ /**+ * Install handler for scroll event for storing state.+ * @param name Name to store setting in cookie as.+ * @param selector The CSS selector for the container.+ */+ installScrollHandler: function(name, selector) {+ $(selector).scroll(function(ev) {+ // Hide context menu+ $("ul#contextMenu").hide();+ // Record position in cookie+ var pos = $(this).scrollTop();+ $.cookie(name + "-position", pos, { path: "/" });+ });+ },++ /**+ * Install click handler for absolute link.+ * @param selector The css selector.+ * @param callback The callback function.+ */+ installAbsoluteClickHandler: function(selector, callback) {+ $(selector).click(function(ev) {+ ev.preventDefault();++ var link = $(this);+ var path = link.attr("href");++ server.performASR(+ path,+ "json",+ false,+ callback,+ function(data, textStatus, err) {+ ui.showDialog("Unable to load view! Is server down?");+ });+ });+ },++ /**+ * Install click handler for relative links.+ * @param selector The CSS selector to use.+ */+ installRelativeClickHandler: function(selector, section, callback) {+ // Remove (possible) old click handler(s)+ $(selector).unbind('click');+ // Add new click handler+ $(selector).click(function(ev) { + ev.preventDefault();+ var element = $(this);+ mainDisplay.loadTarget(+ section,+ element.attr("href"),+ function() {+ if(callback) callback(element);+ });+ });+ },++ /**+ * Install form handler.+ */+ installFormHandler: function() {+ var form = $("#ui-main-display form");+ var path = form.attr("action");+ var submit = form.find("input[type='submit']");+ var cancel = form.find("input[id='cancel-form']");++ cancel.click(function(ev) {+ ev.preventDefault();+ if($.cookie("last-target")) {+ mainDisplay.loadTarget("main", $.cookie("last-target"));+ } else {+ mainDisplay.loadTarget("main", "rules");+ }+ });++ submit.click(function(ev) {+ ev.preventDefault();+ loadingScreen.show(path);+ $.ajax({+ type: "POST",+ url: path,+ data: form.serialize(),+ dataType: "json",+ success: function(data, textStatus) {+ loadingScreen.reset();+ server.handleJson(data, mainDisplay.setContent);+ }+ });+ });+ },++}++/*-----------------------------------------------------------*+ * Proof script display *+ *-----------------------------------------------------------*/++var proofScript = {+ /**+ * Focus the active link by scrolling to it.+ */+ focusActive: function() {+ var element = $("#proof");+ var wrapper = $("#proof-wrapper");+ var selector = "a.active-link";+ var link = element.find(selector).first();++ if(link.length > 0) {+ // Calculate new position+ var pos = wrapper.scrollTop();+ var contOffset = wrapper.offset().top;+ var linkOffset = link.offset().top;+ var height = wrapper.height();+ var newPos = pos + linkOffset - (height/2) - (contOffset/2);+ + // Now scroll there+ wrapper.stop(true, true);+ wrapper.animate(+ { scrollTop: newPos },+ { duration: 'fast', easing: 'swing' }+ );+ }+ },++ /**+ * Jump to new target. Server decides where depending on arguments.+ * @param mode For example 'next/normal' or 'prev/smart'.+ * @param err_callback Callback on error.+ */+ jump: function(mode, err_callback) {+ var element = $("#proof");+ var active = element.find("a.active-link").first();+ + if(active.length > 0) {+ var current = active.attr("href"); + + server.performASR(+ theory.absolutePath(mode, current),+ "text",+ false,+ // Success callback+ function(data, textStatus) {+ var selector = "a.internal-link[href='" + data + "']";+ var link = element.find(selector);++ if(link.length > 0) {+ mainDisplay.loadTarget(+ "main",+ link.attr("href"),+ function() {+ proofScript.focusActive();+ }+ );+ } else if(err_callback != null) {+ err_callback();+ }+ },+ // Error callback+ function(data, textStatus, error) {+ if(err_callback != null) err_callback();+ });+ } else {+ $("div#proof a.internal-link").first().click();+ }+ },++ /**+ * Just jump to next open goal or case if no open goal.+ * @param target Jump relative to this target.+ */+ jumpNextOpenGoal: function(target) {+ this.focusTarget(target);+ // Perform smart jump+ proofScript.jump('next/smart', function() {+ // If smart jump failed (e.g. there are+ // no more open goals), perform normal jump+ proofScript.jump('next/normal', function() {+ // If both failed, just jump to target+ proofScript.jumpToTarget(target);+ });+ });+ },++ /**+ * Jump to a given target.+ * @param target The target.+ */+ jumpToTarget: function(target) {+ this.focusTarget(target).click();+ },++ /**+ * Focus a given target.+ * @param target The target.+ */+ focusTarget: function(target) {+ var element = $("#proof");+ var selector = "a.proof-step.[href='" + target + "']";+ var link = element.find(selector)+ link.addClass("active-link");+ return link;+ }+}++/*-----------------------------------------------------------*+ * Main display *+ *-----------------------------------------------------------*/++var mainDisplay = {+ /**+ * Apply a proof method.+ * @param num Number of proof method to apply (1-9).+ */+ applyProofMethod: function(num) {+ var path = $("a.active-link").attr("href");+ $.cookie("last-target", path, { path: "/" });+ $.cookie("jump-next-open-goal", true, { path: "/" });++ var element = $("#ui-main-display");+ var methods = element.find("div.methods a.internal-link");++ if(methods.length >= num) {+ $(methods.get([ num - 1 ])).click();+ }+ },++ /**+ * Update main view with new HTML data.+ * @param html_data The html data.+ */+ setContent: function(title, html_data) {+ if(title) $("#main-title").html(title);++ var element = $("#ui-main-display");+ var wrapper = $("#main-wrapper");++ // Received html, display it+ element.html(html_data);+ + // Get image settings from cookie+ var params = []+ if($.cookie("uncompact-graphs")) {+ params = params.concat(+ { name: "uncompact", value: "" }+ );+ }+ if($.cookie("uncompress-sequents")) {+ params = params.concat(+ { name: "uncompress", value: "" }+ );+ }+ + // Rewrite image paths (if necessary)+ if(params.length > 0) {+ var query_string = $.param(params);+ element.find("img").each(function(idx, elem) {+ var img = $(elem);+ var path = img.attr("src") + "?" + query_string;+ img.attr("src", path);+ });+ }+ + // Focus main view (so PgUp/PgDown works)+ wrapper.focus();+ + // Re-install click handlers on main+ events.installRelativeClickHandler(+ "div#ui-main-display a.internal-link",+ "main",+ null);+ },++ /**+ * Load a given target.+ * @param target The target to load.+ * @param callback Optional callback to call after successful load.+ */+ loadTarget: function(section, target, callback) {+ // Load main view+ server.performASR(+ theory.absolutePath(section, target),+ "json",+ false,+ // Success callback+ function(data, textStatus) {+ // Handle JSON reponse+ server.handleJson(data, function(title, html_data) {+ mainDisplay.setContent(title, html_data);+ + // Set active-link class for target+ var selector = "a.internal-link[href='" + target + "']";+ $("a.active-link").removeClass("active-link");+ $(selector).first().addClass("active-link");+ + /*+ // Load debug view+ server.performASR(+ theory.absolutePath('debug', target),+ "html",+ false,+ // Success callback+ function(data, textStatus) {+ $("#ui-debug-display").html(data);+ }+ );+ */+ });+ + // Call optional callback+ if(callback) callback();+ },+ // Error callback+ function(data, textStatus, error) {+ ui.showDialog("Unable to load view! Is server down?");+ }+ );+ },++ /**+ * Toggle active/inactive option classes+ * @param obj Jquery-wrapped object to operate on.+ */+ toggleOption: function(obj) {+ if(obj.hasClass('active-option')) {+ obj.removeClass('active-option');+ obj.addClass('inactive-option');+ } else {+ obj.removeClass('inactive-option');+ obj.addClass('active-option');+ }+ }+}++/*-----------------------------------------------------------*+ * Main initialization function. *+ *-----------------------------------------------------------*/++/**+ * Initialize when document is ready.+ */+$(document).ready(function() {+ // Automatically submit upload form on root+ $("input[type=file]").change(function() {+ var obj = $(this);+ if(obj.val()) {+ obj.parents("form").submit(); + }+ });++ // Only run rest of script if the main display is available+ var main_display = $("#ui-main-display");+ if(main_display.length != 1) return;++ // Get theory index+ theory.idx = location.pathname.split('/')[2];++ // Set up the layout+ layout = $('body').layout({+ // Options+ north__spacing_open: 0,+ east__spacing_closed: 0,+ east__spacing_open: 4,+ west__spacing_open: 4,+ east__initClosed: true,++ // Callbacks (store state in cookie)+ onopen: function(name, elem, state, opts, layout) {+ $.cookie(name + "-open", true, { path: '/' });+ },+ onclose: function(name, elem, state, opts, layout) {+ $.cookie(name + "-open", null, { path: '/' });+ },+ onresize: function(name, elem, state, opts, layout) {+ $.cookie(name + "-size", elem.width(), { path: '/' });+ },+ });+ + // Initialize user interface+ ui.init();++ // Process jump instructions+ if($.cookie("jump-to-target")) {+ if($.cookie("last-target")) {+ proofScript.jumpToTarget($.cookie("last-target"));+ }+ $.cookie("jump-to-target", null, { path: "/" });+ } else if($.cookie("jump-next-open-goal")) {+ if($.cookie("last-target")) {+ proofScript.jumpNextOpenGoal($.cookie("last-target"));+ }+ $.cookie("jump-next-open-goal", null, { path: "/" });+ }++});
@@ -0,0 +1,418 @@+{+{-# OPTIONS_GHC -fno-warn-name-shadowing -fno-warn-unused-matches -fno-warn-unused-binds -fno-warn-missing-signatures -fno-warn-lazy-unlifted-bindings #-}+module Theory.Lexer where++-- This file works only with Alex < 3.0. In the long-term, we plan to switch+-- to a lexer-less approach, i.e., relying completely on parsec.+}+++$digit = [0-9]+$letter = [a-zA-Z]+$others = [\192-\214\216-\246\248-\255]++@integer = $digit++@identifierFirst = ($letter | $digit | $others)+@identifierAfter = ($letter | $digit | "_" | $others)+@identifier = @identifierFirst @identifierAfter*+@comment = $printable | $white+@text = $printable | $white+@lineComment = "//".*++tokens :-+ <0> $white+ ;++ <0> @lineComment ;+ <0> "(*" { beginComment "(*" comment }+ <comment> "(*" { beginComment "(*" comment }+ <text> "(*" { beginComment "(*" comment }+ <comment> "*)" { endComment "(*" } + <0> "/*" { beginComment "/*" comment }+ <comment> "/*" { beginComment "/*" comment }+ <text> "/*" { beginComment "/*" comment }+ <comment> "*/" { endComment "/*" } + <comment> @comment { skip }++ <0> "text{*" { beginText "text" text }+ <0> "section{*" { beginText "section" text }+ <0> "subsection{*" { beginText "subsection" text }+ <text> "*}" { endText 0} + <text> @text { scanString (TEXT . TextContent) }+++ <0> "∀" { keyword FORALL }+ <0> "∃" { keyword EXISTS }+ <0> "∧" { keyword LAND }+ <0> "∨" { keyword LOR }+ <0> "¬" { keyword LNOT }+ <0> "≈" { keyword APPROX }++ <0> "," { keyword COMMA }+ <0> "(" { keyword LPAREN }+ <0> ")" { keyword RPAREN }+ <0> "[" { keyword LBRACKET }+ <0> "]" { keyword RBRACKET }+ <0> "{" { keyword LBRACE }+ <0> "}" { keyword RBRACE }+ <0> "/" { keyword SLASH }+ <0> "\\" { keyword BACKSLASH }+ <0> "'" { keyword SQUOTE }+ <0> \" { keyword DQUOTE }+ <0> "~" { keyword TILDE }+ <0> "^" { keyword HAT }+ <0> "=" { keyword EQUAL }+ <0> ":" { keyword COLON }+ <0> "$" { keyword DOLLAR }+ <0> "@" { keyword AT }+ <0> "#" { keyword SHARP }+ <0> "%" { keyword PERCENT }+ <0> "*" { keyword STAR }+ <0> "<" { keyword LESS } + <0> ">" { keyword GREATER } + <0> "?" { keyword QUESTIONMARK } + <0> "!" { keyword BANG } + <0> "&" { keyword AND } + <0> "|" { keyword MID } + <0> "." { keyword DOT } + <0> "_" { keyword UNDERSCORE } + <0> "-" { keyword MINUS } + <0> "+" { keyword PLUS } + <0> "->" { keyword RIGHTARROW } + <0> "<-" { keyword LEFTARROW } + <0> "-->" { keyword LONGRIGHTARROW } + <0> "<--" { keyword LONGLEFTARROW } + <0> @identifier { scanString IDENT}+++{++-- | Lex a keyword+keyword :: Keyword -> AlexAction Keyword+keyword kw input len = return kw++-- | Wrap a string into a keyword+scanString :: (String -> Keyword) -> AlexAction Keyword+scanString kw (_,_,input) len = return $ kw (take len input)++{-+-- | Scan a string until EOF is encountered.+alexScanTokens :: String -> Either String [Keyword]+alexScanTokens inp = runAlex inp gather+ where+ gather = do+ t <- alexMonadScan+ case trace (show t) t of+ EOF -> return [EOF]+ _ -> (t:) `liftM` gather++-- | Scan a file.+scanFile f = do+ inp <- readFile f+ return $ alexScanTokens inp+-}++-- | Formal text types.+data TextType = + TextBegin String + | TextContent String + | TextEnd+ deriving( Eq, Ord, Show )++-- | Lexable Keywords+data Keyword =+ IDENT String+ | TEXT TextType + | SQUOTE+ | DQUOTE+ | RIGHTARROW+ | LEFTARROW+ | LONGRIGHTARROW+ | LONGLEFTARROW+ | COMMA+ | DOT+ | COLON+ | QUESTIONMARK+ | BANG+ | AND+ | MID+ | DOLLAR+ | AT+ | SHARP+ | PERCENT+ | LPAREN+ | RPAREN+ | LBRACKET+ | RBRACKET+ | LBRACE + | RBRACE+ | SLASH+ | BACKSLASH+ | TILDE+ | HAT+ | STAR+ | UNDERSCORE+ | MINUS+ | PLUS+ | EQUAL+ | LESS+ | GREATER+ | EOF+ | FORALL+ | EXISTS+ | LAND+ | LOR+ | LNOT+ | APPROX+ -- dummy keyword to get rid of overlapping pattern matches+ | DUMMY_KEYWORD+ deriving( Eq )++instance Show Keyword where+ show kw = case kw of + IDENT i -> identifier i+ TEXT t -> txt t+ SQUOTE -> symbol "'"+ DQUOTE -> symbol "\""+ RIGHTARROW -> symbol "->"+ LEFTARROW -> symbol "<-"+ LONGRIGHTARROW -> symbol "-->"+ LONGLEFTARROW -> symbol "<--"+ COMMA -> symbol ","+ DOT -> symbol "."+ COLON -> symbol ":"+ QUESTIONMARK -> symbol "?"+ BANG -> symbol "!"+ AND -> symbol "&"+ MID -> symbol "|"+ DOLLAR -> symbol "$"+ AT -> symbol "@"+ SHARP -> symbol "#"+ PERCENT -> symbol "%"+ LPAREN -> symbol "("+ RPAREN -> symbol ")"+ LBRACKET -> symbol "["+ RBRACKET -> symbol "]"+ LBRACE -> symbol "{"+ RBRACE -> symbol "}"+ SLASH -> symbol "/"+ BACKSLASH -> symbol "\\"+ TILDE -> symbol "~"+ HAT -> symbol "^"+ STAR -> symbol "*"+ UNDERSCORE -> symbol "_"+ MINUS -> symbol "-"+ PLUS -> symbol "+"+ EQUAL -> symbol "="+ LESS -> symbol "<"+ GREATER -> symbol ">"+ EOF -> "end of file"+ FORALL -> symbol "∀" + EXISTS -> symbol "∃" + LAND -> symbol "∧" + LOR -> symbol "∨" + LNOT -> symbol "¬" + APPROX -> symbol "≈" + DUMMY_KEYWORD -> "DUMMY_KEYWORD (this should not occur!)"+ where+ identifier i = "identifier `" ++ i ++ "'"+ txt (TextBegin t) = "start of `" ++ t ++ "'"+ txt (TextContent t) = "text `" ++ t ++ "'"+ txt (TextEnd) = "start of text"+ symbol s = "symbol `" ++ s ++ "'"+ keyword s = "keyword `" ++ s ++ "'"++-- -----------------------------------------------------------------------------+-- Alex wrapper code.+--+-- This code is in the PUBLIC DOMAIN; you may copy it freely and use+-- it for any purpose whatsoever.++-- -----------------------------------------------------------------------------+-- The input type+++type AlexInput = (AlexPosn, -- current position,+ Char, -- previous char+ String) -- current input string++alexInputPrevChar :: AlexInput -> Char+alexInputPrevChar (p,c,s) = c++alexGetChar :: AlexInput -> Maybe (Char,AlexInput)+alexGetChar (p,c,[]) = Nothing+alexGetChar (p,_,(c:s)) = let p' = alexMove p c in p' `seq`+ Just (c, (p', c, s))+++-- -----------------------------------------------------------------------------+-- Token positions++-- `Posn' records the location of a token in the input text. It has three+-- fields: the address (number of chacaters preceding the token), line number+-- and column of a token within the file. `start_pos' gives the position of the+-- start of the file and `eof_pos' a standard encoding for the end of file.+-- `move_pos' calculates the new position after traversing a given character,+-- assuming the usual eight character tab stops.++data AlexPosn = AlexPn !Int !Int !Int+ deriving (Eq)++instance Show AlexPosn where+ show (AlexPn _ l c) = "line "++show l++" column "++show c++alexStartPos :: AlexPosn+alexStartPos = AlexPn 0 1 1++alexMove :: AlexPosn -> Char -> AlexPosn+alexMove (AlexPn a l c) '\t' = AlexPn (a+1) l (((c+7) `div` 8)*8+1)+alexMove (AlexPn a l c) '\n' = AlexPn (a+1) (l+1) 1+alexMove (AlexPn a l c) _ = AlexPn (a+1) l (c+1)+++-- -----------------------------------------------------------------------------+-- Default monad+++data AlexState = AlexState {+ alex_pos :: !AlexPosn, -- position at current input location+ alex_inp :: String, -- the current input+ alex_chr :: !Char, -- the character before the input+ alex_scd :: !Int, -- the current startcode+ alex_ocd :: !Int, -- the old startcode before the comment started+ alex_cmt :: [String] -- stack of begin comment identifiers+ }++-- Compile with -funbox-strict-fields for best results!++runAlex :: String -> Alex a -> Either String a+runAlex input (Alex f) + = case f (AlexState {alex_pos = alexStartPos,+ alex_inp = input, + alex_chr = '\n',+ alex_scd = 0,+ alex_ocd = 0,+ alex_cmt = []+ }) of + Left msg -> Left msg+ Right ( _, a ) -> Right a++newtype Alex a = Alex { unAlex :: AlexState -> Either String (AlexState, a) }++instance Monad Alex where+ m >>= k = Alex $ \s -> case unAlex m s of + Left msg -> Left msg+ Right (s',a) -> unAlex (k a) s'+ return a = Alex $ \s -> Right (s,a)++alexGetPos :: Alex AlexPosn+alexGetPos = Alex $ \s@AlexState{alex_pos=pos} -> Right (s, pos)++alexGetInput :: Alex AlexInput+alexGetInput+ = Alex $ \s@AlexState{alex_pos=pos,alex_chr=c,alex_inp=inp} -> + Right (s, (pos,c,inp))++alexSetInput :: AlexInput -> Alex ()+alexSetInput (pos,c,inp)+ = Alex $ \s -> case s{alex_pos=pos,alex_chr=c,alex_inp=inp} of+ s@(AlexState{}) -> Right (s, ())++alexError :: String -> Alex a+alexError message = Alex $ \s -> Left $ message ++ " in " ++ show (alex_pos s)++alexGetStartCode :: Alex Int+alexGetStartCode = Alex $ \s@AlexState{alex_scd=sc} -> Right (s, sc)++alexSetStartCode :: Int -> Alex ()+alexSetStartCode sc = Alex $ \s -> Right (s{alex_scd=sc}, ())++alexGetOldStartCode :: Alex Int+alexGetOldStartCode = Alex $ \s@AlexState{alex_ocd=sc} -> Right (s, sc)++alexSetOldStartCode :: Int -> Alex ()+alexSetOldStartCode sc = Alex $ \s -> Right (s{alex_ocd=sc}, ())++alexGetComments :: Alex [String]+alexGetComments = Alex $ \s -> Right (s, alex_cmt s)++alexSetComments :: [String] -> Alex ()+alexSetComments cmt = Alex $ \s -> Right (s{alex_cmt=cmt}, ())++alexMonadScan = do+ inp <- alexGetInput+ sc <- alexGetStartCode+ case alexScan inp sc of+ AlexEOF -> alexEOF+ AlexError inp' -> alexError "lexical error"+ AlexSkip inp' len -> do+ alexSetInput inp'+ alexMonadScan+ AlexToken inp' len action -> do+ alexSetInput inp'+ action inp len++-- -----------------------------------------------------------------------------+-- Useful token actions++type AlexAction result = AlexInput -> Int -> Alex result++-- just ignore this token and scan another one+skip :: AlexAction Keyword+skip input len = alexMonadScan++-- ignore this token, but set the start code to a new value+begin :: Int -> AlexAction Keyword+begin code input len = do alexSetStartCode code; alexMonadScan++-- | Begin a text starting of the given type.+beginText :: String -> Int -> AlexAction Keyword+beginText ty code _ _ = do+ alexSetStartCode code+ return $ TEXT $ TextBegin ty++-- | End a text.+endText :: Int -> AlexAction Keyword+endText code _ _ = do+ alexSetStartCode code+ return $ TEXT TextEnd++-- | Begin a comment starting with the given sign.+beginComment :: String -> Int -> AlexAction Keyword+beginComment cmtBegin code input len = do+ cmts <- alexGetComments+ alexSetComments $ cmtBegin : cmts+ if null cmts+ then alexGetStartCode >>= alexSetOldStartCode+ else return ()+ alexSetStartCode code+ alexMonadScan++-- | End a comment that started with the given begin comment sign.+endComment :: String -> AlexAction Keyword+endComment cmtBegin input len = do+ cmts <- alexGetComments+ case cmts of+ [] -> alexError $ "comment ended but no beginning '"++cmtBegin++"' marked."+ (cmt:cmts') -> do+ if cmt == cmtBegin + then do+ alexSetComments cmts'+ if null cmts' + then alexGetOldStartCode >>= alexSetStartCode + else return ()+ else return ()+ alexMonadScan++-- perform an action for this token, and set the start code to a new value+-- andBegin :: AlexAction result -> Int -> AlexAction result+(action `andBegin` code) input len = do alexSetStartCode code; action input len++alexEOF :: Alex Keyword+alexEOF = return EOF++++}+++
@@ -0,0 +1,32 @@+module Paths_tamarin_prover (+ version,+ getBinDir, getLibDir, getDataDir, getLibexecDir,+ getDataFileName+ ) where++import qualified Control.Exception as Exception+import Data.Version (Version(..))+import System.Environment (getEnv)+catchIO :: IO a -> (Exception.IOException -> IO a) -> IO a+catchIO = Exception.catch+++version :: Version+version = Version {versionBranch = [0,1,0], versionTags = []}+bindir, libdir, datadir, libexecdir :: FilePath++bindir = "./"+libdir = "./"+datadir = "data"+libexecdir = "./"++getBinDir, getLibDir, getDataDir, getLibexecDir :: IO FilePath+getBinDir = catchIO (getEnv "tamarin_prover_bindir") (\_ -> return bindir)+getLibDir = catchIO (getEnv "tamarin_prover_libdir") (\_ -> return libdir)+getDataDir = catchIO (getEnv "tamarin_prover_datadir") (\_ -> return datadir)+getLibexecDir = catchIO (getEnv "tamarin_prover_libexecdir") (\_ -> return libexecdir)++getDataFileName :: FilePath -> IO FilePath+getDataFileName name = do+ dir <- getDataDir+ return (dir ++ "/" ++ name)
@@ -0,0 +1,715 @@+{-# LANGUAGE DeriveDataTypeable #-}+-- |+-- Copyright : (c) 2010-2012 Benedikt Schmidt & Simon Meier+-- License : GPL v3 (see LICENSE)+-- +-- Maintainer : Simon Meier <iridcode@gmail.com>+-- Portability : GHC only+--+-- Main module for the tamarin prover.+module Main where++import Prelude hiding (id, (.))++import Data.List+import Data.Maybe+import Data.Version (showVersion)+import Data.Monoid+import Data.Char (isSpace, toLower)+import Data.Label++import Control.Basics+import Control.Category+import Control.Exception as E++import System.Console.CmdArgs.Explicit+import System.Console.CmdArgs.Text++import System.Exit+import System.FilePath+import System.Directory+import System.Environment+import System.IO+import System.Process+import System.Timing (timed)++import Extension.Prelude++import qualified Text.Isar as Isar++import Theory+import Theory.Parser+import Theory.Wellformedness++import Paths_tamarin_prover++import Web.Dispatch+import qualified Web.Settings+import qualified Network.Wai.Handler.Warp as Warp (run)++------------------------------------------------------------------------------+-- General definitions for tamarin+------------------------------------------------------------------------------++-- | Program name+programName :: String+programName = "tamarin-prover"++-- | Version string+versionStr :: FilePath -- ^ Path to LICENCE file.+ -> String+versionStr licensePath = unlines+ [ concat+ [ programName+ , " "+ , showVersion version+ , ", (C) Benedikt Schmidt, Simon Meier, ETH Zurich 2010-2012"+ ]+ , ""+ , "This program comes with ABSOLUTELY NO WARRANTY. It is free software, and you"+ , "are welcome to redistribute it according to its LICENSE, see"+ , "'" ++ licensePath ++ "'."+ ]++-- | Line width to use.+lineWidth :: Int+lineWidth = 110++shortLineWidth :: Int+shortLineWidth = 78++{-+-- | Version string with HTML markup.+htmlVersionStr :: String+htmlVersionStr = concat+ [ link "http://www.infsec.ethz.ch/research/software#TAMARIN" programName+ , " "+ , showVersion version+ , ", © "+ , link "https://infsec.ethz.ch/infsec/people/benschmi/index" "Benedikt Schmidt"+ , ", "+ , link "http://people.inf.ethz.ch/meiersi" "Simon Meier"+ , ", ETH Zurich 2010-2012"+ ]+ where+ link href name = + "<a href=\"" ++ href ++ "\" target=\"new\">" ++ name ++ "</a>"+-}++------------------------------------------------------------------------------+-- Argument parsing helpers+------------------------------------------------------------------------------++type Arguments = [(String,String)]++argExists :: String -> Arguments -> Bool+argExists a = isJust . findArg a++findArg :: MonadPlus m => String -> Arguments -> m String+findArg a' as = msum [ return v | (a,v) <- as, a == a' ]++getArg :: String -> Arguments -> String+getArg a = + fromMaybe (error $ "getArg: argument '" ++ a ++ "' not found") . findArg a++addArg :: String -> String -> Arguments -> Arguments+addArg a v = ((a,v):)++withArguments :: Mode Arguments -> (Arguments -> IO ()) -> IO ()+withArguments argMode io = do+ licensePath <- getDataFileName "LICENSE"+ processArgs argMode >>= run licensePath+ where+ run licensePath as+ | argExists "help" as = print $ helpText HelpFormatAll argMode+ | argExists "version" as = putStrLn $ versionStr licensePath+ | otherwise = io as++updateArg :: String -> String -> Arguments -> Either a Arguments+updateArg a v = Right . addArg a v++addEmptyArg :: String -> Arguments -> Arguments+addEmptyArg a = addArg a ""+ +-- | Main mode.+mainMode :: Mode [(String,String)]+mainMode = + -- translateMode { modeGroupModes = toGroup [interactiveMode] }+ translateMode { modeGroupModes = toGroup [interactiveMode, intruderMode] }+ where ++ defaultMode name help = Mode+ { modeGroupModes = toGroup []+ , modeNames = [name] + , modeValue = [] + , modeCheck = updateArg "mode" name+ , modeReform = const Nothing-- no reform possibility+ , modeHelp = help+ , modeHelpSuffix = []+ , modeArgs = Nothing -- no positional arguments+ , modeGroupFlags = toGroup [] -- no flags+ }++ translateMode =+ ( defaultMode programName + "Batch mode for analyzing security protocols using DH-exponentiation."+ )+ { modeCheck = updateArg "mode" "translate"+ , modeArgs = Just $ flagArg (updateArg "inFile") "FILES"+ , modeGroupFlags = Group + { groupUnnamed =+ theoryLoadFlags +++ -- [ flagNone ["html"] (addEmptyArg "html")+ -- "generate HTML visualization of proofs"++ -- [ flagNone ["no-compress"] (addEmptyArg "noCompress")+ -- "Do not use compressed sequent visualization"++ [ flagNone ["parse-only"] (addEmptyArg "parseOnly")+ "Parse the input file and pretty-print it as-is"+ ] +++ outputFlags +++ toolFlags + , groupHidden = []+ , groupNamed =+ [ ("About"+ , [ flagHelpSimple (addEmptyArg "help")+ , flagVersion (addEmptyArg "version")+ ] )+ ]+ }+ }+++ intruderMode =+ ( defaultMode "intruder" + "Compute the variants of the intruder rules for DH-exponentiation."+ )+ { modeArgs = Nothing + , modeCheck = updateArg "mode" "intruder"+ , modeGroupFlags = toGroup outputFlags+ }++ outputFlags = + [ flagOpt "" ["output","o"] (updateArg "outFile") "FILE" "Output file"+ , flagOpt "" ["Output","O"] (updateArg "outDir") "DIR" "Output directory"+ ]++ toolFlags = + -- [ flagOpt "dot" ["with-dot"] (updateArg "withDot") "FILE" "Path to GraphViz 'dot' tool"+ [ flagOpt "maude" ["with-maude"] (updateArg "withMaude") "FILE" "Path to 'maude' rewriting tool"+ ]++ interactiveFlags =+ [ flagOpt "" ["port","p"] (updateArg "port") "PORT" "Port to listen on"+ -- , flagOpt "" ["datadir"] (updateArg "datadir") "DATADIR" "Directory with data"+ , flagNone ["debug"] (addEmptyArg "debug") "Show server debugging output"+ -- , flagNone ["autosave"] (addEmptyArg "autosave") "Automatically save proof state"+ -- , flagNone ["loadstate"] (addEmptyArg "loadstate") "Load proof state if present"+ ] +++ theoryLoadFlags +++ toolFlags++ interactiveMode =+ ( defaultMode "interactive"+ "Start a web-server for interactively constructing the security proofs."+ )+ { modeArgs = Just $ flagArg (updateArg "workDir") "WORKDIR"+ , modeCheck = updateArg "mode" "interactive"+ , modeGroupFlags = toGroup interactiveFlags+ }+++-- | Disply help message and exit.+errHelpExit :: String -> IO ()+errHelpExit msg = do+ putStrLn $ "error: " ++ msg+ putStrLn $ ""+ putStrLn $ showText (Wrap lineWidth) + $ helpText HelpFormatDefault mainMode+ examplePath <- getDataFileName "examples"+ let userGuidePath = examplePath </> "UserGuide.spthy"+ csf12Path = examplePath </> "csf12" </> "*.spthy"+ csf12Cmd = programName ++ " --prove -Ocase-studies +RTS -N -RTS " ++ csf12Path + csf12Cmd' = programName ++ " --interactive +RTS -N -RTS " ++ csf12Path + separator = putStrLn $ replicate shortLineWidth '-'+ putPath info path = putStrLn info >> putStrLn (" " ++ path ++ "\n")+ separator+ putPath "For example protocol models see" examplePath+ putPath "Their syntax is explained in" userGuidePath+ putPath "To run all case-studies from our CSF'12 submission, use" csf12Cmd+ putPath "To construct their security proofs interactively, use" csf12Cmd'+ putStrLn + "Note that the +RTS -N -RTS flags instruct the Haskell runtime system to\n\+ \use as many cores as your system has. This speeds-up some of the computations."+ separator+ exitFailure+ where++------------------------------------------------------------------------------+-- Main mode execution+------------------------------------------------------------------------------++-- | Main function.+main :: IO ()+main = + withArguments mainMode selectMode+ where+ selectMode as = case findArg "mode" as of+ Just "translate" -> translate as+ Just "intruder" -> intruderVariants as+ Just "interactive" -> interactive as+ Just m -> error $ "main: unknown mode '" ++ m ++ "'"+ Nothing -> error $ "main: no mode given"+ +-- shared support functions+---------------------------++renderDoc :: Isar.Doc -> String+renderDoc = Isar.renderStyle (Isar.style { Isar.lineLength = lineWidth }) +++------------------------------------------------------------------------------+-- Intruder variants mode execution+------------------------------------------------------------------------------++intruderVariants :: Arguments -> IO ()+intruderVariants as = do+ ensureMaude as+ hnd <- startMaude (maudePath as) dhMaudeSig+ let thy = dhIntruderTheory hnd+ thyString = renderDoc $ prettyOpenTheory thy+ putStrLn thyString+ writeThy thyString+ where+ -- output generation+ --------------------++ writeThy thyString = case optOutPath of+ Just outPath -> writeFile outPath thyString+ Nothing -> return ()+ + -- Output file name, if output is desired.+ optOutPath :: Maybe FilePath+ optOutPath = + do outFile <- findArg "outFile" as+ guard (outFile /= "")+ return outFile+ <|>+ do outDir <- findArg "outDir" as+ return $ outDir </> defaultIntrVariantsPath ++defaultIntrVariantsPath :: FilePath+defaultIntrVariantsPath = "intruder_variants_dh.spthy"+++------------------------------------------------------------------------------+-- Theory loading: shared between interactive and batch mode+------------------------------------------------------------------------------+ +theoryLoadFlags :: [Flag Arguments]+theoryLoadFlags = + [ flagNone ["prove"] (addEmptyArg "addProofs")+ "Attempt to prove all security properties"++ , flagOpt "dfs" ["stop-on-attack"] (updateArg "stopOnAttack") "DFS|BFS|NONE"+ "How to search for attacks (default DFS)"++ -- , flagOpt "5" ["bound", "b"] (updateArg "bound") "INT"+ -- "Bound the depth of the proofs"++ --, flagOpt "" ["intruder","i"] (updateArg "intruderVariants") "FILE"+ -- "Cached intruder rules to use"++ , flagOpt "" ["defines","D"] (updateArg "defines") "STRING"+ "Define flags for pseudo-preprocessor."+ ]++loadOpenThy :: Arguments -> FilePath -> IO OpenTheory+loadOpenThy = fst . loadThy++loadClosedThy :: Arguments -> FilePath -> IO ClosedTheory+loadClosedThy = uncurry (>=>) . loadThy++loadClosedWfThy :: Arguments -> FilePath -> IO ClosedTheory+loadClosedWfThy as file = do+ thy <- loadOpen file+ case checkWellformedness thy of+ [] -> close thy+ report -> error $ renderDoc $ prettyWfErrorReport report+ where+ (loadOpen, close) = loadThy as++loadClosedThyString :: Arguments -> String -> IO ClosedTheory+loadClosedThyString = uncurry (>=>) . loadThyString++-- | Load an open/closed theory from a file.+loadThy :: Arguments -> (FilePath -> IO OpenTheory, OpenTheory -> IO ClosedTheory)+loadThy as = loadGenericThy (parseOpenTheory (defines as)) as ++-- | Load an open/closed theory from a string.+loadThyString :: Arguments -> (String -> IO OpenTheory, OpenTheory -> IO ClosedTheory)+loadThyString as = loadGenericThy loader as+ where+ loader str =+ case parseOpenTheoryString (defines as) str of+ Right thy -> return thy+ Left err -> error $ show err ++-- | The defined pre-processor flags in the argument.+defines :: Arguments -> [String]+defines = findArg "defines"++-- | Load an open/closed theory given a loader function.+loadGenericThy :: (a -> IO OpenTheory)+ -> Arguments + -> (a -> IO OpenTheory, OpenTheory -> IO ClosedTheory)+loadGenericThy loader as =+ (loader, (closeThy as) <=< tryAddIntrVariants)+ where+ -- intruder variants+ --------------------+ tryAddIntrVariants :: OpenTheory -> IO OpenTheory+ tryAddIntrVariants thy0 = do+ let msig = get (sigpMaudeSig . thySignature) thy0+ thy = addIntrRuleACs (subtermIntruderRules msig ++ specialIntruderRules) thy0+ if (enableDH msig) then+ do variantsFile <- getDataFileName "intruder_variants_dh.spthy"+ ifM (doesFileExist variantsFile)+ (do intrVariants <- + get thyCache <$> parseOpenTheory (defines as) variantsFile+ return $ addIntrRuleACs intrVariants thy+ )+ (error $ "could not find intruder message deduction theory '" + ++ variantsFile ++ "'")+ else return thy++-- | Close a theory according to arguments.+closeThy :: Arguments -> OpenTheory -> IO ClosedTheory+closeThy as = + fmap (proveTheory prover) . closeTheory (maudePath as) . wfCheck + where+ -- handles to relevant arguments+ --------------------------------+ proofBound = read <$> findArg "bound" as+ requireProofs = argExists "addProofs" as++ stopOnAttack :: Maybe String+ stopOnAttack = findArg "stopOnAttack" as++ -- wellformedness check+ -----------------------+ wfCheck :: OpenTheory -> OpenTheory+ wfCheck thy = + noteWellformedness+ (checkWellformedness thy) thy++ -- protocol transformation+ --------------------------+ prover :: Prover+ prover + | requireProofs = cutAttack $ maybe id boundProver proofBound autoProver+ | otherwise = mempty+ where + cutAttack = mapProverProof $ case map toLower <$> stopOnAttack of+ Nothing -> cutOnAttackDFS+ Just "dfs" -> cutOnAttackDFS+ Just "none" -> id+ Just "bfs" -> cutOnAttackBFS+ Just other -> error $ "unknown stop-on-attack method: " ++ other+ +------------------------------------------------------------------------------+-- Tool paths (shared between interactive and batch mode)+------------------------------------------------------------------------------++-- | Path to maude tool+maudePath :: Arguments -> FilePath+maudePath = fromMaybe "maude" . findArg "withMaude"++-- | Path to dot tool+dotPath :: Arguments -> FilePath+dotPath = fromMaybe "dot" . findArg "withDot"++------------------------------------------------------------------------------+-- Interactive proof mode execution+------------------------------------------------------------------------------++-- | Prove lemmas interactively.+interactive :: Arguments -> IO ()+interactive as = case findArg "workDir" as of+ Nothing -> errHelpExit "no working directory specified"+ Just workDir0 -> do+ -- determine working directory+ wdIsFile <- doesFileExist workDir0+ let workDir | wdIsFile = takeDirectory workDir0+ | otherwise = workDir0+ wdIsDir <- doesDirectoryExist workDir+ if wdIsDir+ then do+ -- process theories+ ensureGraphVizDot as+ ensureMaude as+ putStrLn ""+ port <- readPort+ dataDir <- readDataDir+ putStrLn $ intercalate "\n"+ [ "The server is starting up on localhost with port " ++ show port ++ "."+ , "Browse to http://localhost:" ++ show port ++ " once the server is ready."+ , ""+ , "Loading the security protocol theories '" ++ workDir </> "*.spthy" ++ "' ..."+ ]+ withWebUI workDir (argExists "loadstate" as) (argExists "autosave" as)+ (loadClosedWfThy as) (loadClosedThyString as) (closeThy as)+ (argExists "debug" as) (Just dataDir) (Warp.run port)+ + else errHelpExit $ "directory '" ++ workDir ++ "' does not exist."+ where+ -- Datadir argument+ readDataDir =+ case findArg "datadir" as of+ [d] -> return d+ _ -> getDataDir++ -- Port argument+ ----------------+ readPort = do+ let port = findArg "port" as >>= fmap fst . listToMaybe . reads+ when+ (argExists "port" as && isNothing port) + (putStrLn $ "Unable to read port from argument `"+ ++fromMaybe "" (findArg "port" as)++"'. Using default.")+ return $ fromMaybe Web.Settings.defaultPort port++------------------------------------------------------------------------------+-- Translate mode execution+------------------------------------------------------------------------------++-- | Execute a translation.+translate :: Arguments -> IO ()+translate as + | null inFiles = errHelpExit "no input files given"+ | otherwise = do+ ensureMaude as+ putStrLn $ ""+ summaries <- mapM processThy inFiles+ putStrLn $ ""+ putStrLn $ replicate shortLineWidth '='+ putStrLn $ "summary of processed files:"+ putStrLn $ ""+ putStrLn $ renderDoc $ Isar.vcat $ intersperse (Isar.text "") summaries+ putStrLn $ ""+ putStrLn $ replicate shortLineWidth '='+ where+ -- handles to arguments+ -----------------------+ inFiles = reverse $ findArg "inFile" as++ -- output generation+ --------------------++ dryRun = not (argExists "outFile" as || argExists "outDir" as)++ mkOutPath :: FilePath -- ^ Input file name.+ -> FilePath -- ^ Output file name.+ mkOutPath inFile = + fromMaybe (error "please specify an output file or directory") $+ do outFile <- findArg "outFile" as+ guard (outFile /= "")+ return outFile+ <|>+ do outDir <- findArg "outDir" as+ return $ mkAutoPath outDir (takeBaseName inFile)++ -- automatically generate the filename for output+ mkAutoPath :: FilePath -> String -> FilePath+ mkAutoPath dir baseName+ | argExists "html" as = dir </> baseName+ | otherwise = dir </> addExtension (baseName ++ "_analyzed") "spthy"++ -- theory processing functions+ ------------------------------++ processThy :: FilePath -> IO (Isar.Doc)+ processThy inFile+ -- | argExists "html" as = + -- generateHtml inFile =<< loadClosedThy as inFile+ | argExists "parseOnly" as =+ out (const Isar.emptyDoc) prettyOpenTheory (loadOpenThy as inFile)+ | otherwise = + out prettyClosedSummary prettyClosedTheory (loadClosedThy as inFile)+ where+ out :: (a -> Isar.Doc) -> (a -> Isar.Doc) -> IO a -> IO Isar.Doc+ out summaryDoc fullDoc load = do+ res <- try $+ if dryRun + then do writeWithSummary putStrLn "<no file written>"+ else do+ putStrLn $ ""+ putStrLn $ "analyzing: " ++ inFile+ putStrLn $ ""+ let outFile = mkOutPath inFile+ summary <- writeWithSummary (writeFile outFile) outFile+ putStrLn $ replicate shortLineWidth '-'+ putStrLn $ renderDoc summary+ putStrLn $ ""+ putStrLn $ replicate shortLineWidth '-'+ return summary+ case res of+ Right x -> return x+ Left x -> return $ Isar.vcat $ map Isar.text+ [ "failed to analyze: " ++ inFile+ , ""+ , " exception: " ++ show (x :: IOException)+ ]+ where+ writeWithSummary :: (String -> IO ()) -> FilePath -> IO Isar.Doc+ writeWithSummary io outName = do+ (thySummary, t) <- timed $ do+ thy <- load+ io $ renderDoc $ fullDoc thy+ return $ summaryDoc thy+ return $ Isar.vcat+ [ Isar.text $ "analyzed: " ++ inFile+ , Isar.text $ ""+ , Isar.text $ " output: " ++ outName+ , Isar.text $ " processing time: " ++ show t+ , Isar.text $ ""+ , Isar.nest 2 thySummary+ ]++ {- TO BE REACTIVATED once infrastructure from interactive mode can be used++ -- static html generation+ -------------------------++ generateHtml :: FilePath -- ^ Input file+ -> ClosedTheory -- ^ Theory to pretty print+ -> IO ()+ generateHtml inFile thy = do+ cmdLine <- getCommandLine+ time <- getCurrentTime+ cpu <- getCpuModel+ template <- getHtmlTemplate+ theoryToHtml $ GenerationInput {+ giHeader = "Generated by " ++ htmlVersionStr+ , giTime = time+ , giSystem = cpu+ , giInputFile = inFile+ , giTemplate = template+ , giOutDir = mkOutPath inFile+ , giTheory = thy+ , giCmdLine = cmdLine+ , giCompress = not $ argExists "noCompress" as+ }++ -}++------------------------------------------------------------------------------+-- Utility functions+------------------------------------------------------------------------------++-- | Get the string constituting the command line.+getCommandLine :: IO String+getCommandLine = do+ arguments <- getArgs+ return . concat . intersperse " " $ programName : arguments++-- | Read the cpu info using a call to cat /proc/cpuinfo+getCpuModel :: IO String+getCpuModel = + handle handler $ do+ (_, info, _) <- readProcessWithExitCode "cat" ["/proc/cpuinfo"] []+ return $ maybe errMsg+ (("Linux running on an "++) . drop 2 . dropWhile (/=':'))+ (find (isPrefixOf "model name") $ lines info)+ where+ errMsg = "could not extract CPU model"+ handler :: IOException -> IO String+ handler _ = return errMsg++-- | Get the path to the Html template file.+getHtmlTemplate :: IO FilePath+getHtmlTemplate = getDataFileName "HTML_TEMPLATE"+++-- | Build the command line corresponding to a program arguments tuple.+commandLine :: String -> [String] -> String+commandLine prog args = concat $ intersperse " " $ prog : args++-- | Test if a process is executable and check its response. This is used to+-- determine the versions and capabilities of tools that we depend on.+testProcess :: (String -> String -> Either String String) + -- ^ Analysis of stdout, stderr. Use 'Left' to report error.+ -> String -- ^ Test description to display.+ -> FilePath -- ^ Process to start+ -> [String] -- ^ Arguments+ -> String -- ^ Stdin+ -> IO Bool -- ^ True, if test was successful+testProcess check testName prog args inp = do+ putStr testName+ hFlush stdout+ handle handler $ do+ (exitCode, out, err) <- readProcessWithExitCode prog args inp+ let errMsg reason = do+ putStrLn reason+ putStrLn $ " command: " ++ commandLine prog args+ putStrLn $ " stdin: " ++ inp+ putStrLn $ " stdout: " ++ out+ putStrLn $ " stderr: " ++ err+ return False++ case exitCode of+ ExitFailure code -> errMsg $ "failed with exit code " ++ show code+ ExitSuccess -> + case check out err of+ Left msg -> errMsg msg+ Right msg -> do putStrLn msg+ return True+ where+ handler :: IOException -> IO Bool+ handler _ = do putStrLn "caught exception while executing:"+ putStrLn $ commandLine prog args+ putStrLn $ "with input: " ++ inp+ return False++-- | Ensure a suitable version of the Graphviz dot tool is installed.+ensureGraphVizDot :: Arguments -> IO ()+ensureGraphVizDot as = do+ putStrLn $ "GraphViz tool: '" ++ dot ++ "'"+ success <- testProcess check " checking version: " dot ["-V"] ""+ unless success $ putStrLn errMsg+ where+ dot = dotPath as+ check _ err+ | "graphviz" `isInfixOf` map toLower err = Right $ init err ++ ". OK."+ | otherwise = Left $ errMsg+ errMsg = unlines+ [ "WARNING:"+ , ""+ , " The dot tool seems not to be provided by Graphviz."+ , " Graph generation might not work."+ , " Please download an official version from:"+ , " http://www.graphviz.org/"+ ]++-- | Ensure a suitable version of Maude is installed.+ensureMaude :: Arguments -> IO ()+ensureMaude as = do+ putStrLn $ "maude tool: '" ++ maude ++ "'"+ success <- testProcess check " checking version: " maude ["--version"] ""+ unless success $ putStrLn $ errMsg "tool not found / does not work"+ where+ maude = maudePath as+ check out _ + | filter (not . isSpace) out == "2.6" = Right "2.6. OK."+ | otherwise = Left $ errMsg $+ " 'maude --version' returned wrong verison '" ++ out ++ "'"++ errMsg reason = unlines+ [ "WARNING:"+ , ""+ , reason+ , " " ++ programName ++ " will likely not work."+ , " Please download 'Core Maude 2.6' from:"+ , " http://maude.cs.uiuc.edu/download/"+ ]
@@ -0,0 +1,765 @@+{-# LANGUAGE TemplateHaskell, TupleSections, DeriveFunctor #-}+{-# LANGUAGE StandaloneDeriving, TypeSynonymInstances, FlexibleInstances #-}+-- |+-- Copyright : (c) 2010-2012 Benedikt Schmidt & Simon Meier+-- License : GPL v3 (see LICENSE)+-- +-- Maintainer : Simon Meier <iridcode@gmail.com>+-- Portability : GHC only+--+-- Theory datatype and transformations on it.+module Theory (+ -- * Lemmas+ LemmaAttribute(..)+ , Lemma(..)+ , lName+ , lFormulaE+ , lFormulaAC+ , lAttributes+ , lProof+ , unprovenLemma + , skeletonLemma++ -- * Theories+ , Theory(..)+ , TheoryItem(..)+ , thyName+ , thySignature+ , thyCache+ , thyItems+ , addLemma+ , removeLemma+ , lookupLemma+ , addComment+ , addStringComment+ , addFormalComment+ , cprRuleE++ -- ** Open theories+ , OpenTheory+ , defaultOpenTheory+ , dhIntruderTheory+ , addProtoRule+ , addIntrRuleACs++ -- ** Closed theories+ , ClosedTheory+ , ClosedRuleCache(..) -- FIXME: this is only exported for the Binary instances+ , closeTheory+ , openTheory++ , ClosedProtoRule(..)++ , getLemmas+ , getIntrVariants+ , getProtoRuleEs+ , getProofContext+ , getClassifiedRules++ , getCaseDistinction++ -- ** Proving+ , ProofSkeleton+ , proveTheory+ , applicableProofMethods++ -- ** Lemma references+ , lookupLemmaProof+ , modifyLemmaProof++ -- * Pretty printing+ , prettyFormalComment+ , prettyLemmaName+ , prettyLemma+ , prettyClosedTheory+ , prettyOpenTheory++ , prettyClosedSummary++ -- * Convenience exports+ , module Theory.Proof+ , module Theory.IntruderRules+ + ) where++import Prelude hiding ( (.), id )+ +import Data.Maybe+import Data.Monoid (Sum(..))+import qualified Data.Set as S+import Data.List+import Data.Foldable (Foldable, foldMap)+import Data.Traversable (Traversable, traverse)+import Data.DeriveTH+import Data.Binary+ +import Control.Basics+import Control.Parallel.Strategies+import Control.DeepSeq+import Control.Category+import qualified Control.Monad.State as MS+import Control.Monad.Reader++import qualified Extension.Data.Label as L+import Extension.Data.Label hiding (get)++import Text.Isar+ +import Theory.Pretty+import Theory.Rule+import Theory.RuleVariants+import Theory.IntruderRules+import Theory.Proof+++------------------------------------------------------------------------------+-- To MOVE+------------------------------------------------------------------------------++-- | Vertically separate a list of documents by empty lines.+vsep :: Document d => [d] -> d+vsep = foldr ($--$) emptyDoc+++------------------------------------------------------------------------------+-- Specific proof types+------------------------------------------------------------------------------++-- | Proof skeletons are used to represent proofs in open theories.+type ProofSkeleton = Proof ()++-- | Convert a proof skeleton to an incremental proof without any sequent+-- annotations.+skeletonToIncrementalProof :: ProofSkeleton -> IncrementalProof+skeletonToIncrementalProof = fmap (fmap (const Nothing))++-- | Convert an incremental proof to a proof skeleton by dropping all+-- annotations.+incrementalToSkeletonProof :: IncrementalProof -> ProofSkeleton+incrementalToSkeletonProof = fmap (fmap (const ()))+++------------------------------------------------------------------------------+-- Commented sets of rewriting rules+------------------------------------------------------------------------------++-- | A protocol rewriting rule modulo E together with its possible assertion+-- soundness proof.+type OpenProtoRule = ProtoRuleE++-- | A closed proto rule lists its original rule modulo E, the corresponding+-- variant modulo AC, and if required the assertion soundness proof.+data ClosedProtoRule = ClosedProtoRule + { _cprRuleE :: ProtoRuleE -- original rule modulo E+ , _cprRuleAC :: ProtoRuleAC -- variant modulo AC+ }+ deriving( Show )++type OpenRuleCache = [IntrRuleAC]++data ClosedRuleCache = ClosedRuleCache+ { _crcRules :: ClassifiedRules+ , _crcUntypedCaseDists :: [CaseDistinction]+ , _crcTypedCaseDists :: [CaseDistinction]+ }+ deriving( Eq, Ord, Show )+++$(mkLabels [''ClosedProtoRule, ''ClosedRuleCache])++instance HasRuleName ClosedProtoRule where+ ruleName = ruleName . L.get cprRuleE+++-- Relation between open and closed rule sets+---------------------------------------------++-- | All intruder rules of a set of classified rules.+intruderRules :: ClassifiedRules -> [IntrRuleAC]+intruderRules rules = do+ Rule (IntrInfo i) ps cs as <- joinAllRules rules+ return $ Rule i ps cs as++-- | Open a rule cache. Variants and precomputed case distinctions are dropped.+openRuleCache :: ClosedRuleCache -> OpenRuleCache+openRuleCache = intruderRules . L.get crcRules++-- | Open a protocol rule; i.e., drop variants and proof annotations.+openProtoRule :: ClosedProtoRule -> OpenProtoRule+openProtoRule = L.get cprRuleE++-- | Close a protocol rule; i.e., compute AC variant and typing assertion+-- soundness sequent, if required.+closeProtoRule :: MaudeHandle -> OpenProtoRule -> ClosedProtoRule+closeProtoRule hnd ruE = ClosedProtoRule ruE (variantsProtoRule hnd ruE)++-- | Close a rule cache. Hower, note that the+-- requires case distinctions are not computed here.+closeRuleCache :: [LNGuarded] -- ^ Typing lemmas.+ -> SignatureWithMaude -- ^ Signature of theory.+ -> [ClosedProtoRule] -- ^ Protocol rules with variants.+ -> OpenRuleCache -- ^ Intruder rules modulo AC.+ -> ClosedRuleCache -- ^ Cached rules and case distinctions.+closeRuleCache typingAsms sig protoRules intrRulesAC = + ClosedRuleCache classifiedRules untypedCaseDists typedCaseDists+ where+ ctxt0 = ProofContext sig classifiedRules []+ -- precomputing the case distinctions+ untypedCaseDists = precomputeCaseDistinctions ctxt0 [] + typedCaseDists = + refineWithTypingAsms typingAsms ctxt0 untypedCaseDists++ -- classifying the rules+ rulesAC = (fmap IntrInfo <$> intrRulesAC) <|> + ((fmap ProtoInfo . L.get cprRuleAC) <$> protoRules)++ anyOf ps = partition (\x -> any ($ x) ps)++ (nonProto, proto) = + anyOf [ isDestrRule, isConstrRule , isFreshRule, isIRecvRule] rulesAC+ (spec, nonSpec) = anyOf [isIRecvRule, isFreshRule] nonProto+ (constr, destr) = anyOf [isConstrRule] nonSpec+ -- FIXME: Learn, knows, fresh, etc. are special rules++ -- and sort them into ClassifiedRules datastructure for later use in proofs+ classifiedRules = ClassifiedRules+ { _crConstruct = constr+ , _crDestruct = destr+ , _crProtocol = proto+ , _crSpecial = spec+ }++++------------------------------------------------------------------------------+-- Lemmas+------------------------------------------------------------------------------++data LemmaAttribute = + TypingLemma+ | ReuseLemma+ deriving( Eq, Ord, Show )++-- | A lemma describes a property that holds in the context of a theory+-- together with a proof of its correctness.+data Lemma p = Lemma+ { _lName :: String+ , _lFormulaE :: FormulaE+ , _lFormulaAC :: Maybe FormulaAC+ , _lAttributes :: [LemmaAttribute]+ , _lProof :: p+ }+ deriving( Show )++$(mkLabels [''Lemma])+++-- Instances+------------++instance Functor Lemma where+ fmap f (Lemma n fE fAC atts prf) = Lemma n fE fAC atts (f prf)++instance Foldable Lemma where+ foldMap f = f . L.get lProof++instance Traversable Lemma where+ traverse f (Lemma n fE fAC atts prf) = Lemma n fE fAC atts <$> f prf+++-- Lemma construction/modification+----------------------------------++-- | Create a new unproven lemma from a formula modulo E.+unprovenLemma :: String -> [LemmaAttribute] -> FormulaE -> Lemma ProofSkeleton+unprovenLemma name atts fmE = Lemma name fmE Nothing atts (unproven ())++skeletonLemma :: String -> [LemmaAttribute] -> FormulaE+ -> ProofSkeleton -> Lemma ProofSkeleton+skeletonLemma name atts fmE = Lemma name fmE Nothing atts++-- | The case-distinction kind allowed for a lemma+lemmaCaseDistKind :: Lemma p -> CaseDistKind+lemmaCaseDistKind lem+ | TypingLemma `elem` L.get lAttributes lem = UntypedCaseDist+ | otherwise = TypedCaseDist+ ++------------------------------------------------------------------------------+-- Theories+------------------------------------------------------------------------------++-- | A formal comment is a header together with the body of the comment.+type FormalComment = (String, String)++-- | A theory item built over the given rule type.+data TheoryItem r p = + RuleItem r+ | LemmaItem (Lemma p)+ | TextItem FormalComment+ deriving( Show, Functor )+++-- | A theory contains a single set of rewriting rules modeling a protocol+-- and the lemmas that +data Theory sig c r p = Theory {+ _thyName :: String+ , _thySignature :: sig+ , _thyCache :: c+ , _thyItems :: [TheoryItem r p]+ }++$(mkLabels [''Theory])++-- | Open theories can be extended. Invariants:+-- 1. Lemma names are unique. +type OpenTheory = + Theory SignaturePure [IntrRuleAC] OpenProtoRule ProofSkeleton ++deriving instance Show OpenTheory++-- | Closed theories can be proven. Invariants:+-- 1. Lemma names are unique+-- 2. All proof steps with annotated sequents are sound with respect to the+-- closed rule set of the theory.+-- 3. Maude is running under the given handle.+type ClosedTheory = + Theory SignatureWithMaude ClosedRuleCache ClosedProtoRule IncrementalProof++deriving instance Show ClosedTheory+++-- Shared theory modification functions+---------------------------------------++-- | Fold a theory item.+foldTheoryItem :: (r -> a) -> (Lemma p -> a) -> (FormalComment -> a) + -> TheoryItem r p -> a+foldTheoryItem fRule fLemma fText i = case i of+ RuleItem r -> fRule r+ LemmaItem l -> fLemma l+ TextItem t -> fText t++-- | Map a theory item.+mapTheoryItem :: (r -> r') -> (p -> p') -> TheoryItem r p -> TheoryItem r' p'+mapTheoryItem f g = foldTheoryItem (RuleItem . f) (LemmaItem . fmap g) TextItem++-- | All rules of a theory.+theoryRules :: Theory sig c r p -> [r]+theoryRules = foldTheoryItem return (const []) (const []) <=< L.get thyItems++-- | All lemmas of a theory.+theoryLemmas :: Theory sig c r p -> [Lemma p]+theoryLemmas = foldTheoryItem (const []) return (const []) <=< L.get thyItems++-- | Add a new lemma. Fails, if a lemma with the same name exists.+addLemma :: Lemma p -> Theory sig c r p -> Maybe (Theory sig c r p)+addLemma l thy = do+ guard (isNothing $ lookupLemma (L.get lName l) thy)+ return $ modify thyItems (++ [LemmaItem l]) thy++-- | Remove a lemma by name. Fails, if the lemma does not exist.+removeLemma :: String -> Theory sig c r p -> Maybe (Theory sig c r p)+removeLemma lemmaName thy = do+ _ <- lookupLemma lemmaName thy+ return $ modify thyItems (concatMap fItem) thy+ where+ fItem = foldTheoryItem (return . RuleItem) check (return . TextItem)+ check l = do guard (L.get lName l /= lemmaName); return (LemmaItem l)++-- | Find the lemma with the given name.+lookupLemma :: String -> Theory sig c r p -> Maybe (Lemma p)+lookupLemma name = find ((name ==) . L.get lName) . theoryLemmas++-- | Add a comment to the theory.+addComment :: Doc -> Theory sig c r p -> Theory sig c r p+addComment c = modify thyItems (++ [TextItem ("", render c)]) ++-- | Add a comment represented as a string to the theory.+addStringComment :: String -> Theory sig c r p -> Theory sig c r p+addStringComment = addComment . vcat . map text . lines++addFormalComment :: FormalComment -> Theory sig c r p -> Theory sig c r p+addFormalComment c = modify thyItems (++ [TextItem c]) +++------------------------------------------------------------------------------+-- Open theory construction / modification+------------------------------------------------------------------------------++-- | Default theory+defaultOpenTheory :: OpenTheory+defaultOpenTheory = Theory "default" emptySignaturePure [] []++-- | The default intruder theory; uses Maude to perform AC+-- unification for computing the variants.+dhIntruderTheory :: MaudeHandle -> OpenTheory+dhIntruderTheory hnd =+ Theory "intruder_variants" (emptySignaturePure { _sigMaudeInfo = dhMaudeSig })+ (dhIntruderRules `runReader` hnd) []++-- | Open a theory by dropping the closed world assumption and values whose+-- soundness dependens on it.+openTheory :: ClosedTheory -> OpenTheory+openTheory (Theory n sig c items) = + Theory n (toSignaturePure sig) (openRuleCache c) + (map (mapTheoryItem openProtoRule incrementalToSkeletonProof) items)++-- | Find the open protocol rule with the given name.+lookupOpenProtoRule :: ProtoRuleName -> OpenTheory -> Maybe OpenProtoRule+lookupOpenProtoRule name = + find ((name ==) . L.get rInfo) . theoryRules++-- | Add a new protocol rules. Fails, if a protocol rule with the same name+-- exists.+addProtoRule :: ProtoRuleE -> OpenTheory -> Maybe OpenTheory+addProtoRule ruE thy = do+ guard (maybe True ((ruE ==)) $ + lookupOpenProtoRule (L.get rInfo ruE) thy)+ return $ modify thyItems (++ [RuleItem ruE]) thy++-- | Add intruder proof rules.+addIntrRuleACs :: [IntrRuleAC] -> OpenTheory -> OpenTheory+addIntrRuleACs rs' = modify (thyCache) (\rs -> nub $ rs ++ rs')+++------------------------------------------------------------------------------+-- Closed theory querying / construction / modification+------------------------------------------------------------------------------++-- querying+-----------++-- | All lemmas.+getLemmas :: ClosedTheory -> [Lemma IncrementalProof]+getLemmas = theoryLemmas++-- | The variants of the intruder rules.+getIntrVariants :: ClosedTheory -> [IntrRuleAC]+getIntrVariants = intruderRules . L.get (crcRules . thyCache)++-- | All protocol rules modulo E.+getProtoRuleEs :: ClosedTheory -> [ProtoRuleE]+getProtoRuleEs = map openProtoRule . theoryRules ++-- | Get the proof context for a lemma of the closed theory.+getProofContext :: CaseDistKind -> ClosedTheory -> ProofContext+getProofContext kind thy = ProofContext+ ( L.get thySignature thy)+ ( L.get (crcRules . thyCache) thy)+ ( L.get (cases . thyCache) thy)+ where+ cases = case kind of UntypedCaseDist -> crcUntypedCaseDists+ TypedCaseDist -> crcTypedCaseDists++-- | The classified set of rules modulo AC in this theory.+getClassifiedRules :: ClosedTheory -> ClassifiedRules+getClassifiedRules = L.get (crcRules . thyCache)++-- | The precomputed case distinctions.+getCaseDistinction :: CaseDistKind -> ClosedTheory -> [CaseDistinction]+getCaseDistinction UntypedCaseDist = L.get (crcUntypedCaseDists . thyCache)+getCaseDistinction TypedCaseDist = L.get (crcTypedCaseDists . thyCache)+++-- construction+---------------++-- | Close a theory by closing its associated rule set and converting the proof+-- skeletons to unannotated incremental proofs and caching AC variants as well+-- as precomputed case distinctions.+-- +-- This function initializes the relation to the Maude process with the+-- correct signature. This is the right place to do that because in a closed +-- theory the signature may not change any longer.+closeTheory :: FilePath -- ^ Path to the Maude executable.+ -> OpenTheory+ -> IO ClosedTheory+closeTheory maudePath thy0 = do+ sig <- toSignatureWithMaude maudePath $ L.get thySignature thy0+ let cache = closeRuleCache typAsms sig rules $ L.get thyCache thy0+ addSorrys = checkAndExtendProver (sorryProver "not yet proven")++ -- Maude / Signature handle+ hnd = L.get sigmMaudeHandle sig++ -- close all theory items: in parallel+ items = (closeTheoryItem <$> L.get thyItems thy0) `using` parList rdeepseq+ closeTheoryItem = foldTheoryItem + (RuleItem . closeProtoRule hnd) + (LemmaItem . ensureFormulaAC . fmap skeletonToIncrementalProof)+ TextItem++ -- extract typing lemmas+ typAsms = do + LemmaItem lem <- items+ guard (TypingLemma `elem` L.get lAttributes lem)+ let toGuarded = fmap negateGuarded . fromFormulaNegate+ case toGuarded <$> L.get lFormulaAC lem of+ Just (Right gf) -> return gf+ Just (Left err) -> error $ "closeTheory: " ++ err+ _ -> mzero++ -- extract protocol rules+ rules = theoryRules (Theory errClose errClose errClose items)+ errClose = error "closeTheory"++ return $ proveTheory addSorrys $ Theory (L.get thyName thy0) sig cache items+++-- Applying provers+-------------------++-- | A list of proof methods that could be applied to the given sequent.+applicableProofMethods :: ClosedTheory -> Sequent -> [ProofMethod]+applicableProofMethods thy se = do+ m <- possibleProofMethods (L.get pcSignature ctxt) se+ guard (isJust $ execProofMethod ctxt m se)+ return m+ where+ ctxt = getProofContext (L.get sCaseDistKind se) thy++-- | Prove both the assertion soundness as well as all lemmas of the theory. If+-- the prover fails on a lemma, then its proof remains unchanged.+proveTheory :: Prover -> ClosedTheory -> ClosedTheory+proveTheory prover thy = + modify thyItems ((`MS.evalState` []) . mapM prove) thy+ where+ prove item = case item of+ LemmaItem l0 -> do l <- MS.gets (LemmaItem . proveLemma l0)+ MS.modify (l :)+ return l+ _ -> do return item++ proveLemma l0 preItems =+ modify lProof add l+ where+ l = ensureFormulaAC l0+ kind = lemmaCaseDistKind l+ se = formulaToSequent kind preItems $ fromJust $ L.get lFormulaAC l+ ctxt = getProofContext kind thy+ add prf = fromMaybe prf $ runProver prover ctxt se prf++-- | Convert a formula modulo AC to a sequent.+formulaToSequent :: CaseDistKind -> [TheoryItem r p] -> FormulaAC -> Sequent+formulaToSequent kind lems = + addLemmasToSequent lems . sequentFromFormula kind++-- | Add the lemmas that have an associated AC variant to this sequent.+addLemmasToSequent :: [TheoryItem r p] -> Sequent -> Sequent+addLemmasToSequent items se = + modify sLemmas (S.union gfs) se + where+ gfs = S.fromList $ gatherReusableLemmas (L.get sCaseDistKind se) items++-- | Gather reusable lemmas to be added to a sequent.+gatherReusableLemmas :: CaseDistKind -> [TheoryItem r p] -> [LNGuarded]+gatherReusableLemmas kind items = do+ LemmaItem lem <- items+ guard $ lemmaCaseDistKind lem <= kind && + ReuseLemma `elem` L.get lAttributes lem+ Just (Right gf) <- [fromFormula <$> L.get lFormulaAC lem]+ return gf++-- | Ensure that the AC variant of a formula is present.+ensureFormulaAC :: Lemma p -> Lemma p+ensureFormulaAC l =+ set lFormulaAC (Just fmAC) l+ where+ -- FIXME: AC-variant of formula is formula itself.+ -- This is ensured by well-formed check (not implemented yet).+ fmAC = fromMaybe (L.get lFormulaE l) $ L.get lFormulaAC l+++------------------------------------------------------------------------------+-- References to lemmas+------------------------------------------------------------------------------++-- | Lemmas are referenced by their name.+type LemmaRef = String++-- | Resolve a path in a theory. +lookupLemmaProof :: LemmaRef -> ClosedTheory -> Maybe IncrementalProof+lookupLemmaProof name thy = L.get lProof <$> lookupLemma name thy++-- | Modify the proof at the given lemma ref, if there is one. Fails if the+-- path is not present or if the prover fails.+modifyLemmaProof :: Prover -> LemmaRef -> ClosedTheory -> Maybe ClosedTheory+modifyLemmaProof prover name thy = + modA thyItems changeItems thy+ where+ findLemma (LemmaItem lem) = name == L.get lName lem+ findLemma _ = False++ change preItems (LemmaItem l0) = do+ let l1 = ensureFormulaAC l0+ kind = lemmaCaseDistKind l1+ ctxt = getProofContext kind thy+ se <- formulaToSequent kind preItems <$> L.get lFormulaAC l1+ l2 <- modA lProof (runProver prover ctxt se) l1+ return $ LemmaItem l2+ change _ _ = error "LemmaProof: change: impossible"++ changeItems items = case break findLemma items of+ (pre, i:post) -> do+ i' <- change pre i+ return $ pre ++ i':post+ (_, []) -> Nothing+++------------------------------------------------------------------------------+-- Pretty printing+------------------------------------------------------------------------------++-- | Pretty print a formal comment+prettyFormalComment :: HighlightDocument d => String -> String -> d+prettyFormalComment "" body = multiComment_ [body]+prettyFormalComment header body = text $ header ++ "{*" ++ body ++ "*}"++-- | Pretty print a theory.+prettyTheory :: HighlightDocument d + => (sig -> d) -> (c -> d) -> (r -> d) -> (p -> d)+ -> Theory sig c r p -> d+prettyTheory ppSig ppCache ppRule ppPrf thy = vsep $+ [ kwTheoryHeader $ L.get thyName thy+ , lineComment_ "Function signature and definition of the equational theory E"+ , ppSig $ L.get thySignature thy+ , ppCache $ L.get thyCache thy + ] +++ parMap rdeepseq ppItem (L.get thyItems thy) +++ [ kwEnd ]+ where+ ppItem = foldTheoryItem + ppRule (prettyLemma ppPrf) (\(h,c) -> prettyFormalComment h c)++-- | Pretty print the lemma name together with its attributes.+prettyLemmaName :: HighlightDocument d => Lemma p -> d+prettyLemmaName l = case L.get lAttributes l of+ [] -> text (L.get lName l)+ as -> text (L.get lName l) <->+ (brackets $ fsep $ punctuate comma $ map prettyLemmaAttribute as)+ where+ prettyLemmaAttribute TypingLemma = text "typing"+ prettyLemmaAttribute ReuseLemma = text "reuse"++-- | Pretty print a lemma.+prettyLemma :: HighlightDocument d => (p -> d) -> Lemma p -> d+prettyLemma ppPrf l =+ kwLemmaModulo "E" <-> prettyLemmaName l <> colon $-$ + (nest 2 $ doubleQuotes $ prettyFormulaE $ L.get lFormulaE l)+ $-$+ maybe emptyDoc ppFormulaAC (L.get lFormulaAC l)+ $-$+ maybe emptyDoc ppFormulaACGuarded (L.get lFormulaAC l)+ -- $-$+ -- maybe emptyDoc ppFormulaACInduction (L.get lFormulaAC l)+ $-$+ ppPrf (L.get lProof l)+ where+ ppFormulaAC fmAC+ | fmAC == L.get lFormulaE l = multiComment_ ["proof based on the same lemma modulo AC"]+ | otherwise =+ multiComment+ ( text "proof based on the following equivalent lemma modulo AC:" $-$+ doubleQuotes (prettyFormulaAC fmAC) )++ ppFormulaACGuarded fmAC = case fromFormulaNegate fmAC of+ Left err -> multiComment_ + ["conversion to doubly-guarded formula failed:", err]+ Right gf -> multiComment+ ( text "guarded formula characterizing all attacks:" $-$+ doubleQuotes (prettyGuarded gf) )++ {-+ ppFormulaACInduction fmAC = case fmInd of+ Left err -> multiComment_ + ["formula cannot be proven by induction:", err]+ Right gf -> multiComment+ ( text "proof by induction possible over the formula:" $-$+ doubleQuotes (prettyGuarded gf) )+ where+ fmInd = applyInduction =<< fromFormulaNegate fmAC+ -}+{-+-- | Pretty-print a non-empty bunch of intruder rules.+prettyIntruderVariants :: HighlightDocument d => [IntrRuleAC] -> d+prettyIntruderVariants [] = multiComment $ vsep+ [ text "No intruder variants found. You can generate and cache them using the command"+ , nest 2 (text "tamarin-prover intruder -O")+ ]+prettyIntruderVariants vs = vcat . intersperse (text "") $ map prettyIntrRuleAC vs++-- | Pretty-print the intruder variants section.+prettyIntrVariantsSection :: HighlightDocument d => [IntrRuleAC] -> d+prettyIntrVariantsSection rules = + prettyFormalComment "section" " Finite Variants of the Intruder Rules " $--$+ nest 1 (prettyIntruderVariants rules)+-}++-- | Pretty print an open rule together with its assertion soundness proof.+prettyOpenProtoRule :: HighlightDocument d => OpenProtoRule -> d+prettyOpenProtoRule = prettyProtoRuleE++prettyIncrementalProof :: HighlightDocument d => IncrementalProof -> d+prettyIncrementalProof = prettyProofWith ppStep (const id)+ where+ ppStep step =+ (if isNothing (psInfo step) then text "!" else emptyDoc) <-> + prettyProofMethod (psMethod step)++-- | Pretty print an closed rule together with its assertion soundness proof.+prettyClosedProtoRule :: HighlightDocument d => ClosedProtoRule -> d+prettyClosedProtoRule cru =+ (prettyProtoRuleE $ L.get cprRuleE cru) $-$ + (nest 2 $ ppRuleAC $ L.get cprRuleAC cru)+ where+ ppRuleAC ru+ | isTrivialProtoRuleAC ru = multiComment_ ["has exactly the trivial AC variant"]+ | otherwise = multiComment $ prettyProtoRuleAC ru++-- | Pretty print an open theory.+prettyOpenTheory :: HighlightDocument d => OpenTheory -> d+prettyOpenTheory = + prettyTheory prettySignaturePure+ (const emptyDoc) prettyOpenProtoRule prettyProof+ -- prettyIntrVariantsSection prettyOpenProtoRule prettyProof++-- | Pretty print a closed theory.+prettyClosedTheory :: HighlightDocument d => ClosedTheory -> d+prettyClosedTheory = + prettyTheory prettySignatureWithMaude+ (const emptyDoc)+ -- (prettyIntrVariantsSection . intruderRules . L.get crcRules) + prettyClosedProtoRule+ prettyIncrementalProof++prettyClosedSummary :: Document d => ClosedTheory -> d+prettyClosedSummary thy =+ vcat lemmaSummaries+ where+ lemmaSummaries = do+ LemmaItem lem <- L.get thyItems thy+ let (status, Sum siz) = foldProof proofStepSummary $ L.get lProof lem+ return $ text (L.get lName lem) <> colon <-> + text (showProofStatus status) <->+ parens (integer siz <-> text "steps")++ proofStepSummary = proofStepStatus &&& const (Sum (1::Integer))++-- Instances: FIXME: Sort them into the right files+--------------------------------------------------++$( derive makeBinary ''TheoryItem)+$( derive makeBinary ''LemmaAttribute)+$( derive makeBinary ''Lemma)+$( derive makeBinary ''ClosedProtoRule)+$( derive makeBinary ''ClosedRuleCache)+$( derive makeBinary ''Theory)++$( derive makeNFData ''TheoryItem)+$( derive makeNFData ''LemmaAttribute)+$( derive makeNFData ''Lemma)+$( derive makeNFData ''ClosedProtoRule)+$( derive makeNFData ''ClosedRuleCache)+$( derive makeNFData ''Theory)+
@@ -0,0 +1,168 @@+{-# LANGUAGE StandaloneDeriving+ , FlexibleContexts+ , TypeSynonymInstances+ , FlexibleInstances+ , DeriveDataTypeable+ , TupleSections+ , TemplateHaskell+ #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+-- |+-- Copyright : (c) 2011, 2012 Benedikt Schmidt & Simon Meier+-- License : GPL v3 (see LICENSE)+-- +-- Maintainer : Simon Meier <iridcode@gmail.com>+-- Portability : GHC only+--+-- Formulas that represent security properties.+module Theory.Atom(++ -- * Atoms+ Atom(..)+ , NAtom+ , LNAtom++ -- * LFormula+ , BLVar+ , BLAtom++ -- * Pretty-Printing+ , prettyNAtom+ )+where++import Term.Rewriting.NormAC+import Theory.Fact+import Theory.Pretty++import Data.Monoid (mappend)+import Data.Foldable (Foldable, foldMap)+import Data.Traversable +import Data.Generics+import Data.DeriveTH+import Data.Binary++import Control.Basics+import Control.DeepSeq++------------------------------------------------------------------------------+-- Atoms+------------------------------------------------------------------------------++-- | @Atom@'s are the atoms of trace formulas parametrized over arbitrary+-- terms. +data Atom t = Action t (Fact t)+ | EqE t t+ | Less t t+ | Last t+ | DedBefore t t+ | EdgeA (t, Int) (t, Int)+ deriving( Eq, Ord, Show, Data, Typeable )++-- | @LAtom@ are the atoms we actually use in graph formulas input by the user.+type NAtom v = Atom (VTerm Name v)++-- | @LAtom@ are the atoms we actually use in graph formulas input by the user.+type LNAtom = Atom LNTerm++-- | 'LVar's combined with quantified variables. They occur only in 'LFormula's.+type BLVar = BVar LVar++-- | Terms built over names and 'LVar's combined with quantified variables.+type BLTerm = NTerm BLVar++-- | Atoms built over 'BLTerm's.+type BLAtom = Atom BLTerm+++-- Instances+------------++instance Functor Atom where+ fmap f (Action i fa) = Action (f i) (fmap f fa)+ fmap f (EqE l r) = EqE (f l) (f r)+ fmap f (Less v u) = Less (f v) (f u)+ fmap f (Last i) = Last (f i)+ fmap f (DedBefore t i) = DedBefore (f t) (f i)+ fmap f (EdgeA x y) = EdgeA (first f x) (first f y)++instance Foldable Atom where+ foldMap f (Action i fa) = + f i `mappend` (foldMap f fa)+ foldMap f (EqE l r) = f l `mappend` f r+ foldMap f (Less i j) = f i `mappend` f j+ foldMap f (Last i) = f i+ foldMap f (DedBefore t i) = f t `mappend` f i+ foldMap f (EdgeA x y) = f (fst x) `mappend` f (fst y)++instance Traversable Atom where+ traverse f (Action i fa) = + Action <$> f i <*> traverse f fa+ traverse f (EqE l r) = EqE <$> f l <*> f r+ traverse f (Less v u) = Less <$> f v <*> f u+ traverse f (Last i) = Last <$> f i+ traverse f (DedBefore t i) = DedBefore <$> f t <*> f i+ traverse f (EdgeA (x,i) (y,j)) = + EdgeA <$> ((,i) <$> f x) <*> ((,j) <$> f y)++instance HasFrees t => HasFrees (Atom t) where+ foldFrees f = foldMap (foldFrees f)+ mapFrees f = traverse (mapFrees f)++instance Apply LNAtom where+ apply subst (Action i fact) = Action (apply subst i) (apply subst fact)+ apply subst (EqE l r) = EqE (apply subst l) (apply subst r)+ apply subst (Less i j) = Less (apply subst i) (apply subst j)+ apply subst (Last i) = Last (apply subst i)+ apply subst (DedBefore t i) = DedBefore (apply subst t) (apply subst i)+ apply subst (EdgeA x y) = + EdgeA (first (apply subst) x) (first (apply subst) y)++instance Apply BLVar where+ apply _ x@(Bound _) = x+ apply subst x@(Free v) = maybe x extractVar $ imageOf subst v+ where+ extractVar (Lit (Var v')) = Free v'+ extractVar t = + error $ "apply (BLVar): variable '" ++ show v ++ + "' substituted with term '" ++ show t ++ "'"++instance Apply BLTerm where+ apply subst = normAC . (>>= applyBLLit)+ where+ applyBLLit :: Lit Name BLVar -> BLTerm+ applyBLLit l@(Var (Free v)) = + maybe (Lit l) (fmap (fmap Free)) (imageOf subst v)+ applyBLLit l = Lit l++instance Apply BLAtom where+ apply subst (Action i fact) = Action (apply subst i) (apply subst fact)+ apply subst (EqE l r) = EqE (apply subst l) (apply subst r)+ apply subst (Less i j) = Less (apply subst i) (apply subst j)+ apply subst (Last i) = Last (apply subst i)+ apply subst (DedBefore t i) = DedBefore (apply subst t) (apply subst i)+ apply subst (EdgeA x y) = + EdgeA (first (apply subst) x) (first (apply subst) y)+++------------------------------------------------------------------------------+-- Pretty-Printing+------------------------------------------------------------------------------++prettyNAtom :: (Show v, HighlightDocument d) => NAtom v -> d+prettyNAtom (Action v fa) = + prettyFact prettyNTerm fa <-> opAction <-> text (show v) +prettyNAtom (EqE l r) =+ sep [prettyNTerm l <-> opEqual, prettyNTerm r]+ -- sep [prettyNTerm l <-> text "≈", prettyNTerm r]+prettyNAtom (Less u v) = text (show u) <-> opLess <-> text (show v)+prettyNAtom (Last i) = operator_ "Last" <> parens (text (show i))+prettyNAtom (DedBefore t i) = text (show t) <-> opDedBefore <-> text (show i)+prettyNAtom (EdgeA x y) = text (show x) <-> opEdge <-> text (show y)+++-- derived instances+--------------------++$( derive makeNFData ''Atom)+$( derive makeBinary ''Atom)
@@ -0,0 +1,339 @@+{-# LANGUAGE TemplateHaskell, FlexibleContexts, DeriveDataTypeable #-}+-- |+-- Copyright : (c) 2011, 2012 Benedikt Schmidt & Simon Meier+-- License : GPL v3 (see LICENSE)+-- +-- Maintainer : Simon Meier <iridcode@gmail.com>+-- Portability : GHC only+--+-- Facts used to formulate and reason about protocol execution.+module Theory.Fact (++ -- * Fact+ Fact(..)+ , Multiplicity(..)+ , FactTag(..)++ -- ** Queries+ , isLinearFact + , isPersistentFact+ , isProtoFact++ , showFactTag+ , showFactTagArity+ , factTagArity+ , factTagMultiplicity+ , factArity+ , factMultiplicity++ -- ** Message deduction facts+ , ExpTag(..)+ , expTagToTerm+ , termToExpTag++ , DirTag(..)+ , kFactView+ , isKFact+ , kuFact+ , kdFact++ -- ** Construction+ , freshFact+ , outFact+ , inFact+ , kLogFact+ , protoFact++ -- * NFact+ , NFact++ -- * LFact+ , LFact+ , LNFact+ , unifyLNFactEqs+ , matchLNFact++ -- * Pretty-Printing+ + , prettyFact+ , prettyNFact+ , prettyLNFact++ -- * Convenience exports+ , module Term.Unification++ ) where++import Control.Basics+import Control.Monad.Fresh+import Control.DeepSeq++import Data.DeriveTH+import Data.Foldable (Foldable(..))+import Data.Traversable (Traversable(..))+import Data.Binary+import Data.Generics +import Data.Maybe (isJust)++import Term.Unification++import Text.Isar+++------------------------------------------------------------------------------+-- Fact+------------------------------------------------------------------------------++data Multiplicity = Persistent | Linear+ deriving( Eq, Ord, Show, Typeable, Data )++-- | Fact tags/symbols+data FactTag = ProtoFact Multiplicity String Int+ -- ^ A protocol fact together with its arity and multiplicity.+ | FreshFact -- ^ Freshly generated value.+ | OutFact -- ^ Sent by the protocol+ | InFact -- ^ Officially known by the intruder/network.+ | KUFact -- ^ Up-knowledge fact in messsage deduction.+ | KDFact -- ^ Down-knowledge fact in message deduction.+ deriving( Eq, Ord, Show, Typeable, Data )++-- | Facts.+data Fact t = Fact + { factTag :: FactTag + , factTerms :: [t]+ }+ deriving( Eq, Ord, Show, Typeable, Data )+++-- Instances+------------++instance Functor Fact where+ fmap f (Fact tag ts) = Fact tag (fmap f ts)++instance Foldable Fact where+ foldMap f (Fact _ ts) = foldMap f ts+ +instance Traversable Fact where+ sequenceA (Fact tag ts) = Fact tag <$> sequenceA ts+ traverse f (Fact tag ts) = Fact tag <$> traverse f ts++instance Sized t => Sized (Fact t) where+ size (Fact _ args) = size args++instance HasFrees t => HasFrees (Fact t) where+ foldFrees f = foldMap (foldFrees f)+ mapFrees f = traverse (mapFrees f)++instance Apply t => Apply (Fact t) where+ apply subst = fmap (apply subst)+++-- KU and KD facts+------------------++-- | Message fact exponentation tag.+data ExpTag = IsExp | IsNoExp+ deriving( Eq, Ord, Show)++-- | Exponentiation-symbol to term.+expTagToTerm :: ExpTag -> LNTerm+expTagToTerm IsExp = Lit (Con (Name PubName (NameId ("exp"))))+expTagToTerm IsNoExp = Lit (Con (Name PubName (NameId ("noexp"))))++-- | Term to exponentiation-symbol.+termToExpTag :: LNTerm -> Maybe ExpTag+termToExpTag (Lit (Con (Name PubName (NameId ("exp"))))) = return IsExp+termToExpTag (Lit (Con (Name PubName (NameId ("noexp"))))) = return IsNoExp+termToExpTag _ = mzero+++-- | A direction tag +data DirTag = UpK | DnK+ deriving( Eq, Ord, Show )++-- | Construct a message fact. If no 'ExpTag' is given, then+-- a fresh variable that matches any 'ExpTag' is constructed.+kuFact, kdFact :: MonadFresh m => Maybe ExpTag -> LNTerm -> m LNFact+kuFact = mkFact KUFact+kdFact = mkFact KDFact++-- | A generic fact creation function.+mkFact :: MonadFresh m => FactTag -> Maybe ExpTag -> LNTerm -> m LNFact+mkFact tag (Just t) m = return $ Fact tag [expTagToTerm t, m]+mkFact tag Nothing m = do+ v <- freshLVar "f_" LSortMsg+ return $ Fact tag [varTerm v, m]++-- | View a message-deduction fact.+kFactView :: LNFact -> Maybe (DirTag, Maybe ExpTag, LNTerm)+kFactView fa = case fa of+ Fact KUFact [e, m] -> Just (UpK, termToExpTag e, m)+ Fact KUFact _ -> errMalformed+ Fact KDFact [e, m] -> Just (DnK, termToExpTag e, m)+ Fact KDFact _ -> errMalformed+ _ -> Nothing+ where+ errMalformed = error $ show "viewKFact: malformed fact: " ++ show fa++-- | True if the fact is a message-deduction fact.+isKFact :: LNFact -> Bool+isKFact = isJust . kFactView++-- Constructing facts+---------------------++-- | A fact denoting a message sent by the protocol to the intruder.+outFact :: t -> Fact t+outFact = Fact OutFact . return++-- | A fresh fact denotes a fresh unguessable name.+freshFact :: t -> Fact t+freshFact = Fact FreshFact . return++-- | A fact denoting that the intruder sent a message to the protocol.+inFact :: t -> Fact t+inFact = Fact InFact . return++-- | A fact logging that the intruder knows a message.+kLogFact :: t -> Fact t+kLogFact = protoFact Linear "K" . return++-- | A protocol fact denotes a fact generated by a protocol rule.+protoFact :: Multiplicity -> String -> [t] -> Fact t+protoFact multi name ts = Fact (ProtoFact multi name (length ts)) ts+++-- Queries on facts+-------------------++-- | True iff the fact is a non-special protocol fact.+isProtoFact :: Fact t -> Bool+isProtoFact (Fact (ProtoFact _ _ _) _) = True+isProtoFact _ = False++-- | True if the fact is a linear fact.+isLinearFact :: Fact t -> Bool+isLinearFact = (Linear ==) . factMultiplicity++-- | True if the fact is a persistent fact.+isPersistentFact :: Fact t -> Bool+isPersistentFact = (Persistent ==) . factMultiplicity++-- | The multiplicity of a 'FactTag'.+factTagMultiplicity :: FactTag -> Multiplicity+factTagMultiplicity tag = case tag of + ProtoFact multi _ _ -> multi+ KUFact -> Persistent+ KDFact -> Persistent+ _ -> Linear++-- | The arity of a 'FactTag'.+factTagArity :: FactTag -> Int+factTagArity tag = case tag of + ProtoFact _ _ k -> k+ KUFact -> 2+ KDFact -> 2+ FreshFact -> 1+ InFact -> 1+ OutFact -> 1++-- | The arity of a 'Fact'.+factArity :: Fact t -> Int+factArity (Fact tag ts)+ | length ts == k = k+ | otherwise = error $ "factArity: tag of arity " ++ show k ++ + " applied to " ++ show (length ts) ++ " terms"+ where+ k = factTagArity tag++-- | The multiplicity of a 'Fact'.+factMultiplicity :: Fact t -> Multiplicity+factMultiplicity = factTagMultiplicity . factTag+++------------------------------------------------------------------------------+-- NFact+------------------------------------------------------------------------------++-- | Facts with literals containing names and arbitrary variables.+type NFact v = Fact (NTerm v)+++------------------------------------------------------------------------------+-- LFact+------------------------------------------------------------------------------++-- | Facts with literals arbitrary constants and logical variables.+type LFact c = Fact (LTerm c)++-- | Facts used for proving; i.e. variables fixed to logical variables+-- and constant fixed to names.+type LNFact = Fact LNTerm++-- | Unify a list of @LFact@ equalities.+unifyLNFactEqs :: [Equal LNFact] -> WithMaude [LNSubstVFresh]+unifyLNFactEqs eqs + -- TODO: Check if the arity of the facts is also checked.+ | all (evalEqual . fmap factTag) eqs = + unifyLNTerm (map (fmap (listToTerm . factTerms)) eqs)+ | otherwise = return []+ +-- | @matchLFact t p@ is a complete set of AC matchers for the term fact @t@+-- and the pattern fact @p@.+matchLNFact :: LNFact -- ^ Term+ -> LNFact -- ^ Pattern+ -> WithMaude [LNSubst]+matchLNFact t p+ | (factTag t == factTag p && length (factTerms t) == length (factTerms p)) =+ matchLNTerm $ zipWith MatchWith (factTerms t) (factTerms p)+ | otherwise = return []+++------------------------------------------------------------------------------+-- Pretty Printing+------------------------------------------------------------------------------++-- | Show a fact tag as a 'String'.+showFactTag :: FactTag -> String+showFactTag tag = case tag of+ KUFact -> "!KU"+ KDFact -> "!KD"+ InFact -> "In"+ OutFact -> "Out"+ FreshFact -> "Fr"+ (ProtoFact m n _) -> multi m ++ n+ where+ multi Linear = ""+ multi Persistent = "!"++-- | Show a fact tag together with its aritiy.+showFactTagArity :: FactTag -> String+showFactTagArity tag = showFactTag tag ++ "/" ++ show (factTagArity tag)++-- | Pretty print a fact.+prettyFact :: Document d => (t -> d) -> Fact t -> d+prettyFact ppTerm (Fact tag ts)+ | factTagArity tag /= length ts = ppFact ("MALFORMED-" ++ show tag) ts+ | otherwise = ppFact (showFactTag tag) ts+ where+ ppFact n = nestShort' (n ++ "(") ")" . fsep . punctuate comma . map ppTerm++-- | Pretty print a 'NFact'.+prettyNFact :: Document d => LNFact -> d+prettyNFact = prettyFact prettyNTerm++-- | Pretty print a 'LFact'.+prettyLNFact :: Document d => LNFact -> d+prettyLNFact fa = prettyFact prettyNTerm fa++-- derived instances+--------------------++$( derive makeBinary ''Multiplicity)+$( derive makeBinary ''FactTag)+$( derive makeBinary ''Fact)++$( derive makeNFData ''Multiplicity)+$( derive makeNFData ''FactTag)+$( derive makeNFData ''Fact)
@@ -0,0 +1,317 @@+{-# LANGUAGE DeriveDataTypeable, FlexibleContexts, BangPatterns, StandaloneDeriving #-}+{-# LANGUAGE TemplateHaskell, FlexibleInstances, TypeSynonymInstances #-}+-- |+-- Copyright : (c) 2010-2012 Simon Meier & Benedikt Schmidt+-- License : GPL v3 (see LICENSE)+-- +-- Maintainer : Simon Meier <iridcode@gmail.com>+-- Portability : GHC only+--+-- Types and operations for handling sorted first-order logic+module Theory.Formula (++ -- * Formulas+ Connective(..)+ , Quantifier(..)+ , Formula(..)+ , LNFormula+ , LFormula+ , FormulaE+ , FormulaAC++ , quantify+ , openFormula+ , openFormulaPrefix+-- , unquantify++ -- ** More convenient constructors+ , lfalse+ , ltrue+ , (.&&.)+ , (.||.)+ , (.==>.)+ , (.<=>.)+ , exists+ , forall++ -- ** General Transformations+ , mapAtoms+ , foldFormula++ -- ** Pretty-Printing+ , prettyFormulaE+ , prettyFormulaAC++ -- * Convenience exports+ , module Theory.Atom++ ) where++import Prelude hiding (negate)++import Data.Monoid hiding (All)+import Data.Foldable (Foldable, foldMap)+import Data.Traversable+import Data.Generics+import Data.DeriveTH+import Data.Binary++import Control.DeepSeq+import Control.Basics+import Control.Monad.Fresh++import Theory.Atom++import Text.PrettyPrint.Highlight++import Term.LTerm+import Term.Substitution++------------------------------------------------------------------------------+-- Types+------------------------------------------------------------------------------++-- | Logical connectives.+data Connective = And | Or | Imp | Iff+ deriving( Eq, Ord, Show, Enum, Bounded, Data, Typeable )++-- | Quantifiers.+data Quantifier = All | Ex+ deriving( Eq, Ord, Show, Enum, Bounded, Data, Typeable )+++-- | First-order formulas in locally nameless representation with hints for the+-- names/sorts of quantified variables.+data Formula s c v = Ato (Atom (VTerm c (BVar v)))+ | TF !Bool+ | Not (Formula s c v)+ | Conn !Connective (Formula s c v) (Formula s c v)+ | Qua !Quantifier s (Formula s c v)++-- Folding+----------++-- | Fold a formula.+{-# INLINE foldFormula #-}+foldFormula :: (Atom (VTerm c (BVar v)) -> b) -> (Bool -> b) + -> (b -> b) -> (Connective -> b -> b -> b)+ -> (Quantifier -> s -> b -> b)+ -> Formula s c v+ -> b+foldFormula fAto fTF fNot fConn fQua = + go+ where+ go (Ato a) = fAto a+ go (TF b) = fTF b+ go (Not p) = fNot (go p)+ go (Conn c p q) = fConn c (go p) (go q)+ go (Qua qua x p) = fQua qua x (go p)++-- | Fold a formula.+{-# INLINE foldFormulaScope #-}+foldFormulaScope :: (Int -> Atom (VTerm c (BVar v)) -> b) -> (Bool -> b)+ -> (b -> b) -> (Connective -> b -> b -> b)+ -> (Quantifier -> s -> b -> b)+ -> Formula s c v+ -> b+foldFormulaScope fAto fTF fNot fConn fQua =+ go 0+ where+ go !i (Ato a) = fAto i a+ go _ (TF b) = fTF b+ go !i (Not p) = fNot (go i p)+ go !i (Conn c p q) = fConn c (go i p) (go i q)+ go !i (Qua qua x p) = fQua qua x (go (succ i) p)+++-- Instances+------------+++instance Functor (Formula s c) where+ fmap f = foldFormula (Ato . fmap (fmap (fmap (fmap f)))) TF Not Conn Qua++instance Foldable (Formula s c) where+ foldMap f = foldFormula (foldMap (foldMap (foldMap (foldMap f)))) mempty id + (const mappend) (const $ const id)++instance Traversable (Formula a s) where+ traverse f = foldFormula (liftA Ato . traverse (traverse (traverse (traverse f))))+ (pure . TF) (liftA Not)+ (liftA2 . Conn) ((liftA .) . Qua)+++-- Abbreviations+----------------+ +infixl 3 .&&.+infixl 2 .||.+infixr 1 .==>.+infix 1 .<=>.++-- | Logically true.+ltrue :: Formula a s v+ltrue = TF True++-- | Logically false.+lfalse :: Formula a s v+lfalse = TF False++(.&&.), (.||.), (.==>.), (.<=>.) :: Formula a s v -> Formula a s v -> Formula a s v+(.&&.) = Conn And+(.||.) = Conn Or+(.==>.) = Conn Imp+(.<=>.) = Conn Iff++------------------------------------------------------------------------------+-- Dealing with bound variables+------------------------------------------------------------------------------++-- | @LFormula@ are FOL formulas with sorts abused to denote both a hint for+-- the name of the bound variable, as well as the variable's actual sort.+type LFormula c = Formula (String, LSort) c LVar++type LNFormula = Formula (String, LSort) Name LVar++-- | Change the representation of atoms.+mapAtoms :: (Int -> Atom (VTerm c (BVar v))+ -> Atom (VTerm c1 (BVar v1)))+ -> Formula s c v -> Formula s c1 v1+mapAtoms f = foldFormulaScope (\i a -> Ato $ f i a) TF Not Conn Qua++-- | @openFormula f@ returns @Just (v,Q,f')@ if @f = Q v. f'@ modulo+-- alpha renaming and @Nothing otherwise@. @v@ is always chosen to be fresh.+openFormula :: (MonadFresh m)+ => LFormula c -> Maybe (Quantifier, m (LVar, LFormula c))+openFormula (Qua qua (n,s) fm) = + Just ( qua+ , do x <- freshLVar n s+ return $ (x, mapAtoms (\i a -> fmap (fmap (subst x i)) a) fm)+ )+ where+ subst x i (Var (Bound i')) | i == i' = Var $ Free x+ subst _ _ l = l++openFormula _ = Nothing+++-- | @openFormulaPrefix f@ returns @Just (vs,Q,f')@ if @f = Q v_1 .. v_k. f'@+-- modulo alpha renaming and @Nothing otherwise@. @vs@ is always chosen to be+-- fresh.+openFormulaPrefix :: (MonadFresh m)+ => LFormula c -> m ([LVar], Quantifier, LFormula c)+openFormulaPrefix f0 = case openFormula f0 of+ Nothing -> error $ "openFormulaPrefix: no outermost quantifier"+ Just (q, open) -> do + (x, f) <- open+ go q [x] f+ where+ go q xs f = case openFormula f of+ Just (q', open') | q' == q -> do (x', f') <- open'+ go q (x' : xs) f'+ -- no further quantifier of the same kind => return result+ _ -> return (reverse xs, q, f)+++-- Instances+------------++deriving instance Eq LNFormula+deriving instance Show LNFormula+deriving instance Ord LNFormula++instance HasFrees LNFormula where+ foldFrees f = foldMap (foldFrees f)+ mapFrees f = traverse (mapFrees f)++instance Apply LNFormula where+ apply subst = mapAtoms (const $ apply subst)++------------------------------------------------------------------------------+-- Formulas modulo E and modulo AC+------------------------------------------------------------------------------++type FormulaE = LFormula Name+type FormulaAC = LFormula Name++-- | Introduce a bound variable for a free variable.+quantify :: Eq v => v -> Formula s c v -> Formula s c v+quantify x =+ mapAtoms (\i a -> fmap (fmap (fmap (>>= (subst i)))) a)+ where+ subst i v | v == x = Bound i+ | otherwise = Free v++-- | Create a universal quantification with a sort hint for the bound variable.+forall :: Eq v => s -> v -> Formula s c v -> Formula s c v+forall hint x = Qua All hint . quantify x++-- | Create a existential quantification with a sort hint for the bound variable.+exists :: Eq v => s -> v -> Formula s c v -> Formula s c v+exists hint x = Qua Ex hint . quantify x++------------------------------------------------------------------------------+-- Pretty printing+------------------------------------------------------------------------------++-- | Pretty print a formula.+prettyLFormula :: (HighlightDocument d, MonadFresh m) + => (Atom (VTerm c LVar) -> d) -- ^ Function for pretty printing atoms+ -> LFormula c -- ^ Formula to pretty print.+ -> m d -- ^ Pretty printed formula.+prettyLFormula ppAtom =+ pp+ where+ extractFree (Free v) = v+ extractFree (Bound i) = error $ "prettyFormula: illegal bound variable '" ++ show i ++ "'"++ pp (Ato a) = return $ ppAtom (fmap (fmap (fmap extractFree)) a)+ pp (TF True) = return $ operator_ "T" -- "⊤" + pp (TF False) = return $ operator_ "F" -- "⊥" ++ pp (Not p) = do+ p' <- pp p+ return $ operator_ "not" <> opParens p' -- text "¬" <> parens (pp a)++ pp (Conn op p q) = do+ p' <- pp p+ q' <- pp q+ return $ sep [opParens p' <-> operator_ (ppOp op), opParens q']+ where+ ppOp And = "&" -- "∧"+ ppOp Or = "|" -- "∨"+ ppOp Imp = "==>" -- "⇒"+ ppOp Iff = "<=>" -- "⇔"++ pp fm@(Qua _ _ _) = do+ (vs,qua,fm') <- openFormulaPrefix fm+ d' <- pp fm' + return $ sep + [ operator_ (ppQuant qua) <> ppVars vs <> operator_ "."+ , nest 1 d']+ where+ ppVars = fsep . map (text . show)++ ppQuant All = "All " -- "∀"+ ppQuant Ex = "Ex " -- "∃"++prettyFormulaAC, prettyFormulaE :: HighlightDocument d => FormulaE -> d+prettyFormulaE = prettyLNFormula+prettyFormulaAC = prettyLNFormula++-- | Pretty print a logical formula+prettyLNFormula :: HighlightDocument d => LNFormula -> d+prettyLNFormula fm = + prettyLFormula prettyNAtom fm `evalFreshAvoiding` fm+++-- Derived instances+--------------------++$( derive makeBinary ''Connective)+$( derive makeBinary ''Quantifier)+$( derive makeBinary ''Formula)++$( derive makeNFData ''Connective)+$( derive makeNFData ''Quantifier)+$( derive makeNFData ''Formula)
@@ -0,0 +1,222 @@+{-# LANGUAGE FlexibleContexts #-}+-- |+-- Copyright : (c) 2010-2012 Benedikt Schmidt+-- License : GPL v3 (see LICENSE)+-- +-- Maintainer : Benedikt Schmidt <beschmi@gmail.com>+-- Portability : GHC only+--+module Theory.IntruderRules (+ subtermIntruderRules+ , dhIntruderRules+ , specialIntruderRules+-- , xorIntruderRules -- there are no multiset intruder rules+ ) where++import Theory.Rule+import Term.SubtermRule+import Term.Positions+import Term.Rewriting.Norm+import Term.Narrowing.Variants.Compute++import Utils.Misc++import Control.Monad.Fresh+import Data.List+import Control.Basics+import Extension.Data.Label++import Control.Monad.Reader++++-- Variants of intruder deduction rules+----------------------------------------------------------------------+++------------------------------------------------------------------------------+-- Special Intruder rules+------------------------------------------------------------------------------++{-+These are the special intruder that are always included.++rule (modulo AC) coerce:+ [ KD( f_, x ) ] --> [ KU( f_, x ) ]++rule (modulo AC) pub:+ [ ] --> [ KU( f_, $x ) ]++rule (modulo AC) gen_fresh:+ [ Fr( ~x ) ] --> [ KU( 'noexp', ~x ) ]++rule (modulo AC) isend:+ [ KU( f_, x) ] --[ K(x) ]-> [ In(x) ]++-}+specialIntruderRules :: [IntrRuleAC]+specialIntruderRules =+ [ Rule CoerceRule+ [Fact KDFact [f_var, x_var]]+ [Fact KUFact [f_var,x_var]]+ []+ , Rule (IntrApp "pub")+ []+ [Fact KUFact [f_var,x_pub_var]]+ [] + , Rule (IntrApp "fresh")+ [Fact FreshFact [x_fresh_var]]+ [Fact KUFact [f_var,x_fresh_var]]+ []+ , Rule (IntrApp "isend")+ [Fact KUFact [f_var, x_var]]+ [Fact InFact [x_var]]+ [protoFact Linear "K" [x_var]]+ ]+ where+ f_var = varTerm (LVar "f_" LSortMsg 0)+ x_var = varTerm (LVar "x" LSortMsg 0)+ x_pub_var = varTerm (LVar "x" LSortPub 0)+ x_fresh_var = varTerm (LVar "x" LSortFresh 0)++------------------------------------------------------------------------------+-- Subterm Intruder theory+------------------------------------------------------------------------------++destructionRules :: StRule -> [IntrRuleAC]+destructionRules (StRule lhs@(FApp (NonAC (f,_)) _) (RhsPosition pos)) =+ go [] lhs pos+ where+ rhs = lhs >* pos+ go _ _ [] = []+ -- term already in premises+ go _ (FApp _ _) (_:[]) = []+ go uprems (FApp _ as) (i:p) =+ irule ++ go uprems' t' p+ where+ uprems' = uprems++[ t | (j, t) <- zip [0..] as, i /= j ]+ t' = as!!i+ irule = if (t' /= rhs && rhs `notElem` uprems')+ then (`evalFresh` avoid ([rhs,t']++uprems')) $ do+ dfact <- kdFact Nothing t'+ ufacts <- mapM (kuFact Nothing) uprems'+ concfact <- kdFact Nothing rhs+ return [ Rule (IntrApp f) (dfact:ufacts) [concfact] [] ]+ else []+ go _ (Lit _) (_:_) =+ error "IntruderRules.destructionRules: impossible, position invalid"++destructionRules _ = []++-- | Simple removal of subsumed rules for auto-generated free intruder rules.+minimizeIntruderRules :: [IntrRuleAC] -> [IntrRuleAC]+minimizeIntruderRules rules =+ go [] rules+ where+ go checked [] = reverse checked+ go checked (r@(Rule _ prems concs _):unchecked) = go checked' unchecked+ where + checked' = if any (\(Rule _ prems' concs' _)+ -> map dropExpTag concs' == map dropExpTag concs &&+ map dropExpTag prems' `subsetOf` map dropExpTag prems)+ (checked++unchecked)+ then checked+ else (r:checked)++-- | @freeIntruderRules rus@ returns the set of intruder rules for+-- the free (not Xor, DH, and MSet) part of the given signature.+subtermIntruderRules :: MaudeSig -> [IntrRuleAC]+subtermIntruderRules maudeSig =+ minimizeIntruderRules $ concatMap destructionRules (stRules maudeSig)+ ++ constructionRules (funSig maudeSig)++constructionRules :: FunSig -> [IntrRuleAC]+constructionRules fSig =+ [ createRule s k | (s,k) <- fSig ]+ where+ createRule s k = (`evalFresh` nothingUsed) $ do+ vars <- map varTerm <$> (sequence $ replicate k (freshLVar "x" LSortMsg))+ pfacts <- mapM (kuFact Nothing) vars+ concfact <- kuFact (Just IsNoExp) (FApp (NonAC (s,k)) vars)+ return $ Rule (IntrApp s) pfacts [concfact] []++dropExpTag :: Fact a -> Fact a+dropExpTag (Fact KUFact [_e,m]) = Fact KUFact [m]+dropExpTag (Fact KDFact [_e,m]) = Fact KDFact [m]+dropExpTag t = t++------------------------------------------------------------------------------+-- Diffie-Hellman Intruder Rules+------------------------------------------------------------------------------++dhIntruderRules :: WithMaude [IntrRuleAC]+dhIntruderRules = reader $ \hnd -> minimizeIntruderRules $+ [expRule True, invRule True]+ ++ concatMap (variants hnd) [expRule False, invRule False]+ where+ expRule isConstr = (`evalFresh` nothingUsed) $ do+ b <- varTerm <$> freshLVar "x" LSortMsg+ e <- varTerm <$> freshLVar "x" LSortMsg+ bfact <- fact isConstr (Just IsNoExp) b+ efact <- kuFact Nothing e+ concfact <- fact isConstr (Just IsExp) (FApp (NonAC ("exp",2)) [b, e])+ return $ Rule (IntrApp "exp") [bfact, efact] [concfact] []++ invRule isConstr = (`evalFresh` nothingUsed) $ do+ x <- varTerm <$> freshLVar "x" LSortMsg+ bfact <- fact isConstr Nothing x+ concfact <- fact isConstr (Just IsNoExp) (FApp (NonAC invSym) [x])+ return $ Rule (IntrApp "inv") [bfact] [concfact] []++ fact True = kuFact+ fact False = kdFact++ variants hnd ru = do+ let concTerms = concatMap factTerms+ (get rPrems ru++get rConcs ru++get rActs ru)+ fsigma <- computeVariants (listToTerm concTerms) `runReader` hnd+ let sigma = freshToFree fsigma `evalFreshAvoiding` concTerms+ ruvariant = normRule' (apply sigma ru) `runReader` hnd+ guard (frees (get rConcs ruvariant) /= [] &&+ -- ground terms are already deducible by applying construction rules+ ruvariant /= ru &&+ -- this is a construction rule+ (map dropExpTag (get rConcs ruvariant))+ \\ (map dropExpTag (get rPrems ruvariant)) /= []+ -- The conclusion is included in the premises+ )++ case concatMap factTerms $ get rConcs ruvariant of+ [_, FApp (AC Mult) _] ->+ fail "Rules with product conclusion are redundant"+ _ -> return ruvariant+++normRule' :: IntrRuleAC -> WithMaude IntrRuleAC+normRule' (Rule i ps cs as) = reader $ \hnd ->+ let normFactTerms = map (fmap (\t -> norm' t `runReader` hnd)) in+ Rule i (normFactTerms ps) (normFactTerms cs) (normFactTerms as)++++{-+------------------------------------------------------------------------------+-- Xor Intruder Rules+------------------------------------------------------------------------------++xorIntruderRules :: WithMaude [IntrRuleAC]+xorIntruderRules = return []+ -- TODO: extend XOR tagging++maude :: IO MaudeHandle+maude = startMaude "maude" allMaudeSig++t :: IO ()+t = do+ m <- maude+ let rules = dhIntruderRules `runReader` m+ mapM_ (putStrLn . render . prettyIntrRuleAC) rules+ writeFile "/tmp/dhrules" $ unlines (map ((++"\n"). render . prettyIntrRuleAC) rules)+ putStrLn ("\nThere are " ++ show (length rules)+ ++ " and " ++ show (length rules - 3) ++ " of these are exp-down rules")+-}
@@ -0,0 +1,621 @@+{-# LANGUAGE CPP,MagicHash #-}+{-# LINE 1 "src/Theory/Lexer.x" #-}++{-# OPTIONS_GHC -fno-warn-name-shadowing -fno-warn-unused-matches -fno-warn-unused-binds -fno-warn-missing-signatures -fno-warn-lazy-unlifted-bindings #-}+module Theory.Lexer where+++#if __GLASGOW_HASKELL__ >= 603+#include "ghcconfig.h"+#elif defined(__GLASGOW_HASKELL__)+#include "config.h"+#endif+#if __GLASGOW_HASKELL__ >= 503+import Data.Array+import Data.Char (ord)+import Data.Array.Base (unsafeAt)+#else+import Array+import Char (ord)+#endif+#if __GLASGOW_HASKELL__ >= 503+import GHC.Exts+#else+import GlaExts+#endif+alex_base :: AlexAddr+alex_base = AlexA# "\x01\x00\x00\x00\xd9\x00\x00\x00\x4f\x01\x00\x00\x28\x00\x00\x00\x2c\x00\x00\x00\x2d\x00\x00\x00\x18\x00\x00\x00\x00\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x0f\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x1a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1b\x00\x00\x00\x00\x00\x00\x00\x1c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x9e\x01\x00\x00\x6e\x02\x00\x00\x3e\x03\x00\x00\x0e\x04\x00\x00\x20\x00\x00\x00\x00\x00\x00\x00\xde\x04\x00\x00\xae\x05\x00\x00\x7e\x06\x00\x00\x4e\x07\x00\x00\x1e\x08\x00\x00\xee\x08\x00\x00\xbe\x09\x00\x00\x21\x00\x00\x00\x00\x00\x00\x00\x8e\x0a\x00\x00\x5e\x0b\x00\x00\x2e\x0c\x00\x00\xfe\x0c\x00\x00\xce\x0d\x00\x00\x9e\x0e\x00\x00\x6e\x0f\x00\x00\x3e\x10\x00\x00\x0e\x11\x00\x00\x22\x00\x00\x00\x00\x00\x00\x00\xc7\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf1\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x23\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x24\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x25\x00\x00\x00\x00\x00\x00\x00\x11\x00\x00\x00\x00\x00\x00\x00\xde\x11\x00\x00\xae\x12\x00\x00\x7e\x13\x00\x00"#++alex_table :: AlexAddr+alex_table = AlexA# "\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x03\x00\x03\x00\x03\x00\x03\x00\x03\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x03\x00\x4a\x00\x3d\x00\x44\x00\x42\x00\x45\x00\x4b\x00\x3c\x00\x08\x00\x35\x00\x46\x00\x50\x00\x34\x00\x4f\x00\x4d\x00\x06\x00\x03\x00\x03\x00\x03\x00\x03\x00\x03\x00\xff\xff\xff\xff\x07\x00\x09\x00\x0b\x00\x41\x00\xff\xff\x47\x00\x40\x00\x48\x00\x49\x00\x43\x00\x0f\x00\x0d\x00\x30\x00\x10\x00\x12\x00\x04\x00\x03\x00\x14\x00\x16\x00\x1c\x00\x25\x00\x3a\x00\x00\x00\x53\x00\x52\x00\x54\x00\x55\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x36\x00\x3b\x00\x37\x00\x3f\x00\x4e\x00\xff\xff\x51\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d\x00\x17\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x38\x00\x4c\x00\x39\x00\x3e\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x33\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x0a\x00\x15\x00\x0e\x00\x15\x00\x15\x00\x15\x00\x15\x00\x11\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x15\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x0c\x00\x32\x00\x31\x00\x32\x00\x32\x00\x32\x00\x32\x00\x13\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x32\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x58\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x18\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x58\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x19\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x58\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x1a\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x58\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x1b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x58\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x1e\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x26\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x58\x00\x00\x00\x57\x00\x57\x00\x1f\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x58\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x20\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x58\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x21\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x58\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x22\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x58\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x23\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x58\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x24\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x58\x00\x00\x00\x57\x00\x27\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x58\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x28\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x58\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x29\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x58\x00\x00\x00\x57\x00\x57\x00\x2a\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x58\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x2b\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x58\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x2c\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x58\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x2d\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x58\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x2e\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x58\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x2f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x58\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x58\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x58\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x00\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00\x57\x00"#++alex_check :: AlexAddr+alex_check = AlexA# "\xff\xff\x00\x00\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x06\x00\x07\x00\x08\x00\x09\x00\x0a\x00\x0b\x00\x0c\x00\x0d\x00\x0e\x00\x0f\x00\x10\x00\x11\x00\x12\x00\x13\x00\x14\x00\x15\x00\x16\x00\x17\x00\x18\x00\x19\x00\x1a\x00\x1b\x00\x1c\x00\x1d\x00\x1e\x00\x1f\x00\x20\x00\x21\x00\x22\x00\x23\x00\x24\x00\x25\x00\x26\x00\x27\x00\x28\x00\x29\x00\x2a\x00\x2b\x00\x2c\x00\x2d\x00\x2e\x00\x2f\x00\x09\x00\x0a\x00\x0b\x00\x0c\x00\x0d\x00\x0a\x00\x0a\x00\x2a\x00\x2a\x00\x2a\x00\x3a\x00\x3b\x00\x3c\x00\x3d\x00\x3e\x00\x3f\x00\x40\x00\x2a\x00\x29\x00\x7d\x00\x2a\x00\x2a\x00\x2f\x00\x20\x00\x2f\x00\x2a\x00\x2a\x00\x2a\x00\x5c\x00\xff\xff\x3e\x00\x2d\x00\x2d\x00\x2d\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x5b\x00\x5c\x00\x5d\x00\x5e\x00\x5f\x00\x60\x00\x3e\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x73\x00\x74\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x7b\x00\x7c\x00\x7d\x00\x7e\x00\x7f\x00\x80\x00\x81\x00\x82\x00\x83\x00\x84\x00\x85\x00\x86\x00\x87\x00\x88\x00\x89\x00\x8a\x00\x8b\x00\x8c\x00\x8d\x00\x8e\x00\x8f\x00\x90\x00\x91\x00\x92\x00\x93\x00\x94\x00\x95\x00\x96\x00\x97\x00\x98\x00\x99\x00\x9a\x00\x9b\x00\x9c\x00\x9d\x00\x9e\x00\x9f\x00\xa0\x00\xa1\x00\xa2\x00\xa3\x00\xa4\x00\xa5\x00\xa6\x00\xa7\x00\xa8\x00\xa9\x00\xaa\x00\xab\x00\xac\x00\xad\x00\xae\x00\xaf\x00\xb0\x00\xb1\x00\xb2\x00\xb3\x00\xb4\x00\xb5\x00\xb6\x00\xb7\x00\xb8\x00\xb9\x00\xba\x00\xbb\x00\xbc\x00\xbd\x00\xbe\x00\xbf\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xd7\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x09\x00\x0a\x00\x0b\x00\x0c\x00\x0d\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf7\x00\x20\x00\x21\x00\x22\x00\x23\x00\x24\x00\x25\x00\x26\x00\x27\x00\x28\x00\x29\x00\x2a\x00\x2b\x00\x2c\x00\x2d\x00\x2e\x00\x2f\x00\x30\x00\x31\x00\x32\x00\x33\x00\x34\x00\x35\x00\x36\x00\x37\x00\x38\x00\x39\x00\x3a\x00\x3b\x00\x3c\x00\x3d\x00\x3e\x00\x3f\x00\x40\x00\x41\x00\x42\x00\x43\x00\x44\x00\x45\x00\x46\x00\x47\x00\x48\x00\x49\x00\x4a\x00\x4b\x00\x4c\x00\x4d\x00\x4e\x00\x4f\x00\x50\x00\x51\x00\x52\x00\x53\x00\x54\x00\x55\x00\x56\x00\x57\x00\x58\x00\x59\x00\x5a\x00\x5b\x00\x5c\x00\x5d\x00\x5e\x00\x5f\x00\x60\x00\x61\x00\x62\x00\x63\x00\x64\x00\x65\x00\x66\x00\x67\x00\x68\x00\x69\x00\x6a\x00\x6b\x00\x6c\x00\x6d\x00\x6e\x00\x6f\x00\x70\x00\x71\x00\x72\x00\x73\x00\x74\x00\x75\x00\x76\x00\x77\x00\x78\x00\x79\x00\x7a\x00\x7b\x00\x7c\x00\x7d\x00\x7e\x00\x09\x00\x0a\x00\x0b\x00\x0c\x00\x0d\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x20\x00\x21\x00\x22\x00\x23\x00\x24\x00\x25\x00\x26\x00\x27\x00\x28\x00\x29\x00\x2a\x00\x2b\x00\x2c\x00\x2d\x00\x2e\x00\x2f\x00\x30\x00\x31\x00\x32\x00\x33\x00\x34\x00\x35\x00\x36\x00\x37\x00\x38\x00\x39\x00\x3a\x00\x3b\x00\x3c\x00\x3d\x00\x3e\x00\x3f\x00\x40\x00\x41\x00\x42\x00\x43\x00\x44\x00\x45\x00\x46\x00\x47\x00\x48\x00\x49\x00\x4a\x00\x4b\x00\x4c\x00\x4d\x00\x4e\x00\x4f\x00\x50\x00\x51\x00\x52\x00\x53\x00\x54\x00\x55\x00\x56\x00\x57\x00\x58\x00\x59\x00\x5a\x00\x5b\x00\x5c\x00\x5d\x00\x5e\x00\x5f\x00\x60\x00\x61\x00\x62\x00\x63\x00\x64\x00\x65\x00\x66\x00\x67\x00\x68\x00\x69\x00\x6a\x00\x6b\x00\x6c\x00\x6d\x00\x6e\x00\x6f\x00\x70\x00\x71\x00\x72\x00\x73\x00\x74\x00\x75\x00\x76\x00\x77\x00\x78\x00\x79\x00\x7a\x00\x7b\x00\x7c\x00\x7d\x00\x7e\x00\x30\x00\x31\x00\x32\x00\x33\x00\x34\x00\x35\x00\x36\x00\x37\x00\x38\x00\x39\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x41\x00\x42\x00\x43\x00\x44\x00\x45\x00\x46\x00\x47\x00\x48\x00\x49\x00\x4a\x00\x4b\x00\x4c\x00\x4d\x00\x4e\x00\x4f\x00\x50\x00\x51\x00\x52\x00\x53\x00\x54\x00\x55\x00\x56\x00\x57\x00\x58\x00\x59\x00\x5a\x00\xff\xff\xff\xff\xff\xff\xff\xff\x5f\x00\xff\xff\x61\x00\x62\x00\x63\x00\x64\x00\x65\x00\x66\x00\x67\x00\x68\x00\x69\x00\x6a\x00\x6b\x00\x6c\x00\x6d\x00\x6e\x00\x6f\x00\x70\x00\x71\x00\x72\x00\x73\x00\x74\x00\x75\x00\x76\x00\x77\x00\x78\x00\x79\x00\x7a\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\xc1\x00\xc2\x00\xc3\x00\xc4\x00\xc5\x00\xc6\x00\xc7\x00\xc8\x00\xc9\x00\xca\x00\xcb\x00\xcc\x00\xcd\x00\xce\x00\xcf\x00\xd0\x00\xd1\x00\xd2\x00\xd3\x00\xd4\x00\xd5\x00\xd6\x00\xff\xff\xd8\x00\xd9\x00\xda\x00\xdb\x00\xdc\x00\xdd\x00\xde\x00\xdf\x00\xe0\x00\xe1\x00\xe2\x00\xe3\x00\xe4\x00\xe5\x00\xe6\x00\xe7\x00\xe8\x00\xe9\x00\xea\x00\xeb\x00\xec\x00\xed\x00\xee\x00\xef\x00\xf0\x00\xf1\x00\xf2\x00\xf3\x00\xf4\x00\xf5\x00\xf6\x00\xff\xff\xf8\x00\xf9\x00\xfa\x00\xfb\x00\xfc\x00\xfd\x00\xfe\x00\xff\x00\x30\x00\x31\x00\x32\x00\x33\x00\x34\x00\x35\x00\x36\x00\x37\x00\x38\x00\x39\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x41\x00\x42\x00\x43\x00\x44\x00\x45\x00\x46\x00\x47\x00\x48\x00\x49\x00\x4a\x00\x4b\x00\x4c\x00\x4d\x00\x4e\x00\x4f\x00\x50\x00\x51\x00\x52\x00\x53\x00\x54\x00\x55\x00\x56\x00\x57\x00\x58\x00\x59\x00\x5a\x00\xff\xff\xff\xff\xff\xff\xff\xff\x5f\x00\xff\xff\x61\x00\x62\x00\x63\x00\x64\x00\x65\x00\x66\x00\x67\x00\x68\x00\x69\x00\x6a\x00\x6b\x00\x6c\x00\x6d\x00\x6e\x00\x6f\x00\x70\x00\x71\x00\x72\x00\x73\x00\x74\x00\x75\x00\x76\x00\x77\x00\x78\x00\x79\x00\x7a\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\xc1\x00\xc2\x00\xc3\x00\xc4\x00\xc5\x00\xc6\x00\xc7\x00\xc8\x00\xc9\x00\xca\x00\xcb\x00\xcc\x00\xcd\x00\xce\x00\xcf\x00\xd0\x00\xd1\x00\xd2\x00\xd3\x00\xd4\x00\xd5\x00\xd6\x00\xff\xff\xd8\x00\xd9\x00\xda\x00\xdb\x00\xdc\x00\xdd\x00\xde\x00\xdf\x00\xe0\x00\xe1\x00\xe2\x00\xe3\x00\xe4\x00\xe5\x00\xe6\x00\xe7\x00\xe8\x00\xe9\x00\xea\x00\xeb\x00\xec\x00\xed\x00\xee\x00\xef\x00\xf0\x00\xf1\x00\xf2\x00\xf3\x00\xf4\x00\xf5\x00\xf6\x00\xff\xff\xf8\x00\xf9\x00\xfa\x00\xfb\x00\xfc\x00\xfd\x00\xfe\x00\xff\x00\x30\x00\x31\x00\x32\x00\x33\x00\x34\x00\x35\x00\x36\x00\x37\x00\x38\x00\x39\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x41\x00\x42\x00\x43\x00\x44\x00\x45\x00\x46\x00\x47\x00\x48\x00\x49\x00\x4a\x00\x4b\x00\x4c\x00\x4d\x00\x4e\x00\x4f\x00\x50\x00\x51\x00\x52\x00\x53\x00\x54\x00\x55\x00\x56\x00\x57\x00\x58\x00\x59\x00\x5a\x00\xff\xff\xff\xff\xff\xff\xff\xff\x5f\x00\xff\xff\x61\x00\x62\x00\x63\x00\x64\x00\x65\x00\x66\x00\x67\x00\x68\x00\x69\x00\x6a\x00\x6b\x00\x6c\x00\x6d\x00\x6e\x00\x6f\x00\x70\x00\x71\x00\x72\x00\x73\x00\x74\x00\x75\x00\x76\x00\x77\x00\x78\x00\x79\x00\x7a\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\xc1\x00\xc2\x00\xc3\x00\xc4\x00\xc5\x00\xc6\x00\xc7\x00\xc8\x00\xc9\x00\xca\x00\xcb\x00\xcc\x00\xcd\x00\xce\x00\xcf\x00\xd0\x00\xd1\x00\xd2\x00\xd3\x00\xd4\x00\xd5\x00\xd6\x00\xff\xff\xd8\x00\xd9\x00\xda\x00\xdb\x00\xdc\x00\xdd\x00\xde\x00\xdf\x00\xe0\x00\xe1\x00\xe2\x00\xe3\x00\xe4\x00\xe5\x00\xe6\x00\xe7\x00\xe8\x00\xe9\x00\xea\x00\xeb\x00\xec\x00\xed\x00\xee\x00\xef\x00\xf0\x00\xf1\x00\xf2\x00\xf3\x00\xf4\x00\xf5\x00\xf6\x00\xff\xff\xf8\x00\xf9\x00\xfa\x00\xfb\x00\xfc\x00\xfd\x00\xfe\x00\xff\x00\x30\x00\x31\x00\x32\x00\x33\x00\x34\x00\x35\x00\x36\x00\x37\x00\x38\x00\x39\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x41\x00\x42\x00\x43\x00\x44\x00\x45\x00\x46\x00\x47\x00\x48\x00\x49\x00\x4a\x00\x4b\x00\x4c\x00\x4d\x00\x4e\x00\x4f\x00\x50\x00\x51\x00\x52\x00\x53\x00\x54\x00\x55\x00\x56\x00\x57\x00\x58\x00\x59\x00\x5a\x00\xff\xff\xff\xff\xff\xff\xff\xff\x5f\x00\xff\xff\x61\x00\x62\x00\x63\x00\x64\x00\x65\x00\x66\x00\x67\x00\x68\x00\x69\x00\x6a\x00\x6b\x00\x6c\x00\x6d\x00\x6e\x00\x6f\x00\x70\x00\x71\x00\x72\x00\x73\x00\x74\x00\x75\x00\x76\x00\x77\x00\x78\x00\x79\x00\x7a\x00\x7b\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\xc1\x00\xc2\x00\xc3\x00\xc4\x00\xc5\x00\xc6\x00\xc7\x00\xc8\x00\xc9\x00\xca\x00\xcb\x00\xcc\x00\xcd\x00\xce\x00\xcf\x00\xd0\x00\xd1\x00\xd2\x00\xd3\x00\xd4\x00\xd5\x00\xd6\x00\xff\xff\xd8\x00\xd9\x00\xda\x00\xdb\x00\xdc\x00\xdd\x00\xde\x00\xdf\x00\xe0\x00\xe1\x00\xe2\x00\xe3\x00\xe4\x00\xe5\x00\xe6\x00\xe7\x00\xe8\x00\xe9\x00\xea\x00\xeb\x00\xec\x00\xed\x00\xee\x00\xef\x00\xf0\x00\xf1\x00\xf2\x00\xf3\x00\xf4\x00\xf5\x00\xf6\x00\xff\xff\xf8\x00\xf9\x00\xfa\x00\xfb\x00\xfc\x00\xfd\x00\xfe\x00\xff\x00\x30\x00\x31\x00\x32\x00\x33\x00\x34\x00\x35\x00\x36\x00\x37\x00\x38\x00\x39\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x41\x00\x42\x00\x43\x00\x44\x00\x45\x00\x46\x00\x47\x00\x48\x00\x49\x00\x4a\x00\x4b\x00\x4c\x00\x4d\x00\x4e\x00\x4f\x00\x50\x00\x51\x00\x52\x00\x53\x00\x54\x00\x55\x00\x56\x00\x57\x00\x58\x00\x59\x00\x5a\x00\xff\xff\xff\xff\xff\xff\xff\xff\x5f\x00\xff\xff\x61\x00\x62\x00\x63\x00\x64\x00\x65\x00\x66\x00\x67\x00\x68\x00\x69\x00\x6a\x00\x6b\x00\x6c\x00\x6d\x00\x6e\x00\x6f\x00\x70\x00\x71\x00\x72\x00\x73\x00\x74\x00\x75\x00\x76\x00\x77\x00\x78\x00\x79\x00\x7a\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\xc1\x00\xc2\x00\xc3\x00\xc4\x00\xc5\x00\xc6\x00\xc7\x00\xc8\x00\xc9\x00\xca\x00\xcb\x00\xcc\x00\xcd\x00\xce\x00\xcf\x00\xd0\x00\xd1\x00\xd2\x00\xd3\x00\xd4\x00\xd5\x00\xd6\x00\xff\xff\xd8\x00\xd9\x00\xda\x00\xdb\x00\xdc\x00\xdd\x00\xde\x00\xdf\x00\xe0\x00\xe1\x00\xe2\x00\xe3\x00\xe4\x00\xe5\x00\xe6\x00\xe7\x00\xe8\x00\xe9\x00\xea\x00\xeb\x00\xec\x00\xed\x00\xee\x00\xef\x00\xf0\x00\xf1\x00\xf2\x00\xf3\x00\xf4\x00\xf5\x00\xf6\x00\xff\xff\xf8\x00\xf9\x00\xfa\x00\xfb\x00\xfc\x00\xfd\x00\xfe\x00\xff\x00\x30\x00\x31\x00\x32\x00\x33\x00\x34\x00\x35\x00\x36\x00\x37\x00\x38\x00\x39\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x41\x00\x42\x00\x43\x00\x44\x00\x45\x00\x46\x00\x47\x00\x48\x00\x49\x00\x4a\x00\x4b\x00\x4c\x00\x4d\x00\x4e\x00\x4f\x00\x50\x00\x51\x00\x52\x00\x53\x00\x54\x00\x55\x00\x56\x00\x57\x00\x58\x00\x59\x00\x5a\x00\xff\xff\xff\xff\xff\xff\xff\xff\x5f\x00\xff\xff\x61\x00\x62\x00\x63\x00\x64\x00\x65\x00\x66\x00\x67\x00\x68\x00\x69\x00\x6a\x00\x6b\x00\x6c\x00\x6d\x00\x6e\x00\x6f\x00\x70\x00\x71\x00\x72\x00\x73\x00\x74\x00\x75\x00\x76\x00\x77\x00\x78\x00\x79\x00\x7a\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\xc1\x00\xc2\x00\xc3\x00\xc4\x00\xc5\x00\xc6\x00\xc7\x00\xc8\x00\xc9\x00\xca\x00\xcb\x00\xcc\x00\xcd\x00\xce\x00\xcf\x00\xd0\x00\xd1\x00\xd2\x00\xd3\x00\xd4\x00\xd5\x00\xd6\x00\xff\xff\xd8\x00\xd9\x00\xda\x00\xdb\x00\xdc\x00\xdd\x00\xde\x00\xdf\x00\xe0\x00\xe1\x00\xe2\x00\xe3\x00\xe4\x00\xe5\x00\xe6\x00\xe7\x00\xe8\x00\xe9\x00\xea\x00\xeb\x00\xec\x00\xed\x00\xee\x00\xef\x00\xf0\x00\xf1\x00\xf2\x00\xf3\x00\xf4\x00\xf5\x00\xf6\x00\xff\xff\xf8\x00\xf9\x00\xfa\x00\xfb\x00\xfc\x00\xfd\x00\xfe\x00\xff\x00\x30\x00\x31\x00\x32\x00\x33\x00\x34\x00\x35\x00\x36\x00\x37\x00\x38\x00\x39\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x41\x00\x42\x00\x43\x00\x44\x00\x45\x00\x46\x00\x47\x00\x48\x00\x49\x00\x4a\x00\x4b\x00\x4c\x00\x4d\x00\x4e\x00\x4f\x00\x50\x00\x51\x00\x52\x00\x53\x00\x54\x00\x55\x00\x56\x00\x57\x00\x58\x00\x59\x00\x5a\x00\xff\xff\xff\xff\xff\xff\xff\xff\x5f\x00\xff\xff\x61\x00\x62\x00\x63\x00\x64\x00\x65\x00\x66\x00\x67\x00\x68\x00\x69\x00\x6a\x00\x6b\x00\x6c\x00\x6d\x00\x6e\x00\x6f\x00\x70\x00\x71\x00\x72\x00\x73\x00\x74\x00\x75\x00\x76\x00\x77\x00\x78\x00\x79\x00\x7a\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\xc1\x00\xc2\x00\xc3\x00\xc4\x00\xc5\x00\xc6\x00\xc7\x00\xc8\x00\xc9\x00\xca\x00\xcb\x00\xcc\x00\xcd\x00\xce\x00\xcf\x00\xd0\x00\xd1\x00\xd2\x00\xd3\x00\xd4\x00\xd5\x00\xd6\x00\xff\xff\xd8\x00\xd9\x00\xda\x00\xdb\x00\xdc\x00\xdd\x00\xde\x00\xdf\x00\xe0\x00\xe1\x00\xe2\x00\xe3\x00\xe4\x00\xe5\x00\xe6\x00\xe7\x00\xe8\x00\xe9\x00\xea\x00\xeb\x00\xec\x00\xed\x00\xee\x00\xef\x00\xf0\x00\xf1\x00\xf2\x00\xf3\x00\xf4\x00\xf5\x00\xf6\x00\xff\xff\xf8\x00\xf9\x00\xfa\x00\xfb\x00\xfc\x00\xfd\x00\xfe\x00\xff\x00\x30\x00\x31\x00\x32\x00\x33\x00\x34\x00\x35\x00\x36\x00\x37\x00\x38\x00\x39\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x41\x00\x42\x00\x43\x00\x44\x00\x45\x00\x46\x00\x47\x00\x48\x00\x49\x00\x4a\x00\x4b\x00\x4c\x00\x4d\x00\x4e\x00\x4f\x00\x50\x00\x51\x00\x52\x00\x53\x00\x54\x00\x55\x00\x56\x00\x57\x00\x58\x00\x59\x00\x5a\x00\xff\xff\xff\xff\xff\xff\xff\xff\x5f\x00\xff\xff\x61\x00\x62\x00\x63\x00\x64\x00\x65\x00\x66\x00\x67\x00\x68\x00\x69\x00\x6a\x00\x6b\x00\x6c\x00\x6d\x00\x6e\x00\x6f\x00\x70\x00\x71\x00\x72\x00\x73\x00\x74\x00\x75\x00\x76\x00\x77\x00\x78\x00\x79\x00\x7a\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\xc1\x00\xc2\x00\xc3\x00\xc4\x00\xc5\x00\xc6\x00\xc7\x00\xc8\x00\xc9\x00\xca\x00\xcb\x00\xcc\x00\xcd\x00\xce\x00\xcf\x00\xd0\x00\xd1\x00\xd2\x00\xd3\x00\xd4\x00\xd5\x00\xd6\x00\xff\xff\xd8\x00\xd9\x00\xda\x00\xdb\x00\xdc\x00\xdd\x00\xde\x00\xdf\x00\xe0\x00\xe1\x00\xe2\x00\xe3\x00\xe4\x00\xe5\x00\xe6\x00\xe7\x00\xe8\x00\xe9\x00\xea\x00\xeb\x00\xec\x00\xed\x00\xee\x00\xef\x00\xf0\x00\xf1\x00\xf2\x00\xf3\x00\xf4\x00\xf5\x00\xf6\x00\xff\xff\xf8\x00\xf9\x00\xfa\x00\xfb\x00\xfc\x00\xfd\x00\xfe\x00\xff\x00\x30\x00\x31\x00\x32\x00\x33\x00\x34\x00\x35\x00\x36\x00\x37\x00\x38\x00\x39\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x41\x00\x42\x00\x43\x00\x44\x00\x45\x00\x46\x00\x47\x00\x48\x00\x49\x00\x4a\x00\x4b\x00\x4c\x00\x4d\x00\x4e\x00\x4f\x00\x50\x00\x51\x00\x52\x00\x53\x00\x54\x00\x55\x00\x56\x00\x57\x00\x58\x00\x59\x00\x5a\x00\xff\xff\xff\xff\xff\xff\xff\xff\x5f\x00\xff\xff\x61\x00\x62\x00\x63\x00\x64\x00\x65\x00\x66\x00\x67\x00\x68\x00\x69\x00\x6a\x00\x6b\x00\x6c\x00\x6d\x00\x6e\x00\x6f\x00\x70\x00\x71\x00\x72\x00\x73\x00\x74\x00\x75\x00\x76\x00\x77\x00\x78\x00\x79\x00\x7a\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\xc1\x00\xc2\x00\xc3\x00\xc4\x00\xc5\x00\xc6\x00\xc7\x00\xc8\x00\xc9\x00\xca\x00\xcb\x00\xcc\x00\xcd\x00\xce\x00\xcf\x00\xd0\x00\xd1\x00\xd2\x00\xd3\x00\xd4\x00\xd5\x00\xd6\x00\xff\xff\xd8\x00\xd9\x00\xda\x00\xdb\x00\xdc\x00\xdd\x00\xde\x00\xdf\x00\xe0\x00\xe1\x00\xe2\x00\xe3\x00\xe4\x00\xe5\x00\xe6\x00\xe7\x00\xe8\x00\xe9\x00\xea\x00\xeb\x00\xec\x00\xed\x00\xee\x00\xef\x00\xf0\x00\xf1\x00\xf2\x00\xf3\x00\xf4\x00\xf5\x00\xf6\x00\xff\xff\xf8\x00\xf9\x00\xfa\x00\xfb\x00\xfc\x00\xfd\x00\xfe\x00\xff\x00\x30\x00\x31\x00\x32\x00\x33\x00\x34\x00\x35\x00\x36\x00\x37\x00\x38\x00\x39\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x41\x00\x42\x00\x43\x00\x44\x00\x45\x00\x46\x00\x47\x00\x48\x00\x49\x00\x4a\x00\x4b\x00\x4c\x00\x4d\x00\x4e\x00\x4f\x00\x50\x00\x51\x00\x52\x00\x53\x00\x54\x00\x55\x00\x56\x00\x57\x00\x58\x00\x59\x00\x5a\x00\xff\xff\xff\xff\xff\xff\xff\xff\x5f\x00\xff\xff\x61\x00\x62\x00\x63\x00\x64\x00\x65\x00\x66\x00\x67\x00\x68\x00\x69\x00\x6a\x00\x6b\x00\x6c\x00\x6d\x00\x6e\x00\x6f\x00\x70\x00\x71\x00\x72\x00\x73\x00\x74\x00\x75\x00\x76\x00\x77\x00\x78\x00\x79\x00\x7a\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\xc1\x00\xc2\x00\xc3\x00\xc4\x00\xc5\x00\xc6\x00\xc7\x00\xc8\x00\xc9\x00\xca\x00\xcb\x00\xcc\x00\xcd\x00\xce\x00\xcf\x00\xd0\x00\xd1\x00\xd2\x00\xd3\x00\xd4\x00\xd5\x00\xd6\x00\xff\xff\xd8\x00\xd9\x00\xda\x00\xdb\x00\xdc\x00\xdd\x00\xde\x00\xdf\x00\xe0\x00\xe1\x00\xe2\x00\xe3\x00\xe4\x00\xe5\x00\xe6\x00\xe7\x00\xe8\x00\xe9\x00\xea\x00\xeb\x00\xec\x00\xed\x00\xee\x00\xef\x00\xf0\x00\xf1\x00\xf2\x00\xf3\x00\xf4\x00\xf5\x00\xf6\x00\xff\xff\xf8\x00\xf9\x00\xfa\x00\xfb\x00\xfc\x00\xfd\x00\xfe\x00\xff\x00\x30\x00\x31\x00\x32\x00\x33\x00\x34\x00\x35\x00\x36\x00\x37\x00\x38\x00\x39\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x41\x00\x42\x00\x43\x00\x44\x00\x45\x00\x46\x00\x47\x00\x48\x00\x49\x00\x4a\x00\x4b\x00\x4c\x00\x4d\x00\x4e\x00\x4f\x00\x50\x00\x51\x00\x52\x00\x53\x00\x54\x00\x55\x00\x56\x00\x57\x00\x58\x00\x59\x00\x5a\x00\xff\xff\xff\xff\xff\xff\xff\xff\x5f\x00\xff\xff\x61\x00\x62\x00\x63\x00\x64\x00\x65\x00\x66\x00\x67\x00\x68\x00\x69\x00\x6a\x00\x6b\x00\x6c\x00\x6d\x00\x6e\x00\x6f\x00\x70\x00\x71\x00\x72\x00\x73\x00\x74\x00\x75\x00\x76\x00\x77\x00\x78\x00\x79\x00\x7a\x00\x7b\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\xc1\x00\xc2\x00\xc3\x00\xc4\x00\xc5\x00\xc6\x00\xc7\x00\xc8\x00\xc9\x00\xca\x00\xcb\x00\xcc\x00\xcd\x00\xce\x00\xcf\x00\xd0\x00\xd1\x00\xd2\x00\xd3\x00\xd4\x00\xd5\x00\xd6\x00\xff\xff\xd8\x00\xd9\x00\xda\x00\xdb\x00\xdc\x00\xdd\x00\xde\x00\xdf\x00\xe0\x00\xe1\x00\xe2\x00\xe3\x00\xe4\x00\xe5\x00\xe6\x00\xe7\x00\xe8\x00\xe9\x00\xea\x00\xeb\x00\xec\x00\xed\x00\xee\x00\xef\x00\xf0\x00\xf1\x00\xf2\x00\xf3\x00\xf4\x00\xf5\x00\xf6\x00\xff\xff\xf8\x00\xf9\x00\xfa\x00\xfb\x00\xfc\x00\xfd\x00\xfe\x00\xff\x00\x30\x00\x31\x00\x32\x00\x33\x00\x34\x00\x35\x00\x36\x00\x37\x00\x38\x00\x39\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x41\x00\x42\x00\x43\x00\x44\x00\x45\x00\x46\x00\x47\x00\x48\x00\x49\x00\x4a\x00\x4b\x00\x4c\x00\x4d\x00\x4e\x00\x4f\x00\x50\x00\x51\x00\x52\x00\x53\x00\x54\x00\x55\x00\x56\x00\x57\x00\x58\x00\x59\x00\x5a\x00\xff\xff\xff\xff\xff\xff\xff\xff\x5f\x00\xff\xff\x61\x00\x62\x00\x63\x00\x64\x00\x65\x00\x66\x00\x67\x00\x68\x00\x69\x00\x6a\x00\x6b\x00\x6c\x00\x6d\x00\x6e\x00\x6f\x00\x70\x00\x71\x00\x72\x00\x73\x00\x74\x00\x75\x00\x76\x00\x77\x00\x78\x00\x79\x00\x7a\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\xc1\x00\xc2\x00\xc3\x00\xc4\x00\xc5\x00\xc6\x00\xc7\x00\xc8\x00\xc9\x00\xca\x00\xcb\x00\xcc\x00\xcd\x00\xce\x00\xcf\x00\xd0\x00\xd1\x00\xd2\x00\xd3\x00\xd4\x00\xd5\x00\xd6\x00\xff\xff\xd8\x00\xd9\x00\xda\x00\xdb\x00\xdc\x00\xdd\x00\xde\x00\xdf\x00\xe0\x00\xe1\x00\xe2\x00\xe3\x00\xe4\x00\xe5\x00\xe6\x00\xe7\x00\xe8\x00\xe9\x00\xea\x00\xeb\x00\xec\x00\xed\x00\xee\x00\xef\x00\xf0\x00\xf1\x00\xf2\x00\xf3\x00\xf4\x00\xf5\x00\xf6\x00\xff\xff\xf8\x00\xf9\x00\xfa\x00\xfb\x00\xfc\x00\xfd\x00\xfe\x00\xff\x00\x30\x00\x31\x00\x32\x00\x33\x00\x34\x00\x35\x00\x36\x00\x37\x00\x38\x00\x39\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x41\x00\x42\x00\x43\x00\x44\x00\x45\x00\x46\x00\x47\x00\x48\x00\x49\x00\x4a\x00\x4b\x00\x4c\x00\x4d\x00\x4e\x00\x4f\x00\x50\x00\x51\x00\x52\x00\x53\x00\x54\x00\x55\x00\x56\x00\x57\x00\x58\x00\x59\x00\x5a\x00\xff\xff\xff\xff\xff\xff\xff\xff\x5f\x00\xff\xff\x61\x00\x62\x00\x63\x00\x64\x00\x65\x00\x66\x00\x67\x00\x68\x00\x69\x00\x6a\x00\x6b\x00\x6c\x00\x6d\x00\x6e\x00\x6f\x00\x70\x00\x71\x00\x72\x00\x73\x00\x74\x00\x75\x00\x76\x00\x77\x00\x78\x00\x79\x00\x7a\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\xc1\x00\xc2\x00\xc3\x00\xc4\x00\xc5\x00\xc6\x00\xc7\x00\xc8\x00\xc9\x00\xca\x00\xcb\x00\xcc\x00\xcd\x00\xce\x00\xcf\x00\xd0\x00\xd1\x00\xd2\x00\xd3\x00\xd4\x00\xd5\x00\xd6\x00\xff\xff\xd8\x00\xd9\x00\xda\x00\xdb\x00\xdc\x00\xdd\x00\xde\x00\xdf\x00\xe0\x00\xe1\x00\xe2\x00\xe3\x00\xe4\x00\xe5\x00\xe6\x00\xe7\x00\xe8\x00\xe9\x00\xea\x00\xeb\x00\xec\x00\xed\x00\xee\x00\xef\x00\xf0\x00\xf1\x00\xf2\x00\xf3\x00\xf4\x00\xf5\x00\xf6\x00\xff\xff\xf8\x00\xf9\x00\xfa\x00\xfb\x00\xfc\x00\xfd\x00\xfe\x00\xff\x00\x30\x00\x31\x00\x32\x00\x33\x00\x34\x00\x35\x00\x36\x00\x37\x00\x38\x00\x39\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x41\x00\x42\x00\x43\x00\x44\x00\x45\x00\x46\x00\x47\x00\x48\x00\x49\x00\x4a\x00\x4b\x00\x4c\x00\x4d\x00\x4e\x00\x4f\x00\x50\x00\x51\x00\x52\x00\x53\x00\x54\x00\x55\x00\x56\x00\x57\x00\x58\x00\x59\x00\x5a\x00\xff\xff\xff\xff\xff\xff\xff\xff\x5f\x00\xff\xff\x61\x00\x62\x00\x63\x00\x64\x00\x65\x00\x66\x00\x67\x00\x68\x00\x69\x00\x6a\x00\x6b\x00\x6c\x00\x6d\x00\x6e\x00\x6f\x00\x70\x00\x71\x00\x72\x00\x73\x00\x74\x00\x75\x00\x76\x00\x77\x00\x78\x00\x79\x00\x7a\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\xc1\x00\xc2\x00\xc3\x00\xc4\x00\xc5\x00\xc6\x00\xc7\x00\xc8\x00\xc9\x00\xca\x00\xcb\x00\xcc\x00\xcd\x00\xce\x00\xcf\x00\xd0\x00\xd1\x00\xd2\x00\xd3\x00\xd4\x00\xd5\x00\xd6\x00\xff\xff\xd8\x00\xd9\x00\xda\x00\xdb\x00\xdc\x00\xdd\x00\xde\x00\xdf\x00\xe0\x00\xe1\x00\xe2\x00\xe3\x00\xe4\x00\xe5\x00\xe6\x00\xe7\x00\xe8\x00\xe9\x00\xea\x00\xeb\x00\xec\x00\xed\x00\xee\x00\xef\x00\xf0\x00\xf1\x00\xf2\x00\xf3\x00\xf4\x00\xf5\x00\xf6\x00\xff\xff\xf8\x00\xf9\x00\xfa\x00\xfb\x00\xfc\x00\xfd\x00\xfe\x00\xff\x00\x30\x00\x31\x00\x32\x00\x33\x00\x34\x00\x35\x00\x36\x00\x37\x00\x38\x00\x39\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x41\x00\x42\x00\x43\x00\x44\x00\x45\x00\x46\x00\x47\x00\x48\x00\x49\x00\x4a\x00\x4b\x00\x4c\x00\x4d\x00\x4e\x00\x4f\x00\x50\x00\x51\x00\x52\x00\x53\x00\x54\x00\x55\x00\x56\x00\x57\x00\x58\x00\x59\x00\x5a\x00\xff\xff\xff\xff\xff\xff\xff\xff\x5f\x00\xff\xff\x61\x00\x62\x00\x63\x00\x64\x00\x65\x00\x66\x00\x67\x00\x68\x00\x69\x00\x6a\x00\x6b\x00\x6c\x00\x6d\x00\x6e\x00\x6f\x00\x70\x00\x71\x00\x72\x00\x73\x00\x74\x00\x75\x00\x76\x00\x77\x00\x78\x00\x79\x00\x7a\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\xc1\x00\xc2\x00\xc3\x00\xc4\x00\xc5\x00\xc6\x00\xc7\x00\xc8\x00\xc9\x00\xca\x00\xcb\x00\xcc\x00\xcd\x00\xce\x00\xcf\x00\xd0\x00\xd1\x00\xd2\x00\xd3\x00\xd4\x00\xd5\x00\xd6\x00\xff\xff\xd8\x00\xd9\x00\xda\x00\xdb\x00\xdc\x00\xdd\x00\xde\x00\xdf\x00\xe0\x00\xe1\x00\xe2\x00\xe3\x00\xe4\x00\xe5\x00\xe6\x00\xe7\x00\xe8\x00\xe9\x00\xea\x00\xeb\x00\xec\x00\xed\x00\xee\x00\xef\x00\xf0\x00\xf1\x00\xf2\x00\xf3\x00\xf4\x00\xf5\x00\xf6\x00\xff\xff\xf8\x00\xf9\x00\xfa\x00\xfb\x00\xfc\x00\xfd\x00\xfe\x00\xff\x00\x30\x00\x31\x00\x32\x00\x33\x00\x34\x00\x35\x00\x36\x00\x37\x00\x38\x00\x39\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x41\x00\x42\x00\x43\x00\x44\x00\x45\x00\x46\x00\x47\x00\x48\x00\x49\x00\x4a\x00\x4b\x00\x4c\x00\x4d\x00\x4e\x00\x4f\x00\x50\x00\x51\x00\x52\x00\x53\x00\x54\x00\x55\x00\x56\x00\x57\x00\x58\x00\x59\x00\x5a\x00\xff\xff\xff\xff\xff\xff\xff\xff\x5f\x00\xff\xff\x61\x00\x62\x00\x63\x00\x64\x00\x65\x00\x66\x00\x67\x00\x68\x00\x69\x00\x6a\x00\x6b\x00\x6c\x00\x6d\x00\x6e\x00\x6f\x00\x70\x00\x71\x00\x72\x00\x73\x00\x74\x00\x75\x00\x76\x00\x77\x00\x78\x00\x79\x00\x7a\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\xc1\x00\xc2\x00\xc3\x00\xc4\x00\xc5\x00\xc6\x00\xc7\x00\xc8\x00\xc9\x00\xca\x00\xcb\x00\xcc\x00\xcd\x00\xce\x00\xcf\x00\xd0\x00\xd1\x00\xd2\x00\xd3\x00\xd4\x00\xd5\x00\xd6\x00\xff\xff\xd8\x00\xd9\x00\xda\x00\xdb\x00\xdc\x00\xdd\x00\xde\x00\xdf\x00\xe0\x00\xe1\x00\xe2\x00\xe3\x00\xe4\x00\xe5\x00\xe6\x00\xe7\x00\xe8\x00\xe9\x00\xea\x00\xeb\x00\xec\x00\xed\x00\xee\x00\xef\x00\xf0\x00\xf1\x00\xf2\x00\xf3\x00\xf4\x00\xf5\x00\xf6\x00\xff\xff\xf8\x00\xf9\x00\xfa\x00\xfb\x00\xfc\x00\xfd\x00\xfe\x00\xff\x00\x30\x00\x31\x00\x32\x00\x33\x00\x34\x00\x35\x00\x36\x00\x37\x00\x38\x00\x39\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x41\x00\x42\x00\x43\x00\x44\x00\x45\x00\x46\x00\x47\x00\x48\x00\x49\x00\x4a\x00\x4b\x00\x4c\x00\x4d\x00\x4e\x00\x4f\x00\x50\x00\x51\x00\x52\x00\x53\x00\x54\x00\x55\x00\x56\x00\x57\x00\x58\x00\x59\x00\x5a\x00\xff\xff\xff\xff\xff\xff\xff\xff\x5f\x00\xff\xff\x61\x00\x62\x00\x63\x00\x64\x00\x65\x00\x66\x00\x67\x00\x68\x00\x69\x00\x6a\x00\x6b\x00\x6c\x00\x6d\x00\x6e\x00\x6f\x00\x70\x00\x71\x00\x72\x00\x73\x00\x74\x00\x75\x00\x76\x00\x77\x00\x78\x00\x79\x00\x7a\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\xc1\x00\xc2\x00\xc3\x00\xc4\x00\xc5\x00\xc6\x00\xc7\x00\xc8\x00\xc9\x00\xca\x00\xcb\x00\xcc\x00\xcd\x00\xce\x00\xcf\x00\xd0\x00\xd1\x00\xd2\x00\xd3\x00\xd4\x00\xd5\x00\xd6\x00\xff\xff\xd8\x00\xd9\x00\xda\x00\xdb\x00\xdc\x00\xdd\x00\xde\x00\xdf\x00\xe0\x00\xe1\x00\xe2\x00\xe3\x00\xe4\x00\xe5\x00\xe6\x00\xe7\x00\xe8\x00\xe9\x00\xea\x00\xeb\x00\xec\x00\xed\x00\xee\x00\xef\x00\xf0\x00\xf1\x00\xf2\x00\xf3\x00\xf4\x00\xf5\x00\xf6\x00\xff\xff\xf8\x00\xf9\x00\xfa\x00\xfb\x00\xfc\x00\xfd\x00\xfe\x00\xff\x00\x30\x00\x31\x00\x32\x00\x33\x00\x34\x00\x35\x00\x36\x00\x37\x00\x38\x00\x39\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x41\x00\x42\x00\x43\x00\x44\x00\x45\x00\x46\x00\x47\x00\x48\x00\x49\x00\x4a\x00\x4b\x00\x4c\x00\x4d\x00\x4e\x00\x4f\x00\x50\x00\x51\x00\x52\x00\x53\x00\x54\x00\x55\x00\x56\x00\x57\x00\x58\x00\x59\x00\x5a\x00\xff\xff\xff\xff\xff\xff\xff\xff\x5f\x00\xff\xff\x61\x00\x62\x00\x63\x00\x64\x00\x65\x00\x66\x00\x67\x00\x68\x00\x69\x00\x6a\x00\x6b\x00\x6c\x00\x6d\x00\x6e\x00\x6f\x00\x70\x00\x71\x00\x72\x00\x73\x00\x74\x00\x75\x00\x76\x00\x77\x00\x78\x00\x79\x00\x7a\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\xc1\x00\xc2\x00\xc3\x00\xc4\x00\xc5\x00\xc6\x00\xc7\x00\xc8\x00\xc9\x00\xca\x00\xcb\x00\xcc\x00\xcd\x00\xce\x00\xcf\x00\xd0\x00\xd1\x00\xd2\x00\xd3\x00\xd4\x00\xd5\x00\xd6\x00\xff\xff\xd8\x00\xd9\x00\xda\x00\xdb\x00\xdc\x00\xdd\x00\xde\x00\xdf\x00\xe0\x00\xe1\x00\xe2\x00\xe3\x00\xe4\x00\xe5\x00\xe6\x00\xe7\x00\xe8\x00\xe9\x00\xea\x00\xeb\x00\xec\x00\xed\x00\xee\x00\xef\x00\xf0\x00\xf1\x00\xf2\x00\xf3\x00\xf4\x00\xf5\x00\xf6\x00\xff\xff\xf8\x00\xf9\x00\xfa\x00\xfb\x00\xfc\x00\xfd\x00\xfe\x00\xff\x00\x30\x00\x31\x00\x32\x00\x33\x00\x34\x00\x35\x00\x36\x00\x37\x00\x38\x00\x39\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x41\x00\x42\x00\x43\x00\x44\x00\x45\x00\x46\x00\x47\x00\x48\x00\x49\x00\x4a\x00\x4b\x00\x4c\x00\x4d\x00\x4e\x00\x4f\x00\x50\x00\x51\x00\x52\x00\x53\x00\x54\x00\x55\x00\x56\x00\x57\x00\x58\x00\x59\x00\x5a\x00\xff\xff\xff\xff\xff\xff\xff\xff\x5f\x00\xff\xff\x61\x00\x62\x00\x63\x00\x64\x00\x65\x00\x66\x00\x67\x00\x68\x00\x69\x00\x6a\x00\x6b\x00\x6c\x00\x6d\x00\x6e\x00\x6f\x00\x70\x00\x71\x00\x72\x00\x73\x00\x74\x00\x75\x00\x76\x00\x77\x00\x78\x00\x79\x00\x7a\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\xc1\x00\xc2\x00\xc3\x00\xc4\x00\xc5\x00\xc6\x00\xc7\x00\xc8\x00\xc9\x00\xca\x00\xcb\x00\xcc\x00\xcd\x00\xce\x00\xcf\x00\xd0\x00\xd1\x00\xd2\x00\xd3\x00\xd4\x00\xd5\x00\xd6\x00\xff\xff\xd8\x00\xd9\x00\xda\x00\xdb\x00\xdc\x00\xdd\x00\xde\x00\xdf\x00\xe0\x00\xe1\x00\xe2\x00\xe3\x00\xe4\x00\xe5\x00\xe6\x00\xe7\x00\xe8\x00\xe9\x00\xea\x00\xeb\x00\xec\x00\xed\x00\xee\x00\xef\x00\xf0\x00\xf1\x00\xf2\x00\xf3\x00\xf4\x00\xf5\x00\xf6\x00\xff\xff\xf8\x00\xf9\x00\xfa\x00\xfb\x00\xfc\x00\xfd\x00\xfe\x00\xff\x00\x30\x00\x31\x00\x32\x00\x33\x00\x34\x00\x35\x00\x36\x00\x37\x00\x38\x00\x39\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x41\x00\x42\x00\x43\x00\x44\x00\x45\x00\x46\x00\x47\x00\x48\x00\x49\x00\x4a\x00\x4b\x00\x4c\x00\x4d\x00\x4e\x00\x4f\x00\x50\x00\x51\x00\x52\x00\x53\x00\x54\x00\x55\x00\x56\x00\x57\x00\x58\x00\x59\x00\x5a\x00\xff\xff\xff\xff\xff\xff\xff\xff\x5f\x00\xff\xff\x61\x00\x62\x00\x63\x00\x64\x00\x65\x00\x66\x00\x67\x00\x68\x00\x69\x00\x6a\x00\x6b\x00\x6c\x00\x6d\x00\x6e\x00\x6f\x00\x70\x00\x71\x00\x72\x00\x73\x00\x74\x00\x75\x00\x76\x00\x77\x00\x78\x00\x79\x00\x7a\x00\x7b\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\xc1\x00\xc2\x00\xc3\x00\xc4\x00\xc5\x00\xc6\x00\xc7\x00\xc8\x00\xc9\x00\xca\x00\xcb\x00\xcc\x00\xcd\x00\xce\x00\xcf\x00\xd0\x00\xd1\x00\xd2\x00\xd3\x00\xd4\x00\xd5\x00\xd6\x00\xff\xff\xd8\x00\xd9\x00\xda\x00\xdb\x00\xdc\x00\xdd\x00\xde\x00\xdf\x00\xe0\x00\xe1\x00\xe2\x00\xe3\x00\xe4\x00\xe5\x00\xe6\x00\xe7\x00\xe8\x00\xe9\x00\xea\x00\xeb\x00\xec\x00\xed\x00\xee\x00\xef\x00\xf0\x00\xf1\x00\xf2\x00\xf3\x00\xf4\x00\xf5\x00\xf6\x00\xff\xff\xf8\x00\xf9\x00\xfa\x00\xfb\x00\xfc\x00\xfd\x00\xfe\x00\xff\x00\x30\x00\x31\x00\x32\x00\x33\x00\x34\x00\x35\x00\x36\x00\x37\x00\x38\x00\x39\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x41\x00\x42\x00\x43\x00\x44\x00\x45\x00\x46\x00\x47\x00\x48\x00\x49\x00\x4a\x00\x4b\x00\x4c\x00\x4d\x00\x4e\x00\x4f\x00\x50\x00\x51\x00\x52\x00\x53\x00\x54\x00\x55\x00\x56\x00\x57\x00\x58\x00\x59\x00\x5a\x00\xff\xff\xff\xff\xff\xff\xff\xff\x5f\x00\xff\xff\x61\x00\x62\x00\x63\x00\x64\x00\x65\x00\x66\x00\x67\x00\x68\x00\x69\x00\x6a\x00\x6b\x00\x6c\x00\x6d\x00\x6e\x00\x6f\x00\x70\x00\x71\x00\x72\x00\x73\x00\x74\x00\x75\x00\x76\x00\x77\x00\x78\x00\x79\x00\x7a\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\xc1\x00\xc2\x00\xc3\x00\xc4\x00\xc5\x00\xc6\x00\xc7\x00\xc8\x00\xc9\x00\xca\x00\xcb\x00\xcc\x00\xcd\x00\xce\x00\xcf\x00\xd0\x00\xd1\x00\xd2\x00\xd3\x00\xd4\x00\xd5\x00\xd6\x00\xff\xff\xd8\x00\xd9\x00\xda\x00\xdb\x00\xdc\x00\xdd\x00\xde\x00\xdf\x00\xe0\x00\xe1\x00\xe2\x00\xe3\x00\xe4\x00\xe5\x00\xe6\x00\xe7\x00\xe8\x00\xe9\x00\xea\x00\xeb\x00\xec\x00\xed\x00\xee\x00\xef\x00\xf0\x00\xf1\x00\xf2\x00\xf3\x00\xf4\x00\xf5\x00\xf6\x00\xff\xff\xf8\x00\xf9\x00\xfa\x00\xfb\x00\xfc\x00\xfd\x00\xfe\x00\xff\x00\x30\x00\x31\x00\x32\x00\x33\x00\x34\x00\x35\x00\x36\x00\x37\x00\x38\x00\x39\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x41\x00\x42\x00\x43\x00\x44\x00\x45\x00\x46\x00\x47\x00\x48\x00\x49\x00\x4a\x00\x4b\x00\x4c\x00\x4d\x00\x4e\x00\x4f\x00\x50\x00\x51\x00\x52\x00\x53\x00\x54\x00\x55\x00\x56\x00\x57\x00\x58\x00\x59\x00\x5a\x00\xff\xff\xff\xff\xff\xff\xff\xff\x5f\x00\xff\xff\x61\x00\x62\x00\x63\x00\x64\x00\x65\x00\x66\x00\x67\x00\x68\x00\x69\x00\x6a\x00\x6b\x00\x6c\x00\x6d\x00\x6e\x00\x6f\x00\x70\x00\x71\x00\x72\x00\x73\x00\x74\x00\x75\x00\x76\x00\x77\x00\x78\x00\x79\x00\x7a\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\xc1\x00\xc2\x00\xc3\x00\xc4\x00\xc5\x00\xc6\x00\xc7\x00\xc8\x00\xc9\x00\xca\x00\xcb\x00\xcc\x00\xcd\x00\xce\x00\xcf\x00\xd0\x00\xd1\x00\xd2\x00\xd3\x00\xd4\x00\xd5\x00\xd6\x00\xff\xff\xd8\x00\xd9\x00\xda\x00\xdb\x00\xdc\x00\xdd\x00\xde\x00\xdf\x00\xe0\x00\xe1\x00\xe2\x00\xe3\x00\xe4\x00\xe5\x00\xe6\x00\xe7\x00\xe8\x00\xe9\x00\xea\x00\xeb\x00\xec\x00\xed\x00\xee\x00\xef\x00\xf0\x00\xf1\x00\xf2\x00\xf3\x00\xf4\x00\xf5\x00\xf6\x00\xff\xff\xf8\x00\xf9\x00\xfa\x00\xfb\x00\xfc\x00\xfd\x00\xfe\x00\xff\x00\x30\x00\x31\x00\x32\x00\x33\x00\x34\x00\x35\x00\x36\x00\x37\x00\x38\x00\x39\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x41\x00\x42\x00\x43\x00\x44\x00\x45\x00\x46\x00\x47\x00\x48\x00\x49\x00\x4a\x00\x4b\x00\x4c\x00\x4d\x00\x4e\x00\x4f\x00\x50\x00\x51\x00\x52\x00\x53\x00\x54\x00\x55\x00\x56\x00\x57\x00\x58\x00\x59\x00\x5a\x00\xff\xff\xff\xff\xff\xff\xff\xff\x5f\x00\xff\xff\x61\x00\x62\x00\x63\x00\x64\x00\x65\x00\x66\x00\x67\x00\x68\x00\x69\x00\x6a\x00\x6b\x00\x6c\x00\x6d\x00\x6e\x00\x6f\x00\x70\x00\x71\x00\x72\x00\x73\x00\x74\x00\x75\x00\x76\x00\x77\x00\x78\x00\x79\x00\x7a\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\xc1\x00\xc2\x00\xc3\x00\xc4\x00\xc5\x00\xc6\x00\xc7\x00\xc8\x00\xc9\x00\xca\x00\xcb\x00\xcc\x00\xcd\x00\xce\x00\xcf\x00\xd0\x00\xd1\x00\xd2\x00\xd3\x00\xd4\x00\xd5\x00\xd6\x00\xff\xff\xd8\x00\xd9\x00\xda\x00\xdb\x00\xdc\x00\xdd\x00\xde\x00\xdf\x00\xe0\x00\xe1\x00\xe2\x00\xe3\x00\xe4\x00\xe5\x00\xe6\x00\xe7\x00\xe8\x00\xe9\x00\xea\x00\xeb\x00\xec\x00\xed\x00\xee\x00\xef\x00\xf0\x00\xf1\x00\xf2\x00\xf3\x00\xf4\x00\xf5\x00\xf6\x00\xff\xff\xf8\x00\xf9\x00\xfa\x00\xfb\x00\xfc\x00\xfd\x00\xfe\x00\xff\x00"#++alex_deflt :: AlexAddr+alex_deflt = AlexA# "\x56\x00\xff\xff\xff\xff\xff\xff\x05\x00\x05\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"#++alex_accept = listArray (0::Int,88) [[],[],[],[(AlexAccSkip)],[(AlexAccSkip)],[(AlexAccSkip)],[(AlexAcc (alex_action_29))],[(AlexAcc (alex_action_2))],[(AlexAcc (alex_action_23))],[(AlexAcc (alex_action_3))],[(AlexAcc (alex_action_10))],[(AlexAcc (alex_action_4))],[(AlexAcc (alex_action_15))],[(AlexAcc (alex_action_5))],[(AlexAcc (alex_action_10))],[(AlexAcc (alex_action_6))],[(AlexAcc (alex_action_7))],[(AlexAcc (alex_action_10))],[(AlexAcc (alex_action_8))],[(AlexAcc (alex_action_15))],[(AlexAcc (alex_action_9))],[(AlexAcc (alex_action_10))],[(AlexAcc (alex_action_11))],[(AlexAcc (alex_action_56))],[(AlexAcc (alex_action_56))],[(AlexAcc (alex_action_56))],[(AlexAcc (alex_action_56))],[],[(AlexAcc (alex_action_12))],[(AlexAcc (alex_action_56))],[(AlexAcc (alex_action_56))],[(AlexAcc (alex_action_56))],[(AlexAcc (alex_action_56))],[(AlexAcc (alex_action_56))],[(AlexAcc (alex_action_56))],[(AlexAcc (alex_action_56))],[],[(AlexAcc (alex_action_13))],[(AlexAcc (alex_action_56))],[(AlexAcc (alex_action_56))],[(AlexAcc (alex_action_56))],[(AlexAcc (alex_action_56))],[(AlexAcc (alex_action_56))],[(AlexAcc (alex_action_56))],[(AlexAcc (alex_action_56))],[(AlexAcc (alex_action_56))],[(AlexAcc (alex_action_56))],[],[(AlexAcc (alex_action_14))],[(AlexAcc (alex_action_15))],[(AlexAcc (alex_action_15))],[(AlexAcc (alex_action_20))],[(AlexAcc (alex_action_22))],[(AlexAcc (alex_action_24))],[(AlexAcc (alex_action_25))],[(AlexAcc (alex_action_26))],[(AlexAcc (alex_action_27))],[(AlexAcc (alex_action_28))],[(AlexAcc (alex_action_30))],[],[(AlexAcc (alex_action_31))],[(AlexAcc (alex_action_32))],[(AlexAcc (alex_action_33))],[(AlexAcc (alex_action_34))],[(AlexAcc (alex_action_35))],[(AlexAcc (alex_action_36))],[(AlexAcc (alex_action_37))],[(AlexAcc (alex_action_38))],[(AlexAcc (alex_action_39))],[(AlexAcc (alex_action_40))],[(AlexAcc (alex_action_41))],[(AlexAcc (alex_action_42))],[(AlexAcc (alex_action_43))],[(AlexAcc (alex_action_44))],[(AlexAcc (alex_action_45))],[(AlexAcc (alex_action_46))],[(AlexAcc (alex_action_47))],[(AlexAcc (alex_action_48))],[(AlexAcc (alex_action_49))],[(AlexAcc (alex_action_50))],[(AlexAcc (alex_action_51))],[(AlexAcc (alex_action_52))],[(AlexAcc (alex_action_53))],[(AlexAcc (alex_action_54))],[],[(AlexAcc (alex_action_55))],[(AlexAcc (alex_action_56))],[(AlexAcc (alex_action_56))],[(AlexAcc (alex_action_56))]]+{-# LINE 84 "src/Theory/Lexer.x" #-}+++-- | Lex a keyword+keyword :: Keyword -> AlexAction Keyword+keyword kw input len = return kw++-- | Wrap a string into a keyword+scanString :: (String -> Keyword) -> AlexAction Keyword+scanString kw (_,_,input) len = return $ kw (take len input)++{-+-- | Scan a string until EOF is encountered.+alexScanTokens :: String -> Either String [Keyword]+alexScanTokens inp = runAlex inp gather+ where+ gather = do+ t <- alexMonadScan+ case trace (show t) t of+ EOF -> return [EOF]+ _ -> (t:) `liftM` gather++-- | Scan a file.+scanFile f = do+ inp <- readFile f+ return $ alexScanTokens inp+-}++-- | Formal text types.+data TextType = + TextBegin String + | TextContent String + | TextEnd+ deriving( Eq, Ord, Show )++-- | Lexable Keywords+data Keyword =+ IDENT String+ | TEXT TextType + | SQUOTE+ | DQUOTE+ | RIGHTARROW+ | LEFTARROW+ | LONGRIGHTARROW+ | LONGLEFTARROW+ | COMMA+ | DOT+ | COLON+ | QUESTIONMARK+ | BANG+ | AND+ | MID+ | DOLLAR+ | AT+ | SHARP+ | PERCENT+ | LPAREN+ | RPAREN+ | LBRACKET+ | RBRACKET+ | LBRACE + | RBRACE+ | SLASH+ | BACKSLASH+ | TILDE+ | HAT+ | STAR+ | UNDERSCORE+ | MINUS+ | PLUS+ | EQUAL+ | LESS+ | GREATER+ | EOF+ | FORALL+ | EXISTS+ | LAND+ | LOR+ | LNOT+ | APPROX+ -- dummy keyword to get rid of overlapping pattern matches+ | DUMMY_KEYWORD+ deriving( Eq )++instance Show Keyword where+ show kw = case kw of + IDENT i -> identifier i+ TEXT t -> txt t+ SQUOTE -> symbol "'"+ DQUOTE -> symbol "\""+ RIGHTARROW -> symbol "->"+ LEFTARROW -> symbol "<-"+ LONGRIGHTARROW -> symbol "-->"+ LONGLEFTARROW -> symbol "<--"+ COMMA -> symbol ","+ DOT -> symbol "."+ COLON -> symbol ":"+ QUESTIONMARK -> symbol "?"+ BANG -> symbol "!"+ AND -> symbol "&"+ MID -> symbol "|"+ DOLLAR -> symbol "$"+ AT -> symbol "@"+ SHARP -> symbol "#"+ PERCENT -> symbol "%"+ LPAREN -> symbol "("+ RPAREN -> symbol ")"+ LBRACKET -> symbol "["+ RBRACKET -> symbol "]"+ LBRACE -> symbol "{"+ RBRACE -> symbol "}"+ SLASH -> symbol "/"+ BACKSLASH -> symbol "\\"+ TILDE -> symbol "~"+ HAT -> symbol "^"+ STAR -> symbol "*"+ UNDERSCORE -> symbol "_"+ MINUS -> symbol "-"+ PLUS -> symbol "+"+ EQUAL -> symbol "="+ LESS -> symbol "<"+ GREATER -> symbol ">"+ EOF -> "end of file"+ FORALL -> symbol "∀" + EXISTS -> symbol "∃" + LAND -> symbol "∧" + LOR -> symbol "∨" + LNOT -> symbol "¬" + APPROX -> symbol "≈" + DUMMY_KEYWORD -> "DUMMY_KEYWORD (this should not occur!)"+ where+ identifier i = "identifier `" ++ i ++ "'"+ txt (TextBegin t) = "start of `" ++ t ++ "'"+ txt (TextContent t) = "text `" ++ t ++ "'"+ txt (TextEnd) = "start of text"+ symbol s = "symbol `" ++ s ++ "'"+ keyword s = "keyword `" ++ s ++ "'"++-- -----------------------------------------------------------------------------+-- Alex wrapper code.+--+-- This code is in the PUBLIC DOMAIN; you may copy it freely and use+-- it for any purpose whatsoever.++-- -----------------------------------------------------------------------------+-- The input type+++type AlexInput = (AlexPosn, -- current position,+ Char, -- previous char+ String) -- current input string++alexInputPrevChar :: AlexInput -> Char+alexInputPrevChar (p,c,s) = c++alexGetChar :: AlexInput -> Maybe (Char,AlexInput)+alexGetChar (p,c,[]) = Nothing+alexGetChar (p,_,(c:s)) = let p' = alexMove p c in p' `seq`+ Just (c, (p', c, s))+++-- -----------------------------------------------------------------------------+-- Token positions++-- `Posn' records the location of a token in the input text. It has three+-- fields: the address (number of chacaters preceding the token), line number+-- and column of a token within the file. `start_pos' gives the position of the+-- start of the file and `eof_pos' a standard encoding for the end of file.+-- `move_pos' calculates the new position after traversing a given character,+-- assuming the usual eight character tab stops.++data AlexPosn = AlexPn !Int !Int !Int+ deriving (Eq)++instance Show AlexPosn where+ show (AlexPn _ l c) = "line "++show l++" column "++show c++alexStartPos :: AlexPosn+alexStartPos = AlexPn 0 1 1++alexMove :: AlexPosn -> Char -> AlexPosn+alexMove (AlexPn a l c) '\t' = AlexPn (a+1) l (((c+7) `div` 8)*8+1)+alexMove (AlexPn a l c) '\n' = AlexPn (a+1) (l+1) 1+alexMove (AlexPn a l c) _ = AlexPn (a+1) l (c+1)+++-- -----------------------------------------------------------------------------+-- Default monad+++data AlexState = AlexState {+ alex_pos :: !AlexPosn, -- position at current input location+ alex_inp :: String, -- the current input+ alex_chr :: !Char, -- the character before the input+ alex_scd :: !Int, -- the current startcode+ alex_ocd :: !Int, -- the old startcode before the comment started+ alex_cmt :: [String] -- stack of begin comment identifiers+ }++-- Compile with -funbox-strict-fields for best results!++runAlex :: String -> Alex a -> Either String a+runAlex input (Alex f) + = case f (AlexState {alex_pos = alexStartPos,+ alex_inp = input, + alex_chr = '\n',+ alex_scd = 0,+ alex_ocd = 0,+ alex_cmt = []+ }) of + Left msg -> Left msg+ Right ( _, a ) -> Right a++newtype Alex a = Alex { unAlex :: AlexState -> Either String (AlexState, a) }++instance Monad Alex where+ m >>= k = Alex $ \s -> case unAlex m s of + Left msg -> Left msg+ Right (s',a) -> unAlex (k a) s'+ return a = Alex $ \s -> Right (s,a)++alexGetPos :: Alex AlexPosn+alexGetPos = Alex $ \s@AlexState{alex_pos=pos} -> Right (s, pos)++alexGetInput :: Alex AlexInput+alexGetInput+ = Alex $ \s@AlexState{alex_pos=pos,alex_chr=c,alex_inp=inp} -> + Right (s, (pos,c,inp))++alexSetInput :: AlexInput -> Alex ()+alexSetInput (pos,c,inp)+ = Alex $ \s -> case s{alex_pos=pos,alex_chr=c,alex_inp=inp} of+ s@(AlexState{}) -> Right (s, ())++alexError :: String -> Alex a+alexError message = Alex $ \s -> Left $ message ++ " in " ++ show (alex_pos s)++alexGetStartCode :: Alex Int+alexGetStartCode = Alex $ \s@AlexState{alex_scd=sc} -> Right (s, sc)++alexSetStartCode :: Int -> Alex ()+alexSetStartCode sc = Alex $ \s -> Right (s{alex_scd=sc}, ())++alexGetOldStartCode :: Alex Int+alexGetOldStartCode = Alex $ \s@AlexState{alex_ocd=sc} -> Right (s, sc)++alexSetOldStartCode :: Int -> Alex ()+alexSetOldStartCode sc = Alex $ \s -> Right (s{alex_ocd=sc}, ())++alexGetComments :: Alex [String]+alexGetComments = Alex $ \s -> Right (s, alex_cmt s)++alexSetComments :: [String] -> Alex ()+alexSetComments cmt = Alex $ \s -> Right (s{alex_cmt=cmt}, ())++alexMonadScan = do+ inp <- alexGetInput+ sc <- alexGetStartCode+ case alexScan inp sc of+ AlexEOF -> alexEOF+ AlexError inp' -> alexError "lexical error"+ AlexSkip inp' len -> do+ alexSetInput inp'+ alexMonadScan+ AlexToken inp' len action -> do+ alexSetInput inp'+ action inp len++-- -----------------------------------------------------------------------------+-- Useful token actions++type AlexAction result = AlexInput -> Int -> Alex result++-- just ignore this token and scan another one+skip :: AlexAction Keyword+skip input len = alexMonadScan++-- ignore this token, but set the start code to a new value+begin :: Int -> AlexAction Keyword+begin code input len = do alexSetStartCode code; alexMonadScan++-- | Begin a text starting of the given type.+beginText :: String -> Int -> AlexAction Keyword+beginText ty code _ _ = do+ alexSetStartCode code+ return $ TEXT $ TextBegin ty++-- | End a text.+endText :: Int -> AlexAction Keyword+endText code _ _ = do+ alexSetStartCode code+ return $ TEXT TextEnd++-- | Begin a comment starting with the given sign.+beginComment :: String -> Int -> AlexAction Keyword+beginComment cmtBegin code input len = do+ cmts <- alexGetComments+ alexSetComments $ cmtBegin : cmts+ if null cmts+ then alexGetStartCode >>= alexSetOldStartCode+ else return ()+ alexSetStartCode code+ alexMonadScan++-- | End a comment that started with the given begin comment sign.+endComment :: String -> AlexAction Keyword+endComment cmtBegin input len = do+ cmts <- alexGetComments+ case cmts of+ [] -> alexError $ "comment ended but no beginning '"++cmtBegin++"' marked."+ (cmt:cmts') -> do+ if cmt == cmtBegin + then do+ alexSetComments cmts'+ if null cmts' + then alexGetOldStartCode >>= alexSetStartCode + else return ()+ else return ()+ alexMonadScan++-- perform an action for this token, and set the start code to a new value+-- andBegin :: AlexAction result -> Int -> AlexAction result+(action `andBegin` code) input len = do alexSetStartCode code; action input len++alexEOF :: Alex Keyword+alexEOF = return EOF++++++comment,text :: Int+comment = 1+text = 2+alex_action_2 = beginComment "(*" comment +alex_action_3 = beginComment "(*" comment +alex_action_4 = beginComment "(*" comment +alex_action_5 = endComment "(*" +alex_action_6 = beginComment "/*" comment +alex_action_7 = beginComment "/*" comment +alex_action_8 = beginComment "/*" comment +alex_action_9 = endComment "/*" +alex_action_10 = skip +alex_action_11 = beginText "text" text +alex_action_12 = beginText "section" text +alex_action_13 = beginText "subsection" text +alex_action_14 = endText 0+alex_action_15 = scanString (TEXT . TextContent) +alex_action_16 = keyword FORALL +alex_action_17 = keyword EXISTS +alex_action_18 = keyword LAND +alex_action_19 = keyword LOR +alex_action_20 = keyword LNOT +alex_action_21 = keyword APPROX +alex_action_22 = keyword COMMA +alex_action_23 = keyword LPAREN +alex_action_24 = keyword RPAREN +alex_action_25 = keyword LBRACKET +alex_action_26 = keyword RBRACKET +alex_action_27 = keyword LBRACE +alex_action_28 = keyword RBRACE +alex_action_29 = keyword SLASH +alex_action_30 = keyword BACKSLASH +alex_action_31 = keyword SQUOTE +alex_action_32 = keyword DQUOTE +alex_action_33 = keyword TILDE +alex_action_34 = keyword HAT +alex_action_35 = keyword EQUAL +alex_action_36 = keyword COLON +alex_action_37 = keyword DOLLAR +alex_action_38 = keyword AT +alex_action_39 = keyword SHARP +alex_action_40 = keyword PERCENT +alex_action_41 = keyword STAR +alex_action_42 = keyword LESS +alex_action_43 = keyword GREATER +alex_action_44 = keyword QUESTIONMARK +alex_action_45 = keyword BANG +alex_action_46 = keyword AND +alex_action_47 = keyword MID +alex_action_48 = keyword DOT +alex_action_49 = keyword UNDERSCORE +alex_action_50 = keyword MINUS +alex_action_51 = keyword PLUS +alex_action_52 = keyword RIGHTARROW +alex_action_53 = keyword LEFTARROW +alex_action_54 = keyword LONGRIGHTARROW +alex_action_55 = keyword LONGLEFTARROW +alex_action_56 = scanString IDENT+{-# LINE 1 "templates/GenericTemplate.hs" #-}+{-# LINE 1 "templates/GenericTemplate.hs" #-}+{-# LINE 1 "<built-in>" #-}+{-# LINE 1 "<command-line>" #-}+{-# LINE 1 "templates/GenericTemplate.hs" #-}+-- -----------------------------------------------------------------------------+-- ALEX TEMPLATE+--+-- This code is in the PUBLIC DOMAIN; you may copy it freely and use+-- it for any purpose whatsoever.++-- -----------------------------------------------------------------------------+-- INTERNALS and main scanner engine++{-# LINE 37 "templates/GenericTemplate.hs" #-}++{-# LINE 47 "templates/GenericTemplate.hs" #-}+++data AlexAddr = AlexA# Addr#++#if __GLASGOW_HASKELL__ < 503+uncheckedShiftL# = shiftL#+#endif++{-# INLINE alexIndexInt16OffAddr #-}+alexIndexInt16OffAddr (AlexA# arr) off =+#ifdef WORDS_BIGENDIAN+ narrow16Int# i+ where+ i = word2Int# ((high `uncheckedShiftL#` 8#) `or#` low)+ high = int2Word# (ord# (indexCharOffAddr# arr (off' +# 1#)))+ low = int2Word# (ord# (indexCharOffAddr# arr off'))+ off' = off *# 2#+#else+ indexInt16OffAddr# arr off+#endif++++++{-# INLINE alexIndexInt32OffAddr #-}+alexIndexInt32OffAddr (AlexA# arr) off = +#ifdef WORDS_BIGENDIAN+ narrow32Int# i+ where+ i = word2Int# ((b3 `uncheckedShiftL#` 24#) `or#`+ (b2 `uncheckedShiftL#` 16#) `or#`+ (b1 `uncheckedShiftL#` 8#) `or#` b0)+ b3 = int2Word# (ord# (indexCharOffAddr# arr (off' +# 3#)))+ b2 = int2Word# (ord# (indexCharOffAddr# arr (off' +# 2#)))+ b1 = int2Word# (ord# (indexCharOffAddr# arr (off' +# 1#)))+ b0 = int2Word# (ord# (indexCharOffAddr# arr off'))+ off' = off *# 4#+#else+ indexInt32OffAddr# arr off+#endif++++++#if __GLASGOW_HASKELL__ < 503+quickIndex arr i = arr ! i+#else+-- GHC >= 503, unsafeAt is available from Data.Array.Base.+quickIndex = unsafeAt+#endif+++++-- -----------------------------------------------------------------------------+-- Main lexing routines++data AlexReturn a+ = AlexEOF+ | AlexError !AlexInput+ | AlexSkip !AlexInput !Int+ | AlexToken !AlexInput !Int a++-- alexScan :: AlexInput -> StartCode -> AlexReturn a+alexScan input (I# (sc))+ = alexScanUser undefined input (I# (sc))++alexScanUser user input (I# (sc))+ = case alex_scan_tkn user input 0# input sc AlexNone of+ (AlexNone, input') ->+ case alexGetChar input of+ Nothing -> ++++ AlexEOF+ Just _ ->++++ AlexError input'++ (AlexLastSkip input'' len, _) ->++++ AlexSkip input'' len++ (AlexLastAcc k input''' len, _) ->++++ AlexToken input''' len k+++-- Push the input through the DFA, remembering the most recent accepting+-- state it encountered.++alex_scan_tkn user orig_input len input s last_acc =+ input `seq` -- strict in the input+ let + new_acc = check_accs (alex_accept `quickIndex` (I# (s)))+ in+ new_acc `seq`+ case alexGetChar input of+ Nothing -> (new_acc, input)+ Just (c, new_input) -> ++++ let+ (base) = alexIndexInt32OffAddr alex_base s+ ((I# (ord_c))) = ord c+ (offset) = (base +# ord_c)+ (check) = alexIndexInt16OffAddr alex_check offset+ + (new_s) = if (offset >=# 0#) && (check ==# ord_c)+ then alexIndexInt16OffAddr alex_table offset+ else alexIndexInt16OffAddr alex_deflt s+ in+ case new_s of + -1# -> (new_acc, input)+ -- on an error, we want to keep the input *before* the+ -- character that failed, not after.+ _ -> alex_scan_tkn user orig_input (len +# 1#) + new_input new_s new_acc++ where+ check_accs [] = last_acc+ check_accs (AlexAcc a : _) = AlexLastAcc a input (I# (len))+ check_accs (AlexAccSkip : _) = AlexLastSkip input (I# (len))+ check_accs (AlexAccPred a predx : rest)+ | predx user orig_input (I# (len)) input+ = AlexLastAcc a input (I# (len))+ check_accs (AlexAccSkipPred predx : rest)+ | predx user orig_input (I# (len)) input+ = AlexLastSkip input (I# (len))+ check_accs (_ : rest) = check_accs rest++data AlexLastAcc a+ = AlexNone+ | AlexLastAcc a !AlexInput !Int+ | AlexLastSkip !AlexInput !Int++data AlexAcc a user+ = AlexAcc a+ | AlexAccSkip+ | AlexAccPred a (AlexAccPred user)+ | AlexAccSkipPred (AlexAccPred user)++type AlexAccPred user = user -> AlexInput -> Int -> AlexInput -> Bool++-- -----------------------------------------------------------------------------+-- Predicates on a rule++alexAndPred p1 p2 user in1 len in2+ = p1 user in1 len in2 && p2 user in1 len in2++--alexPrevCharIsPred :: Char -> AlexAccPred _ +alexPrevCharIs c _ input _ _ = c == alexInputPrevChar input++--alexPrevCharIsOneOfPred :: Array Char Bool -> AlexAccPred _ +alexPrevCharIsOneOf arr _ input _ _ = arr ! alexInputPrevChar input++--alexRightContext :: Int -> AlexAccPred _+alexRightContext (I# (sc)) user _ _ input = + case alex_scan_tkn user input 0# input sc AlexNone of+ (AlexNone, _) -> False+ _ -> True+ -- TODO: there's no need to find the longest+ -- match when checking the right context, just+ -- the first match will do.++-- used by wrappers+iUnbox (I# (i)) = i
@@ -0,0 +1,829 @@+{-# LANGUAGE TupleSections #-}+-- |+-- Copyright : (c) 2010-2012 Simon Meier, Benedikt Schmidt+-- License : GPL v3 (see LICENSE)+-- +-- Maintainer : Simon Meier <iridcode@gmail.com>+-- Portability : portable+--+-- Parsing protocol theories.+module Theory.Parser (+ parseOpenTheory+ , parseOpenTheoryString+ , parseProofMethod+ , parseLemma+ ) where++import Prelude hiding (id, (.))++import Data.Char (toUpper, isUpper, isDigit)+import Data.Foldable (asum)+import Data.Label+import qualified Data.Set as S+import qualified Data.Map as M+import Data.Monoid+import Data.Maybe++import Control.Monad+import Control.Applicative hiding (empty, many, optional)+import Control.Category++import Extension.Prelude++import Text.Parsec.Pos+import Text.Parsec hiding (token, (<|>), string )+import qualified Text.Parsec as P++import Theory.Lexer + ( Keyword(..), TextType(..), runAlex, AlexPosn(..)+ , alexGetPos, alexMonadScan+ )+import Term.SubtermRule++import Text.Isar (render)++import Theory++------------------------------------------------------------------------------+-- Specializing Parsec to our needs+------------------------------------------------------------------------------++-- Scanner+----------++-- | The tokens delivered by our Alex based scanner+type Token = (SourcePos, Keyword)++-- | Scan a string using the given filename in the error messages.+--+-- NOTE: Lexical errors are thrown using 'error'.+scanString :: FilePath -> String -> [Token]+scanString filename s = + case runAlex s gatherUntilEOF of+ Left err -> error err+ Right kws -> kws+ where+ gatherUntilEOF = do+ AlexPn _ line col <- alexGetPos+ let pos = newPos filename line col+ k <- alexMonadScan+ case k of + EOF -> return [(pos,EOF)]+ _ -> do kws <- gatherUntilEOF+ return $ (pos,k) : kws++-- Parser+---------++-- | A parser for a stream of tokens.+type Parser a = Parsec [Token] MaudeSig a++-- | Parse a token based on the acceptance condition+token :: (Keyword -> Maybe a) -> Parser a+token p = P.token (show . snd) fst (p . snd)++-- | Parse a term.+kw :: Keyword -> Parser ()+kw t = token check+ where + check t' | t == t' = Just () | otherwise = Nothing++-- | Parse content between keywords.+betweenKWs :: Keyword -> Keyword -> Parser a -> Parser a+betweenKWs l r = between (kw l) (kw r)++{-+-- | Between braces.+braced :: Parser a -> Parser a+braced = betweenKWs LBRACE RBRACE+-}++-- | Between parentheses.+parens :: Parser a -> Parser a+parens = betweenKWs LPAREN RPAREN++-- | Between single quotes.+singleQuoted :: Parser a -> Parser a+singleQuoted = betweenKWs SQUOTE SQUOTE++-- | Between double quotes.+doubleQuoted :: Parser a -> Parser a+doubleQuoted = betweenKWs DQUOTE DQUOTE++-- | Parse an identifier as a string+identifier :: Parser String+identifier = token extract+ where extract (IDENT name) = Just $ name+ extract _ = Nothing++-- | Parse a fixed string which could be an identifier.+string :: String -> Parser ()+string cs = (try $ do { i <- identifier; guard (i == cs) }) <?> ('`' : cs ++ "'")++-- | Parse a sequence of fixed strings.+strings :: [String] -> Parser ()+strings = mapM_ string++-- | Parse an integer.+integer :: Parser Int+integer = do i <- identifier+ guard (all isDigit i)+ return (read i)++-- | A comma separated list of elements.+commaSep :: Parser a -> Parser [a]+commaSep = (`sepBy` kw COMMA)++{-+-- | A comma separated non-empty list of elements.+commaSep1 :: Parser a -> Parser [a]+commaSep1 = (`sepBy1` kw COMMA)+-}++-- | Parse a list of items '[' item ',' ... ',' item ']'+list :: Parser a -> Parser [a]+list p = kw LBRACKET *> commaSep p <* kw RBRACKET++-- | A formal comment; i.e., (header, body)+formalComment :: Parser (String, String)+formalComment =+ (,) <$> text begin + <*> (concat <$> many (text content) <* text end)+ where+ text f = token (\t -> case t of TEXT ty -> f ty; _ -> mzero)+ begin (TextBegin str) = return str+ begin _ = mzero+ content (TextContent str) = return str+ content _ = mzero+ end (TextEnd) = return ()+ end _ = mzero+++------------------------------------------------------------------------------+-- Lexing and parsing theory files and proof methods+------------------------------------------------------------------------------++-- | Parser a file.+parseFile :: Parser a -> FilePath -> IO a+parseFile parser f = do+ s <- readFile f+ case runParser parser minimalMaudeSig f (scanString f s) of+ Right p -> return p+ Left err -> error $ show err++-- | Parse a security protocol theory file.+parseOpenTheory :: [String] -- ^ Defined flags+ -> FilePath -> IO OpenTheory+parseOpenTheory flags = parseFile (theory flags)++-- | Parse a security protocol theory file.+-- TODO: This function seems to parse a string, not a file from a file path?+parseProofMethod :: FilePath -> Either ParseError ProofMethod+parseProofMethod = + runParser proofMethod minimalMaudeSig dummySource . scanString dummySource+ where + dummySource = "<interactive>"++-- | Parse a security protocol theory from a string.+parseOpenTheoryString :: [String] -- ^ Defined flags.+ -> String -> Either ParseError OpenTheory+parseOpenTheoryString flags = parseFromString (theory flags)++-- | Parse a lemma for an open theory from a string.+parseLemma :: String -> Either ParseError (Lemma ProofSkeleton)+parseLemma = parseFromString lemma++-- | Run a given parser on a given string.+parseFromString :: Parser a -> String -> Either ParseError a+parseFromString parser =+ runParser parser minimalMaudeSig dummySource . scanString dummySource+ where+ dummySource = "<interactive>"++------------------------------------------------------------------------------+-- Parsing Terms+------------------------------------------------------------------------------+++{-+BNF: Not completely up to date...++theory := 'theory' ident 'begin' protocol 'end'+protocol := rules+rules := rule | rule rules+intrrule := ident '[' intrinfo ']' ':' terms '-->' terms+intrinfo := 'Destr' | 'Constr'+protorule := ident ':' factList '-->' factList+factList := '[' [facts] ']'+facts := fact | fact ',' facts+protoFact := ident '(' terms ')'+terms := term | term ',' terms +term := lit | application | '<' term ',' terms '>' -- right assoc pairing+application := ident '(' terms ')'+lit := ident | '\'' ident '\''+ident := <a-zA-Z> (<a-zA-Z0-9-_)+++// example protocol rule++ Init_1: + [ Pub(I), Pub(R), Fresh(ni) ]+ -->+ [ Init_1(I,R,ni), Send(encA(pk(R), <I,R,ni>)) ]++// example intruder rule+ + Exp [Constr]:+ [ (x^_((x1*x2))), ((x3*x1)*_x4) ]+ -->+ [ (x^(x3*_((x4*x2)))) ]++-}++------------------------------------------------------------------------------+-- Parsing Terms+------------------------------------------------------------------------------++-- | Parse an identifier possibly indexed with a number.+indexedIdentifier :: Parser (String, Int)+indexedIdentifier =+ -- FIXME: It might be confusing that 'x.0' and 'x' denote the same variable+ (\s mi -> (s, fromMaybe 0 mi)) <$> identifier <*> optionMaybe (try (kw DOT *> integer))++-- | Parse a logical variable with the given sorts allowed.+sortedLVar :: [LSort] -> Parser LVar+sortedLVar ss = + asum $ map (try . mkSuffixParser) ss ++ map mkPrefixParser ss+ where+ mkSuffixParser s = do+ (n, i) <- indexedIdentifier+ kw COLON+ string (sortSuffix s)+ return (LVar n s i)++ mkPrefixParser s = do+ case s of+ LSortMsg -> pure ()+ LSortPub -> kw DOLLAR+ LSortFresh -> kw TILDE+ LSortNode -> kw SHARP+ LSortMSet -> kw PERCENT+ (n, i) <- indexedIdentifier+ return (LVar n s i)++-- | An arbitrary logical variable.+lvar :: Parser LVar+lvar = sortedLVar [minBound..]++-- | Parse a non-node variable.+msgvar :: Parser LVar+msgvar = sortedLVar [LSortFresh, LSortPub, LSortMsg, LSortMSet]++-- | Parse a graph node variable.+nodevar :: Parser NodeId+nodevar = asum + [ sortedLVar [LSortNode]+ , (\(n, i) -> LVar n LSortNode i) <$> indexedIdentifier ]+ <?> "node"++-- | Parse an lit with logical variables.+llit :: Parser LNTerm+llit = asum+ [ freshTerm <$> try (kw TILDE *> singleQuoted identifier) <?> "fresh name"+ , pubTerm <$> singleQuoted identifier <?> "public name"+ , varTerm <$> msgvar+ ]++-- | Lookup the arity of a non-ac symbol. Fails with a sensible error message+-- if the operator is not known.+lookupNonACArity :: String -> Parser Int+lookupNonACArity op = do+ maudeSig <- getState+ case lookup op (funSigForMaudeSig maudeSig) of+ Nothing -> fail $ "unknown operator `" ++ op ++ "'"+ Just k -> return k++-- | Parse an n-ary operator application for arbitrary n.+naryOpApp :: Parser (Term l) -> Parser (Term l)+naryOpApp lit = do+ op <- identifier+ k <- lookupNonACArity op+ ts <- parens $ if k == 1+ then return <$> tupleterm lit+ else sepBy (multterm lit) (kw COMMA)+ let k' = length ts+ when (k /= k') $+ fail $ "operator `" ++ op ++"' has arity " ++ show k +++ ", but here it is used with arity " ++ show k'+ return $ FApp (NonAC (op, k')) ts++-- | Parse a binary operator written as @op{arg1}arg2@.+binaryAlgApp :: Parser (Term l) -> Parser (Term l)+binaryAlgApp lit = do+ op <- identifier+ k <- lookupNonACArity op+ arg1 <- kw LBRACE *> tupleterm lit <* kw RBRACE+ arg2 <- term lit+ when (k /= 2) $ fail $ + "only operators of arity 2 can be written using the `op{t1}t2' notation"+ return $ FApp (NonAC (op, 2)) [arg1, arg2]++-- | Parse a term.+term :: Parser (Term l) -> Parser (Term l)+term lit = asum+ [ pairing <?> "pairs"+ , parens (multterm lit)+ , kw UNDERSCORE *> (FApp (NonAC invSym) . return <$> term lit)+ , string "1" *> pure (FApp (NonAC oneSym) [])+ , application <?> "function application"+ , nullaryApp+ , lit + ]+ <?> "term"+ where+ application = asum $ map (try . ($ lit)) [naryOpApp, binaryAlgApp]+ pairing = kw LESS *> tupleterm lit <* kw GREATER+ nullaryApp = do+ maudeSig <- getState+ asum [ try (string sym) *> pure (FApp (NonAC (sym,0)) [])+ | (sym,0) <- funSigForMaudeSig maudeSig ]++-- | A left-associative sequence of exponentations.+expterm :: Parser (Term l) -> Parser (Term l)+expterm lit = chainl1 (term lit) ((\a b -> FApp (NonAC expSym) [a,b]) <$ kw HAT)++-- | A left-associative sequence of multiplications.+multterm :: Parser (Term l) -> Parser (Term l)+multterm lit = chainl1 (expterm lit) ((\a b -> FApp (AC Mult) [a,b]) <$ kw STAR)+ -- FIXME: parse as n-ary multiplication++-- | A right-associative sequence of tuples.+tupleterm :: Parser (Term l) -> Parser (Term l)+tupleterm lit = chainr1 pterm ((\a b -> FApp (NonAC pairSym) [a,b])<$ kw COMMA)+ where pterm = ifM (enableDH <$> getState) (multterm lit) (term lit)++-- | Parse a fact.+fact :: Parser (Term l) -> Parser (Fact (Term l))+fact lit = + do multi <- option Linear (kw BANG *> pure Persistent)+ i <- identifier+ case i of+ [] -> fail "empty identifier"+ (c:_) | isUpper c -> return ()+ | otherwise -> fail "facts must start with upper-case letters"+ ts <- parens (sepBy (multterm lit) (kw COMMA))+ mkProtoFact multi i ts+ <?> "protocol fact"+ where+ singleTerm _ constr [t] = return $ constr t+ singleTerm f _ ts = fail $ "fact '" ++ f ++ "' used with arity " +++ show (length ts) ++ " instead of arity one"++ mkProtoFact multi f = case map toUpper f of+ "OUT" -> singleTerm f outFact + "IN" -> singleTerm f inFact+ "KU" -> return . Fact KUFact+ "KD" -> return . Fact KDFact+ "FR" -> singleTerm f freshFact+ _ -> return . protoFact multi f+++------------------------------------------------------------------------------+-- Parsing Rules+------------------------------------------------------------------------------++-- | Parse a "(modulo ..)" information.+modulo :: String -> Parser ()+modulo thy = parens $ strings ["modulo", thy]++moduloE, moduloAC :: Parser ()+moduloE = modulo "E"+moduloAC = modulo "AC"++{-+-- | Parse a typing assertion modulo E.+typeAssertions :: Parser TypingE+typeAssertions = fmap TypingE $+ do try (strings ["type", "assertions"])+ optional moduloE+ kw COLON+ many1 ((,) <$> (try (msgvar <* kw COLON))+ <*> ( commaSep1 (try $ multterm llit) <|> + (kw MINUS *> pure [])+ )+ ) + <|> pure []+-}++-- | Parse a protocol rule. For the special rules 'Reveal_fresh', 'Fresh',+-- 'Knows', and 'Learn' no rule is returned as the default theory already+-- contains them.+protoRule :: Parser (ProtoRuleE)+protoRule = do+ name <- try (string "rule" *> optional moduloE *> identifier <* kw COLON) + (ps,as,cs) <- genericRule+ return $ Rule (StandRule name) ps cs as++-- | Parse an intruder rule.+intrRule :: Parser IntrRuleAC+intrRule = do+ info <- try (string "rule" *> moduloAC *> intrInfo <* kw COLON) + (ps,as,cs) <- genericRule+ return $ Rule info ps cs as+ where+ intrInfo = do+ name <- identifier+ if map toUpper name == "COERCE"+ then return $ CoerceRule+ else return $ IntrApp name++genericRule :: Parser ([LNFact], [LNFact], [LNFact])+genericRule = + (,,) <$> list (fact llit) + <*> ((pure [] <* kw LONGRIGHTARROW) <|>+ (kw MINUS *> kw MINUS *> list (fact llit) <* kw RIGHTARROW))+ <*> list (fact llit)++{-+-- | Add facts to a rule.+addFacts :: String -- ^ Command to be used: add_concs, add_prems+ -> Parser (String, [LNFact])+addFacts cmd = + (,) <$> (string cmd *> identifier <* kw COLON) <*> commaSep1 fact+-}++------------------------------------------------------------------------------+-- Parsing transfer notation+------------------------------------------------------------------------------++{-+-- | Parse an lit with strings for both constants as well as variables.+tlit :: Parser TTerm+tlit = asum+ [ constTerm <$> singleQuoted identifier+ , varTerm <$> identifier+ ]++-- | Parse a single transfer.+transfer :: Parser Transfer+transfer = do+ tf <- (\l -> Transfer l Nothing Nothing) <$> identifier <* kw DOT+ (do right <- kw RIGHTARROW *> identifier <* kw COLON+ desc <- transferDesc+ return $ tf { tfRecv = Just (desc right) }+ <|>+ do right <- kw LEFTARROW *> identifier <* kw COLON+ descr <- transferDesc+ (do left <- try $ identifier <* kw LEFTARROW <* kw COLON+ descl <- transferDesc+ return $ tf { tfSend = Just (descr right)+ , tfRecv = Just (descl left) }+ <|>+ do return $ tf { tfSend = Just (descr right) }+ )+ <|>+ do left <- identifier+ (do kw RIGHTARROW+ (do right <- identifier <* kw COLON+ desc <- transferDesc+ return $ tf { tfSend = Just (desc left)+ , tfRecv = Just (desc right) }+ <|>+ do descl <- kw COLON *> transferDesc+ (do right <- kw RIGHTARROW *> identifier <* kw COLON+ descr <- transferDesc+ return $ tf { tfSend = Just (descl left)+ , tfRecv = Just (descr right) }+ <|>+ do return $ tf { tfSend = Just (descl left) }+ )+ )+ <|>+ do kw LEFTARROW+ (do desc <- kw COLON *> transferDesc+ return $ tf { tfRecv = Just (desc left) }+ <|>+ do right <- identifier <* kw COLON+ desc <- transferDesc+ return $ tf { tfSend = Just (desc right)+ , tfRecv = Just (desc left) }+ )+ )+ ) + where+ transferDesc = do+ ts <- tupleterm tlit+ moreConcs <- (string "note" *> many1 (try $ fact tlit))+ <|> pure []+ types <- typeAssertions+ return $ \a -> TransferDesc a ts moreConcs types+++-- | Parse a protocol in transfer notation+transferProto :: Parser [ProtoRuleE]+transferProto = do+ name <- string "anb" *> kw MINUS *> string "proto" *> identifier + braced (convTransferProto name <$> abbrevs <*> many1 transfer)+ where+ abbrevs = (string "let" *> many1 abbrev) <|> pure []+ abbrev = (,) <$> try (identifier <* kw EQUAL) <*> multterm tlit ++-}++------------------------------------------------------------------------------+-- Parsing Proofs+------------------------------------------------------------------------------++{-+-- | Parse a node premise.+nodePrem :: Parser NodePrem+nodePrem = NodePrem <$> parens ((,) <$> nodevar <*> (kw COMMA *> integer))++-- | Parse a node conclusion.+nodeConc :: Parser NodeConc+nodeConc = NodeConc <$> parens ((,) <$> nodevar <*> (kw COMMA *> integer))+-}+++-- | Parse the @\@@ requires operator.+actionOp :: Parser ()+actionOp = try (kw AT)++-- | Parse the @<@ temporal less operator.+edgeOp :: Parser ()+edgeOp = try (kw GREATER *> kw RIGHTARROW)++-- | Parse the @<@ temporal less operator.+lessOp :: Parser ()+lessOp = try (kw LESS)++-- | Parse the @=@ equal operator.+equalOp :: Parser ()+equalOp = kw APPROX <|> kw EQUAL++-- | Parse the @--|@ deduced before operator.+dedBeforeOp :: Parser ()+dedBeforeOp = try (kw MINUS *> kw MINUS *> kw MID)++{-+-- | Parse the @~~>@ chain operator.+chainOp :: Parser ()+chainOp = kw TILDE *> kw TILDE *> kw TILDE *> kw GREATER+-}++-- | Parse a goal.+goal :: Parser Goal+goal = fail "SM: reimplement goal parsing" {- asum + [ splitGoal+ , premiseGoal+ , chainGoal+ ]+ where+ premiseGoal = try $ do+ v <- nodevar+ i <- brackets integer <* requiresOp+ fa <- fact llit+ return $ PremiseGoal fa (NodePrem (v, i))++ chainGoal = ChainGoal + <$> (try $ term llit <* kw COLON)+ <*> (Chain <$> (nodeConc <* chainOp) <*> nodePrem)++ splitGoal = do+ split <- (string "splitEqsOn" *> pure SplitEqs) <|>+ (string "splitTypingOn" *> pure SplitTyping)+ SplitGoal split <$> parens integer+-}++-- | Parse a proof method.+proofMethod :: Parser ProofMethod+proofMethod = optional (kw BANG) *> asum+ [ string "sorry" *> pure (Sorry "not yet proven")+ , string "simplify" *> pure Simplify+ , string "solve" *> (SolveGoal <$> parens goal)+ , string "contradiction" *> pure (Contradiction Nothing)+ ]++-- | Parse a proof skeleton.+proofSkeleton :: Parser ProofSkeleton+proofSkeleton = + finalProof <|> interProof+ where+ finalProof = do+ method <- string "by" *> proofMethod+ return (LNode (ProofStep method ()) M.empty)++ interProof = do+ method <- proofMethod+ cases <- (sepBy oneCase (string "next") <* string "qed") <|> + ((return . ("",)) <$> proofSkeleton )+ return (LNode (ProofStep method ()) (M.fromList cases))++ oneCase = (,) <$> (string "case" *> identifier) <*> proofSkeleton ++------------------------------------------------------------------------------+-- Parsing Formulas and Lemmas+------------------------------------------------------------------------------++-- | Parse an atom with possibly bound logical variables.+blatom :: Parser BLAtom+blatom = (fmap (fmap (fmap Free))) <$> asum+ [ flip Action <$> try (fact llit <* actionOp) <*> nodevarTerm <?> "action"+ , Less <$> try (nodevarTerm <* lessOp) <*> nodevarTerm <?> "less"+ , DedBefore <$> try (term llit <* dedBeforeOp) <*> nodevarTerm <?> "deduced before"+ , EdgeA <$> try (nodePrem <* edgeOp) <*> nodeConc <?> "edge"+ , EqE <$> try (multterm llit <* equalOp) <*> multterm llit <?> "term equality"+ , EqE <$> (nodevarTerm <* equalOp) <*> nodevarTerm <?> "node equality"+ ]+ where + nodevarTerm = (Lit . Var) <$> nodevar+ nodePrem = parens ((,) <$> (nodevarTerm <* kw COMMA) <*> integer)+ nodeConc = nodePrem++-- | Parse an atom of a formula.+fatom :: Parser (LFormula Name)+fatom = asum+ [ pure lfalse <* string "F"+ , pure ltrue <* string "T"+ , Ato <$> try blatom+ , quantification+ , parens iff+ ]+ where+ quantification = do+ q <- (pure forall <* (kw FORALL <|> string "All")) <|>+ (pure exists <* (kw EXISTS <|> string "Ex") )+ vs <- many1 lvar <* kw DOT+ f <- iff+ return $ foldr (hinted q) f vs++ hinted :: ((String, LSort) -> LVar -> a) -> LVar -> a+ hinted f v@(LVar n s _) = f (n,s) v++++-- | Parse a negation.+negation :: Parser (LFormula Name)+negation = ((kw LNOT <|> string "not") *> (Not <$> fatom)) <|> fatom++-- | Parse a left-associative sequence of conjunctions.+conjuncts :: Parser (LFormula Name)+conjuncts = chainl1 negation ((.&&.) <$ (kw LAND <|> kw AND))++-- | Parse a left-associative sequence of disjunctions.+disjuncts :: Parser (LFormula Name)+disjuncts = chainl1 conjuncts ((.||.) <$ (kw LOR <|> kw MID))++-- | An implication.+imp :: Parser (LFormula Name)+imp = do+ lhs <- disjuncts+ asum [ try (kw EQUAL *> kw EQUAL *> kw GREATER) *> + ((lhs .==>.) <$> disjuncts)+ , pure lhs ]++-- | An logical equivalence.+iff :: Parser (LFormula Name)+iff = do+ lhs <- imp+ asum [ try (kw LESS *> kw EQUAL *> kw GREATER) *> + ((lhs .<=>.) <$> imp)+ , pure lhs ]++-- | Parse a lemma attribute.+lemmaAttribute :: Parser LemmaAttribute+lemmaAttribute = asum+ [ string "typing" *> pure TypingLemma+ , string "reuse" *> pure ReuseLemma+ ]++-- | Parse a lemma.+lemma :: Parser (Lemma ProofSkeleton)+lemma = skeletonLemma <$> (string "lemma" *> optional moduloE *> identifier) + <*> (option [] $ list lemmaAttribute)+ <*> (kw COLON *> doubleQuoted iff)+ <*> (proofSkeleton <|> pure (unproven ()))+++-- | Parse a globally fresh 'FactTag' written as+-- +-- fresh proto/2++globallyFresh :: Parser (S.Set FactTag)+globallyFresh = + string "unique_insts" *> kw COLON *> + (S.fromList <$> sepBy1 factSymbol (kw COMMA))+ where+ factSymbol = + ProtoFact Linear <$> identifier <*> (kw SLASH *> integer)++builtin :: Parser ()+builtin =+ string "builtin" *> kw COLON *> sepBy1 builtinTheory (kw COMMA) *> pure ()+ where+ extendSig msig = modifyState (`mappend` msig)+ builtinTheory = asum+ [ try (string "diffie" *> kw MINUS *> string "hellman")+ *> extendSig dhMaudeSig+ , try (string "symmetric" *> kw MINUS *> string "encryption")+ *> extendSig symEncMaudeSig+ , try (string "asymmetric" *> kw MINUS *> string "encryption")+ *> extendSig asymEncMaudeSig+ , try (string "signing")+ *> extendSig signatureMaudeSig+ , string "hashing"+ *> extendSig hashMaudeSig+ ]++functions :: Parser ()+functions =+ string "functions" *> kw COLON *> sepBy1 functionSymbol (kw COMMA) *> pure ()+ where+ functionSymbol = do+ funsym <- (,) <$> identifier <*> (kw SLASH *> integer)+ sig <- getState+ case lookup (fst funsym) (funSig sig) of+ Just k | k /= snd funsym ->+ fail $ "conflicting arities " ++ + show k ++ " and " ++ show (snd funsym) ++ + " for `" ++ fst funsym+ _ -> setState (sig `mappend` emptyMaudeSig {funSig = [funsym]})++equations :: Parser ()+equations =+ string "equations" *> kw COLON *> sepBy1 equation (kw COMMA) *> pure ()+ where+ equation = do+ rrule <- RRule <$> term llit <*> (kw EQUAL *> term llit)+ case rRuleToStRule rrule of+ Just str ->+ modifyState (`mappend` emptyMaudeSig {stRules = [str]})+ Nothing ->+ fail $ "Not a subterm rule: " ++ show rrule++------------------------------------------------------------------------------+-- Parsing Theories+------------------------------------------------------------------------------+++-- | Parse a theory.+theory :: [String] -- ^ Defined flags.+ -> Parser OpenTheory+theory flags0 = do+ string "theory"+ thyId <- identifier+ string "begin" + *> addItems (S.fromList flags0) (set thyName thyId defaultOpenTheory) + <* string "end"+ where+ addItems :: S.Set String -> OpenTheory -> Parser OpenTheory+ addItems flags thy = asum+ [ do fresh <- globallyFresh+ addItems flags $ + modify (sigpUniqueInsts . thySignature) (S.union fresh) thy+ , do builtin+ msig <- getState+ addItems flags $ set (sigpMaudeSig . thySignature) msig thy+ , do functions+ msig <- getState+ addItems flags $ set (sigpMaudeSig . thySignature) msig thy+ , do equations+ msig <- getState+ addItems flags $ set (sigpMaudeSig . thySignature) msig thy+-- , do thy' <- foldM liftedAddProtoRule thy =<< transferProto+-- addItems flags thy'+ , do thy' <- liftedAddLemma thy =<< lemma+ addItems flags thy'+ , do ru <- protoRule+ thy' <- liftedAddProtoRule thy ru+ addItems flags thy'+ , do r <- intrRule+ addItems flags (addIntrRuleACs [r] thy)+ , do c <- formalComment+ addItems flags (addFormalComment c thy)+ , do ifdef flags thy+ , do define flags thy+ , do return thy+ ]++ define :: S.Set String -> OpenTheory -> Parser OpenTheory+ define flags thy = do+ flag <- try (kw SHARP *> string "define") *> identifier+ addItems (S.insert flag flags) thy++ ifdef :: S.Set String -> OpenTheory -> Parser OpenTheory+ ifdef flags thy = do+ flag <- try (kw SHARP *> string "ifdef") *> identifier+ thy' <- addItems flags thy+ try (kw SHARP *> string "endif")+ if flag `S.member` flags+ then addItems flags thy'+ else addItems flags thy++ liftedAddProtoRule thy ru = case addProtoRule ru thy of+ Just thy' -> return thy'+ Nothing -> fail $ "duplicate rule: " ++ render (prettyRuleName ru)++ liftedAddLemma thy l = case addLemma l thy of+ Just thy' -> return thy'+ Nothing -> fail $ "duplicate lemma: " ++ get lName l
@@ -0,0 +1,109 @@+-- |+-- Copyright : (c) 2011 Simon Meier+-- License : GPL v3 (see LICENSE)+-- +-- Maintainer : Simon Meier <iridcode@gmail.com>+-- Portability : portable+--+-- General support for pretty printing theories.+module Theory.Pretty (+ -- * General highlighters+ module Text.PrettyPrint.Highlight++ -- * Comments+ , lineComment+ , multiComment++ , lineComment_+ , multiComment_++ -- * Keywords+ , kwTheoryHeader+ , kwEnd + , kwModulo+ , kwBy+ , kwCase+ , kwNext+ , kwQED++ -- ** Composed forms+ , kwLemmaModulo+ , kwRuleModulo+ , kwInstanceModulo+ , kwVariantsModulo+ , kwTypesModulo++ -- * Operators+ , opProvides+ , opRequires+ , opAction+ , opPath+ , opLess+ , opEqual+ , opDedBefore+ , opEdge++ ) where++import Text.PrettyPrint.Highlight++------------------------------------------------------------------------------+-- Comments+------------------------------------------------------------------------------++lineComment :: HighlightDocument d => d -> d+lineComment d = comment $ text "//" <-> d++lineComment_ :: HighlightDocument d => String -> d+lineComment_ = lineComment . text++multiComment :: HighlightDocument d => d -> d+multiComment d = comment $ fsep [text "/*", d, text "*/"]++multiComment_ :: HighlightDocument d => [String] -> d+multiComment_ ls = comment $ fsep [text "/*", vcat $ map text ls, text "*/"]++------------------------------------------------------------------------------+-- Keywords+------------------------------------------------------------------------------++kwTheoryHeader :: HighlightDocument d => String -> d+kwTheoryHeader name = keyword_ "theory" <-> text name <-> keyword_ "begin"++kwEnd, kwBy, kwCase, kwNext, kwQED :: HighlightDocument d => d+kwEnd = keyword_ "end"+kwBy = keyword_ "by"+kwCase = keyword_ "case"+kwNext = keyword_ "next"+kwQED = keyword_ "qed"++kwModulo :: HighlightDocument d+ => String -- ^ What+ -> String -- ^ modulo theory+ -> d+kwModulo what thy = keyword_ what <-> parens (keyword_ "modulo" <-> text thy)++kwLemmaModulo, kwRuleModulo, kwInstanceModulo, kwTypesModulo, kwVariantsModulo+ :: HighlightDocument d => String -> d+kwLemmaModulo = kwModulo "lemma"+kwRuleModulo = kwModulo "rule"+kwInstanceModulo = kwModulo "instance"+kwTypesModulo = kwModulo "type assertions"+kwVariantsModulo = kwModulo "variants"+++------------------------------------------------------------------------------+-- Operators+------------------------------------------------------------------------------++opProvides, opRequires, opAction, opPath, opLess, opEqual, opDedBefore, opEdge+ :: HighlightDocument d => d+opProvides = operator_ ":>"+opRequires = operator_ "<:"+opAction = operator_ "@"+opPath = operator_ ">+>"+opLess = operator_ "<"+opEqual = operator_ "="+opDedBefore = operator_ "--|"+opEdge = operator_ ">->"+
@@ -0,0 +1,772 @@+{-# LANGUAGE TemplateHaskell, TupleSections #-}+-- |+-- Copyright : (c) 2010-2012 Simon Meier & Benedikt Schmidt+-- License : GPL v3 (see LICENSE)+-- +-- Maintainer : Simon Meier <iridcode@gmail.com>+-- Portability : GHC only+--+-- Types to represent proofs.+module Theory.Proof (+ -- * Utilities+ LTree(..)+ , mergeMapsWith++ -- * Types+ , Contradiction(..)+ , ProofMethod(..)+ , ProofStep(..)+ , CaseName+ , Proof++ -- ** Paths inside proofs+ , ProofPath+ , atPath+ , insertPaths++ -- ** Folding/modifying proofs+ , foldProof+ , ProofStatus+ , proofStepStatus++ , cutOnAttackDFS+ , cutOnAttackBFS++ -- ** Unfinished proofs+ , sorry+ , unproven++ -- ** Proof methods+ , execProofMethod+ , possibleProofMethods++ -- ** Incremental proof construction+ , IncrementalProof+ , Prover+ , runProver+ , mapProverProof++ , orelse+ , tryProver+ , sorryProver+ , oneStepProver+ , autoProver+ , boundProver+ , focus+ , checkAndExtendProver+ , replaceSorryProver+ , contradictionAndClauseProver++ -- ** Pretty Printing+ , prettyProofMethod+ , prettyProof+ , prettyProofWith++ , showProofStatus++ -- ** Parallel Strategy for exploring a proof+ , parLTreeDFS++ -- * Convenience exports+ , module Theory.Proof.CaseDistinctions+) where++import Safe+import Data.Maybe+import Data.List+import Data.Ord (comparing)+import Data.Function (on)+import qualified Data.Map as M+import qualified Data.Set as S+import Data.Monoid+import Data.Foldable (Foldable, foldMap, asum)+import Data.Traversable+import qualified Data.Label as L+import Data.Label hiding (get)+import Data.DeriveTH+import Data.Binary++import Debug.Trace+ +import Control.Basics+import qualified Control.Monad.State as S+import Control.Parallel.Strategies+import Control.DeepSeq++import Text.Isar+ +import Theory.Pretty+import Theory.Proof.CaseDistinctions+++------------------------------------------------------------------------------+-- Utilities+------------------------------------------------------------------------------++-- | @uniqueListBy eq changes xs@ zips the @changes@ with all sequences equal+-- elements in the list.+--+-- > uniqueListBy compare id (const [ (++ show i) | i <- [1..] ]) ["a","b","a"] =+-- > ["a1","b","a2"]+--+uniqueListBy :: (a -> a -> Ordering) -> (a -> a) -> (Int -> [a -> a]) -> [a] -> [a]+uniqueListBy ord single distinguish xs0 =+ map fst+ $ sortBy (comparing snd)+ $ concat $ map uniquify $ groupBy (\x y -> ord (fst x) (fst y) == EQ)+ $ sortBy (ord `on` fst)+ $ zip xs0 [(0::Int)..]+ where+ uniquify [] = error "impossible"+ uniquify [(x,i)] = [(single x, i)]+ uniquify xs = zipWith (\f (x,i) -> (f x, i)) dist xs+ where+ dist = distinguish $ length xs++------------------------------------------------------------------------------+-- Utility: Trees with uniquely labelled edges.+------------------------------------------------------------------------------++-- | Trees with uniquely labelled edges.+data LTree l a = LNode + { root :: a+ , children :: M.Map l (LTree l a)+ }+ deriving( Eq, Ord, Show )++instance Functor (LTree l) where+ fmap f (LNode r cs) = LNode (f r) (M.map (fmap f) cs)++instance Foldable (LTree l) where+ foldMap f (LNode x cs) = f x `mappend` foldMap (foldMap f) cs++instance Traversable (LTree l) where+ traverse f (LNode x cs) = LNode <$> f x <*> traverse (traverse f) cs++-- | A parallel evaluation strategy well-suited for DFS traversal: As soon as+-- a node is forced it sparks off the computation of the number of case-maps+-- of all its children. This way most of the data is already evaulated, when+-- the actual DFS traversal visits it.+--+-- NOT used for now. It sometimes required too much memory.+parLTreeDFS :: Strategy (LTree l a)+parLTreeDFS (LNode x0 cs0) = do+ cs0' <- (`parTraversable` cs0) $ \(LNode x cs) -> LNode x <$> rseq cs+ return $ LNode x0 (M.map (runEval . parLTreeDFS) cs0')++------------------------------------------------------------------------------+-- Utility: Merging maps+------------------------------------------------------------------------------++-- | /O(n+m)/. A generalized union operator for maps with differing types.+mergeMapsWith :: Ord k + => (a -> c) -> (b -> c) -> (a -> b -> c) + -> M.Map k a -> M.Map k b -> M.Map k c+mergeMapsWith leftOnly rightOnly combine l r =+ M.map extract $ M.unionWith combine' l' r'+ where+ l' = M.map (Left . Left) l+ r' = M.map (Left . Right) r++ combine' (Left (Left a)) (Left (Right b)) = Right $ combine a b+ combine' _ _ = error "mergeMapsWith: impossible"++ extract (Left (Left a)) = leftOnly a+ extract (Left (Right b)) = rightOnly b+ extract (Right c) = c+++------------------------------------------------------------------------------+-- Contradictions+------------------------------------------------------------------------------++-- | Reasons why a sequent can be contradictory.+data Contradiction = + Cyclic -- ^ The paths are cyclic.+ | NonNormalTerms -- ^ Has terms that are not in normal form.+ -- | NonLastNode -- ^ Has a non-silent node after the last node.+ | ForbiddenExp -- ^ Forbidden Exp-down rule instance+ | NonUniqueFactInstance (NodeId, NodeId, NodeId) + -- ^ Contradicts that certain facts have unique instances.+ | IncompatibleEqs -- ^ Incompatible equalities.+ | FormulasFalse -- ^ False in formulas+ | SuperfluousLearn LNTerm NodeId -- ^ A term is derived both before and after a learn+ deriving( Eq, Ord, Show )++instance HasFrees Contradiction where+ foldFrees f (SuperfluousLearn t v) = foldFrees f t `mappend` foldFrees f v+ foldFrees _ _ = mempty++ mapFrees f (SuperfluousLearn t v) = + SuperfluousLearn <$> mapFrees f t <*> mapFrees f v+ mapFrees _ c = pure c++-- | A list of all trivial contradictions in the sequent.+contradictions :: SignatureWithMaude -> Sequent -> [Contradiction]+contradictions sig se = asum+ [ guard (proveCyclic se) *> pure Cyclic+ , guard (hasNonNormalTerms sig se) *> pure NonNormalTerms+ , guard (hasForbiddenExp se) *> pure ForbiddenExp+ , guard (eqsIsFalse $ L.get sEqStore se) *> pure IncompatibleEqs+ , guard (formulasFalse se) *> pure FormulasFalse+ -- , guard (hasNonLastNode se) *> pure NonLastNode+ -- , maybe [] (pure . uncurry SuperfluousLearn) $ findSuperfluousLearn se+ ]+ +++ (NonUniqueFactInstance <$> nonUniqueFactInstances sig se)+++------------------------------------------------------------------------------+-- Proof Methods+------------------------------------------------------------------------------++-- | Sound transformations of sequents.+data ProofMethod = + Sorry String -- ^ Proof was not completed + | Attack -- ^ An attack was fond+ | Simplify -- ^ A simplification step.+ | SolveGoal Goal -- ^ A goal was solved.+ | Contradiction (Maybe Contradiction) + | Induction+ -- ^ A contradiction could be derived, possibly with a reason.+ deriving( Eq, Ord, Show )++instance HasFrees ProofMethod where+ foldFrees f (SolveGoal g) = foldFrees f g+ foldFrees f (Contradiction c) = foldFrees f c+ foldFrees _ _ = mempty++ mapFrees f (SolveGoal g) = SolveGoal <$> mapFrees f g+ mapFrees f (Contradiction c) = Contradiction <$> mapFrees f c+ mapFrees _ method = pure method++++------------------------------------------------------------------------------+-- Proof Steps+------------------------------------------------------------------------------+ +-- | A proof steps is a proof method together with additional context-dependent+-- information.+data ProofStep a = ProofStep+ { psMethod :: ProofMethod+ , psInfo :: a+ }+ deriving( Eq, Ord, Show )++instance Functor ProofStep where+ fmap f (ProofStep m i) = ProofStep m (f i)++instance Foldable ProofStep where+ foldMap f = f . psInfo++instance Traversable ProofStep where+ traverse f (ProofStep m i) = ProofStep m <$> f i+++------------------------------------------------------------------------------+-- Proof Trees+------------------------------------------------------------------------------++-- | Every case in a proof is uniquely named.+type CaseName = String++-- | A path to a subproof.+type ProofPath = [CaseName]++-- | A proof is a tree of proof steps whose edges are labelled with case names.+type Proof a = LTree CaseName (ProofStep a)++-- Unfinished proofs+--------------------++-- | A proof using the 'sorry' proof method.+sorry :: String -> a -> Proof a+sorry reason ann = LNode (ProofStep (Sorry reason) ann) M.empty++-- | A proof denoting an unproven part of the proof.+unproven :: a -> Proof a+unproven = sorry "not yet proven"+++-- Paths in proofs+------------------++-- | @prf `atPath` path@ returns the subproof at the @path@ in @prf@.+atPath :: Proof a -> ProofPath -> Maybe (Proof a)+atPath = foldM (flip M.lookup . children)++-- | @modifyAtPath f path prf@ applies @f@ to the subproof at @path@,+-- if there is one.+modifyAtPath :: (Proof a -> Maybe (Proof a)) -> ProofPath+ -> Proof a -> Maybe (Proof a)+modifyAtPath f =+ go + where+ go [] prf = f prf+ go (l:ls) prf = do+ let cs = children prf+ prf' <- go ls =<< M.lookup l cs+ return (prf { children = M.insert l prf' cs })++-- | @insertPaths prf@ inserts the path to every proof node.+insertPaths :: Proof a -> Proof (a, ProofPath)+insertPaths =+ insertPath []+ where+ insertPath path (LNode ps cs) =+ LNode (fmap (,reverse path) ps)+ (M.mapWithKey (\n prf -> insertPath (n:path) prf) cs)+++-- Utilities for dealing with proofs+------------------------------------+++-- | Apply a function to the information of every proof step.+mapProofInfo :: (a -> b) -> Proof a -> Proof b+mapProofInfo = fmap . fmap++-- | @boundProofDepth bound prf@ bounds the depth of the proof @prf@ using+-- 'Sorry' steps to replace the cut sub-proofs.+boundProofDepth :: Int -> Proof a -> Proof a+boundProofDepth bound =+ go bound+ where+ go n (LNode ps@(ProofStep _ info) cs)+ | 0 < n = LNode ps $ M.map (go (pred n)) cs+ | otherwise = sorry ("bound " ++ show bound ++ " hit") info++-- | Fold a proof.+foldProof :: Monoid m => (ProofStep a -> m) -> Proof a -> m+foldProof f = + go + where+ go (LNode step cs) = f step `mappend` foldMap go (M.elems cs)+++-- Proof cutting+----------------++-- | The status of a 'Proof'.+data ProofStatus = + CompleteProof -- ^ The proof is complete: no sorry, no attack+ | IncompleteProof -- ^ There is a sorry, but no attack.+ | AttackFound -- ^ There is an attack++instance Monoid ProofStatus where+ mempty = CompleteProof++ mappend AttackFound _ = AttackFound+ mappend _ AttackFound = AttackFound+ mappend IncompleteProof _ = IncompleteProof+ mappend _ IncompleteProof = IncompleteProof+ mappend CompleteProof CompleteProof = CompleteProof++-- | The status of a 'ProofStep'.+proofStepStatus :: ProofStep a -> ProofStatus+proofStepStatus (ProofStep Attack _) = AttackFound+proofStepStatus (ProofStep (Sorry _) _) = IncompleteProof+proofStepStatus (ProofStep _ _) = CompleteProof++-- | @cutOnAttackDFS prf@ remove all other cases if attack is found.+-- FIXME: Probably holds onto the whole proof tree. Use iterative deepening.+cutOnAttackDFS :: Proof (Maybe Sequent) -> Proof (Maybe Sequent)+cutOnAttackDFS prf =+ case getFirst $ findAttacks $ insertPaths prf of+ Nothing -> prf+ Just path -> extractAttack path prf+ where+ findAttacks (LNode (ProofStep Attack (_,path)) _) = First (Just path)+ findAttacks (LNode _ cs) = foldMap findAttacks $ M.elems cs+ {- The following "optimization" didn't work out in practice.+ foldMap findAttacks preferred `mappend` foldMap findAttacks delayed+ where+ (preferred, delayed) = parPartition prefer $ M.elems cs+ prefer = maybe False (S.null . L.get sChains) . fst . psInfo . root+ -}++ extractAttack [] p = p+ extractAttack (label:ps) (LNode pstep m) = case M.lookup label m of+ Just subprf ->+ LNode pstep (M.fromList [(label, extractAttack ps subprf)])+ Nothing ->+ error "Theory.Proof.cutOnAttackDFS: impossible, extractAttack failed, invalid path"++-- | Search for attacks in a BFS manner.+cutOnAttackBFS :: Proof a -> Proof a+cutOnAttackBFS =+ go (1::Int)+ where+ go l prf = + -- FIXME: See if that poor man's logging could be done better.+ trace ("searching for attacks at depth: " ++ show l) $+ case S.runState (checkLevel l prf) CompleteProof of+ (_, CompleteProof) -> prf+ (_, IncompleteProof) -> go (l+1) prf+ (prf', AttackFound) -> + trace ("attack found at depth: " ++ show l) prf'++ checkLevel 0 (LNode step@(ProofStep Attack _) _) = + S.put AttackFound >> return (LNode step M.empty)+ checkLevel 0 prf@(LNode (ProofStep _ x) cs) + | M.null cs = return prf+ | otherwise = do+ st <- S.get+ msg <- case st of+ AttackFound -> return $ "ignored (attack exists)"+ _ -> S.put IncompleteProof >> return "bound reached"+ return $ LNode (ProofStep (Sorry msg) x) M.empty+ checkLevel l (LNode step cs) =+ LNode step <$> traverse (checkLevel (l-1)) cs+ +++-- Proof method execution+-------------------------+++-- @execMethod rules method se@ checks first if the @method@ is applicable to+-- the sequent @se@. Then, it applies the @method@ to the sequent under the+-- assumption that the @rules@ describe all rewriting rules in scope.+execProofMethod :: ProofContext + -> ProofMethod -> Sequent -> Maybe (M.Map CaseName Sequent)+execProofMethod ctxt method se = + case method of+ Sorry _ -> return M.empty+ Attack + | null (openGoals se) -> return M.empty+ | otherwise -> Nothing+ SolveGoal goal -> execSolveGoal goal+ Simplify -> singleCase (/=) simplifySequent+ Induction -> execInduction+ Contradiction _ + | null (contradictions (L.get pcSignature ctxt) se) -> Nothing+ | otherwise -> Just M.empty+ where+ -- Maude handle / signature to use+ hnd = L.get sigmMaudeHandle $ L.get pcSignature ctxt++ -- expect only one or no subcase in the given case distinction+ singleCase check m = + case map fst $ execSeProof m ctxt se (avoid se) of+ [] -> return $ M.empty+ [se'] | check se se' -> return $ M.singleton "" se'+ | otherwise -> mzero+ ses -> + error $ "execMethod: unexpected number of sequents: " ++ show (length ses) +++ render (nest 2 $ vcat $ map ((text "" $-$) . prettySequent) ses)++ -- solve the given goal+ -- PRE: Goal must be valid in this sequent.+ execSolveGoal goal = do+ return $ makeCaseNames $ map fst $ getDisj $ + runSeProof solver ctxt se (avoid se)+ where+ ths = L.get pcCaseDists ctxt+ solver = do name <- maybe (solveGoal goal) + (fmap $ concat . intersperse "_")+ (solveWithCaseDistinction hnd ths goal)+ simplifySequent+ return name++ makeCaseNames = + M.fromListWith (error "case names not unique")+ . uniqueListBy (comparing fst) id distinguish+ where+ distinguish n = + [ (\(x,y) -> (x ++ "_case_" ++ pad (show i), y)) + | i <- [(1::Int)..] ]+ where+ l = length (show n)+ pad cs = replicate (l - length cs) '0' ++ cs++ -- Apply induction: possible if the sequent contains only+ -- a single formula.+ execInduction+ | se == se0 =+ case S.toList $ L.get sFormulas se of+ [gf] -> case applyInduction gf of+ Right gf' -> Just $ M.singleton "induction" $ + set sFormulas (S.singleton gf') se+ _ -> Nothing+ _ -> Nothing++ | otherwise = Nothing+ where+ se0 = set sFormulas (L.get sFormulas se) $ + set sLemmas (L.get sLemmas se) $+ emptySequent (L.get sCaseDistKind se) ++-- | A list of possibly applicable proof methods.+possibleProofMethods :: SignatureWithMaude -> Sequent -> [ProofMethod]+possibleProofMethods sig se =+ ((Contradiction . Just) <$> contradictions sig se)+ -- For now (12/01/22), we add induction after simplification to ensure+ -- that the autoprover doesn't use induction. (Induction can only be+ -- executed in a sequent that contains exactly one formula eligible for+ -- induction.)+ <|> [Simplify, Induction]+ <|> (SolveGoal <$> openGoals se)++-- | @proveSequentDFS rules se@ tries to construct a proof that @se@ is valid+-- using a depth-first-search strategy to resolve the non-determinism wrt. what+-- goal to solve next. This proof can be of infinite depth, if the proof+-- strategy loops. Children at the same level are evaluated in parallel.+proveSequentDFS :: ProofContext -> Sequent -> Proof Sequent+proveSequentDFS ctxt se0 = + prove se0 -- `using` parLTreeDFS+ where+ prove se =+ LNode (ProofStep method se) (M.map prove cases)+ where+ (method, cases) = + headDef (Attack, M.empty) $ do+ m <- possibleProofMethods (L.get pcSignature ctxt) se + (m,) <$> maybe mzero return (execProofMethod ctxt m se)+++{- TODO: Test and probably improve+ +-- | @proveSequent rules se@ tries to construct a proof that @se@ is valid.+-- This proof may contain 'Sorry' steps, if the prover is stuck. It can also be+-- of infinite depth, if the proof strategy loops.+proveSequentIterDeep :: ProofContext -> Sequent -> Proof Sequent+proveSequentIterDeep rules se0 =+ fromJust $ asum $ map (prove se0 . round) $ iterate (*1.5) (3::Double)+ where+ prove :: Sequent -> Int -> Maybe (Proof Sequent)+ prove se bound+ | bound < 0 = Nothing+ | otherwise =+ case next of+ [] -> pure $ sorry "prover stuck => possible attack found" se+ xs -> asum $ map mkProof xs+ where+ next = do m <- possibleProofMethods se + (m,) <$> maybe mzero return (execProofMethod rules m se)+ mkProof (method, cases) = + LNode (ProofStep method se) <$> traverse (`prove` (bound - 1)) cases+-}++-- | @checkProof rules se prf@ replays the proof @prf@ against the start+-- sequent @se@. A failure to apply a proof method is denoted by a resulting+-- proof step without an annotated sequent. An unhandled case is denoted using+-- the 'Sorry' proof method.+checkProof :: ProofContext+ -> (Sequent -> Proof (Maybe Sequent)) -- prover for new cases+ -> Sequent + -> Proof a+ -> Proof (Maybe a, Maybe Sequent)+checkProof ctxt prover se (LNode (ProofStep method info) cs) =+ fromMaybe (node method (M.map noSequentPrf cs)) $ headMay $ do+ method' <- method : possibleProofMethods (L.get pcSignature ctxt) se+ guard (method `eqModuloFreshness` method')+ cases <- maybe mzero return $ execProofMethod ctxt method' se+ return $ node method' $ checkChildren cases+ + where+ node m = LNode (ProofStep m (Just info, Just se)) ++ -- cases = msum (execProofMethod rules method se) $++ noSequentPrf = mapProofInfo (\i -> (Just i, Nothing))++ checkChildren cases = + mergeMapsWith unhandledCase noSequentPrf (checkProof ctxt prover) cases cs+ where+ unhandledCase = mapProofInfo ((,) Nothing) . prover+ ++------------------------------------------------------------------------------+-- Provers: the interface to the outside world.+------------------------------------------------------------------------------++-- | Incremental proofs are used to represent intermediate results of proof+-- checking/construction.+type IncrementalProof = Proof (Maybe Sequent)++-- | Provers whose sequencing is handled via the 'Monoid' instance.+--+-- > p1 `mappend` p2+--+-- Is a prover that first runs p1 and then p2 on the resulting proof.+newtype Prover = Prover + { runProver + :: ProofContext -- proof rules to use+ -> Sequent -- original sequent to start with+ -> IncrementalProof -- original proof+ -> Maybe IncrementalProof -- resulting proof+ }++instance Monoid Prover where+ mempty = Prover $ \_ _ -> return+ p1 `mappend` p2 = Prover $ \rules se ->+ runProver p1 rules se >=> runProver p2 rules se++-- | Map the proof generated by the prover.+mapProverProof :: (IncrementalProof -> IncrementalProof) -> Prover -> Prover+mapProverProof f p = Prover $ \ rules se prf -> f<$> runProver p rules se prf++-- | Prover that always fails.+failProver :: Prover +failProver = Prover (\ _ _ _ -> Nothing)++-- | Resorts to the second prover, if the first one is not successful.+orelse :: Prover -> Prover -> Prover+orelse p1 p2 = Prover $ \rules se prf -> + runProver p1 rules se prf `mplus` runProver p2 rules se prf++-- | Try to apply a prover. If it fails, just return the original proof.+tryProver :: Prover -> Prover+tryProver = (`orelse` mempty)++-- | Try to execute one proof step using the given proof method.+oneStepProver :: ProofMethod -> Prover+oneStepProver method = Prover $ \rules se _ -> do+ cases <- execProofMethod rules method se+ return $ LNode (ProofStep method (Just se)) (M.map (unproven . Just) cases)++-- | Replace the current proof with a sorry step and the given reason.+sorryProver :: String -> Prover+sorryProver reason = Prover $ \_ se _ -> return $ sorry reason (Just se)++-- | Bound the depth of proofs generated by the given prover.+boundProver :: Int -> Prover -> Prover+boundProver b p = Prover $ \rules se prf ->+ boundProofDepth b <$> runProver p rules se prf++-- | The standard automatic prover that ignores the existing proof and tries to+-- find one by itself.+autoProver :: Prover+autoProver = Prover $ \rules se _ -> + -- evaluate cases in parallel+ return $ fmap (fmap Just) $ proveSequentDFS rules se++-- | Apply a prover only to a sub-proof, fails if the subproof doesn't exist.+focus :: ProofPath -> Prover -> Prover+focus [] prover = prover+focus path prover = + Prover $ \rules _ prf -> modifyAtPath (prover' rules) path prf+ where+ prover' rules prf = do+ se <- psInfo (root prf)+ runProver prover rules se prf++-- | Check the proof and handle new cases using the given prover.+checkAndExtendProver :: Prover -> Prover+checkAndExtendProver prover0 = Prover $ \rules se prf ->+ return $ mapProofInfo snd $ checkProof rules (prover rules) se prf+ where+ unhandledCase = sorry "unhandled case" Nothing+ prover rules se = + fromMaybe unhandledCase $ runProver prover0 rules se unhandledCase++-- | Replace all annotated sorry steps with +replaceSorryProver :: Prover -> Prover+replaceSorryProver prover0 = Prover prover+ where+ prover rules _ = return . replace+ where+ replace prf@(LNode (ProofStep (Sorry _) (Just se)) _) = + fromMaybe prf $ runProver prover0 rules se prf+ replace (LNode ps cases) = + LNode ps $ M.map replace cases+++-- | Use the first prover that works.+firstProver :: [Prover] -> Prover+firstProver = foldr orelse failProver++-- | Prover that does one contradiction step or one graph clause resolution+-- step.+contradictionAndClauseProver :: Prover+contradictionAndClauseProver = Prover $ \ctxt se prf ->+ runProver + (firstProver $ map oneStepProver $ + (Contradiction . Just <$> + contradictions (L.get pcSignature ctxt) se))+ ctxt se prf+++------------------------------------------------------------------------------+-- Pretty printing+------------------------------------------------------------------------------++prettyContradiction :: Document d => Contradiction -> d+prettyContradiction contra = case contra of+ Cyclic -> text "cyclic"+ IncompatibleEqs -> text "incompatible equalities"+ NonNormalTerms -> text "non-normal terms"+ ForbiddenExp -> text "non-normal exponentiation instance"+ NonUniqueFactInstance cex -> text $ "non-unique facts" ++ show cex+ FormulasFalse -> text "from formulas"+ SuperfluousLearn m v ->+ doubleQuotes (prettyLNTerm m) <->+ text ("derived before and after") <-> + doubleQuotes (prettyNodeId v)++prettyProofMethod :: HighlightDocument d => ProofMethod -> d+prettyProofMethod method = case method of+ Attack -> keyword_ "SOLVED (trace found)"+ Induction -> keyword_ "induction"+ Sorry reason -> fsep [keyword_ "sorry", lineComment_ reason]+ SolveGoal goal -> hsep [keyword_ "solve(", prettyGoal goal, keyword_ ")"]+ Simplify -> keyword_ "simplify"+ Contradiction reason ->+ fsep [ keyword_ "contradiction"+ , maybe emptyDoc (lineComment . prettyContradiction) reason+ ]++prettyProof :: HighlightDocument d => Proof a -> d+prettyProof = prettyProofWith (prettyProofMethod . psMethod) (const id)++prettyProofWith :: HighlightDocument d+ => (ProofStep a -> d) -- ^ Make proof step pretty+ -> (ProofStep a -> d -> d) -- ^ Make whole case pretty+ -> Proof a -- ^ The proof to prettify+ -> d+prettyProofWith prettyStep prettyCase =+ ppPrf+ where+ ppPrf (LNode ps cs) = ppCases ps (M.toList cs)++ ppCases ps@(ProofStep Attack _) [] = prettyStep ps+ ppCases ps [] = prettyCase ps (kwBy <> text " ") + <> prettyStep ps+ ppCases ps [("", prf)] = prettyStep ps $-$ ppPrf prf+ ppCases ps cases =+ prettyStep ps $-$+ (vcat $ intersperse (prettyCase ps kwNext) $ map ppCase cases) $-$ + prettyCase ps kwQED++ ppCase (name, prf) = nest 2 $+ (prettyCase (root prf) $ kwCase <-> text name) $-$+ ppPrf prf++-- | Convert a proof status to a redable string.+showProofStatus :: ProofStatus -> String+showProofStatus AttackFound = "attack found"+showProofStatus IncompleteProof = "incomplete proof"+showProofStatus CompleteProof = "complete proof"+++-- Derived instances+--------------------++$( derive makeBinary ''Contradiction)+$( derive makeBinary ''ProofMethod)+$( derive makeBinary ''ProofStep)+$( derive makeBinary ''ProofStatus)++$( derive makeNFData ''Contradiction)+$( derive makeNFData ''ProofMethod)+$( derive makeNFData ''ProofStep)+$( derive makeNFData ''ProofStatus)++instance (Ord l, NFData l, NFData a) => NFData (LTree l a) where+ rnf (LNode r m) = rnf r `seq` rnf m++instance (Ord l, Binary l, Binary a) => Binary (LTree l a) where+ put (LNode r m) = put r >> put m+ get = LNode <$> get <*> get
@@ -0,0 +1,388 @@+{-# LANGUAGE DeriveDataTypeable, TupleSections, TypeOperators #-}+{-# LANGUAGE TemplateHaskell, TypeSynonymInstances, FlexibleInstances #-}+{-# LANGUAGE FlexibleContexts, GeneralizedNewtypeDeriving #-}+-- |+-- Copyright : (c) 2011,2012 Simon Meier+-- License : GPL v3 (see LICENSE)+-- +-- Maintainer : Simon Meier <iridcode@gmail.com>+-- Portability : GHC only+--+-- Big-step proofs using case distinctions on the possible sources of a fact.+module Theory.Proof.CaseDistinctions (+ -- * Big-step case distinctions+ -- | Types declared in "Theory.Proof.Types"++ -- ** Queries+ unsolvedChainConstraints++ -- ** Construction+ , precomputeCaseDistinctions+ , refineWithTypingAsms++ -- ** Application+ , solveWithCaseDistinction ++ -- ** Pretty-printing+ , prettyBigStepGoal++ -- * Convenience export of used modules+ , module Theory.Proof.Sequent+ ) where++import Safe+import Prelude hiding ( (.), id )+import Debug.Trace++import qualified Data.Set as S+import qualified Data.DAG.Simple as D+import Data.Foldable (asum)++import Control.Basics+import Control.Category+import Control.Monad.Disj+import Control.Monad.Bind+import Control.Monad.Reader+import Control.Monad.State (gets)+import Control.Parallel.Strategies++import Text.Isar++import Extension.Prelude+import Extension.Data.Label++import Theory.Rule+import Theory.Proof.Sequent+++-- | AC-Matching for big-step goals. MessageBigSteps can be matched+-- to the corresponding K-up facts.+matchBigStepGoal :: BigStepGoal -- ^ Term.+ -> BigStepGoal -- ^ Pattern.+ -> WithMaude [LNSubst]+matchBigStepGoal (PremiseBigStep faTerm) (PremiseBigStep faPat) =+ matchLNFact faTerm faPat+matchBigStepGoal (MessageBigStep mTerm) (MessageBigStep mPat) =+ matchLNTerm [mTerm `MatchWith` mPat]+matchBigStepGoal (MessageBigStep mTerm) (PremiseBigStep faPat) =+ case kFactView faPat of+ Just (UpK, _, mPat) -> matchLNTerm [mTerm `MatchWith` mPat]+ _ -> return []+matchBigStepGoal _ _ = return []+++------------------------------------------------------------------------------+-- Big Step Proofs+------------------------------------------------------------------------------++-- | The number of remaining chain constraints of each case.+unsolvedChainConstraints :: CaseDistinction -> [Int]+unsolvedChainConstraints =+ map (S.size . get sChains . snd . snd) . getDisj . get cdCases+++-- Construction+---------------++-- | The initial case distinction if the given goal is required and the+-- given typing assumptions are justified.+initialCaseDistinction :: ProofContext + -> [LNGuarded] -- ^ Typing assumptions.+ -> BigStepGoal -> CaseDistinction+initialCaseDistinction ctxt typAsms goal =+ CaseDistinction goal cases+ where+ polish (((name, prem), se), _) = ([name], (prem, se))+ se0 = set sFormulas (S.fromList typAsms) (emptySequent UntypedCaseDist)+ cases = fmap polish $ runSeProof instantiate ctxt se0 (avoid (goal, se0))+ instantiate = do+ i <- freshLVar "i" LSortNode+ let p = NodePrem (i, 0)+ err = error . ("requiresCasesThm: no or too many edges: " ++)+ case goal of+ PremiseBigStep fa -> do+ name <- solveGoal (PremiseG p fa)+ edges <- getM sEdges+ case filter ((p ==) . eTgt) (S.toList edges) of+ [e] -> do modM sEdges (S.delete e)+ return (name, eSrc e)+ es -> err $ show es++ -- FIXME: Probably this code is not required.+ MessageBigStep m -> do+ name <- solveGoal (PremUpKG p m)+ edges <- getM sMsgEdges+ case filter ((p ==) . meTgt) (S.toList edges) of+ [e] -> do modM sMsgEdges (S.delete e)+ return (name, meSrc e)+ es -> err $ show es+++-- | Refine a source case distinction by applying the additional proof step.+refineCaseDistinction + :: ProofContext+ -> SeProof (a, [String]) -- proof step with result and path extension+ -> CaseDistinction + -> ([a],CaseDistinction)+refineCaseDistinction ctxt proofStep th = + ( map fst $ getDisj refinement+ , set cdCases (snd <$> refinement) th )+ where+ fs = avoid th+ refinement = do+ (names, (p, se)) <- get cdCases th+ ((x, names'), se') <- fst <$> runSeProof proofStep ctxt se fs+ return (x, (combine names names', (p, se')))++ -- Combine names such that the coerce rule is blended out.+ combine [] ns' = ns'+ combine ("coerce":ns) ns' = combine ns ns'+ combine (n :_) _ = [n]++-- | Solves all chain and splitting goals as well as all premise goals solvable+-- with one of the given precomputed requires case distinction theorems, while+-- repeatedly simplifying the proof state. +--+-- Returns the names of the steps applied.+solveAllSafeGoals + :: (LNFact -> Bool) -- ^ True, if this fact may be refined further.+ -- Required for loop-breaking.+ -> [CaseDistinction] + -> SeProof [String]+solveAllSafeGoals nonLoopingFact ths = + solve []+ where+ safeGoal _ (ChainG _) = True+ safeGoal _ (PremDnKG _) = True+ safeGoal _ (ActionG _ _) = True+ safeGoal splitAllowed (DisjG _) = splitAllowed+ -- NOTE: Uncomment the line below to get more extensive case splitting+ -- for precomputed case distinctions.+ -- safeGoal splitAllowed (SplitG _ _) = splitAllowed+ safeGoal _ (PremiseG _ fa) = nonLoopingFact fa+ safeGoal _ _ = False++ nonLoopingGoal (PremiseG _ fa) = nonLoopingFact fa+ nonLoopingGoal _ = True++ solve caseNames = do+ simplifySequent+ sig <- askM pcSignature+ contradictoryIf =<< gets (contradictorySequent sig)+ goals <- gets openGoals+ chains <- getM sChains+ hnd <- getMaudeHandle+ -- try to either solve a safe goal or use one of the precomputed case+ -- distinctions+ let noChainGoals = null [ () | ChainG _ <- goals ]+ -- we perform equation splits, if there is a chain goal starting+ -- from a message variable; i.e., a chain constraint that is no+ -- open goal.+ splitAllowed = noChainGoals && not (S.null chains)+ safeGoals = filter (safeGoal splitAllowed) goals+ nonLoopingGoals = filter nonLoopingGoal goals+ nextStep = + ((fmap return . solveGoal) <$> headMay safeGoals) <|>+ (asum $ map (solveWithCaseDistinction hnd ths) nonLoopingGoals)+ case nextStep of+ Nothing -> return $ caseNames+ Just step -> solve . (caseNames ++) =<< step++-- | Try to solve a premise goal using the first precomputed case distinction+-- with a matching premise.+solveWithCaseDistinction :: MaudeHandle+ -> [CaseDistinction] + -> Goal+ -> Maybe (SeProof [String])+solveWithCaseDistinction hnd ths goal0 = case goal0 of + PremiseG p fa -> applyTo p (PremiseBigStep fa)+ PremUpKG p m -> applyTo p (MessageBigStep m)+ _ -> mzero+ where+ applyTo p goal = asum [ applyCaseDistinction hnd th p goal | th <- ths ]++-- | Apply a precomputed case distinction theorem to a required fact.+applyCaseDistinction :: MaudeHandle+ -> CaseDistinction -- ^ Case distinction theorem.+ -> NodePrem -- ^ Premise+ -> BigStepGoal -- ^ Required goal+ -> Maybe (SeProof [String])+applyCaseDistinction hnd th prem goal =+ case (`runReader` hnd) $ matchBigStepGoal goal (get cdGoal th) of+ [] -> Nothing+ _ -> Just $ do (names, subst, seTh) <- instTheorem `evalBindT` noBindings+ solveSubstEqs SplitNow subst+ conjoinSequent seTh+ return names+ where+ instTheorem :: BindT LVar LVar SeProof ([String], LNSubst, Sequent)+ instTheorem = do+ goalTh <- someInst $ get cdGoal th+ -- We only have to choose one matcher, as the theorem holds for all+ -- premises equal modulo AC.+ subst <- disjunctionOfList $ take 1 $ + matchBigStepGoal goal goalTh `runReader` hnd+ (names, (concTh, seTh)) <- someInst =<< + (disjunctionOfList $ getDisj $ get cdCases th)++ let seTh' = case goal of+ PremiseBigStep _ -> + modify sEdges (S.insert (Edge concTh prem)) seTh+ MessageBigStep _ -> + modify sMsgEdges (S.insert (MsgEdge concTh prem)) seTh++ -- solving the matcher equalities and + -- conjoining the sequent will be done later+ return (names, subst, seTh')++-- | Saturate the case distinctions with respect to each other such that no+-- additional splitting is introduced; i.e., only rules with a single or no+-- conclusion are used for the saturation.+saturateCaseDistinctions + :: ProofContext -> [CaseDistinction] -> [CaseDistinction]+saturateCaseDistinctions ctxt = + go+ where+ nonLoopingFact = saturationLoopBreakers ctxt++ go ths =+ if any or (changes `using` parList rdeepseq)+ then go ths'+ else ths'+ where+ (changes, ths') = unzip $ map (refineCaseDistinction ctxt solver) ths+ noSplitThs = filter ((<= 1) . length . getDisj . get cdCases) ths+ solver = do names <- solveAllSafeGoals nonLoopingFact noSplitThs+ return (not $ null names, names)++{-+ go changed done []+ | changed = go False [] (reverse done)+ | otherwise = reverse done+ go changed done (th:ths) =+ go (changed || or changes ) (th':done) ths+ where+ solver = do names <- solveAllSafeGoals nonLoopingFact noSplitThs+ return (not $ null names, names)+ (changes, th') = refineCaseDistinction ctxt solver th+ noSplitThs = + filter ((<= 1) . length . getDisj . get cdCases) (done ++ ths)+-}++-- | Precompute a saturated set of case distinctions.+precomputeCaseDistinctions + :: ProofContext + -> [LNGuarded] -- ^ Typing assumptions.+ -> [CaseDistinction]+precomputeCaseDistinctions ctxt typAsms =+ map cleanupCaseNames $ saturateCaseDistinctions ctxt rawCaseDists+ where+ cleanupCaseNames = modify cdCases $ fmap $ first $+ filter (not . null)+ . map (filter (`elem` '_' : ['a'..'z'] ++ ['A'..'Z'] ++ ['0'..'9']))++ rawCaseDists = + initialCaseDistinction ctxt typAsms <$> (protoGoals ++ msgGoals)++ -- construct case distinction starting from facts from non-special rules+ protoGoals = someProtoGoal <$> absProtoFacts + msgGoals = someKUGoal <$> absMsgFacts++ getProtoFact (Fact KUFact _ ) = mzero+ getProtoFact (Fact KDFact _ ) = mzero+ getProtoFact fa = return fa++ absFact (Fact tag ts) = (tag, length ts)++ nMsgVars n = [ varTerm (LVar "t" LSortMsg i) | i <- [1..n] ]++ someProtoGoal :: (FactTag, Int) -> BigStepGoal+ someProtoGoal (tag, arity) = PremiseBigStep $ Fact tag (nMsgVars arity)++ someKUGoal :: LNTerm -> BigStepGoal+ someKUGoal m = PremiseBigStep (Fact KUFact [varTerm (LVar "f_" LSortMsg 0), m])++ -- FIXME: Also use facts from proof context.+ rules = get pcRules ctxt+ absProtoFacts = sortednub $ do+ ru <- joinNonSpecialRules rules+ fa <- absFact <$> (getProtoFact =<< (get rConcs ru ++ get rPrems ru))+ -- exclude facts handled specially by the prover+ guard (not $ fst fa `elem` [OutFact, InFact, FreshFact])+ return fa++ absMsgFacts :: [LNTerm]+ absMsgFacts = asum $ sortednub $ + [ do return $ Lit $ Var (LVar "t" LSortFresh 1)++ , [ FApp (NonAC (s,k)) $ nMsgVars k+ | (s,k) <- funSigForMaudeSig . mhMaudeSig . get sigmMaudeHandle . get pcSignature $ ctxt+ , s `notElem` [ "inv", "pair" ] ]+ ] ++-- | Refine a set of case distinction by exploiting additional typing+-- assumptions.+refineWithTypingAsms + :: [LNGuarded] -- ^ Typing assumptions to use.+ -> ProofContext -- ^ Proof context to use.+ -> [CaseDistinction] -- ^ Original, untyped case distinctions.+ -> [CaseDistinction] -- ^ Refined, typed case distinctions.+refineWithTypingAsms typAsms ctxt cases0 =+ fmap (modifySequents removeFormulas) $+ saturateCaseDistinctions ctxt $ + modifySequents updateSequent <$> cases0+ where+ modifySequents = modify cdCases . fmap . second . second+ updateSequent se = + modify sFormulas (S.union (S.fromList typAsms)) $+ set sCaseDistKind TypedCaseDist $ se+ removeFormulas = set sFormulas S.empty . set sSolvedFormulas S.empty++-- Loop-breaker computation+---------------------------++-- | Compute the loop-breakers for saturating the pre-computated case+-- distinctions.+saturationLoopBreakers :: ProofContext -> (LNFact -> Bool)+saturationLoopBreakers ctxt =+ trace (" loop breakers: " ++ show (loopBreakers absProtoFactRel)) $+ \fa -> absFact fa `S.notMember` loopBreakers absProtoFactRel+ where+ rules = get pcRules ctxt+ -- detect cycles on abstracted protocol facts; i.e., (tag, arity) facts+ absFact (Fact tag ts) = (tag, length ts)++ absProtoFactRel = sortednub $ do+ ru <- joinNonSpecialRules rules+ conc <- absFact <$> get rConcs ru+ prem <- absFact <$> get rPrems ru+ return (conc, prem)+++-- | Given a relation compute a set of loop-breakers; i.e., a feedback vertex+-- set (<http://en.wikipedia.org/wiki/Feedback_vertex_set>). No guarantee for+-- minimality is made. The current algorithm only removes self-loops and hopes+-- that this is sufficient. We should implement something along the lines of+-- Ann Becker, Dan Geiger, Optimization of Pearl's method of conditioning and+-- greedy-like approximation algorithms for the vertex feedback set problem,+-- Artificial Intelligence, Volume 83, Issue 1, May 1996, Pages 167-188, ISSN+-- 0004-3702, 10.1016/0004-3702(95)00004-6.+-- <http://www.sciencedirect.com/science/article/pii/0004370295000046>.+loopBreakers :: Ord a => [(a,a)] -> S.Set a+loopBreakers rel+ | D.cyclic rel' = + error "loopBreakers: trivial loop-breaker computation failed.\+ \The relation is still cyclic."+ | otherwise = breakers+ where+ breakers = S.fromList [ x | (x, y) <- rel, x == y ]+ rel' = [ r | r@(x, y) <- rel+ , x `S.notMember` breakers, y `S.notMember` breakers]++------------------------------------------------------------------------------+-- Pretty-printing+------------------------------------------------------------------------------++prettyBigStepGoal :: Document d => BigStepGoal -> d+prettyBigStepGoal (PremiseBigStep fa) = prettyLNFact fa+prettyBigStepGoal (MessageBigStep m) = prettyLNTerm m
@@ -0,0 +1,438 @@+{-# LANGUAGE TypeOperators, TemplateHaskell, DeriveDataTypeable, ScopedTypeVariables, TupleSections #-}+-- |+-- Copyright : (c) 2010-2012 Benedikt Schmidt+-- License : GPL v3 (see LICENSE)+-- +-- Maintainer : Benedikt Schmidt <beschmi@gmail.com>+-- Portability : GHC only+--+-- Support for reasoning with and about disjunctions of substitutions.+module Theory.Proof.EquationStore (++ -- * Transformation+ simp+ , addEqs+ , addRuleVariants+ , splitAtPos+ , eqSplits+ , constrainedVarsPos++ , SplitStrategy(..)++ -- * simplify a disjunction+ , simpDisjunction++) where++import Term.Unification+import Logic.Connectives+import Theory.Proof.Types++import Control.Monad.Reader+import Control.Monad.Fresh+import Utils.Misc+import Extension.Prelude++-- import qualified Debug.Trace as DT++import Debug.Trace.Ignore++import Data.List+import Data.Label hiding ( for )+import Data.Maybe+import Data.Monoid+import Data.Traversable hiding ( mapM )+import qualified Data.Foldable as F+import Control.Basics+import Control.Monad.State hiding (get, modify)+import qualified Control.Monad.State as MS+++-- Equation Store+----------------------------------------------------------------------++-- | We use an empty disjunction to denote false.+falseDisj :: Disj (LNSubstVFresh)+falseDisj = Disj []++data SplitStrategy = SplitNow | SplitLater++-- Dealing with equations+----------------------------------------------------------------------++-- | Returns the list of all @SplitId@s corresponding equation disjunctions.+eqSplits :: EqStore -> [SplitId]+eqSplits eqs = [0.. length (getConj . get eqsConj $ eqs) -1 ]++-- | Add a list of term equalities to the equation store.+-- Returns the resulting equation store(s) depending+-- on the split strategy.+addEqs :: MonadFresh m => SplitStrategy -> MaudeHandle+ -> [Equal LNTerm] -> EqStore -> m [EqStore]+addEqs splitStrat hnd eqs0 eqStore =+ case unifyLNTermFactored eqs `runReader` hnd of+ (_, []) -> return [set eqsConj falseEqConstrConj eqStore]+ (subst, substs) ->+ case splitStrat of+ SplitLater ->+ return $ [addDisj (applyEqStore hnd subst eqStore) (Disj substs)]+ SplitNow -> + addEqsAC (modify eqsSubst (compose subst) eqStore)+ <$> simpDisjunction hnd (Disj substs)+ where+ eqs = apply (get eqsSubst eqStore) $ trace (unlines ["addEqs: ", show eqs0]) $ eqs0+ addEqsAC eqSt (sfree, Nothing) = [applyEqStore hnd sfree eqSt]+ addEqsAC eqSt (sfree, Just disj) =+ fromMaybe (error "addEqsSplit: impossible, splitAtPos failed")+ (splitAtPos (applyEqStore hnd sfree (addDisj eqSt (Disj disj))) 0)++-- | Apply a substitution to an equation store and bring resulting equations into+-- normal form again by using unification.+applyEqStore :: MaudeHandle -> LNSubst -> EqStore -> EqStore+applyEqStore hnd asubst eqStore+ | dom asubst `intersect` varsRange asubst /= [] || trace (show ("applyEqStore", asubst, eqStore)) False+ = error $ "applyS2EqStore: dom and vrange not disjoint for `"++show asubst++"'"+ | otherwise+ = modify eqsConj (fmap ((Disj . concatMap applyBound . getDisj))) $+ set eqsSubst newsubst eqStore+ where+ newsubst = asubst `compose` get eqsSubst eqStore+ applyBound s = map (restrictVFresh (varsRange newsubst ++ domVFresh s)) $ + (`runReader` hnd) $ unifyLNTerm+ [ Equal (apply newsubst (varTerm $ lv)) t+ | let slist = substToListVFresh s,+ -- variables in the range are fresh, so we have to rename+ -- them away from all other variables in unification problem+ -- NOTE: these variables never enter the global context+ let ran = renameAvoiding (map snd slist)+ (domVFresh s ++ varsRange newsubst),+ (lv,t) <- zip (map fst slist) ran+ ]++{- NOTES for @applyEqStore tau@ to a fresh substitution sigma:+[ FIXME: extend explanation to multiple unifiers ]+Let dom(sigma) = x1,..,xk, vrange(sigma) = y1, .. yl, vrange(tau) = z1,..,zn+Fresh substitution denotes formula+ exists #y1, .., #yl. x1 = t1 /\ .. /\ xk = tk+for variables #yi that do not clash with xi and zi [renameAwayFrom]+and with vars(ti) `subsetOf` [#y1, .. #yl].+We apply tau with vrange(tau) = z1,..,zn to the formula to obtain+ exists ##y1, .., ##yl. tau(x1) = t1 /\ .. /\ tau(xk) = tk+unification then yields a lemma+ forall xi zi #yi.+ tau(x1) = t1 /\ .. /\ tau(xk) = tk+ <-> exists vars(s1,..sm). x1 = .. /\ z1 = .. /\ #y1 = ..+So we have+ exists #y1, .., #yl.+ exists vars(s1,..sm). x1 = .. /\ z1 = .. /\ #y1 = ..+<=>+ exists vars(s1,..sm). x1 = .. /\ z1 = ..+ /\ (exists #y1, .., #yl. #y1 = ..)+<=> [restric]+ exists vars(s1,..sm). x1 = .. /\ z1 = .. /\ True+-}++-- | Add the given rule variants.+addRuleVariants :: (Disj (LNSubstVFresh)) -> EqStore -> EqStore+addRuleVariants (Disj substs) eqStore+ | dom freeSubst `intersect` concatMap domVFresh substs /= []+ = error $ "addRuleVariants: Nonempty intersection between domain of variants and free substitution. "+ ++"This case has not been implemented, add rule variants earlier."+ | otherwise = addDisj eqStore (Disj substs)+ where+ freeSubst = get eqsSubst eqStore++-- | Return the set of variables that is constrained by disjunction at give position.+constrainedVarsPos :: EqStore -> Int -> [LVar]+constrainedVarsPos eqStore k+ | k < length conj = frees (conj!!k)+ | otherwise = []+ where+ conj = getConj . get eqsConj $ eqStore++-- Internal functions+----------------------------------------------------------------------++-- | Add a disjunction to the equation store at the beginning+addDisj :: EqStore -> (Disj (LNSubstVFresh)) -> EqStore+addDisj eqStore disj = modify eqsConj ((Conj [disj]) `mappend`) eqStore+++-- | @splitEqStoreAt eqs i@ takes the disjunction at position @i@ in @eqs@+-- and returns a list of resulting substitutions and the equality store+-- with the remaining equations.+splitAtPos :: EqStore -> Int -> Maybe [EqStore]+splitAtPos eqStore i+ | i `notElem` eqSplits eqStore = Nothing+ | otherwise = Just $ map (\d -> set eqsConj (conjNew d) eqStore) disj+ where+ conj = getConj $ get eqsConj eqStore+ disj = getDisj $ conj !! i+ conjNew d = Conj $ take i conj ++ [Disj [d]] ++ drop (i+1) conj++-- Simplifying disjunctions+----------------------------------------------------------------------++-- | Simplify given disjunction via EqStore simplification. Obtains fresh+-- names for variables from the underlying 'MonadFresh'.+simpDisjunction :: MonadFresh m+ => MaudeHandle+ -> Disj (LNSubstVFresh)+ -> m (LNSubst, Maybe [LNSubstVFresh])+simpDisjunction hnd disj0 = do+ eqStore' <- simp hnd eqStore+ return (get eqsSubst eqStore', wrap $ get eqsConj eqStore')+ where+ eqStore = set eqsConj (Conj [disj0]) $ emptyEqStore+ wrap (Conj []) = Nothing+ wrap (Conj [Disj disj]) = Just $ disj+ wrap conj =+ error ("simplifyDisjunction: imposible, unexpected conjuction `"+ ++ show conj ++ "'")++-- Simplification+----------------------------------------------------------------------++-- | @simp eqStore@ simplifies the equation store.+simp :: MonadFresh m => MaudeHandle -> EqStore -> m EqStore+simp hnd eqStore = (`execStateT` (trace (show ("eqStore", eqStore)) eqStore)) $ whileTrue (simp1 hnd)+++-- | @simp1@ tries to execute one simplification step+-- for the equation store. It returns @True@ if+-- the equation store was modified.+simp1 :: MonadFresh m => MaudeHandle -> StateT EqStore m Bool+simp1 hnd = do+ s <- MS.get+ b1 <- simpMinimize+ b2 <- simpRemoveRenamings+ b3 <- simpEmptyDisj+ b4 <- foreachDisj hnd simpSingleton+ b5 <- foreachDisj hnd simpAbstractSortedVar+ b6 <- foreachDisj hnd simpIdentify+ b7 <- foreachDisj hnd simpAbstractFun+ b8 <- foreachDisj hnd simpAbstractName+ s' <- MS.get+ (trace (show ("simp:", [b1, b2, b3, b4, b5, b6, b7, b8], s, s'))) $ return $ (or [b1, b2, b3, b4, b5, b6, b7, b8])++-- | Remove variable renamings in fresh substitutions.+simpRemoveRenamings :: MonadFresh m => StateT EqStore m Bool+simpRemoveRenamings = do+ conj <- gets (get eqsConj)+ let (conj',changed) =+ runState (traverse (traverse rmRenamings) conj) False+ when changed $ MS.modify (set eqsConj conj')+ return changed+ where + rmRenamings :: LNSubstVFresh -> State Bool LNSubstVFresh+ rmRenamings subst = do+ let subst' = removeRenamings subst+ when (domVFresh subst /= domVFresh subst') $ put True+ return subst'++-- | If empty disjunction is found, the whole conjunct+-- can be simplified to False.+simpEmptyDisj :: MonadFresh m => StateT EqStore m Bool+simpEmptyDisj = do+ conj <- gets (get eqsConj)+ if (F.any (==falseDisj) conj && conj /= falseEqConstrConj)+ then MS.modify (set eqsConj falseEqConstrConj) >> return True+ else return False++-- | If there is a singleton disjunction, it can be+-- composed with the free substitution.+simpSingleton :: MonadFresh m => Disj LNSubstVFresh+ -> m (Maybe (Maybe LNSubst, [Disj LNSubstVFresh]))+simpSingleton (Disj [subst0]) = do+ subst <- freshToFree subst0+ return (Just (Just subst, []))+simpSingleton _ = return Nothing+++-- | If all substitutions @si@ map a variable @v@ to terms with the same+-- outermost function symbol @f@, then they all contain the common factor+-- @{v |-> f(x1,..,xk)}@ for fresh variables xi and we can replace+-- @x |-> ..@ by @{x1 |-> ti1, x2 |-> ti2, ..}@ in all substitutions @si@.+simpAbstractFun :: MonadFresh m => Disj LNSubstVFresh+ -> m (Maybe (Maybe LNSubst, [Disj LNSubstVFresh]))+simpAbstractFun (Disj []) = return Nothing+simpAbstractFun (Disj (subst:others)) = case commonOperators of+ [] -> return Nothing+ -- abstract all arguments+ (v, o, argss@(args:_)):_ | all ((==length args) . length) argss -> do+ fvars <- mapM (\_ -> freshLVar "x" LSortMsg) args+ let substs' = zipWith (abstractAll v fvars) (subst:others) argss+ fsubst = substFromList [(v, FApp o (map varTerm fvars))]+ return $ Just (Just $ fsubst, [Disj substs'])+ -- abstract first two arguments+ (v, o@(AC _), argss):_ -> do+ fv1 <- freshLVar "x" LSortMsg+ fv2 <- freshLVar "x" LSortMsg+ let substs' = zipWith (abstractTwo o v fv1 fv2) (subst:others) argss+ fsubst = substFromList [(v, FApp o (map varTerm [fv1,fv2]))]+ return $ Just (Just $ fsubst, [Disj substs'])+ (_, _ ,_):_ ->+ error "simpAbstract: impossible, invalid arities or List operator encountered."+ where+ commonOperators = do+ (v, FApp o args) <- substToListVFresh subst+ let images = map (\s -> imageOfVFresh s v) others+ argss = [ args' | Just (FApp o' args') <- images, o' == o ]+ guard (length argss == length others)+ return (v, o, args:argss)++ abstractAll v freshVars s args = substFromListVFresh $+ filter ((/= v) . fst) (substToListVFresh s) ++ zip freshVars args++ abstractTwo o v fv1 fv2 s args = substFromListVFresh $+ filter ((/= v) . fst) (substToListVFresh s) ++ newMappings args+ where+ newMappings [] =+ error "simpAbstract: impossible, AC symbols must have arity >= 2."+ newMappings [a1,a2] = [(fv1, a1), (fv2, a2)]+ -- here we always abstract from left to right and do not+ -- take advantage of the AC property of o+ newMappings (a:as) = [(fv1, a), (fv2, FApp o as)]+++-- | If all substitutions @si@ map a variable @v@ to the same name @n@,+-- then they all contain the common factor +-- @{v |-> n}@ and we can remove @{v -> n} from all substitutions @si@+simpAbstractName :: MonadFresh m => Disj LNSubstVFresh+ -> m (Maybe (Maybe LNSubst, [Disj LNSubstVFresh]))+simpAbstractName (Disj []) = return Nothing+simpAbstractName (Disj (subst:others)) = case commonNames of+ [] -> return Nothing+ (v, c):_ ->+ return $ Just (Just $ substFromList [(v, c)]+ , [Disj (map (\s -> restrictVFresh (delete v (domVFresh s)) s) (subst:others))])+ + where+ commonNames = do+ (v, c@(Lit (Con _))) <- substToListVFresh subst+ let images = map (\s -> imageOfVFresh s v) others+ guard (length images == length [ () | Just c' <- images, c' == c])+ return (v, c)++-- | If all substitutions @si@ map a variable @v@ to variables @xi@ of the same+-- sort @s@ then they all contain the common factor +-- @{v |-> y}@ for a fresh variable of sort @s@+-- and we can replace @{v -> xi}@ by @{y -> xi} in all substitutions @si@+simpAbstractSortedVar :: MonadFresh m => Disj LNSubstVFresh+ -> m (Maybe (Maybe LNSubst, [Disj LNSubstVFresh]))+simpAbstractSortedVar (Disj []) = return Nothing+simpAbstractSortedVar (Disj (subst:others)) = case commonSortedVar of+ [] -> return Nothing+ (v, s, lvs):_ -> do+ fv <- freshLVar (lvarName v) s+ return $ Just (Just $ substFromList [(v, varTerm fv)]+ , [Disj (zipWith (replaceMapping v fv) lvs (subst:others))])+ where+ commonSortedVar = do+ (v, (Lit (Var lx))) <- substToListVFresh subst+ guard (sortCompare (lvarSort v) (lvarSort lx) == Just GT)+ let images = map (\s -> imageOfVFresh s v) others+ -- FIXME: could be generalized to choose topsort s of all images if s < sortOf v+ -- could also be generalized to terms of a given sort+ goodImages = [ ly | Just (Lit (Var ly)) <- images, lvarSort lx == lvarSort ly]+ guard (length images == length goodImages)+ return (v, lvarSort lx, (lx:goodImages))+ replaceMapping v fv lv sigma =+ substFromListVFresh $ (filter ((/=v) . fst) $ substToListVFresh sigma) ++ [(fv, varTerm lv)]++++-- | If all substitutions @si@ map two variables @x@ and @y@ to identical terms @ti@,+-- then they all contain the common factor @{x |-> y} for a fresh variable @z@+-- and we can remove @{x |-> ti}@ from all @si@.+simpIdentify :: MonadFresh m => Disj (LNSubstVFresh)+ -> m (Maybe (Maybe LNSubst, [Disj LNSubstVFresh]))+simpIdentify (Disj []) = return Nothing+simpIdentify (Disj (subst:others)) = case equalImgPairs of+ [] -> return Nothing+ ((v,v'):_) -> do+ let (vkeep, vremove) = case sortCompare (lvarSort v) (lvarSort v') of+ Just GT -> (v', v)+ Just _ -> (v, v')+ Nothing -> error $ "EquationStore.simpIdentify: impossible, variables with incomparable sorts: "+ ++ show v ++" and "++ show v'+ return $ Just (Just (substFromList [(vremove, varTerm vkeep)]),+ [Disj (map (removeMappings [vkeep]) (subst:others))])+ where+ equalImgPairs = do+ (v,t) <- substToListVFresh subst+ (v', t') <- substToListVFresh subst+ guard (t == t' && v < v' && all (agrees_on v v') others)+ return (v,v')+ agrees_on v v' s =+ imageOfVFresh s v == imageOfVFresh s v' && isJust (imageOfVFresh s v)+ removeMappings vs s = restrictVFresh (domVFresh s \\ vs) s++-- | Traverse disjunctions without msgBefore fact in conjunction and+-- execute @f@ until it returns @Just (mfreeSubst, disjs)@.+-- Then the @disjs@ is inserted at the current position, if @mfreeSubst@ is+-- @Just freesubst@, then it is applied to the equation store. @True@ is+-- returned if any modifications took place.+foreachDisj :: MonadFresh m+ => MaudeHandle+ -> (Disj (LNSubstVFresh) -> m (Maybe (Maybe LNSubst, [Disj LNSubstVFresh])))+ -> StateT EqStore m Bool+foreachDisj hnd f = do+ conj <- gets (get eqsConj)+ go [] (getConj conj)+ where+ go _ [] = return False+ go lefts (d:rights) = do+ b <- lift $ f d+ case b of+ Nothing -> go (d:lefts) rights+ Just (msubst, disjs) -> do+ MS.modify (set eqsConj (Conj (reverse lefts ++ disjs ++ rights)))+ maybe (return ()) (\s -> MS.modify (applyEqStore hnd s)) msubst+ return True+++-- Renaming and subsumption+----------------------------------------------------------------------++-- | Simplify by removing substitutions that occur twice in a disjunct.+-- We could generalize this function by using AC-equality or subsumption.+simpMinimize :: MonadFresh m => StateT EqStore m Bool+simpMinimize = do+ eqs <- MS.get+ let eqs' = modify eqsConj (fmap (Disj . sortednub . getDisj)) eqs+ MS.put eqs'+ return (eqs /= eqs')++{-++ +t2 = simpAbstract (Disj (map substFromListVFresh [s1,s2])) `evalFresh` nothingUsed+ where s1 = [(lx1,pair(y1,y2))]+ s2 = [(lx1,pair(inv(y1),inv(y2)))]+++t3 = simpAbstract (Disj (map substFromListVFresh [s1,s2,s3])) `evalFresh` nothingUsed+ where s1 = [(lx1, mult [y1,y2] )]+ s2 = [(lx1, mult [inv(y1), inv(y2), inv(y3)])]+ s3 = [(lx1, mult[y5, y6, y7, y8])]+++t4 = simpIdentify (Disj (map substFromListVFresh [s1,s2])) `evalFresh` nothingUsed+ where s1 = [(lx1, mult [y1,y2,y3] ), (lx2, mult [y1,y2,y3] )]+ s2 = [(lx1, mult [inv(y1), inv(y2), inv(y3)]), (lx2, mult [inv(y1), inv(y2), inv(y3)])]++-}++{-+t5 = simpAbstractFun (Disj (map substFromListVFresh [s1,s2,s3])) `evalFresh` nothingUsed+ where s1 = [(lx1, mult [y1,y2] )]+ s2 = [(lx1, x3)]+ s3 = [(lx1, mult[y5, y6, y7, y8])]++t6 = simpIdentify (Disj (map substFromListVFresh [s1,s2,s3])) `evalFresh` nothingUsed+ where s1 = [(lx1, mult [y1,y2,y3] ), (lx2, mult [y1,y2,y3] )]+ s2 = [(lx1, mult [inv(y1), inv(y2), inv(y3)]), (lx2, mult [inv(y1), inv(y2), inv(y3)])]+ s3 = [(lx1, y1), (lx2, y2)]++-}
@@ -0,0 +1,562 @@+{-# LANGUAGE TypeOperators, TemplateHaskell, DeriveDataTypeable, ScopedTypeVariables, TupleSections+ , StandaloneDeriving, TypeSynonymInstances, BangPatterns, FlexibleInstances, FlexibleContexts #-}+-- |+-- Copyright : (c) 2011 Benedikt Schmidt & Simon Meier+-- License : GPL v3 (see LICENSE)+-- +-- Maintainer : Benedikt Schmidt <beschmi@gmail.com>+-- Portability : GHC only+--+-- Guarded Formulas.+module Theory.Proof.Guarded (++ -- * Guarded logical formulas+ Guarded(..)+ , LGuarded+ , LNGuarded+ + -- ** Formula Construction+ , gfalse+ , gtrue+ , gdisj+ , gconj++ -- ** Traversals+ , mapGuardedAtoms++ -- ** Conversions to non-bound representations+ , fromFormula+ , fromFormulaNegate+ , bvarToLVar++ -- ** Induction+ , applyInduction+ , negateGuarded++ -- ** Queries+ , isConjunction+ , isDisjunction+ , isAllGuarded+ , isExGuarded++ -- ** Opening quantifiers+ , openExGuarded+ , openAllGuarded++ -- ** Substitutions+ , substBound+ , substBoundAtom+ , substFree+ , substFreeAtom++ -- ** Pretty-printing+ , prettyGuarded++ ) where++import Control.Applicative+import Control.Monad.Error+import Control.DeepSeq++import Data.Traversable hiding ( mapM, sequence )+import Data.List+import Data.Monoid (mappend, mconcat)+import Data.Foldable (Foldable(..), foldMap)+import Data.Either (partitionEithers)+import Data.DeriveTH+import Data.Binary+++import Theory.Rule+import Logic.Connectives+import Theory.Atom+import Theory.Formula++import Text.PrettyPrint.Highlight++import Control.Monad.Fresh hiding ( mapM )+import Control.Arrow++------------------------------------------------------------------------------+-- Types+------------------------------------------------------------------------------++data Guarded s c v = GAto (Atom (VTerm c (BVar v)))+ | GDisj (Disj (Guarded s c v))+ | GConj (Conj (Guarded s c v))+ | GGuarded Quantifier [s] [Atom (VTerm c (BVar v))] (Guarded s c v)+ -- ^ Denotes @ALL xs. as => gf@ or @Ex xs. as & gf&+ -- depending on the 'Quantifier'.+ -- We assume that all bound variables xs occur in+ -- f@i atoms in as.+ deriving (Eq, Ord, Show)++isConjunction :: Guarded t t1 t2 -> Bool+isConjunction (GConj _) = True+isConjunction _ = False++isDisjunction :: Guarded t t1 t2 -> Bool+isDisjunction (GDisj _) = True+isDisjunction _ = False++isExGuarded :: Guarded t t1 t2 -> Bool+isExGuarded (GGuarded Ex _ _ _) = True+isExGuarded _ = False++isAllGuarded :: Guarded t t1 t2 -> Bool+isAllGuarded (GGuarded All _ _ _) = True+isAllGuarded _ = False++------------------------------------------------------------------------------+-- Folding+------------------------------------------------------------------------------++-- | Fold a guarded formula.+foldGuarded :: (Atom (VTerm c (BVar v)) -> b)+ -> (Disj b -> b)+ -> (Conj b -> b)+ -> (Quantifier -> [s] -> [Atom (VTerm c (BVar v))] -> b -> b)+ -> Guarded s c v+ -> b+foldGuarded fAto fDisj fConj fGuarded =+ go+ where+ go (GAto a) = fAto a+ go (GDisj disj) = fDisj $ fmap go disj+ go (GConj conj) = fConj $ fmap go conj+ go (GGuarded qua ss as gf) = fGuarded qua ss as (go gf)++-- | Fold a guarded formula with scope info.+-- The Int argument denotes the number of+-- quantifiers that have been encountered so far.+foldGuardedScope :: (Int -> Atom (VTerm c (BVar v)) -> b)+ -> (Disj b -> b)+ -> (Conj b -> b)+ -> (Quantifier -> [s] -> Int -> [Atom (VTerm c (BVar v))] -> b -> b)+ -> Guarded s c v+ -> b+foldGuardedScope fAto fDisj fConj fGuarded =+ go 0+ where+ go !i (GAto a) = fAto i a+ go !i (GDisj disj) = fDisj $ fmap (go i) disj+ go !i (GConj conj) = fConj $ fmap (go i) conj+ go !i (GGuarded qua ss as gf) =+ fGuarded qua ss i' as (go i' gf)+ where+ i' = i + length ss+++-- | Map a guarded formula with scope info.+-- The Int argument denotes the number of+-- quantifiers that have been encountered so far.+mapGuardedAtoms :: (Int -> Atom (VTerm c (BVar v))+ -> Atom (VTerm d (BVar w)))+ -> Guarded s c v+ -> Guarded s d w+mapGuardedAtoms f = + foldGuardedScope (\i a -> GAto $ f i a) GDisj GConj+ (\qua ss i as gf -> GGuarded qua ss (map (f i) as) gf) ++------------------------------------------------------------------------------+-- Instances+------------------------------------------------------------------------------++instance Functor (Guarded s c) where+ fmap f = foldGuarded (GAto . fmap (fmap (fmap (fmap f)))) GDisj GConj+ (\qua ss as gf -> GGuarded qua ss (map (fmap (fmap (fmap (fmap f)))) as) gf)++instance Foldable (Guarded s c) where+ foldMap f = foldGuarded (foldMap (foldMap (foldMap (foldMap f))))+ (mconcat . getDisj)+ (mconcat . getConj)+ (\_qua _ss as b -> foldMap (foldMap (foldMap (foldMap (foldMap f)))) as `mappend` b)+++instance Traversable (Guarded s c) where+ traverse f = foldGuarded (liftA GAto . traverse (traverse (traverse (traverse f))))+ (liftA GDisj . sequenceA)+ (liftA GConj . sequenceA)+ (\qua ss as gf -> GGuarded qua ss <$> traverse (traverse (traverse (traverse (traverse f)))) as <*> gf)++instance HasFrees (Guarded (String, LSort) c LVar) where+ foldFrees f = foldMap (foldFrees f)+ mapFrees f = traverse (mapFrees f)+++-- FIXME: remove name hints for variables for saturation?+type LGuarded c = Guarded (String, LSort) c LVar++------------------------------------------------------------------------------+-- Substitutions of bound for free and vice versa+------------------------------------------------------------------------------++-- | @substBoundAtom s a@ substitutes each occurence of a bound variables @i@+-- in @dom(s)@ with the corresponding free variable @x=s(i)@ in the atom @a@.+substBoundAtom :: [(Int,LVar)] -> Atom (VTerm c (BVar LVar)) -> Atom (VTerm c (BVar LVar))+substBoundAtom s = fmap (fmap (fmap subst))+ where subst bv@(Bound i') = case lookup i' s of+ Just x -> Free x+ Nothing -> bv+ subst fv = fv++-- | @substBound s gf@ substitutes each occurence of a bound+-- variable @i@ in @dom(s)@ with the corresponding free variable+-- @s(i)=x@ in all atoms in @gf@.+substBound :: [(Int,LVar)] -> LGuarded c -> LGuarded c+substBound s = mapGuardedAtoms (\j a -> substBoundAtom [(i+j,v) | (i,v) <- s] a)+++-- | @substFreeAtom s a@ substitutes each occurence of a free variables @v@+-- in @dom(s)@ with the bound variables @i=s(v)@ in the atom @a@.+substFreeAtom :: [(LVar,Int)] + -> Atom (VTerm c (BVar LVar)) -> Atom (VTerm c (BVar LVar))+substFreeAtom s = fmap (fmap (fmap subst))+ where subst fv@(Free x) = case lookup x s of+ Just i -> Bound i+ Nothing -> fv+ subst bv = bv++-- | @substFreeAtom s gf@ substitutes each occurence of a free variables+-- @v in dom(s)@ with the correpsonding bound variables @i=s(v)@+-- in all atoms in @gf@.+substFree :: [(LVar,Int)] -> LGuarded c -> LGuarded c+substFree s = mapGuardedAtoms (\j a -> substFreeAtom [(v,i+j) | (v,i) <- s] a)++-- | Assuming that there are no more bound variables left in an atom of a+-- formula, convert it to an atom with free variables only.+bvarToLVar :: Atom (VTerm c (BVar LVar)) -> Atom (VTerm c LVar)+bvarToLVar = + fmap (fmap (fmap (foldBVar boundError id)))+ where+ boundError v = error $ "bvarToLVar: left-over bound variable '" + ++ show v ++ "'"++------------------------------------------------------------------------------+-- Opening and Closing+------------------------------------------------------------------------------++-- | @openGuarded gf@ returns @Just (qua,vs,ats,gf')@ if @gf@ is a guarded+-- clause and @Nothing@ otherwise. In the first case, @quao@ is the quantifier,+-- @vs@ is a list of fresh variables, @ats@ is the antecedent, and @gf'@ is the+-- succedent. In both antecedent and succedent, the bound variables are+-- replaced by @vs@.+openGuarded :: (MonadFresh m)+ => LGuarded c -> m (Maybe (Quantifier, [LVar], [Atom (VTerm c LVar)], LGuarded c))+openGuarded (GGuarded qua vs as gf) = do+ xs <- mapM (\(n,s) -> freshLVar n s) vs+ return $ Just (qua, xs, openas xs, opengf xs)+ where + openas xs = map (bvarToLVar . substBoundAtom (subst xs)) as+ opengf xs = substBound (subst xs) gf+ subst xs = zip [0..] (reverse xs)+openGuarded _ = return Nothing++-- | @closeGuarded vs ats gf@ is a smart constructor for @GGuarded@.+closeGuarded :: Quantifier -> [LVar] -> [Atom (VTerm c LVar)] + -> LGuarded c -> LGuarded c+closeGuarded qua vs as gf = GGuarded qua vs' as' gf'+ where as' = map (substFreeAtom s . fmap (fmap (fmap Free))) as+ gf' = substFree s gf+ s = zip (reverse vs) [0..]+ vs' = map (lvarName &&& lvarSort) vs++-- | @openAllGuarded gf@ returns @Just (vs,ats,gf')@ if @gf@ is a guarded+-- all quantified trace formula and @Nothing@ otherwise. In the first case,+-- @vs@ is a list of fresh variables, @ats@ is the antecedent, and @gf'@ is+-- the succedent. In both antecedent and succedent, the bound variables are+-- replaced by @vs@.+openAllGuarded :: (MonadFresh m)+ => LGuarded c -> m (Maybe ([LVar],[Atom (VTerm c LVar)], LGuarded c))+openAllGuarded = (fmap adapt) . openGuarded+ where+ adapt (Just (All, vs, as, gf)) = Just (vs, as, gf)+ adapt _ = Nothing++-- | @openExGuarded gf@ returns @Just (vs,gf')@ if @gf@ is a guarded+-- existentially quantified trace formula and @Nothing@ otherwise. In the+-- first case, @vs@ is a list of fresh variables and @gf'@ is the body of @gf@+-- with the bound variable replaced by @v@.+openExGuarded :: (MonadFresh m, Eq c) + => LGuarded c -> m (Maybe ([LVar], LGuarded c))+openExGuarded (GGuarded Ex ss as gf0) = do+ xs <- mapM (uncurry freshLVar) ss+ return $ Just (xs, substBound (zip [0..] (reverse xs)) gf)+ where + gf = gconj (map GAto as ++ [gf0])+openExGuarded _ = return Nothing+++------------------------------------------------------------------------------+-- Conversion and negation+------------------------------------------------------------------------------++-- | @fromFormulaNegate f@ returns a guarded formula @gf@ that is+-- equivalent to @f@ if possible.+fromFormula :: LNFormula -> Either String LNGuarded+fromFormula = convert False++-- | @fromFormulaNegate f@ returns a guarded formula @gf@ that is+-- equivalent to @not f@ if possible.+fromFormulaNegate :: LNFormula -> Either String LNGuarded+fromFormulaNegate = convert True++type LNGuarded = Guarded (String,LSort) Name LVar++-- | @gtf b@ returns the guarded formula f with @b <-> f@.+gtf :: Bool -> Guarded s c v+gtf False = GDisj (Disj [])+gtf True = GConj (Conj [])++-- | @gfalse@ returns the guarded formula f with @False <-> f@.+gfalse :: Guarded s c v+gfalse = gtf False++-- | @gtrue@ returns the guarded formula f with @True <-> f@.+gtrue :: Guarded s c v+gtrue = gtf True++-- | @gnot a@ returns the guarded formula f with @not a <-> f@.+gnot :: Atom (VTerm c (BVar v)) -> Guarded s c v+gnot a = GGuarded All [] [a] gfalse+-- FIXME: This was the old code. However, it should be necessary to quantify+-- the frees, as we are working in a closed formula always.+-- gnot a = GGuarded All (map (lvarName &&& lvarSort) $ frees a) [a] gfalse++-- | @gconj gfs@ smart constructor for the conjunction of gfs.+gconj :: (Eq s, Eq c, Eq v) => [Guarded s c v] -> Guarded s c v+gconj gfs0 = case concatMap flatten gfs0 of + [gf] -> gf+ gfs | any (gfalse ==) gfs -> gfalse+ | otherwise -> GConj $ Conj $ nub gfs+ where+ flatten (GConj conj) = concatMap flatten $ getConj conj+ flatten gf = [gf]++-- | @gdisj gfs@ smart constructor for the disjunction of gfs.+gdisj :: (Eq s, Eq c, Eq v) => [Guarded s c v] -> Guarded s c v+gdisj gfs0 = case concatMap flatten gfs0 of+ [gf] -> gf+ gfs | any (gtrue ==) gfs -> gtrue+ | otherwise -> GDisj $ Disj $ nub gfs+ where+ flatten (GDisj disj) = concatMap flatten $ getDisj disj+ flatten gf = [gf]++-- @ A smart constructor for @GGuarded Ex@ that removes empty quantifications.+gex :: (Eq s, Eq c, Eq v)+ => [s] -> [Atom (VTerm c (BVar v))] -> Guarded s c v -> Guarded s c v+gex [] as gf = gconj (map GAto as ++ [gf])+gex ss as gf = GGuarded Ex ss as gf++-- @ A smart constructor for @GGuarded All@ that does nothing special+-- (currently).+gall :: [s] -> [Atom (VTerm c (BVar v))] -> Guarded s c v -> Guarded s c v+gall = GGuarded All++-- | @convert neg f@ returns @Nothing@ if @f@ cannot be converted,+-- @Just gf@ such that @mneg f <-> gf@ with @mneg = id@ if @neg@ is @False@+-- and @mneg=not@ if @neg@ is true.+convert :: Bool -> LNFormula -> Either String LNGuarded+convert True (Ato a) = pure $ gnot a+convert False (Ato a) = pure $ GAto a++convert polarity (Not f) = convert (not polarity) f++convert True (Conn And f g) = gdisj <$> mapM (convert True) [f, g]+convert False (Conn And f g) = gconj <$> mapM (convert False) [f, g]++convert True (Conn Or f g) = gconj <$> mapM (convert True) [f, g]+convert False (Conn Or f g) = gdisj <$> mapM (convert False) [f, g]++convert True (Conn Imp f g ) = + gconj <$> sequence [convert False f, convert True g]+convert False (Conn Imp f g ) = + gdisj <$> sequence [convert True f, convert False g]++convert polarity (TF b) = pure $ gtf (polarity /= b)++convert polarity f0@(Qua qua0 _ _) =+ -- The quantifier switch stems from our implicit negation of the formula.+ case (qua0, polarity) of+ (All, True ) -> convAll Ex+ (All, False) -> convAll All+ (Ex, True ) -> convEx All+ (Ex, False) -> convEx Ex+ where+ convEx qua = do+ (xs,_,f) <- openFormulaPrefix f0 `evalFreshT` avoid f0+ case partitionEithers $ partitionConj f of+ (as, fs) -> do+ let guardedvars = frees as+ -- all existentially quantified variables must be guarded+ unguarded = xs \\ guardedvars++ unless (null unguarded) $ throwError $ + "unguarded variables " ++ show unguarded ++ " in " ++ show f0+ + gf <- (if polarity then gdisj else gconj)+ <$> mapM (convert polarity) fs+ return $ closeGuarded qua xs as gf+ where+ partitionConj (Conn And f1 f2) = partitionConj f1 ++ partitionConj f2+ partitionConj (Ato a@(Action _ _)) = [Left $ bvarToLVar a]+ partitionConj (Ato e@(EqE _ _)) = [Left $ bvarToLVar e]+ partitionConj f = [Right f]++ convAll qua = do+ (xs,_,f) <- openFormulaPrefix f0 `evalFreshT` avoid f0+ case f of+ Conn Imp ante suc -> do+ allowedAtoms <- collectAllowedAtoms ante++ let guardedvars = frees [ a | a@(Action _ _) <- allowedAtoms ]+ -- all universally quantified variables must be guarded+ unguarded = xs \\ guardedvars++ when (not $ null unguarded) $ throwError $+ "unguarded variables " ++ show unguarded ++ " in " ++ show f0++ g <- convert polarity suc+ return $ closeGuarded qua xs allowedAtoms g++ _ -> throwError $ show f ++ "outside guarded fragment"+ where+ collectAllowedAtoms (Conn And f1 f2) =+ (++) <$> collectAllowedAtoms f1 <*> collectAllowedAtoms f2+ collectAllowedAtoms (Ato a@(Action _ _)) = return [bvarToLVar a]+ collectAllowedAtoms (Ato e@(EqE _ _)) = return [bvarToLVar e]+ collectAllowedAtoms na = + throwError $ show na ++ " not allowed in antecedent"++convert _ (Conn Iff _ _) =+ Left $ "`iff' not supported (yet)"++instance Apply LNGuarded where+ apply subst = mapGuardedAtoms (const $ apply subst)+++------------------------------------------------------------------------------+-- Induction over the trace+------------------------------------------------------------------------------++-- Note that we assume that the guarded formula describes the attack.+-- Hence, we want to show that it is false.++{-+-- | Checks if a doubly guarded formula is last-free; i.e., does not contain a 'Last'+-- atom.+lastFree :: Guarded s c v -> Bool+lastFree = error "lastFree: implement"++-- | Checks if a formula is doubly guarded; i.e., both universal and existential+-- quantifiers are guarded.+doublyGuarded :: Guarded s c v -> Bool+doublyGuarded = either (const False) (const True) . satisfiedByEmptyTrace+-}++-- | Negate a guarded formula.+negateGuarded :: (Eq s, Eq c, Eq v) + => Guarded s c v -> Guarded s c v+negateGuarded = + go+ where+ go (GGuarded All ss as gf) = gex ss as $ go gf+ go (GGuarded Ex ss as gf) = gall ss as $ go gf+ go (GAto ato) = gnot ato+ go (GDisj disj) = gconj $ map go (getDisj disj)+ go (GConj conj) = gdisj $ map go (getConj conj)+++-- | Checks if a doubly guarded formula is satisfied by the empty trace;+-- returns @'Left' errMsg@ if the formula is not doubly guarded.+satisfiedByEmptyTrace :: Guarded s c v -> Either String Bool+satisfiedByEmptyTrace = + foldGuarded + (\_ato -> throwError "atom outside the scope of a quantifier")+ (liftM or . sequence . getDisj) + (liftM and . sequence . getConj)+ (\qua _ss _as _gf -> return $ qua == All) + -- the empty trace always satisfies guarded all-quantification+ -- and always dissatisfies guarded ex-quantification++-- | Tries to convert a doubly guarded formula to an induction hypothesis.+-- Returns @'Left' errMsg@ if the formula is not last-free or not doubly+-- guarded.+toInductionHypothesis :: Eq c => LGuarded c -> Either String (LGuarded c)+toInductionHypothesis =+ go+ where+ go (GGuarded qua ss as gf) = do+ gf' <- go gf+ return $ case qua of+ All -> GGuarded Ex ss as (gconj $ (gnot <$> lastAtos) ++ [gf'])+ Ex -> GGuarded All ss as (gdisj $ (GAto <$> lastAtos) ++ [gf'])+ + where+ lastAtos :: [Atom (VTerm c (BVar LVar))]+ lastAtos = do+ (j, (_, LSortNode)) <- zip [0..] $ reverse ss+ return $ Last (varTerm (Bound j))++ go (GAto (Less i j)) = return $ gdisj [GAto (EqE i j), GAto (Less j i)]+ go (GAto (Last _)) = throwError "formula not last-free"+ go (GAto ato) = return $ gnot ato+ go (GDisj disj) = gconj <$> traverse go (getDisj disj)+ go (GConj conj) = gdisj <$> traverse go (getConj conj)++-- | Try to prove the formula by applying induction over the trace.+-- Returns @'Left' errMsg@ if this is not possible.+applyInduction :: Eq c => LGuarded c -> Either String (LGuarded c)+applyInduction gf = do+ baseCase <- satisfiedByEmptyTrace gf+ if baseCase+ then throwError "cannot apply induction: empty trace is an attack"+ else do+ gfIH <- toInductionHypothesis gf+ return (gconj [gf, gfIH])+++------------------------------------------------------------------------------+-- Pretty Printing+------------------------------------------------------------------------------++-- | Pretty print a formula.+prettyGuarded :: HighlightDocument d + => LNGuarded -- ^ Guarded Formula.+ -> d -- ^ Pretty printed formula.+prettyGuarded f = + pp f `evalFreshAvoiding` f+ where+ pp :: HighlightDocument d => LNGuarded -> Fresh d+ pp (GAto a) = return $ prettyNAtom $ bvarToLVar a++ pp (GDisj (Disj [])) = return $ operator_ "F"++ pp (GDisj (Disj xs)) = do+ ps <- mapM (\x -> opParens <$> pp x) xs+ return $ sep $ punctuate (operator_ " |") ps++ pp (GConj (Conj [])) = return $ operator_ "T"++ pp (GConj (Conj xs)) = do+ ps <- mapM (\x -> opParens <$> pp x) xs+ return $ sep $ punctuate (operator_ " &") ps++ pp gf0@(GGuarded _ _ _ _) = do+ Just (qua, vs, atoms, gf) <- openGuarded gf0+ dante <- pp (GConj (Conj (map (GAto . fmap (fmap (fmap Free))) atoms)))+ dsucc <- pp gf+ return $ sep [ operator_ (show qua) <-> ppVars vs <> operator_ "."+ , nest 1 dante+ , operator_ (case qua of All -> "==>"; Ex -> "&")+ , nest 1 dsucc]+ where+ ppVars = fsep . map (text . show)+++-- Derived instances+--------------------++$( derive makeBinary ''Guarded)+$( derive makeNFData ''Guarded)
@@ -0,0 +1,1035 @@+{-# LANGUAGE ViewPatterns, DeriveDataTypeable, TupleSections, TypeOperators, TemplateHaskell, TypeSynonymInstances, FlexibleInstances, FlexibleContexts, GeneralizedNewtypeDeriving #-}+-- |+-- Copyright : (c) 2010-2012 Benedikt Schmidt & Simon Meier+-- License : GPL v3 (see LICENSE)+--+-- Maintainer : Simon Meier <iridcode@gmail.com>+-- Portability : GHC only+--+-- Proof states and their transformations; i.e., logical deduction.+module Theory.Proof.Sequent (+ -- * Sequent construction+ sequentFromFormula++ -- * Prove methods++ -- ** SeProof monad+ , SeProof+ , execSeProof+ , runSeProof+ , getMaudeHandle++ -- ** Goals+ , openGoals+ , solveGoal++ -- ** Equalitiy solving+ , solveSubstEqs++ -- ** Conjunction with other sequents+ , conjoinSequent++ -- ** Simplification+ , simplifySequent++ -- * Contradiction+ , proveCyclic+ , hasNonNormalTerms+ , hasForbiddenExp+ , formulasFalse+ , nonUniqueFactInstances+ , contradictorySequent++ -- * Convenience export of used modules+ , module Theory.Proof.Types+ , module Theory.Proof.EquationStore+ ) where++import Debug.Trace++import Prelude hiding ( (.), id )++import Data.List+import Data.Either+import qualified Data.DAG.Simple as D (cyclic, reachableSet)+import qualified Data.Set as S+import qualified Data.Map as M+import Data.Monoid (Monoid, mappend )++import Control.Basics+import Control.Category+import Control.Monad.Disj+import Control.Monad.Reader+import Control.Monad.Bind+import Control.Monad.State (StateT, runStateT, execStateT, gets, put)++import Text.Isar++import Extension.Prelude+import Extension.Data.Label++import Logic.Connectives++import Theory.Rule+import Theory.Proof.SolveGuarded+import Theory.Proof.Types+import Theory.Proof.EquationStore++------------------------------------------------------------------------------+-- Sequents+------------------------------------------------------------------------------++-- Construction+---------------++-- | Returns the sequent that has to be proven to show that+-- given formula holds in the context of the given theory.+sequentFromFormula :: CaseDistKind -> LNFormula -> Sequent+sequentFromFormula kind f = + set sFormulas (S.singleton gf) (emptySequent kind)+ where + gf = either error id (fromFormulaNegate f)+++------------------------------------------------------------------------------+-- Graph reasoning+------------------------------------------------------------------------------++-- | True iff there are terms in the sequent that are not in normal form wrt.+-- to 'Term.Rewriting.Norm.norm' (DH/AC).+--+-- FIXME: Might also want to check clauses, equation store, and other+-- components of sequent.+hasNonNormalTerms :: SignatureWithMaude -> Sequent -> Bool+hasNonNormalTerms sig se =+ any (not . (`runReader` (get sigmMaudeHandle sig)) . nfRule) . M.elems . get sNodes $ se++-- | True if there is no @EXP-down@ rule that should be replaced by an+-- @EXP-up@ rule.+hasForbiddenExp :: Sequent -> Bool+hasForbiddenExp se =+ any (isForbiddenExp) $ M.elems $ get sNodes se++-- | @isForbiddenExp ru@ returns @True@ if @ru@ is not allowed in+-- a normal dependency graph.+-- > isForbiddenExp (Rule () [undefined, Fact KUFact [undefined, Mult (Inv x1) x2]]+-- [Fact KDFact [expTagToTerm IsExp, Exp p1 (Mult x2 x3)]] [])+-- > False+-- > isForbiddenExp (Rule () [undefined, Fact KUFact [undefined, Mult (Inv x1) x2]]+-- [Fact KDFact [expTagToTerm IsExp, Exp p1 x2]] [])+-- > True+isForbiddenExp :: Rule a -> Bool+isForbiddenExp ru = maybe False id $ do+ [_,p2] <- return $ get rPrems ru+ [conc] <- return $ get rConcs ru+ (UpK, _, b) <- kFactView p2+ (DnK, Just IsExp, FApp (NonAC ("exp",2)) [g,c]) <- kFactView conc++ -- g should be public and the required inputs for c already required by b+ guard (sortOfTerm g == LSortPub && (input c \\ input b == []))+ return True+ where+ sortOfTerm (Lit (Var lv)) = lvarSort lv+ sortOfTerm (Lit (Con n)) = sortOfName n+ sortOfTerm _ = LSortMsg+++-- | Compute all contradictions to unique fact instances.+--+-- Constraint systems are contradictory, where 'f' is a fact symbol+-- with unique instances and temporal variables i, j, and k are ordered+-- according to i < j < k, j requires a premise f(t), and i provides a+-- conclusion f(t) for the node k. Graphically, the edge from i to k is+-- interrupted by the node j that requires the same fact carried on the edge.+nonUniqueFactInstances :: SignatureWithMaude -> Sequent + -> [(NodeId, NodeId, NodeId)]+nonUniqueFactInstances sig se = do+ Edge c@(NodeConc (i, _)) (NodePrem (k, _)) <- S.toList $ get sEdges se+ let tag = factTag (nodeConcFact c se)+ guard (tag `S.member` get sigmUniqueInsts sig)+ j <- S.toList $ D.reachableSet [i] less++ let isCounterExample = (j /= i) && (j /= k) && + maybe False checkRule (M.lookup j $ get sNodes se)++ checkRule jRu = any ((tag ==) . factTag) (get rPrems jRu) &&+ k `S.member` D.reachableSet [j] less++ guard isCounterExample+ return (i, j, k) -- counter-example to unique fact instances+ where+ less = sRawLessRel se++++-- Under-approximating minimal deducability+-------------------------------------------++-- | @proveCyclic se@ under-approximates @|se| ==> Ex v. v >+> v@.+proveCyclic :: Sequent -> Bool+proveCyclic = D.cyclic . sRawLessRel++-- | @formulasFalse se@ returns @True@ if False is included in the formulas of @se@+formulasFalse :: Sequent -> Bool+formulasFalse = S.member gfalse . get sFormulas++-- | @contradictorySequent se@ holds if the sequent is trivially contradictory.+-- FIXME: duplication with contradictions in Proof+contradictorySequent :: SignatureWithMaude -> Sequent -> Bool+contradictorySequent sig se =+ formulasFalse se ||+ eqsIsFalse (get sEqStore se) ||+ proveCyclic se ||+ hasNonNormalTerms sig se ||+ hasForbiddenExp se ||+ not (null (nonUniqueFactInstances sig se))+++-- SeProof monad+----------------++-- | A proof with respect to a sequent. The fresh variables are existential+-- variables of the sequent and the multiple results are to be interpreted as a+-- disjunction while the inner-most maybe indicates if the proof method is+-- applicable/was successful or not.+type SeProof = StateT Sequent (FreshT (DisjT (Reader ProofContext)))++-- | Run a proof step.+runSeProof :: SeProof a -> ProofContext -> Sequent -> FreshState + -> Disj ((a, Sequent), FreshState)+runSeProof m ctxt se fs = + Disj $ (`runReader` ctxt) $ runDisjT $ (`runFreshT` fs) $ runStateT m se++-- | Run a proof step, returning only the updated states.+execSeProof :: SeProof a -> ProofContext -> Sequent -> FreshState + -> [(Sequent, FreshState)]+execSeProof m ctxt se fs = + (`runReader` ctxt) . runDisjT . (`runFreshT` fs) $ execStateT m se++-- | Retrieve the 'MaudeHandle' from the 'ProofContext'.+getMaudeHandle :: SeProof MaudeHandle+getMaudeHandle = get sigmMaudeHandle <$> askM pcSignature++-- | Import a rule with fresh variables.+importRule :: MonadFresh m+ => RuleAC+ -> m (RuleACInst, Maybe RuleACConstrs)+importRule ru = someRuleACInst ru `evalBindT` noBindings++-- | @proveLinearConc se (v,i)@ tries to prove that the @i@-th conclusion of node+-- @v@ is a linear fact.+proveLinearConc :: Sequent -> NodeConc -> Bool+proveLinearConc se (NodeConc (v,i)) =+ maybe False (isLinearFact . (get (rConc i))) $ M.lookup v $ get sNodes se++-- | Create a node labelled with a fresh instance of one of the rules and solve+-- it's fresh conditions immediatly.+--+-- PRE: Node must not yet be labelled with a rule.+ruleNode :: NodeId -> [RuleAC] -> SeProof RuleACInst+ruleNode i rules = do+ (ru, mrconstrs) <- importRule =<< disjunctionOfList rules+ solveRuleConstraints mrconstrs i+ modM sNodes (M.insert i ru)+ let inFacts = do+ (v, Fact InFact [m]) <- zip [0..] $ get rPrems ru+ return $ do+ j <- freshLVar "vf" LSortNode+ ruKnows <- mkISendRuleAC m+ modM sNodes (M.insert j ruKnows)+ modM sEdges (S.insert $ Edge (NodeConc (j,0)) (NodePrem (i,v)))+ let freshFacts = do+ (v, Fact FreshFact [m]) <- zip [0..] $ get rPrems ru+ return $ do+ j <- freshLVar "vf" LSortNode+ modM sNodes (M.insert j (mkFreshRuleAC m))+ unless (isFreshVar m) $ do + -- 'm' must be of sort fresh+ n <- varTerm <$> freshLVar "n" LSortFresh+ solveTermEqs SplitNow [Equal m n]+ modM sEdges (S.insert $ Edge (NodeConc (j,0)) (NodePrem (i,v)))+ -- solve all Fr and In premises+ sequence_ inFacts+ sequence_ freshFacts+ return ru+ where+ mkISendRuleAC m = do+ faPrem <- kuFact Nothing m+ return $ Rule (ProtoInfo ISendRule) [faPrem] [inFact m] [kLogFact m]++ mkFreshRuleAC m = Rule (ProtoInfo FreshRule) [] [freshFact m] []++-- | Create a fresh node labelled with a fresh instance of one of the rules+-- and solve it's 'Fr' and 'In' facts immediatly.+freshRuleNode :: [RuleAC] -> SeProof (NodeId, RuleACInst)+freshRuleNode rules = do+ i <- freshLVar "vr" LSortNode+ (,) i <$> ruleNode i rules++-- | Generate a fresh coerce rule node; return node-index, premise, and+-- conclusion.+freshCoerceRuleNode :: SeProof (LVar, (LNFact, LNFact))+freshCoerceRuleNode = do+ i <- freshLVar "vc" LSortNode+ x <- varTerm <$> freshLVar "x" LSortMsg+ v <- freshLVar "f_" LSortMsg+ let faPrem = Fact KDFact [varTerm v, x]+ faConc = Fact KUFact [varTerm v, x]+ modM sNodes (M.insert i (Rule (IntrInfo CoerceRule) [faPrem] [faConc] []))+ return (i, (faPrem, faConc))++-- | Create a fresh node labelled with a fresh instance of one of the rules+-- and return one of the conclusions.+freshRuleConc :: [RuleAC]+ -> SeProof (RuleACInst, NodeConc, LNFact)+freshRuleConc rules = do+ (i, ru) <- freshRuleNode rules+ (v, fa) <- disjunctionOfList $ zip [0..] $ get rConcs ru+ return (ru, NodeConc (i,v), fa)++-- | Insert the edges and ensure the equality between the facts+-- at either end of the edge.+insertEdges :: [(NodeConc, LNFact, LNFact, NodePrem)] -> SeProof ()+insertEdges edges = do+ solveFactEqs SplitNow [ Equal fa1 fa2 | (_, fa1, fa2, _) <- edges ]+ modM sEdges (\es -> foldr S.insert es [ Edge c p | (c,_,_,p) <- edges])+++-- Simplification+-----------------++-- | Repeatedly apply the following simplifications to the sequent:+--+-- - merge nodes with equal instances of Fresh rules+-- - remove sequents that violate the sort constraints+-- - merge nodes marked as the last node+-- - merge multiple rule labels of the same node+-- - merge nodes with equal non-pair message conclusions+-- - merge targets of multiple edges from a linear fact and+-- sources of multiple incoming edges to the same fact.+-- - solve Pub and Fresh goals+-- - solve unique action atoms+--+-- The simplification stops when the sequent doesn't change anymore.+--+simplifySequent :: SeProof ()+simplifySequent = do+ -- start simplification, indicating that some change happened+ go (0 :: Int) [True]+ -- ensure that the substitution is applied to the whole sequent+ substSequent+ exploitUniqueMsgOrder+ where+ go n changes0+ | not (or changes0) = return ()+ | otherwise = do+ -- perform one simplification pass+ substSequent+ -- exploit uniqueness of 'Fresh' rule instances+ c1 <- exploitFreshUnique+ when c1 (substNodes >> return ())+ -- exploit that conclusions deriving the same message can be merged+ -- except for merging coerce nodes with non-coerce nodes.+ c2 <- exploitUniqueMsgConcs+ when c2 (substNodes >> return ())+ -- exploit the special properties of the last node+ c3 <- exploitLastNode+ when c3 (substNodes >> return ())++ c4 <- solveSimpleUpK+ substPart sEdges+ c5 <- exploitEdgeProps+ substPart sAtoms+ c6 <- solveUniqueActions + substPart sFormulas+ substPart sSolvedFormulas+ c7 <- simplifyNegativeOrderings+ c8 <- saturateFormulas++ -- report on looping behaviour if necessary+ se <- gets id+ let changes = [c1, c2, c3, c4, c5, c6, c7, c8]+ traceLoop+ | n <= 10 = id+ | otherwise = + trace (" simplify: " ++ show n ++ " " ++ show changes)+ . trace (render $ prettySequent se)++ -- Repeat simplification, if there was some change in this step.+ traceLoop $ go (n + 1) changes+++-- | Saturate the formulas. Return True, if the sequent was changed.+saturateFormulas :: SeProof Bool+saturateFormulas = do+ se <- gets id+ hnd <- getMaudeHandle+ result <- saturateGuarded hnd se+ case result of+ Nothing -> do return False+ Just (eqs, se') -> do put se'+ solveTermEqs SplitNow eqs+ return True+++-- | Solve premise goals that can be solved directly by exploiting special+-- properties of normalized derivation graphs.+--+-- Solve K-up premises can just be connected to already derived knowledge.+--+solveSimpleUpK :: SeProof Bool+solveSimpleUpK = do+ nodes <- M.toList <$> getM sNodes+ let (down, up) = partitionEithers $ do+ (i, ru) <- nodes+ (v, fa) <- zip [0..] $ get rConcs ru+ (d, _, m) <- maybe mzero return $ kFactView fa+ let tag = case d of UpK -> Right; DnK -> Left+ return $ tag (m, (d, fa, NodeConc (i, v)))+ -- retain the up-entry if there are duplicates+ derived = M.fromList $ down ++ up++ goals <- gets (map snd . openPremiseGoals)+ or <$> mapM (trySolveGoal derived) goals+ where+ trySolveGoal derived (PremUpKG p m) = trySolveMessage derived m+ (\c _ -> modM sMsgEdges (S.insert (MsgEdge c p)))++ trySolveGoal derived (PremiseG p faPrem) = case kFactView faPrem of+ Just (UpK, _, m) -> trySolveMessage derived m+ -- For premise goals we have 'inp m == [m]'. We must insert a+ -- direct edge and ensure the equality wrt. an additional coerce+ -- node.+ (\c faConc -> insertEdges [(c, faConc, faPrem, p)])++ _ -> return False+ -- all other goals cannot be solved => the sequent doesn't change+ trySolveGoal _ _ = return False+ + trySolveMessage derived m solveWith = case M.lookup m derived of+ Just (UpK, faConc, c) -> solveWith c faConc >> return True+ Just (DnK, faConc, c) -> do+ (j, (faPrem', faConc')) <- freshCoerceRuleNode+ insertEdges [ (c, faConc , faPrem', NodePrem (j,0)) ]+ _ <- solveWith (NodeConc (j,0)) faConc'+ return True++ Nothing -> return False+++-- | Solve unique actions. Returns 'True' iff the sequent was changed.+solveUniqueActions :: SeProof Bool+solveUniqueActions = do+ rules <- nonSilentRules <$> askM pcRules+ actionAtoms <- gets sActionAtoms++ let uniqueActions = [ x | [x] <- group (sort allActions) ]+ allActions = [ (tag, length ts) + | ru <- rules, Fact tag ts <- get rActs ru ]++ isUnique (Fact tag ts) = (tag, length ts) `elem` uniqueActions++ trySolve (i, fa)+ | isUnique fa = solveAction rules (i, fa) >> return True+ | otherwise = return False++ or <$> mapM trySolve actionAtoms+++-- | Exploit that up-premises must always be deduced before the same+-- down-premise.+exploitUniqueMsgOrder :: SeProof ()+exploitUniqueMsgOrder = do+ nodes <- M.toList <$> getM sNodes+ dedBefore <- gets sDedBeforeAtoms+ let prems = M.fromList $ + dedBefore <|> -- also incorporate deducible-before atoms.+ do (i, ru) <- nodes+ fa <- get rPrems ru+ case kFactView fa of+ Just (UpK, _, m) -> [ (m', i) | m' <- input m ]+ _ -> mzero++ concs = M.fromList $ do+ (i, ru) <- nodes+ fa <- get rConcs ru+ case kFactView fa of+ Just (DnK, _, m) -> return (m, i)+ _ -> mzero++ mkLess i j = Less (varTerm i) (varTerm j)++ -- we can add all elements where we have an intersection+ modM sAtoms $ flip S.union $ S.fromList+ $ M.elems $ M.intersectionWith mkLess concs prems++-- | Exploit that instances of the 'Fresh' rule are unique.+--+-- Returns 'True' if a change was done.+exploitFreshUnique :: SeProof Bool+exploitFreshUnique = do+ -- gather fresh rule nodes and merge nodes with identical conclusions+ updates <- gets ( map merge+ . groupSortOn (get (rConc 0) . snd)+ . filter (isFreshRule . snd)+ . M.toList+ . get sNodes+ )+ -- check if there are changes to be applied+ if all (null . snd) updates+ then do return False+ else do modM sNodes (foldr (.) id $ map fst updates)+ solveNodeIdEqs $ concatMap snd updates+ return True+ where+ -- merge duplicate ones by removing all but one node and adding the+ -- equalities between the kept nodes and the removed nodes+ merge [] = error "exploitFreshUnique: impossible"+ merge (keep:remove) =+ ( \nodes -> foldl' (flip M.delete) nodes (map fst remove)+ , map (Equal (fst keep) . fst) remove+ )++-- | Merge multiple incoming edges to all facts and multiple outgoing edges+-- from linear facts.+exploitEdgeProps :: SeProof Bool -- True, if a simplification step happened.+exploitEdgeProps = do+ se <- gets id+ let edges = [ (getNodeConc src, getNodePrem prem)+ | Edge src prem <- S.toList (get sEdges se) ]+ rawEqs = mergeEqs fst snd edges +++ mergeEqs snd fst (filter (proveLinearConc se . NodeConc . fst) edges)+ -- check if there are changes to be applied+ if all null rawEqs+ then do return False+ else do+ let eqs = concat rawEqs+ -- all indices of merged premises and conclusions must be equal+ contradictoryIf (not $ and [snd l == snd r | Equal l r <- eqs])+ -- nodes must be equal+ solveNodeIdEqs $ map (fmap fst) eqs+ return True+ where+ mergeEqs :: Ord c => (a -> b) -> (a -> c) -> [a] -> [[Equal b]]+ mergeEqs what on = map (merge what) . groupSortOn on++ merge :: (a -> b) -> [a] -> [Equal b]+ merge _ [] = error "exploitEdgeProps: impossible"+ merge proj (keep:remove) = map (Equal (proj keep) . proj) remove+++-- | Merge nodes with equal non-pair msg conclusions.+--+-- PRE: There must not be any node in the sequent with a 'KU' conclusion+-- deriving a pair, inversion, or multiplication. This is in invariant of+-- our constraint solver.+exploitUniqueMsgConcs :: SeProof Bool+exploitUniqueMsgConcs = do+ nodes <- M.toList <$> getM sNodes+ let (coerce, nonCoerce) = partitionEithers $ do+ node@(_, ru) <- nodes+ fa <- get rConcs ru+ case kFactView fa of+ Nothing -> mzero+ Just (_, _, m) | isCoerceRule ru -> return $ Left (m, node)+ | otherwise -> return $ Right (m, node)++ -- coerce nodes can only be merged with themselves.+ (removals1, eqs1) = analyze coerce+ -- all other nodes can be merged with each other.+ (removals2, eqs2) = analyze nonCoerce+ eqs = eqs1 ++ eqs2++ -- check if there are any changes to be done+ if null eqs+ then return False+ else do+ modM sNodes (removals1 . removals2)+ solveNodeIdEqs $ map (fmap fst) eqs+ solveRuleEqs SplitNow $ map (fmap snd) eqs+ return True+ where+ analyze = (foldr (.) id *** concat) . unzip . map merge . groupSortOn fst++ merge [] = error "exploitUniqueMsgs: impossible"+ merge (keep:remove) =+ ( \nodes -> foldl' (flip M.delete) nodes (map (fst . snd) remove)+ , map (Equal (snd keep) . snd) remove+ )++-- | Apply a list of changes to the proof state. Return True, if at least one+-- change was applied; i.e., the list of changes is not null.+applyChanges :: [SeProof ()] -> SeProof Bool+applyChanges changes = sequence_ changes >> return (not $ null changes)++-- | Are these two rule instances unifiable.+unifiableRuleACInsts :: MaudeHandle -> RuleACInst -> RuleACInst -> Bool+unifiableRuleACInsts maude ru1 ru2 = + not $ null $ (`runReader` maude) $ unifyRuleACInstEqs [Equal ru1 ru2]++-- | Simplify implications of the form @ (i < j) ==> F @: They are left-alone,+-- if either @i@ or @j@ have not yet a node associated, converted to @j < i@,+-- if the nodes of @j@ and @i@ are non-unifiable, and converted to the+-- disjunction @i = j | j < i@, otherwise.+--+-- True is returned if some change was performed.+simplifyNegativeOrderings :: SeProof Bool+simplifyNegativeOrderings = do+ fms <- getM sFormulas+ nodes <- getM sNodes+ maude <- getMaudeHandle+ applyChanges $ do+ fm@(GGuarded All [] [Less i0 j0] gf) <- S.toList fms+ guard (gf == gfalse)+ case unifiableRuleACInsts maude <$> M.lookup (nodeFromTerm i0) nodes+ <*> M.lookup (nodeFromTerm j0) nodes+ of+ Just b -> return $ do+ modM sFormulas $ S.delete fm+ modM sSolvedFormulas $ S.insert fm+ if b+ then modM sFormulas $ S.insert $ + gdisj $ [GAto (EqE i0 j0), GAto (Less j0 i0)]+ else modM sAtoms $ S.insert $ bvarToLVar $ Less j0 i0+ Nothing -> []+ where+ nodeFromTerm (Lit (Var (Free v))) | lvarSort v == LSortNode = v+ nodeFromTerm t = error $+ "expected free node variable, but got '" ++ show t ++ "'"+++-- | Exploit that no node with a label can be after the last node. For+-- non-unifiable nodes the ordering is introduced directly. For the+-- remaining ones a disjunction is introduced.+--+-- True is returned if some change was performed.+exploitLastNode :: SeProof Bool+exploitLastNode = do+ lasts <- gets sLastAtoms+ nodes <- getM sNodes+ case lasts of+ [] -> return False+ [iLast] -> -- single last node => add ordering constraints+ case M.lookup iLast nodes of+ Nothing -> return False+ Just ruLast -> do+ beforeLast <- gets (D.reachableSet lasts . sRawGreaterRel)+ fms <- getM sFormulas+ maude <- getMaudeHandle+ applyChanges $ do+ (i, ru) <- M.toList nodes+ let disj = mkOrdDisj i iLast+ guard $ (i /= iLast) &&+ -- only consider nodes with action constraints+ (not $ null $ get rActs ru) && + (i `S.notMember` beforeLast) &&+ (disj `S.notMember` fms)+ if unifiableRuleACInsts maude ru ruLast+ then return $ modM sFormulas $ S.insert disj+ else return $ modM sAtoms $ S.insert $ + Less (varTerm i) (varTerm iLast)++ _ -> do -- multiple last nodes => merge them+ solveTermEqs SplitNow $ zipWith mkEq lasts (tail lasts)+ return True+ where+ mkEq i j = Equal (varTerm i) (varTerm j)+ mkOrdDisj i0 j0 = gdisj $ [GAto (EqE i j), GAto (Less i j)]+ where+ i = Lit $ Var $ Free i0+ j = Lit $ Var $ Free j0++-- | @setNodes nodes@ normalizes the @nodes@ such that node ids are unique and+-- then updates the @sNodes@ field of the proof state to the corresponding map.+-- Return @True@ iff new equalities have been added to the equation store.+setNodes :: [(NodeId, RuleACInst)] -> SeProof Bool+setNodes nodes0 = do+ sNodes =: M.fromList nodes+ if null ruleEqs then return False+ else solveRuleEqs SplitLater ruleEqs >> return True+ where+ -- merge nodes with equal node id+ (ruleEqs, nodes) = first concat $ unzip $ map merge $ groupSortOn fst nodes0++ merge [] = error "setNodes: impossible"+ merge (keep:remove) = (map (Equal (snd keep) . snd) remove, keep)++-- | Apply the current substitution of the equation store to the domain+-- of the '_sNodes' field and restore the one-rule-per-node property. Returns+-- @True@ if there were additional equalities added to the equation store.+substNodesDomain :: SeProof Bool+substNodesDomain =+ go False+ where+ go changed = do+ subst <- getM sSubst+ nodes <- gets (map (first (apply subst)) . M.toList . get sNodes)+ changed' <- setNodes nodes+ if changed' then go True+ else return changed++-- | Apply the current substitution of the equation store to the '_sNodes'+-- field. Returns @True@ if there were additional equalities added to the+-- equation store.+substNodes :: SeProof Bool+substNodes = do+ changed <- substNodesDomain+ (modM sNodes . M.map . apply) =<< getM sSubst+ return changed++-- | Apply the current substitution of the equation store to the remainder of+-- the sequent.+substSequent :: SeProof ()+substSequent = do+ _ <- substNodes+ substPart sEdges+ substPart sMsgEdges+ substPart sChains+ substPart sAtoms+ substPart sFormulas+ substPart sSolvedFormulas+ substPart sLemmas++-- | Apply the current substitution of the equation store to a part of the+-- sequent.+substPart :: Apply a => (Sequent :-> a) -> SeProof ()+substPart l = modM l =<< (apply <$> getM sSubst)++-- | @conjoinSequent se@ conjoins the logical information in @se@ to the proof+-- state. It assumes that the free variables in @se@ are shared with the free+-- variables in the proof state.+conjoinSequent :: Sequent -> SeProof ()+conjoinSequent se = do+ kind <- getM sCaseDistKind + unless (kind == get sCaseDistKind se) $+ error "conjoinSequent: typing-kind mismatch"+ joinSets sEdges+ joinSets sMsgEdges+ joinSets sChains+ joinSets sAtoms+ joinSets sFormulas+ joinSets sSolvedFormulas+ joinSets sLemmas+ -- update nodes+ _ <- (setNodes . (M.toList (get sNodes se) ++) . M.toList) =<< getM sNodes+ -- conjoin equation store+ modM sConjDisjEqs (`mappend` get sConjDisjEqs se)+ solveSubstEqs SplitNow $ get sSubst se+ -- propagate substitution changes+ substSequent+ where+ joinSets :: Ord a => (Sequent :-> S.Set a) -> SeProof ()+ joinSets proj = modM proj (`S.union` get proj se)+++-- Unification through the equation store of the embedded sequent+-----------------------------------------------------------------++-- | @noContradictoryEqStore@ suceeds iff the equation store is not+-- contradictory.+noContradictoryEqStore :: SeProof ()+noContradictoryEqStore =+ (contradictoryIf . eqsIsFalse) =<< getM sEqStore++-- | Add a list of term equalities to the equation store. And+-- split resulting disjunction of equations according+-- to given split strategy.+solveTermEqs :: SplitStrategy -> [Equal LNTerm] -> SeProof ()+solveTermEqs splitStrat eqs = do+ hnd <- getMaudeHandle+ setM sEqStore =<< simp hnd+ =<< disjunctionOfList+ =<< addEqs splitStrat hnd eqs+ =<< getM sEqStore+ noContradictoryEqStore++-- | Add a list of equalities in substitution form to the equation store+solveSubstEqs :: SplitStrategy -> LNSubst -> SeProof ()+solveSubstEqs split subst =+ solveTermEqs split [Equal (varTerm v) t | (v, t) <- substToList subst]++-- | Add a list of node equalities to the equation store.+solveNodeIdEqs :: [Equal NodeId] -> SeProof ()+solveNodeIdEqs = solveTermEqs SplitNow . map (fmap varTerm)++-- | Add a list of fact equalities to the equation store, if possible.+solveFactEqs :: SplitStrategy -> [Equal LNFact] -> SeProof ()+solveFactEqs split eqs = do+ contradictoryIf (not $ all evalEqual $ map (fmap factTag) eqs)+ solveListEqs (solveTermEqs split) $ map (fmap factTerms) eqs++-- | Add a list of rule equalities to the equation store, if possible.+solveRuleEqs :: SplitStrategy -> [Equal RuleACInst] -> SeProof ()+solveRuleEqs split eqs = do+ contradictoryIf (not $ all evalEqual $ map (fmap (get rInfo)) eqs)+ solveListEqs (solveFactEqs split) $+ map (fmap (get rConcs)) eqs ++ map (fmap (get rPrems)) eqs++-- | Solve a list of equalities using the given solver.+solveListEqs :: ([Equal a] -> SeProof b) -> [(Equal [a])] -> SeProof b+solveListEqs solver eqs = do+ contradictoryIf (not $ all evalEqual $ map (fmap length) eqs)+ solver $ concatMap flatten eqs+ where+ flatten (Equal l r) = zipWith Equal l r+++-- | Solve the constraints associated with a rule with the given vertex.+solveRuleConstraints :: Maybe RuleACConstrs -> NodeId -> SeProof ()+solveRuleConstraints (Just eqConstr) _v = do+ hnd <- getMaudeHandle+ setM sEqStore+ =<< (simp hnd . addRuleVariants eqConstr)+ =<< getM sEqStore+ noContradictoryEqStore+solveRuleConstraints Nothing _ = return ()++------------------------------------------------------------------------------+-- Extracting and solving goals+------------------------------------------------------------------------------++data Usefulness = Useful | Useless+ deriving (Show, Eq, Ord)++-- FIXME: SM: Remove support for requires facts.+-- | All open premises stemming both from labelled nodes and requires facts.+openPremiseGoals :: Sequent -> [(Usefulness, Goal)]+openPremiseGoals se = do+ (i, ru) <- oneOfMap $ get sNodes se+ (u, fa) <- zip [0..] $ get rPrems ru+ let p = NodePrem (i, u)+ case fa of+ -- up-K facts+ (kFactView -> Just (UpK, _, m)) -> case input m of+ [m'] | m == m' -> do+ guard (not (trivial m') && (p, m') `S.notMember` coveredMsgPrems)+ return $ markUseless m' i $ PremiseG p fa+ m's -> do+ m' <- sortednub m's+ guard (not (trivial m') && (p, m') `S.notMember` coveredMsgPrems)+ return $ markUseless m' i $ PremUpKG p m'++ -- down-K facts+ (kFactView -> Just (DnK, _, _))+ | p `S.member` coveredPrems -> mzero+ | otherwise -> return . (Useful,) $ PremDnKG p+ -- all other facts+ _ | p `S.member` coveredPrems -> mzero+ | otherwise -> return . (Useful,) $ PremiseG p fa+ where+ coveredPrems = S.fromList $ eTgt <$> S.toList (get sEdges se) <|>+ cTgt <$> S.toList (get sChains se)++ coveredMsgPrems = S.fromList $ do+ (c, p) <- [ (c, p) | MsgEdge c p <- S.toList (get sMsgEdges se) ] <|>+ [ (c, p) | Edge c p <- S.toList (get sEdges se) ]++ case kFactView =<< resolveNodeConcFact c se of+ Just (UpK, _, m) -> return (p, m)+ _ -> []++ existingDeps = sRawLessRel se++ -- We use the following heuristic for marking KU-goals as useful (worth+ -- solving now) or useless (to be delayed until no more useful goal+ -- remain). We ignore all goals that do not contain a fresh variable+ -- or where there exists a node, not after the premise or the last node,+ -- providing an Out or KD conclusion that provides the message we are+ -- looking for as a toplevel term.+ --+ -- If such a node exist, then solving the goal will result in at least one+ -- case where we didn't make real progress except.+ markUseless m i+ | not (containsFreshVars m) || deducible = (,) Useless+ | otherwise = (,) Useful+ where+ containsFreshVars = any ((LSortFresh ==) . lvarSort) . frees++ toplevelTerms t@(destPair -> Just (t1, t2)) = + t : toplevelTerms t1 ++ toplevelTerms t2+ toplevelTerms t@(destInv -> Just t1) = t : toplevelTerms t1+ toplevelTerms t = [t]++ deducible = or $ do+ (j, ru) <- M.toList $ get sNodes se+ -- We cannot deduce a message from a last node.+ guard (Last (varTerm j) `S.notMember` get sAtoms se)+ let derivedMsgs = concatMap toplevelTerms $+ [ t | Fact OutFact [t] <- get rConcs ru] <|>+ [ t | Just (DnK, _, t) <- kFactView <$> get rConcs ru]+ -- m is deducible from j without an immediate contradiction+ -- if it is a derived message of 'ru' and the dependency does+ -- not make the graph cyclic.+ return $ m `elem` derivedMsgs && + not (D.cyclic ((j, i) : existingDeps))+++-- | All open chain goals. These are all the chains that do not end in a+-- message variable in the sequent because they are deleted upon solving.+openChainGoals :: Sequent -> [Goal]+openChainGoals se = do+ ch@(Chain c _) <- S.toList $ get sChains se+ case kFactView (nodeConcFact c se) of+ Just (DnK, _, m) | isMsgVar m -> mzero+ | otherwise -> return $ ChainG ch+ fa -> error $ "openChainGoals: impossible fact: " ++ show fa++-- | All open splitting goals.+openSplitGoals :: Sequent -> [Goal]+openSplitGoals se = SplitG <$> eqSplits (get sEqStore se)++-- | All open action goals.+openActionGoals :: Sequent -> [Goal]+openActionGoals se = uncurry ActionG <$> sActionAtoms se++-- | All open goals (non-deterministic choices of possible proof steps) in the+-- sequent.+openGoals :: Sequent -> [Goal]+openGoals se = delayUseless $ concat $+ [ (Useful,) <$> openActionGoals se+ , (Useful,) <$> openDisjunctionGoals se+ , (Useful,) <$> openChainGoals se+ , preferProtoFactGoals $ openPremiseGoals se+ -- SM: Commented out as automatic saturation works again.+ -- , (Useful,) <$> openImplicationGoals se+ , (Useful,) <$> openSplitGoals se+ ]+ where+ isProtoFactGoal (_, PremiseG _ _) = True+ isProtoFactGoal _ = False+ preferProtoFactGoals goals =+ uncurry (++) $ partition isProtoFactGoal goals++ delayUseless = map snd . sortOn fst+++-- | Solve an action goal.+solveAction :: [RuleAC] -- ^ All rules labelled with an action+ -> (LVar, LNFact) -- ^ The action we are looking for.+ -> SeProof String -- ^ Sensible case name.+solveAction rules (i, fa) = do+ modM sAtoms (S.delete (Action (varTerm i) fa))+ mayRu <- M.lookup i <$> getM sNodes+ showRuleCaseName <$> case mayRu of+ Nothing -> do ru <- ruleNode i rules+ act <- disjunctionOfList $ get rActs ru+ solveFactEqs SplitNow [Equal fa act]+ return ru+ Just ru -> do unless (fa `elem` get rActs ru) $ do+ act <- disjunctionOfList $ get rActs ru+ solveFactEqs SplitNow [Equal fa act]+ return ru++-- | Solve a K-up-knowledge premise.+solvePremUpK :: [RuleAC] -- ^ All construction rules.+ -> NodePrem+ -> LNTerm+ -> SeProof String+solvePremUpK rules p m = do+ (ru, c, faConc) <- freshRuleConc rules+ case kFactView faConc of+ Just (UpK, _, m') ->+ do solveTermEqs SplitNow [(Equal m m')]+ modM sMsgEdges (S.insert (MsgEdge c p))+ return $ showRuleCaseName ru++ _ -> error $ "solvePremUpK: unexpected fact: " ++ show faConc++-- | Solve a premise with a direct edge from a unifying conclusion.+--+-- Note that 'In' and 'Fr' facts are solved directly when adding a 'ruleNode'.+solvePremise :: [RuleAC] -- ^ All construction and protocol rules.+ -> NodePrem -- ^ Premise to solve.+ -> LNFact -- ^ Fact required at this premise.+ -> SeProof String -- ^ Case name to use+solvePremise rules p faPrem = do+ (ru, c, faConc) <- freshRuleConc rules+ solveFactEqs SplitNow [(Equal faPrem faConc)]+ modM sEdges (S.insert (Edge c p))+ return $ showRuleCaseName ru++-- | Solve a K-down-knowledge premise.+solvePremDnK :: [RuleAC] -- ^ All rules that derive a send fact.+ -> NodePrem -- ^ The K-down premise to solve.+ -> SeProof String+solvePremDnK rules p = do+ iLearn <- freshLVar "vl" LSortNode+ mLearn <- varTerm <$> freshLVar "t" LSortMsg+ concLearn <- kdFact (Just IsNoExp) mLearn+ let premLearn = outFact mLearn+ ruLearn = Rule (ProtoInfo IRecvRule) [premLearn] [concLearn] []+ cLearn = NodeConc (iLearn, 0)+ pLearn = NodePrem (iLearn, 0)+ modM sNodes (M.insert iLearn ruLearn)+ modM sChains (S.insert (Chain cLearn p))+ solvePremise rules pLearn premLearn++-- | Solve a chain constraint.+solveChain :: [RuleAC] -- ^ All destruction rules.+ -> Chain -- ^ The chain to extend by one step+ -> SeProof String+solveChain rules ch@(Chain c p) = do+ modM sChains (S.delete ch)+ faConc <- gets $ nodeConcFact c+ (do -- solve it by a direct edge+ faPrem <- gets $ nodePremFact p+ solveFactEqs SplitNow [(Equal faPrem faConc)]+ modM sEdges (S.insert (Edge c p))+ let m = case kFactView faConc of+ Just (DnK, _, m') -> m'+ _ -> error $ "solveChain: impossible"+ caseName (FApp o _) = show o+ caseName t = show t+ return $ caseName m + `disjunction`+ do -- extend it with one step+ (i, ru) <- freshRuleNode rules+ (v, faPrem) <- disjunctionOfList $ zip [0..] $ get rPrems ru+ solveFactEqs SplitNow [(Equal faPrem faConc)]+ modM sEdges (S.insert (Edge c (NodePrem (i,v))))+ modM sChains (S.insert (Chain (NodeConc (i,0)) p))+ return $ showRuleCaseName ru+ )++-- | Solve an equation split.+solveSplit :: SplitId -> SeProof String+solveSplit x = do+ split <- gets ((`splitAtPos` x) . get sEqStore)+ let errMsg = error "solveSplit: split of equations on unconstrained variable!"+ store <- maybe errMsg disjunctionOfList split+ hnd <- getMaudeHandle+ store' <- simp hnd store+ contradictoryIf (eqsIsFalse store')+ sEqStore =: store'+ return "split"++-- | Solve a disjunction of guarded formulas using splitting.+-- Returns a case name.+solveDisjunction :: Disj LNGuarded -> SeProof String+solveDisjunction disj = do+ modM sSolvedFormulas (S.insert $ GDisj disj)+ modM sSolvedFormulas (S.insert $ GDisj disj)+ (i, gfm) <- disjunctionOfList $ zip [(1::Int)..] $ getDisj disj+ modM sFormulas (S.insert gfm)+ return $ "case_" ++ show i++-- | @solveGoal rules goal@ enumerates all possible solutions how this goal+-- could be solved in the context of the given @rules@.+--+-- Returns a usable case name.+--+solveGoal :: Goal -> SeProof String+solveGoal goal = do+ rules <- askM pcRules+ trace (" solving goal: " ++ render (prettyGoal goal)) $+ case goal of+ ActionG i fa -> solveAction (nonSilentRules rules) (i, fa) + PremiseG p fa -> + solvePremise (get crProtocol rules ++ get crConstruct rules) p fa+ PremDnKG p -> solvePremDnK (get crProtocol rules) p+ PremUpKG p m -> solvePremUpK (get crConstruct rules) p m+ ChainG ch -> solveChain (get crDestruct rules) ch+ SplitG i -> solveSplit i+ DisjG disj -> solveDisjunction disj+ ImplG gf -> modM sFormulas (S.insert gf) >> return "add_formula"+
@@ -0,0 +1,425 @@+{-# LANGUAGE TemplateHaskell, TypeOperators #-}+-- |+-- Copyright : (c) 2010, 2011 Simon Meier+-- License : GPL v3 (see LICENSE)+-- +-- Maintainer : Simon Meier <iridcode@gmail.com>+-- Portability : GHC only+--+-- Conversion of the graph part of a sequent to a Graphviz Dot file.+module Theory.Proof.Sequent.Dot (+ dotSequentLoose+ , dotSequentCompact+ , compressSequent+ ) where++import Safe+import Data.Maybe+import Data.List+import Data.Monoid (Any(..))+import qualified Data.Set as S+import qualified Data.Map as M+import Data.Color++import Extension.Prelude+import Extension.Data.Label++import Control.Basics+import Control.Monad.State (StateT, evalStateT)+import Control.Monad.Reader++import qualified Text.Dot as D+import Text.Isar hiding (style)++import Theory.Rule+import Theory.Proof.Sequent++type NodeColorMap = M.Map (RuleInfo ProtoRuleName IntrRuleACInfo) (HSV Double)+type SeDot = ReaderT (Sequent, NodeColorMap) (StateT DotState D.Dot)++-- | State to avoid multiple drawing of the same entity.+data DotState = DotState {+ _dsNodes :: M.Map NodeId D.NodeId+ , _dsPrems :: M.Map NodePrem D.NodeId+ , _dsConcs :: M.Map NodeConc D.NodeId+ , _dsSingles :: M.Map (NodeConc, NodePrem) D.NodeId+ }++$(mkLabels [''DotState])++-- | Lift a 'D.Dot' action.+liftDot :: D.Dot a -> SeDot a+liftDot = lift . lift++-- | All edges in a bipartite graph that have neither start point nor endpoint+-- in common with any other edge.+singleEdges :: (Ord a, Ord b) => [(a,b)] -> [(a,b)]+singleEdges es = + singles fst es `intersect` singles snd es+ where+ singles proj = concatMap single . groupOn proj . sortOn proj+ single [] = error "impossible"+ single [x] = return x+ single _ = mzero++-- | Get a lighter color.+lighter :: HSV Double -> RGB Double+lighter = hsvToRGB -- fmap (\c -> 1 - 0.3*(1-c)) . hsvToRGB++-- | Ensure that a 'SeDot' action is only executed once by querying and+-- updating the 'DotState' accordingly.+dotOnce :: Ord k + => (DotState :-> M.Map k D.NodeId) -- ^ Accessor to map storing this type of actions.+ -> k -- ^ Action index.+ -> SeDot D.NodeId -- ^ Action to execute only once.+ -> SeDot D.NodeId +dotOnce mapL k dot = do+ i <- join $ (maybe dot return . M.lookup k) `liftM` getM mapL+ modM mapL (M.insert k i)+ return i++dotNode :: NodeId -> SeDot D.NodeId+dotNode v = dotOnce dsNodes v $ do+ (se, colorMap) <- ask+ let nodes = get sNodes se+ dot info moreStyle facts = do+ vId <- liftDot $ D.node $ [("label", show v ++ info),("shape","ellipse")] + ++ moreStyle+ _ <- facts vId+ return vId++ case M.lookup v nodes of+ Nothing -> do+ dot "" [] (const $ return ()) -- \vId -> do+ {-+ premIds <- mapM dotPrem+ [ NodePremFact v fa + | SeRequires v' fa <- S.toList $ get sRequires se+ , v == v' ]+ sequence_ [ dotIntraRuleEdge premId vId | premId <- premIds ]+ -}+ Just ru -> do+ let + color = M.lookup (get rInfo ru) colorMap+ nodeColor = maybe "white" (rgbToHex . lighter) color+ dot (label ru) [("fillcolor", nodeColor),("style","filled")] $ \vId -> do+ premIds <- mapM dotPrem+ [ NodePrem (v,i) | (i,_) <- zip [0..] $ get rPrems ru ]+ concIds <- mapM (dotConc . NodeConc) + [ (v,i) | (i,_) <- zip [0..] $ get rConcs ru ]+ sequence_ [ dotIntraRuleEdge premId vId | premId <- premIds ]+ sequence_ [ dotIntraRuleEdge vId concId | concId <- concIds ]+ where+ label ru = " : " ++ render nameAndActs+ where+ nameAndActs = + ruleInfo prettyProtoRuleName prettyIntrRuleACInfo (get rInfo ru) <->+ brackets (vcat $ punctuate comma $ map prettyLNFact $ get rActs ru)++-- | An edge from a rule node to its premises or conclusions.+dotIntraRuleEdge :: D.NodeId -> D.NodeId -> SeDot ()+dotIntraRuleEdge from to = liftDot $ D.edge from to [("color","gray")]++{-+-- | An edge from a rule node to some of its premises or conclusions.+dotNonFixedIntraRuleEdge :: D.NodeId -> D.NodeId -> SeDot ()+dotNonFixedIntraRuleEdge from to = + liftDot $ D.edge from to [("color","steelblue")]+-}++-- | The style of a node displaying a fact.+factNodeStyle :: LNFact -> [(String,String)]+factNodeStyle fa+ | isJust (kFactView fa) = []+ | otherwise = [("fillcolor","gray85"),("style","filled")]++-- | An edge that shares no endpoints with another edge and is therefore+-- contracted.+--+-- FIXME: There may be too many edges being contracted.+dotSingleEdge :: (NodeConc, NodePrem) -> SeDot D.NodeId+dotSingleEdge edge@(_, to) = dotOnce dsSingles edge $ do+ se <- asks fst+ let fa = nodePremFact to se+ label = render $ prettyLNFact fa+ liftDot $ D.node $ [("label", label),("shape", "hexagon")]+ ++ factNodeStyle fa++-- | A compressed edge.+dotTrySingleEdge :: Eq c+ => ((NodeConc, NodePrem) -> c) -> c+ -> SeDot D.NodeId -> SeDot D.NodeId+dotTrySingleEdge sel x dot = do+ singles <- getM dsSingles+ maybe dot (return . snd) $ find ((x ==) . sel . fst) $ M.toList singles++-- | Premises.+dotPrem :: NodePrem -> SeDot D.NodeId+dotPrem prem@(NodePrem (v,i)) = + dotOnce dsPrems prem $ dotTrySingleEdge snd prem $ do+ nodes <- asks (get sNodes . fst)+ let ppPrem = show prem -- FIXME: Use better pretty printing here+ (label, moreStyle) = fromMaybe (ppPrem, []) $ do+ ru <- M.lookup v nodes+ fa <- get rPrems ru `atMay` i+ return ( render $ prettyLNFact fa+ , factNodeStyle fa+ )+ liftDot $ D.node $ [("label", label),("shape",shape)] + ++ moreStyle+ where+ shape = "invtrapezium"++-- | Conclusions.+dotConc :: NodeConc -> SeDot D.NodeId+dotConc = + dotNodeWithIndex dsConcs fst rConcs getNodeConc "trapezium" + where+ dotNodeWithIndex stateSel edgeSel ruleSel unwrap shape x0 = + dotOnce stateSel x0 $ dotTrySingleEdge edgeSel x0 $ do+ let x = unwrap x0+ nodes <- asks (get sNodes . fst)+ let (label, moreStyle) = fromMaybe (show x, []) $ do+ ru <- M.lookup (fst x) nodes+ fa <- (`atMay` snd x) $ get ruleSel ru+ return ( render $ prettyLNFact fa+ , factNodeStyle fa+ )+ liftDot $ D.node $ [("label", label),("shape",shape)] + ++ moreStyle++-- | Convert the sequent to a 'D.Dot' action representing this sequent as a+-- graph in the GraphViz format. The style is loose in the sense that each+-- premise and conclusion gets its own node.+dotSequentLoose :: Sequent -> D.Dot ()+dotSequentLoose se =+ (`evalStateT` DotState M.empty M.empty M.empty M.empty) $ + (`runReaderT` (se, nodeColorMap (M.elems $ get sNodes se))) $ do+ liftDot $ setDefaultAttributes+ -- draw single edges with matching facts.+ mapM_ dotSingleEdge $ singleEdges $ do+ Edge from to <- S.toList $ get sEdges se+ -- FIXME: ensure that conclusion and premise are equal+ guard (nodeConcFact from se == nodePremFact to se)+ return (from, to)+ sequence_ $ do+ (v, ru) <- M.toList $ get sNodes se+ (i, _) <- zip [0..] $ get rConcs ru+ return (dotConc (NodeConc (v, i)))+ sequence_ $ do+ (v, ru) <- M.toList $ get sNodes se+ (i, _) <- zip [0..] $ get rPrems ru+ return (dotPrem (NodePrem (v,i)))+ mapM_ dotNode $ M.keys $ get sNodes se+ mapM_ dotEdge $ S.toList $ get sEdges se+ mapM_ dotChain $ S.toList $ get sChains se+ mapM_ dotMsgEdge $ S.toList $ get sMsgEdges se+ mapM_ dotLess $ sLessAtoms se+ where+ dotEdge (Edge src tgt) = do+ mayNid <- M.lookup (src,tgt) `liftM` getM dsSingles+ maybe (dotGenEdge [] src tgt) (const $ return ()) mayNid++ dotChain (Chain src tgt) = + dotGenEdge [("style","dashed"),("color","green")] src tgt ++ dotMsgEdge (MsgEdge src tgt) = + dotGenEdge [("style","dotted"),("color","orange")] src tgt ++ dotLess (src, tgt) = do+ srcId <- dotNode src+ tgtId <- dotNode tgt+ liftDot $ D.edge srcId tgtId + [("color","black"),("style","dotted"),("constraint","false")]+ -- setting constraint to false ignores less-edges when ranking nodes.++ dotGenEdge style src tgt = do+ srcId <- dotConc src+ tgtId <- dotPrem tgt+ liftDot $ D.edge srcId tgtId style++ {-+ dotProvides (SeProvides v fa) = do+ vId <- dotNode v+ faId <- liftDot $ D.node [("label",label),("shape","trapezium")]+ dotNonFixedIntraRuleEdge vId faId+ where+ label = render $ prettyLNFact fa++ dotRequires (SeRequires v _fa) = do+ _vId <- dotNode v+ return ()+ -- FIXME: Reenable+ -- premId <- dotPrem (NodePremFact v fa)+ -- dotNonFixedIntraRuleEdge premId vId+ -}++-- | Set default attributes for nodes and edges.+setDefaultAttributes :: D.Dot ()+setDefaultAttributes = do+ D.attribute ("nodesep","0.3")+ D.attribute ("ranksep","0.3")+ D.nodeAttributes [("fontsize","8"),("fontname","Helvetica"),("width","0.3"),("height","0.2")]+ D.edgeAttributes [("fontsize","8"),("fontname","Helvetica")]+++-- | Compute a color map for nodes labelled with a proof rule info of one of+-- the given rules.+nodeColorMap :: [RuleACInst] -> NodeColorMap+nodeColorMap rules = + M.fromList $ + [ (get rInfo ru, getColor (gIdx, mIdx))+ | (gIdx, grp) <- groups, (mIdx, ru) <- zip [0..] grp ]+ where+ groupIdx ru | isDestrRule ru = 0+ | isConstrRule ru = 2+ | isFreshRule ru || isISendRule ru = 3+ | otherwise = 1++ -- groups of rules labeled with their index in the group+ groups = [ (gIdx, [ ru | ru <- rules, gIdx == groupIdx ru])+ | gIdx <- [0..3]+ ]+ + -- color for each member of a group+ colors = M.fromList $ lightColorGroups intruderHue (map (length . snd) groups)+ getColor idx = fromMaybe (HSV 0 1 1) $ M.lookup idx colors++ -- The hue of the intruder rules+ intruderHue :: Double+ intruderHue = 18 / 360++------------------------------------------------------------------------------+-- Record based dotting+------------------------------------------------------------------------------++-- | Dot a node in record based (compact) format.+dotNodeCompact :: NodeId -> SeDot D.NodeId+dotNodeCompact v = dotOnce dsNodes v $ do+ (se, colorMap) <- ask+ case M.lookup v $ get sNodes se of+ Nothing -> liftDot $ D.node $ [("label", show v),("shape","ellipse")] + Just ru -> do+ let color = M.lookup (get rInfo ru) colorMap+ nodeColor = maybe "white" (rgbToHex . lighter) color+ attrs = [("fillcolor", nodeColor),("style","filled")]+ (_, ids) <- liftDot $ D.record (mkRecord ru) attrs+ let prems = [ (NodePrem (v, i), nid) | (Just (Left i), nid) <- ids ]+ concs = [ (NodeConc (v, i), nid) | (Just (Right i), nid) <- ids ]+ modM dsPrems $ M.union $ M.fromList prems+ modM dsConcs $ M.union $ M.fromList concs+ return $ fromJust $ lookup Nothing ids+ where+ mkRecord ru = D.vcat $ map D.hcat $ filter (not . null)+ [ [ D.portField (Just (Left i)) (render (prettyLNFact p))+ | (i, p) <- zip [(0::Int)..] $ get rPrems ru ]+ , [ D.portField Nothing (show v ++ " : " ++ showRuleCaseName ru ++ acts) ]+ , [ D.portField (Just (Right i)) (render (prettyLNFact c))+ | (i, c) <- zip [(0::Int)..] $ get rConcs ru ]+ ]+ where+ acts = (" " ++) $ render $+ brackets $ vcat $ punctuate comma $ map prettyLNFact $ get rActs ru+ ++-- | Dot a sequent in compact form (one record per rule)+dotSequentCompact :: Sequent -> D.Dot ()+dotSequentCompact se = + (`evalStateT` DotState M.empty M.empty M.empty M.empty) $ + (`runReaderT` (se, nodeColorMap (M.elems $ get sNodes se))) $ do+ liftDot $ setDefaultAttributes+ mapM_ dotNodeCompact $ M.keys $ get sNodes se+ mapM_ dotEdge $ S.toList $ get sEdges se+ mapM_ dotChain $ S.toList $ get sChains se+ mapM_ dotMsgEdge $ S.toList $ get sMsgEdges se+ mapM_ dotLess $ sLessAtoms se+ where+ missingNode shape label = liftDot $ D.node $ [("label", render label),("shape",shape)] + dotPremC prem = dotOnce dsPrems prem $ missingNode "invtrapezium" $ prettyNodePrem prem+ dotConcC conc = dotOnce dsConcs conc $ missingNode "trapezium" $ prettyNodeConc conc+ dotEdge (Edge src tgt) = do+ let check p = maybe False p (resolveNodePremFact tgt se) ||+ maybe False p (resolveNodeConcFact src se)+ attrs | check isProtoFact = [("style","bold"),("weight","10.0")]+ | check isKFact = [("color","orangered2")]+ | otherwise = [("color","gray30")]+ dotGenEdge attrs src tgt++ dotGenEdge style src tgt = do+ srcId <- dotConcC src+ tgtId <- dotPremC tgt+ liftDot $ D.edge srcId tgtId style+ + dotChain (Chain src tgt) = + dotGenEdge [("style","dashed"),("color","green")] src tgt ++ dotMsgEdge (MsgEdge src tgt) = + dotGenEdge [("style","dotted"),("color","orange")] src tgt ++ dotLess (src, tgt) = do+ srcId <- dotNodeCompact src+ tgtId <- dotNodeCompact tgt+ liftDot $ D.edge srcId tgtId + [("color","black"),("style","dotted"),("constraint","false")]+ -- setting constraint to false ignores less-edges when ranking nodes.++ {-+ dotProvides (SeProvides v fa) = do+ vId <- dotNodeCompact v+ faId <- liftDot $ D.node [("label",label),("shape","trapezium")]+ dotNonFixedIntraRuleEdge vId faId+ where+ label = render $ prettyLNFact fa+ dotRequires (SeRequires v _fa) = do+ _vId <- dotNodeCompact v+ return ()+ -- FIXME: Reenable+ -- premId <- dotPremC (NodePremFact v fa)+ -- dotNonFixedIntraRuleEdge premId vId+ -}++------------------------------------------------------------------------------+-- Compressed versions of a sequent+------------------------------------------------------------------------------++-- | Unsound compression of the sequent that drops fully connected learns and+-- knows nodes.+compressSequent :: Sequent -> Sequent+compressSequent se = + foldl' (flip hideTransferNode) se $ + [ x | x@(_, ru) <- M.toList $ get sNodes se+ , isFreshRule ru || isDestrRule ru || isConstrRule ru || isIRecvRule ru || isISendRule ru ]++-- | @hideTransferNode v se@ hides node @v@ in sequent @se@ if it is a+-- transfer node; i.e., a node annotated with a rule with exactly one premise+-- and one conclusion with exactly one incoming and one outgoing edge.+hideTransferNode :: (NodeId, RuleACInst) -> Sequent -> Sequent+hideTransferNode (v, ru) se = fromMaybe se $ do+ guard $ + all (\l -> length (get l ru) <= 1) [rPrems, rConcs]+ && (null $ get rActs ru)+ && (length eIns == length (get rPrems ru))+ && (length eOuts == length (get rConcs ru))+ && all (\(Edge cIn pOut) -> nodeConcNode cIn /= nodePremNode pOut) eNews+ && notOccursIn sMsgEdges+ && notOccursIn sChains + && notOccursIn sAtoms+ && notOccursIn sFormulas++ return $ modify sEdges ( (`S.union` S.fromList eNews)+ . (`S.difference` S.fromList eIns)+ . (`S.difference` S.fromList eOuts)+ )+ $ modify sNodes (M.delete v)+ $ se+ where+ selectPart :: (Sequent :-> S.Set a) -> (a -> Bool) -> [a]+ selectPart l p = filter p $ S.toList $ get l se++ notOccursIn :: HasFrees a => (Sequent :-> a) -> Bool+ notOccursIn l = not $ getAny $ foldFrees (Any . (v ==)) $ get l se++ eIns = selectPart sEdges ((v ==) . nodePremNode . eTgt)+ eOuts = selectPart sEdges ((v ==) . nodeConcNode . eSrc)++ eNews = [ Edge cIn pOut | Edge cIn _ <- eIns, Edge _ pOut <- eOuts ]
@@ -0,0 +1,323 @@+{-# LANGUAGE DeriveDataTypeable, FlexibleInstances, TemplateHaskell, StandaloneDeriving, TypeSynonymInstances #-}+-- |+-- Copyright : (c) 2011, 2012 Benedikt Schmidt & Simon Meier+-- License : GPL v3 (see LICENSE)+-- +-- Maintainer : Benedikt Schmidt <beschmi@gmail.com>+-- Portability : GHC only+--+-- Ensuring consistency of a constraint system (sequent) with guarded trace+-- formulas.+module Theory.Proof.SolveGuarded (+ saturateGuarded+ , openDisjunctionGoals+ , openImplicationGoals++ -- * Literal formula constants+ , gfalse+ ) where++import Theory.Proof.Guarded+import Theory.Atom+import Term.LTerm++import Term.Rewriting.NormAC++import Theory.Proof.Types++import Data.Typeable+import Data.Data+import Data.Maybe (catMaybes)+import qualified Data.Set as S++import Control.Basics+import Control.Monad.State hiding (get)+import Control.Monad.Fresh+import Control.Monad.Reader++import Extension.Data.Label++-- Terms, facts, and formulas with skolem constants+---------------------------------------------------++-- | A constant type that supports names and skolem constants.+data SkConst = SkName Name+ | SkConst LVar+ deriving( Eq, Ord, Show, Data, Typeable )++type SkTerm = VTerm SkConst LVar+type SkFact = Fact SkTerm+type SkSubst = Subst SkConst LVar+type SkGuarded = LGuarded SkConst++-- | A term with skolem constants and bound variables+type BSkTerm = VTerm SkConst BLVar++-- | An term with skolem constants and bound variables+type BSkAtom = Atom BSkTerm++instance IsConst SkConst++-- | @saturateGuarded seq@ returns @Nothing@ if @sFormulas seq@ is already+-- saturated and saturated it otherwise. Additionally, the equalities in the+-- saturation are removed and returned separately. @sSolvedFormulas seq@ is+-- used to determine which formulas are considered 'solved'.+saturateGuarded :: MonadFresh m+ => MaudeHandle+ -> Sequent+ -> m (Maybe ([Equal LNTerm], Sequent))+ -- ^ return the new solved, unsolved, and equalities sets+saturateGuarded hnd se0 = do+ (eqs, se) <- (`runStateT` se0) $ do+ do existentials <- S.filter isExGuarded <$> getM sFormulas+ newExs <- mapM solveExistential $ S.toList existentials+ modM sFormulas (S.union $ S.fromList newExs)+ modM sSolvedFormulas (S.union existentials)++ do conjs <- S.filter isConjunction <$> getM sFormulas+ let newConjs = [ gf | GConj (Conj gfs) <- S.toList conjs, gf <- gfs ]+ modM sFormulas (S.union $ S.fromList newConjs)+ modM sSolvedFormulas (S.union conjs)++ do gfs <- S.toList <$> getM sFormulas+ lems <- S.toList <$> getM sLemmas+ let clauses = filter isAllGuarded $ gfs ++ lems+ newSuccs = [ gf | cl <- clauses+ , gf <- solveImplication hnd se0 cl ]+ modM sFormulas (S.union $ S.fromList newSuccs)++ -- solve all atoms in guarded formulas by moving them to the graph+ fms <- S.toList <$> getM sFormulas+ eqs <- fmap catMaybes $ forM fms $ \fm -> case fm of+ GAto ato -> do+ modM sSolvedFormulas (S.insert fm)+ case bvarToLVar ato of+ EqE s t -- only add non-trivial equalities+ | not (s ==# t) -> return $ Just $ Equal s t+ | otherwise -> return Nothing+ EdgeA (Lit (Var i), v) (Lit (Var j), u) -> do+ modM sEdges $ S.insert $ Edge (NodeConc (i,v)) (NodePrem (j,u))+ return Nothing+ EdgeA _ _ ->+ error $ "saturateGuarded: ill-formed edge atom: " ++ show ato+ ato' ->+ modM sAtoms (S.insert ato') >> return Nothing++ _ -> return Nothing++ -- remove solved formulas from open formulas.+ solved <- getM sSolvedFormulas+ modM sFormulas (`S.difference` solved)++ -- return new equality and less atoms+ return eqs++ -- check if there was a change.+ if (null eqs && get sFormulas se0 == get sFormulas se+ && get sSolvedFormulas se0 == get sSolvedFormulas se)+ then return Nothing+ else return (Just (eqs, se))++-- | @solveExistential ex@ converts the existentially quantified variables into+-- free variables.+solveExistential :: MonadFresh m => LNGuarded -> m LNGuarded+solveExistential gf0 = do+ Just (_, gf) <- openExGuarded gf0+ return gf++-- | @solveImplication se imp@ returns the list of guarded formulas that are+-- implied by @se@.+solveImplication :: MaudeHandle -> Sequent -> LNGuarded -> [LNGuarded]+solveImplication hnd se gf = + map (unskolemizeLNGuarded . flip applySkGuarded suc) substs+ where+ (suc,substs) = satisfyingSubsts hnd se gf++-- | @satisfyingSubsts se gf@ returns all satisfying substitutions for the+-- antecedent of gf. This function expects a clause gf and fails with an error+-- otherwise.+satisfyingSubsts :: MaudeHandle -> Sequent -> LNGuarded -> (SkGuarded, [SkSubst])+satisfyingSubsts hnd se gf0 =+ ( succedent+ , candidateSubsts emptySubst [ (i,f) | (Action i f) <- antecedent ]+ )+ where+ -- skolemize and open guarded all-quantification+ gf = skolemizeGuarded gf0+ Just (_ss, antecedent, succedent) = openAllGuarded gf `evalFresh` avoid gf++ -- the actions present in the sequent+ sequentActions = + ((skolemizeTerm . varTerm) *** skolemizeFact) <$> sActions se++ -- candidate substitutions such that the antecedent is implied by @se@+ candidateSubsts subst [] = do+ guard (all (atomHolds subst) antecedent) + return subst+ candidateSubsts subst (a:as) = do+ seAct <- sequentActions+ subst' <- (`runReader` hnd) $ matchAction seAct (applySkAction subst a)+ candidateSubsts (compose subst' subst) as+ + -- cache predicates+ dedBefore = deducibleBefore se+ hapBefore = happensBefore se++ atomHolds subst ato = case unskolemizeTerm . applySkTerm subst <$> ato of+ Action _ _ -> True -- correct by construction+ EqE t s -> t ==# s -- compare terms modulo AC+ Last i -> Last i `S.member` get sAtoms se+ DedBefore t (Lit (Var i)) -> t `dedBefore` i+ Less (Lit (Var i)) (Lit (Var j)) -> i `hapBefore` j+ EdgeA (Lit (Var i), v) (Lit (Var j), u) -> + Edge (NodeConc (i, v)) (NodePrem (j, u)) `S.member` get sEdges se+ -- play it safe and sound: all other atoms don't hold+ _ -> False+++-- Find open goals+------------------++-- | All open disjunction goals.+--+-- We assume that solved formulas have been removed from sFormulas+openDisjunctionGoals :: Sequent -> [Goal]+openDisjunctionGoals se = do+ GDisj d <- filter (/= gfalse) $ S.toList $ get sFormulas se+ return $ DisjG d++-- | Consequents of clauses that could be added to the sequent.+openImplicationGoals :: MaudeHandle -> Sequent -> [Goal]+openImplicationGoals hnd se = do+ clause <- filter isAllGuarded $ S.toList $ get sFormulas se+ conseq <- solveImplication hnd se clause+ guard $ + all (conseq `S.notMember`) [get sSolvedFormulas se, get sFormulas se]+ return $ ImplG conseq+++-- Skolemization of terms without bound variables.+-------------------------------------------------- skolemizeTerm :: VTerm Name LVar -> SkTerm++skolemizeTerm :: LNTerm -> SkTerm+skolemizeTerm = fmap conv+ where+ conv :: Lit Name LVar -> Lit SkConst LVar+ conv (Var v) = Con (SkConst v)+ conv (Con n) = Con (SkName n)++skolemizeFact :: LNFact -> Fact SkTerm+skolemizeFact = fmap skolemizeTerm++skolemizeAtom :: BLAtom -> BSkAtom+skolemizeAtom = fmap skolemizeBTerm++skolemizeGuarded :: LNGuarded -> SkGuarded+skolemizeGuarded = mapGuardedAtoms (const skolemizeAtom)++unskolemizeTerm :: SkTerm -> VTerm Name LVar+unskolemizeTerm t = fmap conv t+ where+ conv :: Lit SkConst LVar -> Lit Name LVar+ conv (Con (SkConst x)) = Var x+ conv (Var v) = error $ "unskolemizeBTerm: free variable " +++ show v++" found in "++show t+ conv (Con (SkName n)) = Con n++applySkTerm :: SkSubst -> SkTerm -> SkTerm+applySkTerm subst t = applyVTerm subst t++applySkFact :: SkSubst -> SkFact -> SkFact+applySkFact subst = fmap (applySkTerm subst) ++applySkAction :: SkSubst -> (SkTerm,SkFact) -> (SkTerm,SkFact)+applySkAction subst (t,f) = (applySkTerm subst t, applySkFact subst f)+++-- Skolemization of terms wit bound variables.+----------------------------------------------++skolemizeBTerm :: VTerm Name BLVar -> BSkTerm+skolemizeBTerm = fmap conv+ where+ conv :: Lit Name BLVar -> Lit SkConst BLVar+ conv (Var (Free x)) = Con (SkConst x)+ conv (Var (Bound b)) = Var (Bound b)+ conv (Con n) = Con (SkName n)++unskolemizeBTerm :: BSkTerm -> VTerm Name BLVar+unskolemizeBTerm t = fmap conv t+ where+ conv :: Lit SkConst BLVar -> Lit Name BLVar+ conv (Con (SkConst x)) = Var (Free x)+ conv (Var (Bound b)) = Var (Bound b)+ conv (Var (Free v)) = error $ "unskolemizeBTerm: free variable " +++ show v++" found in "++show t+ conv (Con (SkName n)) = Con n++unskolemizeBLAtom :: BSkAtom -> BLAtom+unskolemizeBLAtom = fmap unskolemizeBTerm++unskolemizeLNGuarded :: SkGuarded -> LNGuarded+unskolemizeLNGuarded = mapGuardedAtoms (const unskolemizeBLAtom)++applyBSkTerm :: SkSubst -> VTerm SkConst BLVar -> VTerm SkConst BLVar+applyBSkTerm subst t = (>>= applyBLLit) t+ where+ applyBLLit :: Lit SkConst BLVar -> VTerm SkConst BLVar+ applyBLLit l@(Var (Free v)) =+ maybe (Lit l) (fmap (fmap Free)) (imageOf subst v)+ applyBLLit l = Lit l++applyBSkAtom :: SkSubst -> Atom (VTerm SkConst BLVar) -> Atom (VTerm SkConst BLVar)+applyBSkAtom subst = fmap (applyBSkTerm subst)++applySkGuarded :: SkSubst -> LGuarded SkConst -> LGuarded SkConst+applySkGuarded subst = mapGuardedAtoms (const $ applyBSkAtom subst)++-- Matching+-----------++matchAction :: (SkTerm, SkFact) -> (SkTerm, SkFact) -> WithMaude [SkSubst]+matchAction (i1,Fact f1 t1) (i2,Fact f2 t2)+ | f1 == f2 && length t1 == length t2+ = matchLTerm sortOfSkol (zipWith MatchWith (i1:t1) (i2:t2))+ | otherwise = return []+ where+ sortOfSkol (SkName n) = sortOfName n+ sortOfSkol (SkConst v) = lvarSort v+++{-+-- Test+-------++parseFormula = get lFormulaE . either (error "parsing failed") id . parseLemma++t1 = parseFormula+ "lemma test1:\+ \ \"\+ \ All y z #i #j. (A(y)@#j & B(z)@#i) ==> (C(y,z) @ #i) & (D(y,z) @ #j) \+ \ \""++t2 = parseFormula+ "lemma test1:\+ \ \"\+ \ All y #i #j. (A(y)@#j & B(y1)@#i) ==> (C(y) @ #i) & (D(y) @ #j) \+ \ \""++-- \ All x #i. A(x)@i ==> Ex y #j. B(y)@j\+++gas = [(skolemizeTerm $ i1, skolemizeFact $ Fact (ProtoFact "A") [y1]),+ (skolemizeTerm $ i1, skolemizeFact $ Fact (ProtoFact "B") [y1]),+ (skolemizeTerm $ i2, skolemizeFact $ Fact (ProtoFact "B") [y3])+ ]++t1_g = fromJust $ convert False t1+t2_g = fromJust $ convert False t2++t3 = putStrLn $ render $ prettyGuarded $ t1_g++t4 = mapM_ (putStrLn . render . prettyGuarded) $ solveImplication t1_g gas+-}
@@ -0,0 +1,828 @@+{-# LANGUAGE TypeOperators, StandaloneDeriving, DeriveDataTypeable, TemplateHaskell #-}+-- |+-- Copyright : (c) 2010-2012 Benedikt Schmidt & Simon Meier+-- License : GPL v3 (see LICENSE)+-- +-- Maintainer : Simon Meier <iridcode@gmail.com>+-- Portability : GHC only+--+-- Common types for reasoning about sequents: Graph part of a sequent,+-- clauses, and equation store.+--+-- NOTE that sequents are what we call constraint systems in CSF'12 paper.+module Theory.Proof.Types (++ -- * Graph part of a sequent+ NodeId+ , NodePrem(..)+ , NodeConc(..)+ , Edge(..)+ , MsgEdge(..)+ , Chain(..)++ -- * The first-order logic part of a sequent+++ -- ** Typing and equation store+ , SplitId++ , EqStore(..)+ , emptyEqStore+ , eqsSubst+ , eqsConj++ -- ** Equalitiy constraint conjunctions+ , falseEqConstrConj++ -- ** Queries+ , eqsIsFalse++ -- * Goals+ , Goal(..)++ -- * Keeping track of typing+ , CaseDistKind(..)++ -- * Sequents+ , Sequent(..)+ , emptySequent++ -- ** Accessors+ , sNodes+ , sEdges+ , sMsgEdges+ , sChains+ , sEqStore+ , sAtoms+ , sFormulas+ , sSolvedFormulas+ , sLemmas+ , sSubst+ , sConjDisjEqs + , sCaseDistKind++ -- ** Queries+ , sLessAtoms+ , sActionAtoms+ , sLastAtoms+ , sDedBeforeAtoms+ , sActions+ , sRawLessRel+ , sRawGreaterRel+ , deducibleBefore+ , happensBefore++ , nodeRule+ , nodeConcFact+ , nodeConcNode+ , nodePremNode+ , nodePremFact+ , resolveNodePremFact+ -- , resolveNodePremMsg+ , resolveNodeConcFact+ -- , resolveNodeConcMsg++ -- * Pretty-printing+ , prettyNodeId+ , prettyNode+ , prettyNodePrem+ , prettyNodeConc+ , prettyEdge+ , prettyMsgEdge+ , prettyChain++ , prettyEqStore++ , prettyGoal+ , prettySequent+ , prettyNonGraphSequent++ -- * Proof context+ , ProofContext(..)++ , pcSignature+ , pcRules+ , pcCaseDists+++ -- ** Classified rules+ , ClassifiedRules(..)+ , emptyClassifiedRules+ , crConstruct+ , crDestruct+ , crProtocol+ , crSpecial+ , joinAllRules+ , joinNonSpecialRules+ , nonSilentRules++ -- ** Big-step case distinctions+ -- | See the module "Theory.Proof.CaseDistinction" for ways+ -- to construct case distinctions.+ , BigStepGoal(..)+ , CaseDistinction(..)+ + , cdGoal+ , cdCases++ -- * Convenience exports+ , module Theory.Rule+ , module Theory.Formula+ , module Theory.Signature+ , module Logic.Connectives+ , module Theory.Proof.Guarded+ ) where++import Prelude hiding ( (.), id )++import Safe++import Data.Maybe (mapMaybe, fromMaybe)+import qualified Data.Set as S+import qualified Data.Map as M+import qualified Data.DAG.Simple as D+import Data.Monoid (Monoid(..))+import Data.Generics+import qualified Data.Label as L+import Data.Label hiding (get)+import Data.DeriveTH+import Data.Binary++import Control.DeepSeq+import Control.Category+import Control.Basics++import Text.Isar++import Logic.Connectives++import Theory.Pretty+import Theory.Rule+import Theory.Proof.Guarded+import Theory.Formula+import Theory.Signature++------------------------------------------------------------------------------+-- Graph part of a sequent --+------------------------------------------------------------------------------++-- | The graph part of our sequent consists of nodes labelled with instances of+-- rules modulo AC. We identify these nodes using 'NodeId's.+type NodeId = LVar++-- | A premise (index) of a node.+newtype NodePrem = NodePrem { getNodePrem :: (NodeId, Int) }+ deriving( Eq, Ord, Show, Data, Typeable )++-- | A conclusion (index) of a node.+newtype NodeConc = NodeConc { getNodeConc :: (NodeId, Int) }+ deriving( Eq, Ord, Show, Data, Typeable )++-- | A labeled edge in a derivation graph.+data Edge = Edge {+ eSrc :: NodeConc+ , eTgt :: NodePrem+ }+ deriving (Show, Ord, Eq, Data, Typeable)++-- | A message edge.+data MsgEdge = MsgEdge {+ meSrc :: NodeConc+ , meTgt :: NodePrem+ }+ deriving (Show, Ord, Eq, Data, Typeable)++-- | A chain always starts at a rule with only one conclusion.+data Chain = Chain {+ cSrc :: NodeConc+ , cTgt :: NodePrem+ }+ deriving (Show, Ord, Eq, Data, Typeable)+++-- Instances+------------++instance Apply NodePrem where+ apply subst = NodePrem . first (apply subst) . getNodePrem++instance Apply NodeConc where+ apply subst = NodeConc . first (apply subst) . getNodeConc++instance Apply Edge where+ apply subst (Edge from to) = Edge (apply subst from) (apply subst to)++instance Apply MsgEdge where+ apply subst (MsgEdge from to) = MsgEdge (apply subst from) (apply subst to)++instance Apply Chain where+ apply subst (Chain from to) = Chain (apply subst from) (apply subst to)++instance HasFrees NodePrem where+ foldFrees f = foldFrees f . fst . getNodePrem+ mapFrees f (NodePrem (v, i)) = + NodePrem <$> ((,) <$> mapFrees f v <*> pure i)++instance HasFrees NodeConc where+ foldFrees f = foldFrees f . fst . getNodeConc+ mapFrees f (NodeConc (v, i)) = + NodeConc <$> ((,) <$> mapFrees f v <*> pure i)++instance HasFrees Edge where+ foldFrees f (Edge x y) = foldFrees f x `mappend` foldFrees f y+ mapFrees f (Edge x y) = Edge <$> mapFrees f x <*> mapFrees f y++instance HasFrees MsgEdge where+ foldFrees f (MsgEdge x y) = foldFrees f x `mappend` foldFrees f y+ mapFrees f (MsgEdge x y) = MsgEdge <$> mapFrees f x <*> mapFrees f y++instance HasFrees Chain where+ foldFrees f (Chain x y) = foldFrees f x `mappend` foldFrees f y+ mapFrees f (Chain x y) = Chain <$> mapFrees f x <*> mapFrees f y+++------------------------------------------------------------------------------+-- The first-order logic part of a sequent --+------------------------------------------------------------------------------++------------------------------------------------------------------------------+-- Typing and equation store --+------------------------------------------------------------------------------++-- | Index of disjunction in equation store+type SplitId = Int++-- FIXME: Make comment parse.+--+-- The semantics of an equation store+-- > EqStore sigma_free+-- > [ [sigma_i1,..,sigma_ik_i] | i <- [1..l] ]+-- where sigma_free = {t1/x1, .., tk/xk} is+-- > (x1 = t1 /\ .. /\ xk = tk)+-- > /\_{i in [1..l]}+-- > ([|sigma_i1|] \/ .. \/ [|sigma_ik_1|] \/ [|mtinfo_i|]+-- where @[|{t_1/x_1,..,t_l/x_l}|] = EX vars(t1,..,tl). x_1 = t1 /\ .. /\ x_l = t_l@.+-- Note that the 'LVar's in the range of a substitution are interpreted as+-- fresh variables, i.e., different by construction from the x_i which are+-- free variables.+--+-- The variables in the domain of the substitutions sigma_ij and all+-- variables in sigma_free are free (usually globally existentially quantified).+-- We use Conj [] as a normal form to denote True and Conj [Disj []]+-- as a normal form to denote False.+-- We say a variable @x@ is constrained by a disjunction if there is a substition+-- @s@ in the disjunction with @x `elem` dom s@.+data EqStore = EqStore {+ _eqsSubst :: LNSubst+ , _eqsConj :: Conj (Disj (LNSubstVFresh))+ }+ deriving( Eq, Ord )++$(mkLabels [''EqStore])++-- | @emptyEqStore@ is the empty equation store.+emptyEqStore :: EqStore+emptyEqStore = EqStore emptySubst (Conj [])++-- | @True@ iff the 'EqStore' is contradictory.+eqsIsFalse :: EqStore -> Bool+eqsIsFalse = (== falseEqConstrConj) . L.get eqsConj++-- | The false typing conjunction.+falseEqConstrConj :: Conj (Disj (LNSubstVFresh))+falseEqConstrConj = Conj [(Disj [])]+++-- Instances+------------++instance HasFrees EqStore where+ foldFrees f (EqStore subst substs) = foldFrees f subst `mappend` foldFrees f substs+ mapFrees f (EqStore subst substs) = EqStore <$> mapFrees f subst <*> mapFrees f substs+++------------------------------------------------------------------------------+-- New goaling infrastructure+------------------------------------------------------------------------------+++------------------------------------------------------------------------------+-- Goals+------------------------------------------------------------------------------++-- | A 'Goal' denotes that a constraint reduction rule is applicable, which +-- might result in case splits. We either use a heuristic to decide what goal+-- to solve next or leave the choice to user (in case of the interactive UI).+data Goal = + ActionG LVar LNFact+ -- ^ An action that must exist in the trace.+ | PremiseG NodePrem LNFact+ -- ^ A premise that must have an incoming direct edge.+ | PremDnKG NodePrem+ -- ^ A KD goal that must be solved using a destruction chain.+ | PremUpKG NodePrem LNTerm+ -- ^ A KU goal requiring a term built using pairing, inversion, or+ -- multiplication. 'PremUpKG p m' denotes that premise 'p' requires+ -- the term 'm' as in input to construct its actual term.+ | ChainG Chain+ -- A destruction chain that does not start from a message variable.+ | SplitG SplitId+ -- ^ A case split over equalities.+ | DisjG (Disj LNGuarded)+ -- ^ A case split over a disjunction.+ | ImplG LNGuarded+ -- ^ The consequent of a universally quantified clause that could be+ -- added to the sequent. For debugging mode only; currently commented+ -- out.+ deriving( Eq, Ord, Show )++-- Instances+------------++instance HasFrees Goal where+ foldFrees f goal = case goal of+ ActionG i fa -> foldFrees f i `mappend` foldFrees f fa+ PremiseG p fa -> foldFrees f p `mappend` foldFrees f fa+ PremDnKG p -> foldFrees f p+ PremUpKG p m -> foldFrees f p `mappend` foldFrees f m+ ChainG ch -> foldFrees f ch+ SplitG i -> foldFrees f i+ DisjG x -> foldFrees f x+ ImplG x -> foldFrees f x++ mapFrees f goal = case goal of+ ActionG i fa -> ActionG <$> mapFrees f i <*> mapFrees f fa+ PremiseG p fa -> PremiseG <$> mapFrees f p <*> mapFrees f fa+ PremDnKG p -> PremDnKG <$> mapFrees f p+ PremUpKG p m -> PremUpKG <$> mapFrees f p <*> mapFrees f m+ ChainG ch -> ChainG <$> mapFrees f ch+ SplitG i -> SplitG <$> mapFrees f i+ DisjG x -> DisjG <$> mapFrees f x+ ImplG x -> ImplG <$> mapFrees f x++instance Apply Goal where+ apply subst goal = case goal of+ ActionG i fa -> ActionG (apply subst i) (apply subst fa)+ PremiseG p fa -> PremiseG (apply subst p) (apply subst fa)+ PremDnKG p -> PremDnKG (apply subst p)+ PremUpKG p m -> PremUpKG (apply subst p) (apply subst m)+ ChainG ch -> ChainG (apply subst ch)+ SplitG i -> SplitG (apply subst i)+ DisjG x -> DisjG (apply subst x)+ ImplG x -> ImplG (apply subst x)+++------------------------------------------------------------------------------+-- Keeping track of what case distinctions are allowed.+------------------------------------------------------------------------------++-- | Case dinstinction kind that are allowed. The order of the kinds+-- corresponds to the subkinding relation: untyped < typed.+data CaseDistKind = UntypedCaseDist | TypedCaseDist+ deriving( Eq, Ord )++instance Show CaseDistKind where+ show UntypedCaseDist = "untyped"+ show TypedCaseDist = "typed"+++instance Apply CaseDistKind where+ apply = const id++instance HasFrees CaseDistKind where+ foldFrees = const mempty+ mapFrees = const pure++------------------------------------------------------------------------------+-- Sequents --+------------------------------------------------------------------------------++-- | A sequent / constraint system.+--+data Sequent = Sequent {+ _sNodes :: M.Map NodeId RuleACInst+ , _sEdges :: S.Set Edge+ , _sMsgEdges :: S.Set MsgEdge+ , _sChains :: S.Set Chain+ , _sEqStore :: EqStore+ , _sAtoms :: S.Set LNAtom+ , _sFormulas :: S.Set LNGuarded+ , _sSolvedFormulas :: S.Set LNGuarded+ , _sLemmas :: S.Set LNGuarded+ , _sCaseDistKind :: CaseDistKind+ }+ deriving( Eq, Ord )++$(mkLabels [''Sequent])++-- | The empty sequent. Logically equivalent to true.+emptySequent :: CaseDistKind -> Sequent+emptySequent = Sequent + M.empty S.empty S.empty S.empty emptyEqStore S.empty S.empty S.empty S.empty++-- Custom accessors for atoms+-----------------------------++-- | All actions that hold in a sequent.+sActions :: Sequent -> [(NodeId, LNFact)]+sActions se = + sActionAtoms se <|> do (i, ru) <- M.toList $ L.get sNodes se+ (,) i <$> L.get rActs ru++-- | The less-relation.+sLessAtoms :: Sequent -> [(NodeId, NodeId)]++-- | The actions.+sActionAtoms :: Sequent -> [(NodeId, LNFact)]++-- | The last nodes.+sLastAtoms :: Sequent -> [NodeId]++-- | The deduced before atoms.+sDedBeforeAtoms :: Sequent -> [(LNTerm, NodeId)]++(sLessAtoms, sActionAtoms, sLastAtoms, sDedBeforeAtoms) = + (accessor aLess, accessor aAction, accessor aLast, accessor aDedBefore)+ where+ accessor :: (LNAtom -> Maybe a) -> Sequent -> [a]+ accessor f = mapMaybe f . S.toList . L.get sAtoms++ malformed ato = error $ "malformed atom in sequent: " ++ show ato++ aLess (Less (Lit (Var from)) (Lit (Var to))) = Just (from, to)+ aLess ato@(Less _ _) = malformed ato+ aLess _ = Nothing++ aAction (Action (Lit (Var i)) fa) = Just (i, fa)+ aAction ato@(Action _ _) = malformed ato+ aAction _ = Nothing++ aLast (Last (Lit (Var i))) = Just i+ aLast ato@(Last _) = malformed ato+ aLast _ = Nothing++ aDedBefore (DedBefore t (Lit (Var i))) = Just (t, i)+ aDedBefore ato@(DedBefore _ _) = malformed ato+ aDedBefore _ = Nothing+++-- | @(from,to)@ is in @sRawLessRel se@ iff we can prove that there is a path+-- from @from@ to @to@ in @se@ without appealing to transitivity.+sRawLessRel :: Sequent -> [(NodeId,NodeId)]+sRawLessRel se =+ sLessAtoms se +++ map (nodeConcNode *** nodePremNode)+ ([ (from, to) | Edge from to <- S.toList $ L.get sEdges se ] +++ [ (from, to) | MsgEdge from to <- S.toList $ L.get sMsgEdges se ] +++ [ (from, to) | Chain from to <- S.toList $ L.get sChains se ])++-- | 'sRawGreaterRel' is the inverse of 'sRawLessRel'. +sRawGreaterRel :: Sequent -> [(NodeId,NodeId)]+sRawGreaterRel = map (\(x,y) -> (y,x)) . sRawLessRel++-- | Returns a predicate that is 'True' iff the first argument happens before+-- the second argument in all models of the sequent.+happensBefore :: Sequent -> (NodeId -> NodeId -> Bool)+happensBefore se =+ check -- lessRel is cached for partial applications+ where+ lessRel = sRawLessRel se+ check i j = j `S.member` D.reachableSet [i] lessRel++-- | Returns a predicate that is 'True' iff the given term is deducible+-- before the given node in all models of the sequent.+deducibleBefore :: Sequent -> (LNTerm -> NodeId -> Bool)+deducibleBefore se = + check -- lessRel is cached for partial applications+ where+ lessRel = sRawLessRel se+ check t i = + i `S.member` D.reachableSet startNodes lessRel+ where+ startNodes = + [ j | (t', j) <- sDedBeforeAtoms se, t == t' ] +++ do (j, ru) <- M.toList $ L.get sNodes se+ fa <- L.get rPrems ru+ case kFactView fa of+ Just (_, _, m) | t `elem` input m -> return j+ _ -> []+++-- Instances for sequents+-------------------------++instance HasFrees Sequent where+ foldFrees fun (Sequent a b c d e f g h i j) =+ foldFrees fun a `mappend`+ foldFrees fun b `mappend`+ foldFrees fun c `mappend`+ foldFrees fun d `mappend`+ foldFrees fun e `mappend`+ foldFrees fun f `mappend`+ foldFrees fun g `mappend`+ foldFrees fun h `mappend`+ foldFrees fun i `mappend`+ foldFrees fun j++ mapFrees fun (Sequent a b c d e f g h i j) =+ Sequent <$> mapFrees fun a+ <*> mapFrees fun b+ <*> mapFrees fun c+ <*> mapFrees fun d+ <*> mapFrees fun e+ <*> mapFrees fun f+ <*> mapFrees fun g+ <*> mapFrees fun h+ <*> mapFrees fun i+ <*> mapFrees fun j++-- Accessors+------------++-- | @nodeRule v@ accesses the rule label of node @v@ under the assumption that+-- it is present in the sequent.+nodeRule :: NodeId -> Sequent -> RuleACInst+nodeRule v se = + fromMaybe errMsg $ M.lookup v $ L.get sNodes se+ where+ errMsg = error $ + "nodeRule: node '" ++ show v ++ "' does not exist in sequent\n" +++ render (nest 2 $ prettySequent se)+++-- | @nodePremFact prem se@ computes the fact associated to premise @prem@ in+-- sequent @se@ under the assumption that premise @prem@ is a a premise in+-- @se@.+nodePremFact :: NodePrem -> Sequent -> LNFact+nodePremFact (NodePrem (v, i)) se = L.get (rPrem i) $ nodeRule v se++-- | @nodePremNode prem@ is the node that this premise is referring to.+nodePremNode :: NodePrem -> NodeId+nodePremNode (NodePrem (v, _)) = v++-- | All facts associated to this node premise.+resolveNodePremFact :: NodePrem -> Sequent -> Maybe LNFact+resolveNodePremFact (NodePrem (v, i)) se = + (`atMay` i) =<< L.get rPrems <$> M.lookup v (L.get sNodes se)++{-+-- | All msg fact premises required by the sequent for the given node premise.+resolveNodePremMsg :: NodePrem -> Sequent -> Maybe LTerm+resolveNodePremMsg prem = msgFactTerm <=< resolveNodePremFact prem+-}+ +-- | The fact associated with this node conclusion, if there is one.+resolveNodeConcFact :: NodeConc -> Sequent -> Maybe LNFact+resolveNodeConcFact (NodeConc (v, i)) se = + (`atMay` i) =<< L.get rConcs <$> M.lookup v (L.get sNodes se)++{-+-- | The msg fact provided by the sequent for the given node conclusion+resolveNodeConcMsg :: NodeConc -> Sequent -> Maybe LTerm+resolveNodeConcMsg conc = msgFactTerm <=< resolveNodeConcFact conc+-}++-- | @nodeConcFact (NodeConc (v, i))@ accesses the @i@-th conclusion of the+-- rule associated with node @v@ under the assumption that @v@ is labeled with+-- a rule that has an @i@-th conclusion.+nodeConcFact :: NodeConc -> Sequent -> LNFact+nodeConcFact (NodeConc (v, i)) = L.get (rConc i) . nodeRule v++-- | 'nodeConcNode' @c@ compute the node-id of the node conclusion @c@.+nodeConcNode :: NodeConc -> NodeId+nodeConcNode = fst . getNodeConc++-- | Label to access the free substitution of the equation store.+sSubst :: Sequent :-> LNSubst+sSubst = eqsSubst . sEqStore++-- | Label to access the conjunction of disjunctions of fresh substutitution in+-- the equation store.+sConjDisjEqs :: Sequent :-> Conj (Disj (LNSubstVFresh))+sConjDisjEqs = eqsConj . sEqStore+++------------------------------------------------------------------------------+-- Pretty printing --+------------------------------------------------------------------------------++-- | Pretty print a node id+prettyNodeId :: Document d => NodeId -> d+prettyNodeId = text . show++-- | Pretty print a node.+prettyNode :: HighlightDocument d => (NodeId, RuleACInst) -> d+prettyNode (v,ru) = prettyNodeId v <> colon <-> prettyRuleACInst ru++-- | Pretty print a node conclusion.+prettyNodeConc :: HighlightDocument d => NodeConc -> d+prettyNodeConc (NodeConc (v, i)) = parens (prettyNodeId v <> comma <-> int i)++-- | Pretty print a node premise.+prettyNodePrem :: HighlightDocument d => NodePrem -> d+prettyNodePrem (NodePrem (v, i)) = parens (prettyNodeId v <> comma <-> int i)++-- | Pretty print a edge as @src >-i--j-> tgt@.+prettyEdge :: HighlightDocument d => Edge -> d+prettyEdge (Edge c p) = + prettyNodeConc c <-> operator_ ">-->" <-> prettyNodePrem p++-- | Pretty print a edge as @src >-i--j-> tgt@.+prettyMsgEdge :: HighlightDocument d => MsgEdge -> d+prettyMsgEdge (MsgEdge c p) = + prettyNodeConc c <-> operator_ "-->>" <-> prettyNodePrem p++-- | Pretty print a chain as @src ~~> tgt@.+prettyChain :: HighlightDocument d => Chain -> d+prettyChain (Chain c p) = + prettyNodeConc c <-> operator_ "~~>" <-> prettyNodePrem p++-- | Pretty print a sequent+prettySequent :: HighlightDocument d => Sequent -> d+prettySequent se = vcat $ + map combine+ [ ("nodes", vcat $ map prettyNode $ M.toList $ L.get sNodes se)+ , ("edges", commasep $ map prettyEdge $ S.toList $ L.get sEdges se)+ , ("msg-edges", commasep $ map prettyMsgEdge $ S.toList $ L.get sMsgEdges se)+ , ("chains", commasep $ map prettyChain $ S.toList $ L.get sChains se)+ ]+ ++ [prettyNonGraphSequent se]+ where+ combine (header, d) = fsep [keyword_ header <> colon, nest 2 d]+ commasep = fsep . punctuate comma++-- | Pretty print the non-graph part of the sequent; i.e. equation store and+-- clauses.+prettyNonGraphSequent :: HighlightDocument d => Sequent -> d+prettyNonGraphSequent se = foldr ($--$) emptyDoc $ map combine + [ ("atoms", ppAtoms $ S.toList $ L.get sAtoms se)+ , ("allowed cases", text $ show $ L.get sCaseDistKind se)+ , ("formulas", foldr ($--$) emptyDoc $ map prettyGuarded $ S.toList $ L.get sFormulas se)+ , ("equations", prettyEqStore $ L.get sEqStore se)+ , ("solved formulas", foldr ($--$) emptyDoc $ map prettyGuarded $ S.toList $ L.get sSolvedFormulas se)+ , ("lemmas", foldr ($--$) emptyDoc $ map prettyGuarded $ S.toList $ L.get sLemmas se)+ ]+ where+ combine (header, d) = fsep [keyword_ header <> colon, nest 2 d]+ ppAtoms = fsep . punctuate comma . map prettyNAtom+++-- | Pretty print an equation store+prettyEqStore :: HighlightDocument d => EqStore -> d+prettyEqStore eqs@(EqStore subst (Conj disjs)) = vcat $+ [if eqsIsFalse eqs then text "CONTRADICTORY" else emptyDoc] +++ map combine+ [ ("subst", vcat $ prettySubst (text . show) (text . show) subst)+ , ("conj", numbered' $ map ppDisj disjs)+ ]+ where+ combine (header, d) = fsep [keyword_ header <> colon, nest 2 d]+ ppDisj (Disj substs) =+ numbered' conjs+ where + conjs = map ppConj substs+ ppConj = vcat . map prettyEq . substToListVFresh+ prettyEq (a,b) = + prettyNTerm (Lit (Var a)) $$ nest (6::Int) (opEqual <-> prettyNTerm b)+ +-- | Pretty print a goal.+prettyGoal :: HighlightDocument d => Goal -> d+prettyGoal (ActionG i fa) = prettyNAtom (Action (varTerm i) fa)+prettyGoal (ChainG ch) = prettyChain ch+prettyGoal (PremiseG p fa) = prettyNodePrem p <> brackets (prettyLNFact fa)+prettyGoal (PremDnKG p) = text "KD" <> parens (prettyNodePrem p)+prettyGoal (ImplG gf) = + (text "Consequent" <>) $ nest 1 $ parens $ prettyGuarded gf+prettyGoal (DisjG (Disj gfs)) = (text "Disj" <>) $ fsep $+ punctuate (operator_ " |") (map (nest 1 . parens . prettyGuarded) gfs)+prettyGoal (PremUpKG p m) =+ text "KU" <> parens (prettyNodePrem p <> comma <-> prettyLNTerm m)+prettyGoal (SplitG x) =+ text "splitEqs" <> parens (text $ show (succ x))++-- Additional Show instances moved here due to TemplateHaskell splicing rules+-----------------------------------------------------------------------------++instance Show EqStore where+ show = render . prettyEqStore++deriving instance Show Sequent++----------------------------------------------------------------------+-- ClassifiedRules+----------------------------------------------------------------------++data ClassifiedRules = ClassifiedRules+ { _crProtocol :: [RuleAC] -- all protocol rules+ , _crDestruct :: [RuleAC] -- destruction rules+ , _crConstruct :: [RuleAC] -- construction rules+ , _crSpecial :: [RuleAC] -- rules that are handled by other means+ -- than unification.+ }+ deriving( Eq, Ord, Show )++$(mkLabels [''ClassifiedRules])++-- | The empty proof rule set.+emptyClassifiedRules :: ClassifiedRules+emptyClassifiedRules = ClassifiedRules [] [] [] []++-- | @joinNonSpecialRules rules@ computes the union of all non-special @rules@.+joinNonSpecialRules :: ClassifiedRules -> [RuleAC]+joinNonSpecialRules (ClassifiedRules a b c _) = a ++ b ++ c++-- | @joinAllRules rules@ computes the union of all rules classified in+-- @rules@.+joinAllRules :: ClassifiedRules -> [RuleAC]+joinAllRules (ClassifiedRules a b c d) = a ++ b ++ c ++ d++-- | Extract all non-silent rules.+nonSilentRules :: ClassifiedRules -> [RuleAC]+nonSilentRules = filter (not . null . L.get rActs) . L.get crProtocol+++------------------------------------------------------------------------------+-- Proof Context+------------------------------------------------------------------------------++-- | A goal for a big step case distinction.+data BigStepGoal = + PremiseBigStep LNFact+ | MessageBigStep LNTerm+ deriving( Eq, Ord, Show )++-- | A big-step case distinction.+data CaseDistinction = CaseDistinction+ { _cdGoal :: BigStepGoal -- start goal of case distinction+ -- disjunction of named sequents with premise being solved; each name+ -- being the path of proof steps required to arrive at these cases+ , _cdCases :: Disj ([String], (NodeConc, Sequent))+ }+ deriving( Eq, Ord, Show )++-- | A proof context contains the globally fresh facts, classified rewrite+-- rules and the corresponding precomputed premise case distinction theorems.+data ProofContext = ProofContext + { _pcSignature :: SignatureWithMaude+ , _pcRules :: ClassifiedRules+ , _pcCaseDists :: [CaseDistinction]+ }+ deriving( Eq, Ord, Show )++$(mkLabels [''ProofContext, ''CaseDistinction])+++-- Instances+------------++instance HasFrees CaseDistinction where+ foldFrees f th = + foldFrees f (L.get cdGoal th) `mappend` + foldFrees f (L.get cdCases th)++ mapFrees f th = CaseDistinction <$> mapFrees f (L.get cdGoal th)+ <*> mapFrees f (L.get cdCases th)+++-- Instances+------------++instance HasFrees BigStepGoal where+ foldFrees f (PremiseBigStep fa) = foldFrees f fa+ foldFrees f (MessageBigStep m) = foldFrees f m++ mapFrees f (PremiseBigStep fa) = PremiseBigStep <$> mapFrees f fa+ mapFrees f (MessageBigStep m) = MessageBigStep <$> mapFrees f m++instance Apply BigStepGoal where+ apply subst (PremiseBigStep fa) = PremiseBigStep (apply subst fa)+ apply subst (MessageBigStep m) = MessageBigStep (apply subst m)++-- NFData+---------++$( derive makeBinary ''Goal)+$( derive makeBinary ''Chain)+$( derive makeBinary ''MsgEdge)+$( derive makeBinary ''Edge)+$( derive makeBinary ''NodePrem)+$( derive makeBinary ''NodeConc)+$( derive makeBinary ''EqStore)+$( derive makeBinary ''CaseDistKind)+$( derive makeBinary ''Sequent)+$( derive makeBinary ''BigStepGoal)+$( derive makeBinary ''CaseDistinction)+$( derive makeBinary ''ClassifiedRules)++$( derive makeNFData ''Goal)+$( derive makeNFData ''Chain)+$( derive makeNFData ''MsgEdge)+$( derive makeNFData ''Edge)+$( derive makeNFData ''NodePrem)+$( derive makeNFData ''NodeConc)+$( derive makeNFData ''EqStore)+$( derive makeNFData ''CaseDistKind)+$( derive makeNFData ''Sequent)+$( derive makeNFData ''BigStepGoal)+$( derive makeNFData ''CaseDistinction)+$( derive makeNFData ''ClassifiedRules)
@@ -0,0 +1,527 @@+{-# LANGUAGE TemplateHaskell, DeriveDataTypeable, TupleSections, TypeOperators, FlexibleInstances, FlexibleContexts, TypeSynonymInstances #-}+-- |+-- Copyright : (c) 2010-2012 Benedikt Schmidt & Simon Meier+-- License : GPL v3 (see LICENSE)+-- +-- Maintainer : Simon Meier <iridcode@gmail.com>+-- Portability : portable+--+-- Rewriting rules representing protocol execution and intruder deduction. Once+-- modulo the full Diffie-Hellman equational theory and once modulo AC.+module Theory.Rule (+ -- * General Rules+ Rule(..)++ -- ** Accessors+ , rInfo+ , rPrems+ , rConcs+ , rActs+ , rPrem+ , rConc+ , rAct+ , lookupPrem+ , lookupConc++ -- ** Genereal protocol and intruder rules+ , RuleInfo(..)+ , ruleInfo++ -- * Protocol Rule Information+ , ProtoRuleName(..)+ , ProtoRuleACInfo(..)+ , RuleACConstrs++ -- * Intruder Rule Information+ , IntrRuleACInfo(..)+ + -- * Concrete Rules+ , ProtoRuleE+ , ProtoRuleAC+ , IntrRuleAC+ , RuleAC+ , RuleACInst++ -- ** Queries+ , HasRuleName(..)+ , isDestrRule+ , isConstrRule+ , isFreshRule+ , isIRecvRule+ , isISendRule+ , isCoerceRule+ , nfRule+ , isTrivialProtoRuleAC++ -- ** Conversion+ , ruleACToIntrRuleAC+ , ruleACIntrToRuleAC++ -- ** Construction+ , someRuleACInst++ -- ** Unification+ , unifyRuleACInstEqs++ -- * Pretty-Printing+ , showRuleCaseName+ , prettyProtoRuleName+ , prettyRuleName+ , prettyProtoRuleE+ , prettyProtoRuleAC+ , prettyIntrRuleAC+ , prettyIntrRuleACInfo+ , prettyRuleAC+ , prettyRuleACInst++ -- * Convenience exports+ , module Theory.Fact++ ) where++import Prelude hiding ( (.), id )++import Safe+import Data.List+import Data.Monoid+import Data.Foldable (foldMap)+import Data.Generics +import Data.DeriveTH+import Data.Binary++import Control.DeepSeq+import Control.Category+import Control.Basics+import Control.Monad.Bind+import Control.Monad.Reader++import Extension.Data.Label hiding (get)+import qualified Extension.Data.Label as L+import Logic.Connectives++import Theory.Fact+import Theory.Pretty+import Term.Rewriting.Norm++------------------------------------------------------------------------------+-- General Rule+------------------------------------------------------------------------------++-- | Rewriting rules with arbitrary additional information and facts with names+-- and logical variables.+data Rule i = Rule {+ _rInfo :: i+ , _rPrems :: [LNFact]+ , _rConcs :: [LNFact]+ , _rActs :: [LNFact]+ }+ deriving( Eq, Ord, Show, Data, Typeable )++$(mkLabels [''Rule])++-- | @lookupPrem i ru@ returns the @i@-th premise of rule @ru@, if possible.+lookupPrem :: Int -> Rule i -> Maybe LNFact+lookupPrem i = (`atMay` i) . L.get rPrems++-- | @lookupConc i ru@ returns the @i@-th conclusion of rule @ru@, if possible.+lookupConc :: Int -> Rule i -> Maybe LNFact+lookupConc i = (`atMay` i) . L.get rConcs++-- | @rPrem i@ is a lens for the @i@-th premise of a rule.+rPrem :: Int -> (Rule i :-> LNFact)+rPrem i = nthL i . rPrems++-- | @rConc i@ is a lens for the @i@-th conclusion of a rule.+rConc :: Int -> (Rule i :-> LNFact)+rConc i = nthL i . rConcs++-- | @rAct i@ is a lens for the @i@-th action of a rule.+rAct :: Int -> (Rule i :-> LNFact)+rAct i = nthL i . rActs++-- Instances+------------++instance Functor Rule where+ fmap f (Rule i ps cs as) = Rule (f i) ps cs as++instance HasFrees i => HasFrees (Rule i) where+ foldFrees f (Rule i ps cs as) = + (foldFrees f i `mappend`) $ + (foldFrees f ps `mappend`) $+ (foldFrees f cs `mappend`) $+ (foldFrees f as)++ mapFrees f (Rule i ps cs as) =+ Rule <$> mapFrees f i + <*> mapFrees f ps <*> mapFrees f cs <*> mapFrees f as++instance Apply i => Apply (Rule i) where+ apply subst (Rule i ps cs as) = + Rule (apply subst i) (apply subst ps) (apply subst cs) (apply subst as)++instance Sized (Rule i) where+ size (Rule _ ps cs as) = size ps + size cs + size as++------------------------------------------------------------------------------+-- Rule information split into intruder rule and protocol rules+------------------------------------------------------------------------------++-- | Rule information for protocol and intruder rules.+data RuleInfo p i = + ProtoInfo p+ | IntrInfo i + deriving( Eq, Ord, Show )++-- | @ruleInfo proto intr@ maps the protocol information with @proto@ and the+-- intruder information with @intr@.+ruleInfo :: (p -> c) -> (i -> c) -> RuleInfo p i -> c+ruleInfo proto _ (ProtoInfo x) = proto x+ruleInfo _ intr (IntrInfo x) = intr x+++-- Instances+------------++instance (HasFrees p, HasFrees i) => HasFrees (RuleInfo p i) where+ foldFrees f = ruleInfo (foldFrees f) (foldFrees f)++ mapFrees f = ruleInfo (fmap ProtoInfo . mapFrees f) + (fmap IntrInfo . mapFrees f)++instance (Apply p, Apply i) => Apply (RuleInfo p i) where+ apply subst = ruleInfo (ProtoInfo . apply subst) (IntrInfo . apply subst)+++------------------------------------------------------------------------------+-- Protocol Rule Information+------------------------------------------------------------------------------++-- | A name of a protocol rule is either one of the special reserved rules or+-- some standard rule.+data ProtoRuleName = + -- FIXME: Consider also moving them to intruder/model rules.+ FreshRule+ | IRecvRule+ | ISendRule+ | StandRule String -- ^ Some standard protocol rule+ deriving( Eq, Ord, Show, Data, Typeable )+++-- | Information for protocol rules modulo AC. The variants list the possible+-- instantiations of the free variables of the rule. The typing is interpreted+-- modulo AC; i.e., its variants were also built.+data ProtoRuleACInfo = ProtoRuleACInfo+ { pracName :: ProtoRuleName+ , pracVariants :: Disj (LNSubstVFresh)+ }+ deriving( Eq, Ord, Show )+++-- Instances+------------++instance Apply ProtoRuleName where+ apply _ = id++instance HasFrees ProtoRuleName where+ foldFrees _ = const mempty+ mapFrees _ = pure+++instance HasFrees ProtoRuleACInfo where+ foldFrees f (ProtoRuleACInfo na vari) =+ foldFrees f na `mappend` foldFrees f vari+ + mapFrees f (ProtoRuleACInfo na vari) = + ProtoRuleACInfo na <$> mapFrees f vari+++------------------------------------------------------------------------------+-- Intruder Rule Information+------------------------------------------------------------------------------++-- | An intruder rule modulo AC is described by its name.+data IntrRuleACInfo = IntrApp String | CoerceRule+ deriving( Ord, Eq, Show, Data, Typeable )++-- | An intruder rule modulo AC.+type IntrRuleAC = Rule IntrRuleACInfo++-- | Converts between these two types of rules, if possible.+ruleACToIntrRuleAC :: RuleAC -> Maybe IntrRuleAC+ruleACToIntrRuleAC (Rule (IntrInfo i) ps cs as) = Just (Rule i ps cs as)+ruleACToIntrRuleAC _ = Nothing++-- | Converts between these two types of rules.+ruleACIntrToRuleAC :: IntrRuleAC -> RuleAC+ruleACIntrToRuleAC (Rule ri ps cs as) = Rule (IntrInfo ri) ps cs as++-- Instances+------------++instance Apply IntrRuleACInfo where+ apply _ = id++instance HasFrees IntrRuleACInfo where+ foldFrees _ = const mempty+ mapFrees _ = pure+++------------------------------------------------------------------------------+-- Concrete rules+------------------------------------------------------------------------------++-- | A rule modulo E is always a protocol rule. Intruder rules are specified+-- abstractly by their operations generating them and are only available once+-- their variants are built.+type ProtoRuleE = Rule ProtoRuleName++-- | A protocol rule modulo AC.+type ProtoRuleAC = Rule ProtoRuleACInfo++-- | A rule modulo AC is either a protocol rule or an intruder rule+type RuleAC = Rule (RuleInfo ProtoRuleACInfo IntrRuleACInfo)++-- | A rule instance module AC is either a protocol rule or an intruder rule.+-- The info identifies the corresponding rule modulo AC that the instance was+-- derived from.+type RuleACInst = Rule (RuleInfo ProtoRuleName IntrRuleACInfo)++-- Accessing the rule name+--------------------------++-- | Types that have an associated name.+class HasRuleName t where+ ruleName :: t -> RuleInfo ProtoRuleName IntrRuleACInfo++instance HasRuleName ProtoRuleE where+ ruleName = ProtoInfo . L.get rInfo++instance HasRuleName RuleAC where+ ruleName = ruleInfo (ProtoInfo . pracName) IntrInfo . L.get rInfo++instance HasRuleName ProtoRuleAC where+ ruleName = ProtoInfo . pracName . L.get rInfo++instance HasRuleName IntrRuleAC where+ ruleName = IntrInfo . L.get rInfo++instance HasRuleName RuleACInst where+ ruleName = L.get rInfo+++-- Queries+----------++-- | True iff the rule is a destruction rule.+isDestrRule :: Rule r -> Bool+isDestrRule ru = case kFactView <$> L.get rConcs ru of+ [Just (DnK, _, _)] -> True+ _ -> False++-- | True iff the rule is a construction rule.+isConstrRule :: Rule r -> Bool+isConstrRule ru = case kFactView <$> L.get rConcs ru of+ [Just (UpK, _, _)] -> True+ _ -> False++-- | True iff the rule is the special fresh rule.+isFreshRule :: HasRuleName r => r -> Bool+isFreshRule = (ProtoInfo FreshRule ==) . ruleName++-- | True iff the rule is the special learn rule.+isIRecvRule :: HasRuleName r => r -> Bool+isIRecvRule = (ProtoInfo IRecvRule ==) . ruleName++-- | True iff the rule is the special knows rule.+isISendRule :: HasRuleName r => r -> Bool+isISendRule = (ProtoInfo ISendRule ==) . ruleName++-- | True iff the rule is the special coerce rule.+isCoerceRule :: HasRuleName r => r -> Bool+isCoerceRule = (IntrInfo CoerceRule ==) . ruleName++-- | True if the messages in premises and conclusions are in normal form+nfRule :: Rule i -> WithMaude Bool+nfRule (Rule _ ps cs as) = reader $ \hnd ->+ all (nfFactList hnd) [ps, cs, as]+ where+ nfFactList hnd xs = + getAll $ foldMap (foldMap (All . (\t -> nf' t `runReader` hnd))) xs++-- | True if the protocol rule has no variants.+isTrivialProtoRuleAC :: ProtoRuleAC -> Bool+isTrivialProtoRuleAC (Rule info _ _ _) =+ pracVariants info == Disj [emptySubstVFresh]+++-- Construction+---------------++type RuleACConstrs = Disj (LNSubstVFresh)++-- | Compute /some/ rule instance of a rule modulo AC. If the rule is a+-- protocol rule, then the given typing and variants also need to handled.+someRuleACInst :: MonadFresh m + => RuleAC + -> m (RuleACInst, Maybe RuleACConstrs)+someRuleACInst = + (`evalBindT` noBindings) . fmap extractInsts . someInst+ where+ extractInsts (Rule (ProtoInfo i) ps cs as) = + ( Rule (ProtoInfo (pracName i)) ps cs as+ , Just (pracVariants i)+ )+ extractInsts (Rule (IntrInfo i) ps cs as) = + ( Rule (IntrInfo i) ps cs as, Nothing )+++-- Unification+--------------++-- | Unify a list of @RuleACInst@ equalities.+unifyRuleACInstEqs :: [Equal RuleACInst] -> WithMaude [LNSubstVFresh]+unifyRuleACInstEqs eqs + | all unifiable eqs = unifyLNFactEqs $ concatMap ruleEqs eqs+ | otherwise = return []+ where+ unifiable (Equal ru1 ru2) = + L.get rInfo ru1 == L.get rInfo ru2+ && length (L.get rPrems ru1) == length (L.get rPrems ru2)+ && length (L.get rConcs ru1) == length (L.get rConcs ru2)++ ruleEqs (Equal ru1 ru2) = + zipWith Equal (L.get rPrems ru1) (L.get rPrems ru2) ++ + zipWith Equal (L.get rConcs ru1) (L.get rConcs ru2)++++------------------------------------------------------------------------------+-- Fact analysis+------------------------------------------------------------------------------++-- | Globally unique facts.+--+-- A rule instance removes a fact fa if fa is in the rule's premise but not+-- in the rule's conclusion.+--+-- A fact symbol fa is globally fresh with respect to a dependency graph if+-- there are no two rule instances that remove the same fact built from fa.+--+-- We are looking for sufficient criterion to prove that a fact symbol is+-- globally fresh.+--+-- The Fr symbol is globally fresh by construction.+--+-- We have to track every creation of a globally fresh fact to a Fr fact.+--+-- (And show that the equality of of the created fact implies the equality of+-- the corresponding fresh facts. Ignore this for now by assuming that no+-- duplication happens.)+--+-- (fa(x1), fr(y1)), (fa(x2), fr(y2)) : x2 = x1 ==> y1 == y2+--+-- And ensure that every duplication is non-unifiable.+--+-- A Fr fact is described +--+-- We track which symbols are not globally fresh.+--+-- All persistent facts are not globally fresh.+--+-- Adding a rule ru.+-- All fact symbols that occur twice in the conclusion+--+-- For simplicity: globally fresh fact symbols occur at most once in premise+-- and conclusion of a rule.+-- +-- A fact is removed by a rule if it occurs in the rules premise+-- 1. but doesn't occur in the rule's conclusion+-- 2. or does occur but non-unifiable.+--+-- We want a sufficient criterion to prove that a fact is globally unique.+--+--++------------------------------------------------------------------------------+-- Pretty-Printing+------------------------------------------------------------------------------++prettyProtoRuleName :: Document d => ProtoRuleName -> d+prettyProtoRuleName rn = text $ case rn of+ FreshRule -> "Fresh"+ IRecvRule -> "IRecv"+ ISendRule -> "ISend"+ StandRule n + | n `elem` ["Fresh", "IRecv", "ISend"] -> "_" ++ n+ | "_" `isPrefixOf` n -> "_" ++ n+ | otherwise -> n++prettyRuleName :: (HighlightDocument d, HasRuleName (Rule i)) => Rule i -> d+prettyRuleName = ruleInfo prettyProtoRuleName prettyIntrRuleACInfo . ruleName++-- | Pretty print the rule name such that it can be used as a case name+showRuleCaseName :: HasRuleName (Rule i) => Rule i -> String+showRuleCaseName = + render . ruleInfo prettyProtoRuleName prettyIntrRuleACInfo . ruleName++prettyIntrRuleACInfo :: Document d => IntrRuleACInfo -> d+prettyIntrRuleACInfo (IntrApp name) = text $ name+prettyIntrRuleACInfo CoerceRule = text "coerce"++prettyNamedRule :: (HighlightDocument d, HasRuleName (Rule i))+ => d -- ^ Prefix.+ -> (i -> d) -- ^ Rule info pretty printing.+ -> Rule i -> d+prettyNamedRule prefix ppInfo ru =+ prefix <-> prettyRuleName ru <> colon $-$+ nest 2 (sep [ nest 1 $ ppFactsList rPrems+ , if null (L.get rActs ru) + then operator_ "-->"+ else fsep [operator_ "--[", ppFacts rActs, operator_ "]->"]+ , nest 1 $ ppFactsList rConcs]) $--$+ nest 2 (ppInfo $ L.get rInfo ru)+ where+ ppList pp = fsep . punctuate comma . map pp+ ppFacts proj = ppList prettyLNFact $ L.get proj ru+ ppFactsList proj = fsep [operator_ "[", ppFacts proj, operator_ "]"]++prettyProtoRuleACInfo :: HighlightDocument d => ProtoRuleACInfo -> d+prettyProtoRuleACInfo i =+ (ppVariants $ pracVariants i)+ where+ ppVariants (Disj [subst]) | subst == emptySubstVFresh = emptyDoc+ ppVariants substs = kwVariantsModulo "AC" $-$ prettyDisjLNSubstsVFresh substs++prettyProtoRuleE :: HighlightDocument d => ProtoRuleE -> d+prettyProtoRuleE = prettyNamedRule (kwRuleModulo "E") (const emptyDoc)++prettyRuleAC :: HighlightDocument d => RuleAC -> d+prettyRuleAC = + prettyNamedRule (kwRuleModulo "AC") + (ruleInfo prettyProtoRuleACInfo (const emptyDoc))++prettyIntrRuleAC :: HighlightDocument d => IntrRuleAC -> d+prettyIntrRuleAC = prettyNamedRule (kwRuleModulo "AC") (const emptyDoc)++prettyProtoRuleAC :: HighlightDocument d => ProtoRuleAC -> d+prettyProtoRuleAC = prettyNamedRule (kwRuleModulo "AC") prettyProtoRuleACInfo++prettyRuleACInst :: HighlightDocument d => RuleACInst -> d+prettyRuleACInst = prettyNamedRule (kwInstanceModulo "AC") (const emptyDoc)++-- derived instances+--------------------++$( derive makeBinary ''Rule)+$( derive makeBinary ''ProtoRuleName)+$( derive makeBinary ''ProtoRuleACInfo)+$( derive makeBinary ''RuleInfo)+$( derive makeBinary ''IntrRuleACInfo)++$( derive makeNFData ''Rule)+$( derive makeNFData ''ProtoRuleName)+$( derive makeNFData ''ProtoRuleACInfo)+$( derive makeNFData ''RuleInfo)+$( derive makeNFData ''IntrRuleACInfo)
@@ -0,0 +1,87 @@+{-# LANGUAGE GeneralizedNewtypeDeriving, FlexibleInstances, StandaloneDeriving, TypeSynonymInstances #-}+-- |+-- Copyright : (c) 2010-2012 Benedikt Schmidt+-- License : GPL v3 (see LICENSE)+-- +-- Maintainer : Benedikt Schmidt <beschmi@gmail.com>+-- Portability : GHC only+--+-- Variants of protocol rules.+module Theory.RuleVariants where++import Theory.Rule+import Term.Rewriting.Norm+import Term.Narrowing.Variants+import Theory.Proof.EquationStore++import Extension.Prelude+import Logic.Connectives++import Control.Monad.Reader+import Control.Monad.Bind+import Control.Applicative++import qualified Data.Map as M+import Data.Traversable (traverse)++import Debug.Trace.Ignore++-- Variants of protocol rules+----------------------------------------------------------------------++-- | Compute the variants of a protocol rule.+-- 1. Abstract away terms in facts with variables.+-- 2. Compute variants of RHSs of equations.+-- 3. Apply variant substitutions to equations+-- to obtain DNF of equations.+-- 4. Simplify rule.+variantsProtoRule :: MaudeHandle -> ProtoRuleE -> ProtoRuleAC+variantsProtoRule hnd ru@(Rule ri prems0 concs0 acts0) =+ -- rename rule to decrease variable indices+ (`evalFresh` nothingUsed) . rename $ convertRule `evalFreshAvoiding` ru+ where+ convertRule = do+ (abstrPsCsAs, bindings) <- abstrRule+ let eqsAbstr = map swap (M.toList bindings)+ abstractedTerms = map snd eqsAbstr+ abstractionSubst = substFromList eqsAbstr+ variantSubsts = computeVariants (listToTerm abstractedTerms) `runReader` hnd+ substs = [ restrictVFresh (frees abstrPsCsAs) $+ removeRenamings $ ((`runReader` hnd) . normSubstVFresh') $+ composeVFresh vsubst abstractionSubst+ | vsubst <- variantSubsts ]++ case substs of+ [] -> error $ "variantsProtoRule: rule has no variants `"++show ru++"'"+ _ -> do+ -- x <- return (emptySubst, Just substs) -- + x <- simpDisjunction hnd (Disj substs)+ case trace (show ("SIMP",abstractedTerms,+ "abstr", abstrPsCsAs,+ "substs", substs,+ "simpSubsts:", x)) x of+ -- the variants can be simplified to a single case+ (commonSubst, Nothing) ->+ return $ makeRule abstrPsCsAs commonSubst trueDisj+ (commonSubst, Just freshSubsts) ->+ return $ makeRule abstrPsCsAs commonSubst freshSubsts++ abstrRule = (`runBindT` noBindings) $ do+ -- first import all vars into binding to obtain nicer names+ mapM_ abstrTerm [ varTerm v | v <- frees (prems0, concs0, acts0) ]+ (,,) <$> mapM abstrFact prems0+ <*> mapM abstrFact concs0+ <*> mapM abstrFact acts0+ abstrFact = traverse abstrTerm+ abstrTerm t = varTerm <$> importBinding (`LVar` sortOfLNTerm t) t (getHint t)+ where getHint (Lit (Var v)) = lvarName v+ getHint _ = "z"++ makeRule (ps, cs, as) subst freshSubsts0 =+ Rule (ProtoRuleACInfo ri (Disj freshSubsts)) prems concs acts+ where prems = apply subst ps+ concs = apply subst cs+ acts = apply subst as+ freshSubsts = map (restrictVFresh (frees (prems, concs, acts))) freshSubsts0++ trueDisj = [ emptySubstVFresh ]
@@ -0,0 +1,196 @@+{-# LANGUAGE TemplateHaskell, DeriveDataTypeable, DeriveFunctor #-}+{-# LANGUAGE StandaloneDeriving, TypeSynonymInstances #-}+{-# LANGUAGE TypeOperators,FlexibleInstances #-}+-- |+-- Copyright : (c) 2010-2012 Benedikt Schmidt & Simon Meier+-- License : GPL v3 (see LICENSE)+-- +-- Maintainer : Simon Meier <iridcode@gmail.com>+-- Portability : portable+--+-- Signatures for the terms and multiset rewriting rules used to model and+-- reason about a security protocol.+-- modulo the full Diffie-Hellman equational theory and once modulo AC.+module Theory.Signature (++ -- * Signature type+ Signature(..)+ + -- ** Pure signatures+ , SignaturePure+ , emptySignaturePure+ , sigpUniqueInsts+ , sigpMaudeSig++ -- ** Using Maude to handle operations relative to a 'Signature'+ , SignatureWithMaude+ , toSignatureWithMaude+ , toSignaturePure+ , sigmUniqueInsts+ , sigmMaudeHandle++ -- ** Pretty-printing+ , prettySignaturePure+ , prettySignatureWithMaude++ ) where++import qualified Data.Set as S+import qualified Data.Label as L++import Control.Applicative+import Control.DeepSeq++import Theory.Pretty+import Theory.Fact+import Term.Maude.Types++import Data.Binary++import System.IO.Unsafe (unsafePerformIO)++-- | A theory signature.+data Signature a = Signature+ { _sigUniqueInsts :: S.Set FactTag+ -- ^ Fact symbols that are assumed to have unique instances.+ , _sigMaudeInfo :: a+ }++$(L.mkLabels [''Signature])+++------------------------------------------------------------------------------+-- Pure Signatures+------------------------------------------------------------------------------++-- | A 'Signature' without an associated Maude process.+type SignaturePure = Signature MaudeSig++-- | Access the globally fresh field.+sigpUniqueInsts :: SignaturePure L.:-> S.Set FactTag+sigpUniqueInsts = sigUniqueInsts++-- | Access the maude signature.+sigpMaudeSig:: SignaturePure L.:-> MaudeSig+sigpMaudeSig = sigMaudeInfo++-- | The empty pure signature.+emptySignaturePure :: SignaturePure+emptySignaturePure = Signature S.empty emptyMaudeSig++-- Instances+------------++deriving instance Eq SignaturePure+deriving instance Ord SignaturePure+deriving instance Show SignaturePure++instance Binary SignaturePure where+ put sig = put (L.get sigUniqueInsts sig)+ >> put (L.get sigMaudeInfo sig)+ get = Signature <$> get <*> get++instance NFData SignaturePure where+ rnf (Signature x y) = rnf x `seq` rnf y++------------------------------------------------------------------------------+-- Signatures with an attached Maude process+------------------------------------------------------------------------------++-- | A 'Signature' with an associated, running Maude process.+type SignatureWithMaude = Signature MaudeHandle+++-- | Access the facts that are declared as globally fresh.+sigmUniqueInsts :: SignatureWithMaude L.:-> S.Set FactTag+sigmUniqueInsts = sigUniqueInsts++-- | Access the maude handle in a signature.+sigmMaudeHandle :: SignatureWithMaude L.:-> MaudeHandle+sigmMaudeHandle = sigMaudeInfo++-- | Ensure that maude is running and configured with the current signature.+toSignatureWithMaude :: FilePath -- ^ Path to Maude executable.+ -> SignaturePure+ -> IO (SignatureWithMaude)+toSignatureWithMaude maudePath sig = do+ hnd <- startMaude maudePath (L.get sigMaudeInfo sig)+ return $ sig { _sigMaudeInfo = hnd }+++-- | The pure signature of a 'SignatureWithMaude'.+toSignaturePure :: SignatureWithMaude -> SignaturePure+toSignaturePure sig = sig { _sigMaudeInfo = mhMaudeSig $ L.get sigMaudeInfo sig }++{- TODO: There should be a finalizer in place such that as soon as the+ MaudeHandle is garbage collected, the appropriate command is sent to Maude++ The code below is a crutch and leads to unnecessary complication.++ +-- | Stop the maude process. This operation is unsafe, as there still might be+-- thunks that rely on the MaudeHandle to refer to a running Maude process.+unsafeStopMaude :: SignatureWithMaude -> IO (SignaturePure)+unsafeStopMaude = error "unsafeStopMaude: implement"++-- | Run an IO action with maude running and configured with a specific+-- signature. As there must not be any part of the return value that depends+-- on unevaluated calls to the Maude process provided to the inner IO action.+unsafeWithMaude :: FilePath -- ^ Path to Maude executable+ -> SignaturePure -- ^ Signature to use+ -> (SignatureWithMaude -> IO a) -> IO a+unsafeWithMaude maudePath sig =+ bracket (startMaude maudePath sig) unsafeStopMaude ++-}++-- Instances+------------++instance Eq SignatureWithMaude where+ x == y = toSignaturePure x == toSignaturePure y++instance Ord SignatureWithMaude where+ compare x y = compare (toSignaturePure x) (toSignaturePure y)++instance Show SignatureWithMaude where+ show = show . toSignaturePure++instance Binary SignatureWithMaude where+ put sig@(Signature _ maude) = do+ put (mhFilePath maude)+ put (toSignaturePure sig)+ -- FIXME: reload the right signature+ get = unsafePerformIO <$> (toSignatureWithMaude <$> get <*> get)++instance NFData SignatureWithMaude where+ rnf (Signature x _maude) = rnf x++------------------------------------------------------------------------------+-- Pretty-printing+------------------------------------------------------------------------------++-- | Pretty-print a signature with maude.+prettySignaturePure :: HighlightDocument d => SignaturePure -> d+prettySignaturePure sig = foldr ($--$) emptyDoc $ map combine $+ [ ("unique_insts", ppGFresh $ uniqueInsts) | not $ null uniqueInsts ]+ -- FIXME: Print Maude signature completely, this is only used for+ -- intruder-variants for now.+ ++ [ ("builtin", text "diffie-hellman" ) | enableDH . L.get sigpMaudeSig $ sig ]+ where+ uniqueInsts = S.toList $ L.get sigpUniqueInsts sig+ combine (header, d) = fsep [keyword_ header <> colon, nest 2 d]+ ppGFresh = fsep . punctuate comma . map (text . showFactTagArity)+ +-- | Pretty-print a pure signature.+prettySignatureWithMaude :: HighlightDocument d => SignatureWithMaude -> d+prettySignatureWithMaude sig = foldr ($--$) emptyDoc $+ (map combine+ [ ("unique_insts", ppGFresh $ uniqueInsts) | not $ null uniqueInsts ]+ ) +++ [ prettyMaudeSig $ mhMaudeSig $ L.get sigmMaudeHandle sig ]+ where+ uniqueInsts = S.toList $ L.get sigmUniqueInsts sig+ combine (header, d) = fsep [keyword_ header <> colon, nest 2 d]+ ppGFresh = fsep . punctuate comma . map (text . showFactTagArity)+
@@ -0,0 +1,440 @@+-- |+-- Copyright : (c) 2010-2012 Simon Meier & Benedikt Schmidt+-- License : GPL v3 (see LICENSE)+-- +-- Maintainer : Simon Meier <iridcode@gmail.com>+-- Portability : GHC only+--+-- Wellformedness checks for intruder variants, protocol rules, and+-- properties.+--+-- The following checks are/should be performed +-- (FIXME: compare the list below to what is really implemented.)+-- +-- [protocol rules] +--+-- 1. all facts are used with the same arity.+--+-- 2. fr, in, and out, facts are used with arity 1.+--+-- 3. fr facts are used with a variable of sort msg or sort fresh+--+-- 5. fresh facts of the same rule contain different variables. [TODO]+--+-- 4. no fr, or in facts in conclusions.+--+-- 5. no out facts in premises.+--+-- 6. no protocol fact uses a reserved name => +-- [TODO] change parser to ensure this and pretty printer to show this.+--+-- [security properties]+--+-- 1. all facts occur with the same arity in the action of some+-- protocol rule.+--+-- 2. no node variable is used in a message position and vice versa.+--+--+module Theory.Wellformedness (++ -- * Wellformedness checking+ WfErrorReport+ , checkWellformedness+ , noteWellformedness++ , prettyWfErrorReport+ ) where++import Prelude hiding (id, (.))++import Data.Char+import Data.Generics.Uniplate.Data (universeBi)+import Data.List+import Data.Label+import Data.Maybe+import Data.Monoid (mempty, mappend)+import qualified Data.Set as S+import Control.Basics+import Control.Category++import Extension.Prelude+import Text.Isar+import Theory++------------------------------------------------------------------------------+-- Types for error reports+------------------------------------------------------------------------------++type Topic = String+type WfError = (Topic, Doc)+type WfErrorReport = [WfError]++prettyWfErrorReport :: WfErrorReport -> Doc+prettyWfErrorReport [] = text "All well-formedness checks were successful."+prettyWfErrorReport report = foldr1 ($-$)+ [ text "Error: the following well-formedness checks failed!"+ , text ""+ , vcat . intersperse (text "") . map ppTopic $ groupOn fst report+ ]+ where+ ppTopic [] = error "prettyWfErrorReport: groupOn returned empty list"+ ppTopic errs@((topic,_):_) =+ text topic <> colon $-$ + (nest 2 . vcat . intersperse (text "") $ map snd errs)+ ++------------------------------------------------------------------------------+-- Utilities+------------------------------------------------------------------------------++-- | All protocol rules of a theory.+-- thyProtoRules :: OpenTheory ->+thyProtoRules :: OpenTheory -> [ProtoRuleE]+thyProtoRules thy = [ ru | RuleItem ru <- get thyItems thy ]+ +-- | Lower-case a string.+lowerCase :: String -> String+lowerCase = map toLower++-- | Pretty-print a comman, separated list of 'LVar's.+prettyVarList :: Document d => [LVar] -> d+prettyVarList = fsep . punctuate comma . map prettyLVar++-- | Wrap strings at word boundaries.+wrappedText :: Document d => String -> d+wrappedText = fsep . map text . words++-- | Clashes+clashesOn :: (Ord b, Ord c)+ => (a -> b) -- ^ This projection+ -> (a -> c) -- ^ must determine this projection.+ -> [a] -> [[a]]+clashesOn f g xs = do+ grp <- groupOn f $ sortOn f xs+ guard (length (sortednubOn g grp) >= 2)+ return grp+ +-- | Nice quoting.+quote :: String -> String+quote cs = '`' : cs ++ "'"++------------------------------------------------------------------------------+-- Checks+------------------------------------------------------------------------------++--- | Check that the protocol rules are well-formed.+sortsClashCheck :: HasFrees t => String -> t -> WfErrorReport+sortsClashCheck info t = case clashesOn removeSort id $ frees t of+ [] -> []+ cs -> return $ + ( "sorts"+ , text info $-$ (nest 2 $ numbered' $ map prettyVarList cs)+ )+ where+ removeSort lv = (lowerCase (lvarName lv), lvarIdx lv)++-- | Report on sort clashes.+ruleSortsReport :: OpenTheory -> WfErrorReport+ruleSortsReport thy = do+ ru <- thyProtoRules thy+ sortsClashCheck ("rule " ++ quote (showRuleCaseName ru) ++ + " clashing sorts, casings, or multiplicities:") ru++-- | Report on fresh names.+freshNamesReport :: OpenTheory -> WfErrorReport+freshNamesReport thy = do+ ru <- thyProtoRules thy+ case filter ((LSortFresh ==) . sortOfName) $ universeBi ru of+ [] -> []+ names -> return $ (,) "fresh names" $ fsep $+ text ( "rule " ++ quote (showRuleCaseName ru) ++ ": " +++ "fresh names are not allowed in rule:" )+ : punctuate comma (map (nest 2 . text . show) names)++-- | Report on capitalization of public names.+publicNamesReport :: OpenTheory -> WfErrorReport+publicNamesReport thy =+ case findClashes publicNames of+ [] -> []+ clashes -> return $ (,) topic $ numbered' $+ map (nest 2 . fsep . punctuate comma . map ppRuleAndName) clashes+ where+ topic = "public names with mismatching capitalization"+ publicNames = do+ ru <- thyProtoRules thy+ (,) (showRuleCaseName ru) <$> + (filter ((LSortPub ==) . sortOfName) $ universeBi ru)+ findClashes = clashesOn (map toLower . show . snd) (show . snd)+ ppRuleAndName (ruName, pub) = + text $ "rule " ++ show ruName ++ " name " ++ show pub++-- | Check whether a rule has unbound variables.+unboundCheck :: HasFrees i => String -> Rule i -> WfErrorReport+unboundCheck info ru+ | null unboundVars = []+ | otherwise = return $+ ( "unbound"+ , text info $-$ (nest 2 $ prettyVarList unboundVars) )+ where + boundVars = S.fromList $ frees (get rPrems ru)+ unboundVars = do+ v <- frees (get rConcs ru, get rActs ru, get rInfo ru)+ guard $ not (lvarSort v == LSortPub || v `S.member` boundVars)+ return v++-- | Report on sort clashes.+unboundReport :: OpenTheory -> WfErrorReport+unboundReport thy = do+ RuleItem ru <- get thyItems thy+ unboundCheck ("rule " ++ quote (showRuleCaseName ru) ++ + " has unbound variables: "+ ) ru++-- | Report on facts usage.+factReports :: OpenTheory -> WfErrorReport+factReports thy = concat+ [ reservedReport, freshFactArguments, specialFactsUsage+ , factUsage, inexistentActions+ ]+ where+ ruleFacts ru = + ( "rule " ++ quote (showRuleCaseName ru)+ , extFactInfo <$> concatMap (`get` ru) [rPrems, rActs, rConcs])++ -- FIXME: Possibly the check that term arity agrees with fact-tag arity+ -- should be made here instead of just throwing an error, as implemented+ -- in 'factArity'.++ theoryFacts = -- sortednubOn (fst &&& (snd . snd)) $+ do ruleFacts <$> get thyCache thy+ <|> do RuleItem ru <- get thyItems thy+ return $ ruleFacts ru+ <|> do LemmaItem (Lemma name fmE _ _ _) <- get thyItems thy+ return $ (,) ("lemma " ++ quote name) $ do+ fa <- formulaFacts fmE+ return $ (text (show fa), factInfo fa)+ <|> do return $ (,) "unique_insts declaration" $ do+ tag <- S.toList $ get (sigpUniqueInsts . thySignature) thy + return $ ( text $ showFactTagArity tag+ , (tag, factTagArity tag, factTagMultiplicity tag)+ )++ -- we must compute all important information up-front in order to+ -- mangle facts with terms with bound variables and such without them+ extFactInfo fa = (prettyLNFact fa, factInfo fa)++ factInfo :: Fact t -> (FactTag, Int, Multiplicity)+ factInfo fa = (factTag fa, factArity fa, factMultiplicity fa)++ --- Check for usage of protocol facts with reserved names+ reservedReport = do+ (origin, fas) <- theoryFacts+ case mapMaybe reservedFactName fas of+ [] -> []+ errs -> return $ (,) "reseved names" $ foldr1 ($--$) $+ wrappedText ("The " ++ origin ++ + " contains facts with reserved names:")+ : map (nest 2) errs ++ reservedFactName (ppFa, info@(ProtoFact _ name _, _,_))+ | map toLower name `elem` ["fr","ku","kd","out","in"] =+ return $ ppFa $-$ text ("show:" ++ show info)+ reservedFactName _ = Nothing++ freshFactArguments = do+ ru <- thyProtoRules thy+ fa@(Fact FreshFact [m]) <- get rPrems ru+ guard (not (isMsgVar m || isFreshVar m))+ return $ (,) "Fr facts must only use a fresh- or a msg-variable" $+ text ("rule " ++ quote (showRuleCaseName ru)) <->+ text "fact:" <-> prettyLNFact fa++ -- Check for the usage of special facts at wrong positions+ specialFactsUsage = do+ ru <- thyProtoRules thy+ let lhs = [ fa | fa <- get rPrems ru+ , factTag fa `elem` [KUFact, KDFact, OutFact] ]+ rhs = [ fa | fa <- get rConcs ru+ , factTag fa `elem` [FreshFact, KUFact, KDFact, InFact] ]+ check _ [] = mzero+ check msg fas = return $ (,) "special fact usage" $+ text ("rule " ++ quote (showRuleCaseName ru)) <-> text msg $-$+ (nest 2 $ fsep $ punctuate comma $ map prettyLNFact fas)++ msum [ check "uses disallowed facts on left-hand-side:" lhs+ , check "uses disallowed facts on right-hand-side:" rhs ]++ -- Check for facts with equal name modulo capitalization, but different+ -- multiplicity or arity.+ factUsage = do+ clash <- clashesOn factIdentifier (snd . snd) theoryFacts'+ return $ (,) "fact usage" $ numbered' $ do+ (origin, (ppFa, info@(tag, _, _))) <- clash+ return $ text (origin +++ ", fact " ++ show (map toLower $ showFactTag tag) +++ ": " ++ showInfo info)+ $-$ nest 2 ppFa+ where+ showInfo (tag, k, mult) = show $ (showFactTag tag, k, mult)+ theoryFacts' = [ (ru, fa) | (ru, fas) <- theoryFacts, fa <- fas ]+ factIdentifier (_, (_, (tag, _, _))) = map toLower $ showFactTag tag+++ -- Check that every fact referenced in a formula is present as an action+ -- of a protocol rule. We have to add the linear "K/1" fact, as the+ -- WF-check cannot rely on a loaded intruder theory.+ ruleActions = S.fromList $ ((factInfo (kLogFact undefined)) :) $+ do RuleItem ru <- get thyItems thy+ factInfo <$> get rActs ru++ inexistentActions = do+ LemmaItem (Lemma name fmE _ _ _) <- get thyItems thy+ fa <- sortednub $ formulaFacts fmE+ let info = factInfo fa+ if info `S.member` ruleActions + then []+ else return $ (,) "lemma actions" $+ text ("lemma " ++ quote name ++ " references action ") $-$+ nest 2 (text $ show info) $-$+ text "but no rule has such an action."++ + +-- | Gather all facts referenced in a formula.+formulaFacts :: Formula s c v -> [Fact (VTerm c (BVar v))]+formulaFacts = + foldFormula atomFacts + (const mempty) + id + (const mappend) (const $ const id)+ where+ atomFacts (Action _ fa) = [fa]+ atomFacts (EqE _ _) = mempty+ atomFacts (Less _ _) = mempty+ atomFacts (Last _) = mempty+ atomFacts (DedBefore _ _) = mempty+ atomFacts (EdgeA _ _) = mempty++-- | Gather all terms referenced in a formula.+formulaTerms :: Formula s c v -> [VTerm c (BVar v)]+formulaTerms = + foldFormula atomTerms (const mempty) id (const mappend) (const $ const id)+ where+ atomTerms (Action i fa) = i : factTerms fa+ atomTerms (EqE t s) = [t, s]+ atomTerms (Less i j) = [i, j]+ atomTerms (Last i) = [i]+ atomTerms (DedBefore t i) = [t, i]+ atomTerms (EdgeA x y) = [fst x, fst y]+++-- | Check for mistakes in lemmas.+--+-- TODO: Perhaps a lot of errors would be captured when making the signature+-- of facts, term, and atom constructors explicit.+formulaReports :: OpenTheory -> WfErrorReport+formulaReports thy = do+ LemmaItem (Lemma name fmE _ _ _) <- get thyItems thy+ let header = "lemma " ++ quote name + msum [ ((,) "quantifier sorts") <$> checkQuantifiers header fmE+ , ((,) "formula terms") <$> checkTerms header fmE+ , ((,) "guardedness") <$> checkGuarded header fmE + ]+ where+ -- check that only message and node variables are used+ checkQuantifiers header fm+ | null disallowed = []+ | otherwise = return $ fsep $ + (text $ header ++ "uses quantifiers with wrong sort:") :+ (punctuate comma $ map (nest 2 . text . show) disallowed)+ where+ binders = foldFormula (const mempty) (const mempty) id (const mappend) + (\_ binder rest -> binder : rest) fm+ disallowed = filter (not . (`elem` [LSortMsg, LSortNode]) . snd) binders++ -- check that only bound variables and public names are used+ checkTerms header fm+ | null offenders = []+ | otherwise = return $ + (fsep $+ (text $ header ++ " uses terms of the wrong form:") :+ (punctuate comma $ map (nest 2 . text . quote . show) offenders)+ ) $--$+ wrappedText + "The only allowed terms are public names and bound node and message\+ \ variables. If you encounter free message variables, then you might\+ \ have forgotten a #-prefix. Sort prefixes can only be dropped where\+ \ this is unambiguous"+ where+ offenders = filter (not . allowed) $ formulaTerms fm+ allowed (Lit (Var (Bound _))) = True+ allowed (Lit (Con (Name PubName _))) = True+ allowed _ = False++ -- check that the formula can be converted to a guarded formula+ checkGuarded header fm = case fromFormulaNegate fm of+ Left err -> return $ + text (header ++ " cannot be converted to a guarded formula:") $-$+ nest 2 (text err)+ Right _ -> []++ ++uniqueInstsReport :: OpenTheory -> WfErrorReport+uniqueInstsReport thy = do+ tag <- S.toList $ get (sigpUniqueInsts . thySignature) thy+ (,) "unique fact instances" <$> + if (Persistent == factTagMultiplicity tag)+ then return $ text $ showFactTagArity tag ++ " is persistent"+ else msum + [ checkAtMostOneConc tag+ , checkCopying tag+ ]+ where+ checkAtMostOneConc tag = do+ ru <- thyProtoRules thy+ let occs = length $ filter ((tag ==) . factTag) $ get rConcs ru+ guard (occs > 1)+ return $ wrappedText $+ "Failed to prove unique fact instances of " +++ showFactTagArity tag ++ ", as it occurs " ++ show occs +++ " times as a conclusion of rule '" ++ showRuleCaseName ru ++ "'."++ checkCopying _f = [] -- FIXME: Implement check.+ {-+ (ru1, ru2) <- + where+ rules = + filter (any (any ((f ==) . factSymbol) . get rPrems)) $+ thyProtoRules thy+ -}++-- | All 2-multicombinations of a list.+-- multicombine2 :: [a] -> [(a,a)]+-- multicombine2 xs0 = do (x,xs) <- zip xs0 $ tails xs0; (,) x <$> xs+++------------------------------------------------------------------------------+-- Theory+------------------------------------------------------------------------------++++-- | Returns a list of errors, if there are any.+checkWellformedness :: OpenTheory+ -> WfErrorReport+checkWellformedness thy = concatMap ($ thy)+ [ unboundReport+ , freshNamesReport+ , publicNamesReport+ , ruleSortsReport + , factReports+ , formulaReports+ , uniqueInstsReport+ ]++-- | Adds a note to the end of the theory, if it is not well-formed.+noteWellformedness :: WfErrorReport -> OpenTheory -> OpenTheory+noteWellformedness report thy = addComment (prettyWfErrorReport report) thy+
@@ -0,0 +1,147 @@+{- |+Module : Web.Dispatch+Description : Yesod dispatch functions and default handlers.+Copyright : (c) 2011 Cedric Staub+License : GPL-3++Maintainer : Cedric Staub <cstaub@ethz.ch>+Stability : experimental+Portability : non-portable+-}++{-# LANGUAGE MultiParamTypeClasses, OverloadedStrings, TemplateHaskell, TupleSections #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+-- FIXME: See how we can get rid of the Template Haskell induced warning, such+-- that we have the warning again for our code.+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}++module Web.Dispatch + ( withWebUI + )+where++import Theory+import Web.Types+import Web.Handler+import Web.Settings++import Yesod.Core+import Yesod.Helpers.Static+import Network.Wai++import qualified Data.Map as M+import qualified Data.Text as T+import qualified Data.ByteString as B+import qualified Control.Exception as E+import qualified Data.Binary as Bin++import Data.List+import Data.Maybe+import Data.Time.LocalTime+import Control.Concurrent+import Control.Monad+import Control.Applicative+import Control.Monad.IO.Class++import System.FilePath+import System.Directory++-- | Create YesodDispatch instance for the interface.+mkYesodDispatch "WebUI" resourcesWebUI++-- | Static route for favicon file.+faviconRoute :: StaticRoute+faviconRoute = StaticRoute ["img", "favicon.ico"] []++-- | Favicon handler function (favicon.ico).+getFaviconR :: Handler ()+getFaviconR = redirect RedirectPermanent (StaticR faviconRoute)++-- | Robots file handler function (robots.txt).+getRobotsR :: Handler RepPlain+getRobotsR = return $ RepPlain $ toContent ("User-agent: *" :: B.ByteString)++-- | Initialization function for the web application.+withWebUI :: FilePath -- ^ Working directory.+ -> Bool -- ^ Load last proof state if present+ -> Bool -- ^ Automatically save proof state+ -> (FilePath -> IO ClosedTheory) -- ^ Theory loader (from file).+ -> (String -> IO ClosedTheory) -- ^ Theory loader (from string).+ -> (OpenTheory -> IO ClosedTheory) -- ^ Theory closer.+ -> Bool -- ^ Show debugging messages?+ -> Maybe FilePath -- ^ Path to static content directory+ -> (Application -> IO b) -- ^ Function to execute+ -> IO b+withWebUI thDir loadState autosave thLoader thParser thCloser debug' stPath f = do+ thy <- getTheos+ thrVar <- newMVar M.empty+ thyVar <- newMVar thy+ when autosave $ createDirectoryIfMissing False autosaveDir+ (`E.finally` shutdownThreads thrVar) $+ f =<< toWaiApp WebUI+ { workDir = thDir + , parseThy = liftIO . thParser+ , closeThy = thCloser+ , getStatic = static $ fromMaybe defaultStaticDir stPath+ , theoryVar = thyVar+ , threadVar = thrVar+ , autosaveProofstate = autosave+ , debug = debug'+ }+ where+ autosaveDir = thDir++"/"++autosaveSubdir+ getTheos = do+ existsAutosave <- doesDirectoryExist autosaveDir+ if loadState && existsAutosave+ then do+ putStrLn "Using persistent server state ... server ready."+ files <- getDirectoryContents autosaveDir+ thys <- (`mapM` files) $ \fn ->+ case break (`notElem` ['0'..'9']) fn of+ (idx,".img") -> do+ let file = thDir++"/"++autosaveSubdir++fn+ Just . (read idx,) <$> Bin.decodeFile file+ _ -> return Nothing+ return $ M.fromList $ catMaybes thys++ else loadTheories thDir thLoader++ shutdownThreads thrVar = do+ m <- modifyMVar thrVar $ \m -> return (M.empty, m)+ putStrLn $ "Server shutdown: " ++ show (M.size m) ++ " threads still running"+ forM (M.toList m) $ \(str, tid) -> do+ putStrLn $ "killing: " ++ T.unpack str+ killThread tid+++-- | Load theories from the current directory, generate map.+loadTheories :: FilePath -> (FilePath -> IO ClosedTheory) -> IO TheoryMap+loadTheories thDir thLoader = do+ mkImageDir+ thPaths <- filter (".spthy" `isSuffixOf`) <$> getDirectoryContents thDir+ theories <- catMaybes <$> mapM loadThy (zip [1..] (map (thDir </>) thPaths))+ putStrLn ""+ putStrLn "Finished loading theories ... server ready."+ return $ M.fromList theories+ where+ -- Create image directory+ mkImageDir = do+ let dir = thDir </> imageDir+ existsDir <- doesDirectoryExist dir+ unless existsDir (createDirectory dir)+ + -- Load theories+ loadThy (idx, path) = E.handle catchEx $ do+ thy <- thLoader path+ time <- getZonedTime+ return $ Just (idx, TheoryInfo idx thy time Nothing True (Local path))+ where+ -- Exception handler (if loading theory fails)+ catchEx :: E.SomeException -> IO (Maybe (TheoryIdx, TheoryInfo))+ catchEx e = do+ putStrLn ""+ putStrLn $ replicate 78 '-'+ putStrLn $ "Unable to load theory file `" ++ path ++ "'"+ putStrLn $ replicate 78 '-'+ print e+ return Nothing
@@ -0,0 +1,342 @@+{- |+Module : Web.Hamlet+Description : Hamlet templates.+Copyright : (c) 2011 Cedric Staub+License : GPL-3++Maintainer : Cedric Staub <cstaub@ethz.ch>+Stability : experimental+Portability : non-portable+-}++{-# LANGUAGE+ TypeFamilies, QuasiQuotes, TypeSynonymInstances, + PatternGuards, FlexibleInstances, CPP #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++module Web.Hamlet where++import Theory+import Web.Types+import Web.Theory+import Data.Label+import Text.PrettyPrint.Html++import Yesod.Core+import Yesod.Form+import Text.Hamlet++import Data.Ord+import Data.List+import Data.Time.Format+import Data.Version (showVersion)+import qualified Data.Map as M+import qualified Data.Text as T++import Control.Monad.RWS (runRWST)+import qualified Control.Exception as E+import System.Locale++import Paths_tamarin_prover (version)++-- Quasi-quotation syntax changed from GHC 6 to 7,+-- so we need this switch in order to support both+#if __GLASGOW_HASKELL__ >= 700+#define HAMLET hamlet+#else+#define HAMLET $hamlet+#endif++--+-- Wrappers+--++-- | Wrapper for @HtmlDoc@ values.+wrapHtmlDoc :: HamletValue h => HtmlDoc Doc -> h+wrapHtmlDoc doc+ | null res = exceptionTpl err+ | otherwise = [HAMLET|#{preEscapedString res}|]+ where+ res = renderHtmlDoc doc+ err = "Trying to render document yielded empty string. This is a bug."++-- | Run a ThHtml value, catch exceptions.+wrapThHtml :: HamletValue h => HtmlDoc Doc -> IO h+wrapThHtml th = E.catch (return $ wrapHtmlDoc th) handleEx+ where+ handleEx :: HamletValue h => E.SomeException -> IO h+ handleEx e = do+ putStrLn "----------------"+ putStrLn "Caught exception"+ putStrLn "----------------"+ print e+ return (exceptionTpl (show e))++--+-- Templates+--++-- | Exception/error template.+exceptionTpl :: HamletValue h => String -> h+exceptionTpl err = [HAMLET|+ <h1>Caught exception!+ \#{err}+ |]++-- | Simple template for serving sites which are loaded through+-- AJAX instead of a normal request (no html/head/body tags).+--+-- Note: Don't use ajaxLayout and defaultLayout together, use+-- only one or the other.+ajaxLayout :: Monad m => GenericWidget m () -> GenericHandler m RepHtml+ajaxLayout w = do+ (body, _, _) <- runRWST (unGWidget $ extractBody w) () 0+ hamletToRepHtml [HAMLET|^{body}|]++-- | Template for root/welcome page.+rootTpl :: (HamletValue h, HamletUrl h ~ WebUIRoute, h ~ Widget ())+ => TheoryMap -- ^ Map of loaded theories+ -> Widget () -- ^ Form widget (for loading new theories)+ -> Enctype -- ^ Form encoding type (for form)+ -> Html -- ^ Nonce field (for form)+ -> h+rootTpl theories form enctype nonce = [HAMLET|+ \^{introTpl}+ <h2>Currently loaded theories+ <p+ Here is a list of the theories that are currently loaded.<br/>+ \^{theoriesTpl theories}+ <h2>Loading a new theory+ <p+ You can load a new theory file from disk in order to work with it.+ <form class=root-form action=@{RootR} method=POST enctype=#{enctype}>+ ^{form}+ <div .submit-form>+ ^{addHtml nonce}+ <input type=submit value="Load new theory">+ <p>Note: You can save a theory by downloading the source. + |]++-- | Template for listing theories.+theoriesTpl :: (HamletValue h, HamletUrl h ~ WebUIRoute) => TheoryMap -> h+theoriesTpl thmap = [HAMLET|+ $if M.null thmap+ <strong>No theories loaded!</strong>+ $else+ <table>+ <thead>+ <th>Theory name+ <th>Time+ <th>Version+ <th>Origin+ $forall tgroup <- processMap thmap+ ^{theoryTpl (head tgroup)}+ $forall th <- ntail 4 tgroup+ ^{theoryTpl th}+ <br>+ |]+ where+ processMap =+ groupBy (\x y -> comparing tiName x y == EQ) . + sortBy (comparing snd) . M.toList++ tiName = get thyName . tiTheory . snd++ ntail _ [] = []+ ntail i (_:xs)+ | length xs <= i = xs+ | otherwise = ntail i xs++-- | Template for single line in table on root page.+theoryTpl :: (HamletValue h, HamletUrl h ~ WebUIRoute)+ => (TheoryIdx, TheoryInfo) -> h+theoryTpl th = [HAMLET|+ <tr>+ <td>+ <a href=@{OverviewR (fst th)}>+ \#{get thyName $ tiTheory $ snd th}+ </a>+ <td>#{formatTime defaultTimeLocale "%T" $ tiTime $ snd th}+ $if tiPrimary (snd th)+ <td>Original+ $else+ <td><em>Modified</em>+ <td>#{origin th}+ |]+ where+ origin (_, ti) = case tiOrigin ti of+ Local path -> path+ Upload name -> name+ Interactive -> "(interactively created)"++-- | Template for listing threads.+threadsTpl :: (HamletValue h, HamletUrl h ~ WebUIRoute) => [T.Text] -> h+threadsTpl threads = [HAMLET|+ <h2>Threads+ <p>+ This page lists all threads that are currently registered as+ \ evaluating a request within the server. This is meant for debugging+ \ lockups within the server.+ $if null threads+ <strong>No threads registered!</strong>+ $else+ <table>+ <thead>+ <th>Request path+ <th>Kill?+ $forall th <- threads+ <tr>+ <td>#{th}+ <td><a href="@{KillThreadR}?path=#{th}">Kill</a>+ |]++-- | Template for header frame (various information)+headerTpl :: (HamletValue h, HamletUrl h ~ WebUIRoute)+ => TheoryInfo -- ^ Theory information+ -> h+headerTpl info = [HAMLET|+ <div #header-info>+ Running \+ <a href="http://www.infsec.ethz.ch/research/software#TAMARIN">tamarin prover</a>+ \ #{showVersion version}+ <div #header-links>+ <a class=plain-link href=@{RootR}>Index</a>+ <a class=plain-link href=@{DownloadTheoryR idx filename}>Download</a>+ <ul #navigation>+ <li><a href="#">Actions</a>+ <ul>+ <li><a target=_blank href=@{TheorySourceR idx}>Show source</a>+ <li><a href=@{TheoryVariantsR idx}>Show variants</a>+ <li><a class=edit-link href=@{EditTheoryR idx}>Edit theory</a>+ <li><a class=edit-link href=@{EditPathR idx (TheoryLemma "")}>Add lemma</a>+ <li><a href="#">Options</a>+ <ul>+ <li><a id=graph-toggle href="#">Compact graphs</a>+ <li><a id=seqnt-toggle href="#">Compress sequents</a>+ <li><a id=debug-toggle href="#">Debug pane</a>+ |]+ where+ idx = tiIndex info+ filename = get thyName (tiTheory info) ++ ".spthy"++ {- use this snipped to reactivate saving local theories+ localTheory (Local _) = True+ localTheory _ = False++ $if localTheory (tiOrigin info)+ <a class=save-link href=@{SaveTheoryR idx}>Save</a>++ -}++-- | Template for proof state (tree) frame.+proofStateTpl :: (HamletValue h, HamletUrl h ~ WebUIRoute)+ => TheoryInfo -- ^ Theory information+ -> IO h+proofStateTpl = wrapThHtml . theoryIndex . tiTheory++-- | Framing/UI-layout template (based on JavaScript/JQuery)+overviewTpl :: (HamletValue h, HamletUrl h ~ WebUIRoute)+ => TheoryInfo -- ^ Theory information+ -> TheoryPath -- ^ Theory path to load into main+ -> IO h+overviewTpl info path = do+ proofState <- proofStateTpl info+ mainView <- pathTpl info path+ return [HAMLET|+ <div .ui-layout-north>+ ^{headerTpl info}+ <div .ui-layout-west>+ <h1 .pane-head> Proof scripts+ <div #proof-wrapper .scroll-wrapper>+ <div #proof .monospace>+ ^{proofState}+ <div .ui-layout-east>+ <h1 .pane-head> Debug information+ <div #debug-wrapper .scroll-wrapper>+ <div #ui-debug-display>+ <div .ui-layout-center>+ <h1 #main-title .pane-head> Visualization display+ <div #main-wrapper .scroll-wrapper tabindex=0>+ <div #ui-main-display>+ \^{mainView}+ |]++-- | Theory path, displayed when loading main screen for first time.+pathTpl :: (HamletValue h, HamletUrl h ~ WebUIRoute)+ => TheoryInfo -- ^ The theory+ -> TheoryPath -- ^ Path to display on load+ -> IO h+pathTpl info TheoryMain = return [HAMLET|+ <h2>Welcome!</h2><br/>+ <h3>Theory information</h3>+ <ul+ <li>Theory: #{get thyName $ tiTheory info}+ <li>Loaded at #{formatTime defaultTimeLocale "%T" $ tiTime info}+ <li>Origin: #{show $ tiOrigin info}+ <h3>Quick introduction</h3>+ <p>+ <em>Left pane:</em> Proof scripts display. You \+ can select proof states and examine them further \+ by clicking on them!+ <p>+ <em>Center pane:</em> Visualization and \+ information display relating to the currently \+ selected item.+ <p>+ <em>Keyboard shortcuts:</em> The interactive interface supports \+ multiple keyboard shortcuts for convenience. + <ul>+ <li>+ Keys <span class=keys>j and k</span>: Jump to the next/previous \+ proof path within the currently focused lemma.+ <li>+ Keys <span class=keys>J and K</span>: Jump to the next/previous \+ open goal within the currently focused lemma, or to the \+ next/previous lemma if there are no more open goals in the current \+ lemma.+ <li>+ Keys <span class=keys>1 to 9</span>: Apply the proof method with \+ the given number as shown in the applicable proof method section \+ in the main view.+ |]+pathTpl info path = wrapThHtml $ htmlThyPath (tiTheory info) path++-- | Template for introduction.+introTpl :: (HamletValue h, HamletUrl h ~ WebUIRoute) => h+introTpl = [HAMLET|+ <h1>Welcome!</h1>+ <h2>About+ <p>+ You are running the\+ <strong>+ <a href="http://www.infsec.ethz.ch/research/software#TAMARIN">tamarin prover</a>+ </strong>+ \ version #{showVersion version} in interactive mode.<br>+ \ © 2010 - 2012 \+ <a href="https://www1.ethz.ch/infsec/people/benschmi">Benedikt Schmidt</a>+ , <a href="http://people.inf.ethz.ch/meiersi">Simon Meier</a>+ , <a href="https://cssx.ch">Cedric Staub</a>+ , <a href="http://www.infsec.ethz.ch">Information Security Institute</a>+ , <a href="http://www.ethz.ch">ETH Zurich</a>+ <p>+ This program comes with ABSOLUTELY NO WARRANTY. It is free software, and+ \ you are welcome to redistribute it according to its+ \ <a href="/static/LICENSE" type="text/plain">LICENSE</a>.+ |]++-- | Template for editing a theory.+formTpl :: (HamletValue h, HamletUrl h ~ WebUIRoute, h ~ Widget ())+ => WebUIRoute -- ^ Form action route+ -> String -- ^ Submit button label+ -> Widget () -- ^ Form widget+ -> Enctype -- ^ Form encoding type+ -> Html -- ^ Nonce field+ -> h+formTpl action label form enctype nonce = [HAMLET|+ <form action=@{action} method=POST enctype=#{enctype}>+ ^{form}+ <div .submit-form>+ ^{addHtml nonce}+ <input type=submit value=#{label}>+ <input type=button id=cancel-form value=Cancel>+ |]
@@ -0,0 +1,649 @@+{- |+Module : Web.Handler+Description : Application-specific handler functions.+Copyright : (c) 2011 Cedric Staub+License : GPL-3++Maintainer : Cedric Staub <cstaub@ethz.ch>+Stability : experimental+Portability : non-portable+-}++{-# LANGUAGE+ OverloadedStrings, QuasiQuotes, TypeFamilies, + RankNTypes, TemplateHaskell, CPP #-}++module Web.Handler+ ( getOverviewR+ , getRootR+ , postRootR+ , getTheorySourceR+ , getTheoryMessageDeductionR+ , getTheoryVariantsR+ , getTheoryPathMR+ , getTheoryPathDR+ , getTheoryGraphR+ , getAutoProverR+ , getDeleteStepR+ , getKillThreadR+ , getNextTheoryPathR+ , getPrevTheoryPathR+ , getSaveTheoryR+ , getDownloadTheoryR+ , getEditTheoryR+ , postEditTheoryR+ , getEditPathR+ , postEditPathR+ , getUnloadTheoryR+ , getThreadsR+ )+where++import Theory (+ ClosedTheory,+ lName, thyName, + lookupLemma, addLemma, removeLemma,+ openTheory, + mapProverProof, sorryProver, autoProver, cutOnAttackDFS,+ prettyProof, prettyLemma, prettyClosedTheory, prettyOpenTheory + )+import Theory.Parser+import Theory.Proof.Sequent.Dot+import Web.Types+import Web.Hamlet+import Web.Theory+import Web.Instances ()+import Web.Settings+import Text.PrettyPrint.Html++import Yesod.Core+import Yesod.Json()+import Yesod.Form+import Text.Hamlet++import Data.Maybe+import Data.Aeson+import Data.Aeson.Encode (fromValue)+import Data.Label+import Data.Traversable (traverse)++import qualified Data.Map as M+import qualified Data.Text as T+import qualified Data.Traversable as Tr+import qualified Data.ByteString.Lazy.Char8 as BS+import Data.Text.Encoding+import qualified Blaze.ByteString.Builder as B+import Network.HTTP.Types ( urlDecode )++import Control.Monad+import Control.Monad.IO.Class+import Control.Monad.IO.Control+import Control.Applicative+import Control.Concurrent+import Control.DeepSeq+import qualified Control.Exception.Control as E+import Control.Exception.Base+import qualified Control.Concurrent.Thread as Thread ( forkIO )+import Data.Time.LocalTime+import qualified Data.Binary as Bin+import System.Directory++import Debug.Trace (trace)++-- Quasi-quotation syntax changed from GHC 6 to 7,+-- so we need this switch in order to support both+#if __GLASGOW_HASKELL__ >= 700+#define HAMLET hamlet+#else+#define HAMLET $hamlet+#endif+++------------------------------------------------------------------------------+-- Manipulate the state+------------------------------------------------------------------------------++-- | Store theory map in file if option enabled.+storeTheory :: WebUI+ -> TheoryInfo+ -> TheoryIdx+ -> IO ()+storeTheory yesod thy idx =+ when (autosaveProofstate yesod) $ do+ let f = workDir yesod++"/"++autosaveSubdir++"/"++show idx++".img"+ Bin.encodeFile (f++".tmp") thy+ renameFile (f++".tmp") f++-- | Load a theory given an index.+getTheory :: MonadIO m+ => TheoryIdx+ -> GenericHandler m (Maybe TheoryInfo)+getTheory idx = do+ yesod <- getYesod+ liftIO $ withMVar (theoryVar yesod) $ return . M.lookup idx++-- | Store a theory, return index.+putTheory :: MonadIO m+ => Maybe TheoryInfo -- ^ Index of parent theory+ -> Maybe TheoryOrigin -- ^ Origin of this theory+ -> ClosedTheory -- ^ The new closed theory+ -> GenericHandler m TheoryIdx+putTheory parent origin thy = do+ yesod <- getYesod+ liftIO $ modifyMVar (theoryVar yesod) $ \theories -> do+ time <- getZonedTime+ let idx = if M.null theories then 1 else fst (M.findMax theories) + 1+ parentIdx = tiIndex <$> parent+ parentOrigin = tiOrigin <$> parent+ newOrigin = parentOrigin <|> origin <|> (Just Interactive)+ newThy = TheoryInfo idx thy time parentIdx False (fromJust newOrigin)+ storeTheory yesod newThy idx+ return (M.insert idx newThy theories, idx)++-- | Delete theory.+delTheory :: MonadIO m => TheoryIdx -> GenericHandler m ()+delTheory idx = do+ yesod <- getYesod+ liftIO $ modifyMVar_ (theoryVar yesod) $ \theories -> do+ let theories' = M.delete idx theories+ -- FIXME: delete from autosave directory?+ return theories'++-- | Get a map of all stored theories.+getTheories :: MonadIO m => GenericHandler m TheoryMap+getTheories = do+ yesod <- getYesod+ liftIO $ withMVar (theoryVar yesod) return+++-- | Modify a theory in the map of theories.+adjTheory :: MonadIO m+ => TheoryIdx+ -> (TheoryInfo -> TheoryInfo)+ -> GenericHandler m ()+adjTheory idx f = do+ yesod <- getYesod+ liftIO $ modifyMVar_ (theoryVar yesod) $ \theories ->+ case M.lookup idx theories of+ Just thy -> do+ let newThy = f thy+ storeTheory yesod newThy idx+ return $ M.insert idx newThy theories+ Nothing -> error "adjTheory: invalid theory index"++-- | Debug tracing.+dtrace :: WebUI -> String -> a -> a+dtrace yesod msg | debug yesod = trace msg+ | otherwise = id++-- | Register a thread for killing.+putThread :: MonadControlIO m+ => T.Text -- ^ Request path+ -> ThreadId -- ^ Thread ID+ -> GenericHandler m ()+putThread str tid = do+ yesod <- getYesod+ liftIO $ dtrace yesod msg $+ modifyMVar_ (threadVar yesod) $ return . (M.insert str tid)+ where+ msg = "Registering thread: " ++ T.unpack str++-- | Unregister a thread for killing.+delThread :: MonadControlIO m+ => T.Text -- ^ Request path+ -> GenericHandler m ()+delThread str = do+ yesod <- getYesod+ liftIO $ dtrace yesod msg $+ modifyMVar_ (threadVar yesod) $ return . (M.delete str)+ where+ msg = "Deleting thread: " ++ T.unpack str++-- | Get a thread for the given request URL.+getThread :: MonadIO m+ => T.Text -- ^ Request path+ -> GenericHandler m (Maybe ThreadId)+getThread str = do+ yesod <- getYesod+ liftIO $ dtrace yesod msg $+ withMVar (threadVar yesod) $ return . M.lookup str+ where+ msg = "Retrieving thread id of: " ++ T.unpack str++-- | Get the map of all threads.+getThreads :: MonadIO m+ => GenericHandler m [T.Text]+getThreads = do+ yesod <- getYesod+ liftIO $ withMVar (threadVar yesod) (return . M.keys)+++------------------------------------------------------------------------------+-- Helper functions+------------------------------------------------------------------------------++-- | Print exceptions, if they happen.+traceExceptions :: MonadControlIO m => String -> m a -> m a+traceExceptions info = + E.handle handler+ where+ handler :: MonadControlIO m => E.SomeException -> m a+ handler e =+ trace (info ++ ": exception `" ++ show e ++ "'") $ + liftIO $ E.throw e++-- | Helper functions for generating JSON reponses.+jsonResp :: Monad m => JsonResponse -> GenericHandler m RepJson+jsonResp = return . RepJson . toContent . fromValue . responseToJson++responseToJson :: JsonResponse -> Value+responseToJson = go+ where+ jsonObj key val = object [ key .= val ]++ go (JsonAlert msg) = jsonObj "alert" $ toJSON msg+ go (JsonRedirect url) = jsonObj "redirect" $ toJSON url+ go (JsonHtml title content) = object+ [ "html" .= contentToJson content+ , "title" .= title ]+ + contentToJson (ContentBuilder b _) = toJSON $ B.toLazyByteString b + contentToJson _ = error "Unsupported content format in json response!"++-- | Fully evaluate a value in a thread that can be canceled.+evalInThread :: (NFData a, MonadControlIO m)+ => IO a+ -> GenericHandler m (Either SomeException a)+evalInThread io = do+ renderF <- getUrlRender+ maybeRoute <- getCurrentRoute+ case maybeRoute of+ Just route -> do+ let key = renderF route+ (tid, wait) <- liftIO $ Thread.forkIO $ do x <- io+ evaluate (rnf x)+ return x+ putThread key tid+ res <- liftIO $ wait+ delThread key+ return res+ Nothing -> Right `liftM` liftIO io++-- | Evaluate a handler with a given theory specified by the index,+-- return notFound if theory does not exist.+withTheory :: MonadIO m+ => TheoryIdx+ -> (TheoryInfo -> GenericHandler m a)+ -> GenericHandler m a+withTheory idx handler = do+ maybeThy <- getTheory idx+ case maybeThy of+ Just ti -> handler ti+ Nothing -> notFound++-- | Run a form and provide a JSON response.+formHandler :: (HamletValue h, HamletUrl h ~ WebUIRoute, h ~ Widget ())+ => T.Text -- ^ The form title+ -> Form WebUI WebUI a -- ^ The formlet to run+ -> (Widget () -> Enctype -> Html -> h) -- ^ Template to render form with+ -> (a -> GenericHandler IO RepJson) -- ^ Function to call on success+ -> Handler RepJson+formHandler title formlet template success = do+ (result, widget, enctype, nonce) <- runFormPost formlet+ case result of+ FormMissing -> do+ RepHtml content <- ajaxLayout (template widget enctype nonce)+ jsonResp $ JsonHtml title content+ FormFailure _ -> jsonResp $ JsonAlert+ "Missing fields in form. Please fill out all required fields."+ FormSuccess ret -> liftIOHandler (success ret)+++-- | Modify a theory, redirect if successful.+modifyTheory :: (MonadControlIO m, Functor m)+ => TheoryInfo -- ^ Theory to modify+ -> (ClosedTheory -> IO (Maybe ClosedTheory)) -- ^ Function to apply+ -> JsonResponse -- ^ Response on failure+ -> GenericHandler m Value+modifyTheory ti f errResponse = do+ -- res <- evalInThread (liftIO $ f (tiTheory ti))+ res <- evalInThread (liftIO $ f (tiTheory ti))+ case res of+ Left e -> return (excResponse e)+ Right Nothing -> return (responseToJson errResponse)+ Right (Just thy) -> do+ newThyIdx <- putTheory (Just ti) Nothing thy+ newUrl <- getUrlRender <*> pure (OverviewR newThyIdx) + return . responseToJson $ JsonRedirect newUrl+ where+ excResponse e = responseToJson+ (JsonAlert $ "Last request failed with exception: " `T.append` (T.pack (show e)))++------------------------------------------------------------------------------+-- Handler functions+------------------------------------------------------------------------------++-- | The root handler lists all theories by default,+-- or load a new theory if the corresponding form was submitted.+getRootR :: Handler RepHtml+getRootR = postRootR++postRootR :: Handler RepHtml+postRootR = do+ (result, widget, enctype, nonce) <- runFormPost submitForm+ case result of+ FormMissing -> return ()+ FormFailure errs -> do+ mapM_ (liftIO . print) errs+ setMessage "Loading failed."+ FormSuccess fileinfo -> do+ yesod <- getYesod+ closedThy <- parseThy yesod (BS.unpack $ fileContent fileinfo)+ void $ putTheory Nothing+ (Just $ Upload $ T.unpack $ fileName fileinfo) closedThy+ setMessage "Loaded new theory!"+ theories <- getTheories+ defaultLayout $ do+ setTitle "Welcome to the tamarin prover"+ addWidget (rootTpl theories widget enctype nonce)+ where+ submitForm = fieldsToDivs $ fileField $ FormFieldSettings+ "Select file:" "Select file" Nothing Nothing+++-- | Show overview over theory (framed layout).+getOverviewR :: TheoryIdx -> Handler RepHtml+getOverviewR idx = withTheory idx $ \ti -> defaultLayout $ do+ overview <- liftIO $ overviewTpl ti TheoryMain+ setTitle (toHtml $ "Theory: " ++ get thyName (tiTheory ti))+ addWidget overview++-- | Show source (pretty-printed open theory).+getTheorySourceR :: TheoryIdx -> Handler RepPlain+getTheorySourceR idx = withTheory idx $ \ti ->+ return $ RepPlain $ toContent $ prettyRender ti+ where + -- prettyRender = render . prettyOpenTheory . openTheory . tiTheory+ prettyRender = render . prettyClosedTheory . tiTheory++-- | Show variants (pretty-printed closed theory).+getTheoryVariantsR :: TheoryIdx -> Handler RepPlain+getTheoryVariantsR idx = withTheory idx $ \ti ->+ return $ RepPlain $ toContent $ prettyRender ti+ where prettyRender = render . prettyClosedTheory . tiTheory++-- | Show variants (pretty-printed closed theory).+getTheoryMessageDeductionR :: TheoryIdx -> Handler RepPlain+getTheoryMessageDeductionR idx = withTheory idx $ \ti ->+ return $ RepPlain $ toContent $ prettyRender ti+ where prettyRender = render . prettyClosedTheory . tiTheory+++-- | Show a given path within a theory (main view).+getTheoryPathMR :: TheoryIdx+ -> TheoryPath+ -> Handler RepJson+getTheoryPathMR idx path = liftIOHandler $ do+ jsonValue <- withTheory idx (go path)+ return $ RepJson $ toContent $ fromValue jsonValue+ where+ --+ -- Handle method paths by trying to solve the given goal/method+ --+ go (TheoryMethod lemma proofPath i) ti = modifyTheory ti+ (\thy -> return $ applyMethodAtPath thy lemma proofPath i)+ (JsonAlert "Sorry, but the prover failed on the selected method!")++ --+ -- Handle generic paths by trying to render them+ --+ go _ ti = do+ let title = T.pack $ titleThyPath (tiTheory ti) path+ let html = T.pack $ renderHtmlDoc $ htmlThyPath (tiTheory ti) path+ return $ responseToJson (JsonHtml title (toContent html))+++-- | Show a given path within a theory (debug view).+getTheoryPathDR :: TheoryIdx -> TheoryPath -> Handler RepHtml+getTheoryPathDR idx path = withTheory idx $ \ti -> ajaxLayout $ do+ let maybeDebug = htmlThyDbgPath (tiTheory ti) path+ let maybeWidget = wrapHtmlDoc <$> maybeDebug+ addWidget [HAMLET|+ <h2>Theory information</h2>+ <ul>+ <li>Index = #{show (tiIndex ti)}+ <li>Path = #{show path}+ <li>Time = #{show (tiTime ti)}+ <li>Origin = #{show (tiOrigin ti)}+ <li>NextPath = #{show (nextThyPath (tiTheory ti) path)}+ <li>PrevPath = #{show (prevThyPath (tiTheory ti) path)}+ <li>NextSmartPath = #{show (nextSmartThyPath (tiTheory ti) path)}+ <li>PrevSmartPath = #{show (prevSmartThyPath (tiTheory ti) path)}+ $if isJust maybeWidget+ <h2>Current sequent</h2><br>+ \^{fromJust maybeWidget}+ |]++-- | Get rendered graph for theory and given path.+getTheoryGraphR :: TheoryIdx -> TheoryPath -> Handler ()+getTheoryGraphR idx path = withTheory idx $ \ti -> do+ yesod <- getYesod+ compact <- isNothing <$> lookupGetParam "uncompact"+ compress <- isNothing <$> lookupGetParam "uncompress"+ png <- liftIO $ traceExceptions "getTheoryGraphR" $+ pngThyPath+ (workDir yesod)+ (graphStyle compact compress)+ (tiTheory ti) path+ sendFile "image/png" png+ where+ graphStyle d c = dotStyle d . compression c+ dotStyle True = dotSequentCompact+ dotStyle False = dotSequentLoose+ compression True = compressSequent+ compression False = id++-- | Kill a thread (aka 'cancel request').+getKillThreadR :: Handler RepPlain+getKillThreadR = liftIOHandler $ do+ maybeKey <- lookupGetParam "path"+ case maybeKey of+ Just key0 -> do+ let key = decodeUtf8 . urlDecode True . encodeUtf8 $ key0+ tryKillThread key+ return $ RepPlain $ toContent ("Canceled request!" :: T.Text)+ Nothing -> invalidArgs ["No path to kill specified!"]+ where+ -- thread waiting for the result is responsible for+ -- updating the ThreadMap.+ tryKillThread k = do+ maybeTid <- getThread k+ case maybeTid of+ Nothing -> trace ("Killing failed: "++ T.unpack k) $ return ()+ Just tid -> trace ("Killing: " ++ T.unpack k)+ (liftIO $ killThread tid)++-- | Get the 'next' theory path for a given path.+-- This function is used for implementing keyboard shortcuts.+getNextTheoryPathR :: TheoryIdx -- ^ Theory index+ -> String -- ^ Jumping mode (smart?)+ -> TheoryPath -- ^ Current path+ -> Handler RepPlain+getNextTheoryPathR idx md path = withTheory idx $ \ti -> return $+ RepPlain $ toContent $ joinPath' $ renderPath $ next md (tiTheory ti) path+ where+ next "normal" = nextThyPath+ next "smart" = nextSmartThyPath+ next _ = const id++-- | Get the 'prev' theory path for a given path.+-- This function is used for implementing keyboard shortcuts.+getPrevTheoryPathR :: TheoryIdx -> String -> TheoryPath -> Handler RepPlain+getPrevTheoryPathR idx md path = withTheory idx $ \ti -> return $+ RepPlain $ toContent $ joinPath' $ renderPath $ prev md (tiTheory ti) path+ where+ prev "normal" = prevThyPath+ prev "smart" = prevSmartThyPath+ prev _ = const id++-- | Get the edit theory page.+getEditTheoryR :: TheoryIdx -> Handler RepJson+getEditTheoryR = postEditTheoryR++-- | Post edit theory page form data.+postEditTheoryR :: TheoryIdx -> Handler RepJson+postEditTheoryR idx = withTheory idx $ \ti -> formHandler+ "Edit theory"+ (theoryFormlet ti)+ theoryFormTpl $ \(Textarea input) ->+ E.handle exHandler $ do+ yesod <- getYesod+ closedThy <- checkProofs <$> parseThy yesod (T.unpack input)+ newIdx <- putTheory (Just ti) Nothing closedThy+ jsonResp . JsonRedirect =<<+ getUrlRender <*> pure (OverviewR newIdx)+ where+ theoryFormlet ti = fieldsToDivs $ textareaField+ (FormFieldSettings+ ("Edit theory source: " `T.append` name ti)+ (toHtml $ name ti) Nothing Nothing)+ (Just $ Textarea $ T.pack $ render $ prettyClosedTheory $ tiTheory ti)++ exHandler :: MonadControlIO m => E.SomeException -> GenericHandler m RepJson+ exHandler err = jsonResp $ JsonAlert $ T.unlines+ [ "Unable to load theory due to parse error!"+ , "Parser returned the message:"+ , T.pack $ show err ]++ name = T.pack . get thyName . tiTheory+ theoryFormTpl = formTpl (EditTheoryR idx) "Load as new theory" ++-- | Get the add lemma page.+getEditPathR :: TheoryIdx -> TheoryPath -> Handler RepJson+getEditPathR = postEditPathR++-- | Post edit theory page form data.+postEditPathR :: TheoryIdx -> TheoryPath -> Handler RepJson+postEditPathR idx (TheoryLemma lemmaName) = withTheory idx $ \ti -> do+ yesod <- getYesod+ let lemma = lookupLemma lemmaName (tiTheory ti)+ formHandler+ (T.pack $ action lemma)+ (formlet lemma)+ (lemmaFormTpl lemma) $ \(Textarea input) ->+ case parseLemma (T.unpack input) of+ Left err -> jsonResp $ JsonAlert $ T.unlines+ [ "Unable to add lemma to theory due to parse error!"+ , "Parser returned the message:"+ , T.pack $ show err ]+ Right newLemma -> (RepJson . toContent . fromValue) <$> modifyTheory ti+ -- Add or replace lemma+ (\thy -> do+ let openThy = openTheory thy+ openThy' = case lemma of+ Nothing -> addLemma newLemma openThy+ Just _ -> removeLemma lemmaName openThy + >>= addLemma newLemma+ traverse (closeThy yesod) openThy')+ -- Error response+ (JsonAlert $ T.unwords+ [ "Unable to add lemma to theory."+ , "Does a lemma with the same name already exist?" ])+ where+ path (Just l) = TheoryLemma (get lName l)+ path Nothing = TheoryLemma ""++ action (Just l) = "Edit lemma " ++ get lName l+ action Nothing = "Add new lemma"++ formlet lemma = fieldsToDivs $ textareaField+ (FormFieldSettings+ (T.pack $ action lemma)+ (toHtml $ action lemma)+ Nothing Nothing)+ (Textarea . T.pack . render . prettyLemma prettyProof <$> lemma)++ lemmaFormTpl lemma = formTpl (EditPathR idx (path lemma)) "Submit"++postEditPathR _ _ =+ jsonResp $ JsonAlert $ "Editing for this path is not implemented!"+++-- | Run the autoprover on a given proof path.+getAutoProverR :: TheoryIdx -> TheoryPath -> Handler RepJson+getAutoProverR idx path = liftIOHandler $ do+ jsonValue <- withTheory idx (go path)+ return $ RepJson $ toContent $ fromValue jsonValue+ where+ go (TheoryProof lemma proofPath) ti = modifyTheory ti+ (\thy -> + return $ applyProverAtPath thy lemma proofPath (mapProverProof cutOnAttackDFS autoProver))+ (JsonAlert "Sorry, but the autoprover failed on given proof step!")++ go _ _ = return . responseToJson $ JsonAlert+ "Can't run autoprover on the given theory path!"++-- | Delete a given proof step.+getDeleteStepR :: TheoryIdx -> TheoryPath -> Handler RepJson+getDeleteStepR idx path = liftIOHandler $ do+ jsonValue <- withTheory idx (go path)+ return $ RepJson $ toContent $ fromValue jsonValue+ where+ go (TheoryLemma lemma) ti = modifyTheory ti+ (return . removeLemma lemma)+ (JsonAlert "Sorry, but removing the selected lemma failed!")++ go (TheoryProof lemma proofPath) ti = modifyTheory ti+ (\thy -> return $ + applyProverAtPath thy lemma proofPath (sorryProver "removed"))+ (JsonAlert "Sorry, but removing the selected proof step failed!")++ go _ _ = return . responseToJson $ JsonAlert+ "Can't delete the given theory path!"++-- | Save a theory to the working directory.+getSaveTheoryR :: TheoryIdx -> Handler RepJson+getSaveTheoryR idx = withTheory idx $ \ti -> do+ let origin = tiOrigin ti+ case origin of+ -- Saving interactive/uploaded files not supported yet.+ Interactive -> notFound+ Upload _ -> notFound+ -- Saving of local files implemented.+ Local file -> do+ -- Save theory to disk+ liftIO $ writeFile file (prettyRender ti)+ -- Find original theorie(s) with same origin+ -- Set original -> modified+ thys <- M.filter (same origin) <$> getTheories+ _ <- Tr.mapM (\t -> adjTheory (tiIndex t) (setPrimary False)) thys+ -- Find current theory+ -- Set modified -> original+ adjTheory (tiIndex ti) (setPrimary True)+ -- Return message+ jsonResp (JsonAlert $ T.pack $ "Saved theory to file: " ++ file)+ where+ prettyRender = render . prettyOpenTheory . openTheory . tiTheory+ same origin ti = tiPrimary ti && (tiOrigin ti == origin)+ setPrimary bool ti = ti { tiPrimary = bool }+++-- | Prompt downloading of theory.+getDownloadTheoryR :: TheoryIdx -> String -> Handler (ContentType, Content)+getDownloadTheoryR idx _ = do+ RepPlain source <- getTheorySourceR idx+ return (typeOctet, source)++-- | Unload a theory from the interactive server.+getUnloadTheoryR :: TheoryIdx -> Handler RepPlain+getUnloadTheoryR idx = do+ delTheory idx + redirect RedirectPermanent RootR++-- | Show a list of all currently running threads.+getThreadsR :: Handler RepHtml+getThreadsR = do+ threads <- getThreads+ defaultLayout $ do+ setTitle "Registered threads"+ addWidget (threadsTpl threads)
@@ -0,0 +1,44 @@+{- |+Module : Web.Instances+Description : Binary instances for making the server state persistent.+Copyright : (c) 2011, 2012 Benedikt Schmidt & Simon Meier+License : GPL-3++Stability : experimental+Portability : non-portable+-}++{-# LANGUAGE TemplateHaskell, GADTs #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}+module Web.Instances where++import Data.DeriveTH+import Data.Binary++import Web.Types+import Data.Time.Calendar+import Data.Time.LocalTime+import Data.Fixed+import Data.Set ()+import Data.Map ()+import Control.DeepSeq++$( derive makeBinary ''TheoryOrigin)+$( derive makeBinary ''TheoryInfo)++$( derive makeBinary ''TimeZone)+$( derive makeBinary ''Day)+$( derive makeBinary ''TimeOfDay)++instance HasResolution a => Binary (Fixed a) where+ put f = put (showFixed True f)+ -- Fixed constructor is private+ get = do+ s <- get+ -- round to seconds for now+ return . fromInteger . read $ takeWhile (/='.') s++$( derive makeBinary ''LocalTime)+$( derive makeBinary ''ZonedTime)++$( derive makeNFData ''TheoryOrigin)
@@ -0,0 +1,32 @@+{- |+Module : Web.Settings+Description : Various default parameters and settings.+Copyright : (c) 2011 Cedric Staub+License : GPL-3++Maintainer : Cedric Staub <cstaub@ethz.ch>+Stability : experimental+Portability : non-portable+-}++module Web.Settings where++-- | Default port to listen on.+defaultPort :: Int+defaultPort = 3001++-- | Location of static files on the system.+defaultStaticDir :: FilePath+defaultStaticDir = "data"++-- | The base path (URL) for serving static files.+staticRoot :: String+staticRoot = "/static"++-- | Subdirectory to use for images.+imageDir :: FilePath+imageDir = "tamarin-prover-img"++-- | Filename for persistent state+autosaveSubdir :: FilePath+autosaveSubdir = "tamarin-prover-autosave/"
@@ -0,0 +1,798 @@+{- |+Module : Web.Theory+Description : Pretty-printing security protocol theories into HTML code.+Copyright : (c) 2011, 2012 Simon Meier & Cedric Staub+License : GPL-3++Maintainer : Cedric Staub <cstaub@ethz.ch>+Stability : experimental+Portability : non-portable+-}++{-# LANGUAGE PatternGuards, TupleSections #-}++module Web.Theory+ ( htmlThyPath+ , htmlThyDbgPath+ , pngThyPath+ , titleThyPath+ , theoryIndex+ , nextThyPath+ , prevThyPath+ , nextSmartThyPath+ , prevSmartThyPath+ , checkProofs+ , applyMethodAtPath+ , applyProverAtPath+ )+where++import Theory+import Theory.Pretty++import Web.Types+import Web.Settings++import Data.Maybe+import Data.List+import Data.Monoid+import qualified Data.Map as M++import Control.Basics++import System.Directory+import System.FilePath++import Extension.Data.Label++import qualified Text.Dot as D+import Text.Isar+import Text.PrettyPrint.Html+import Utils.Misc (stringSHA256)++import System.Process+import System.Exit++------------------------------------------------------------------------------+-- Various other functions+------------------------------------------------------------------------------++checkProofs :: ClosedTheory -> ClosedTheory+checkProofs = proveTheory checkedProver+ where+ checkedProver = checkAndExtendProver (sorryProver "not yet proven")++applyMethodAtPath :: ClosedTheory -> String -> ProofPath+ -> Int -> Maybe ClosedTheory+applyMethodAtPath thy lemmaName proofPath i = do+ lemma <- lookupLemma lemmaName thy+ subProof <- get lProof lemma `atPath` proofPath+ methods <- applicableProofMethods thy <$> psInfo (root subProof)+ method <- if length methods >= i then Just (methods !! (i-1)) else Nothing+ applyProverAtPath thy lemmaName proofPath + (oneStepProver method `mappend` + replaceSorryProver (oneStepProver Simplify) `mappend`+ replaceSorryProver (contradictionAndClauseProver)+ )++applyProverAtPath :: ClosedTheory -> String -> ProofPath+ -> Prover -> Maybe ClosedTheory+applyProverAtPath thy lemmaName proofPath prover =+ modifyLemmaProof (focus proofPath prover) lemmaName thy++------------------------------------------------------------------------------+-- Pretty printing+------------------------------------------------------------------------------++-- | Reference a dot graph for the given path.+refDotPath :: HtmlDocument d => TheoryPath -> d+refDotPath path = closedTag "img" [("class", "graph"), ("src", imgPath)]+ where imgPath = "graph/" ++ joinPath' (renderPath path)++getDotPath :: String -> FilePath+getDotPath code = imageDir </> addExtension (stringSHA256 code) "dot"++-- | Create a link to a given theory path.+linkToPath :: HtmlDocument d+ => TheoryPath -- ^ Path to link to.+ -> [String] -- ^ Additional class+ -> d -- ^ Document that carries the link.+ -> d+linkToPath path cls = withTag "a" [("class", classes), ("href", linkPath)]+ where+ classes = unwords $ "internal-link" : cls+ linkPath = joinPath' $ renderPath path++-- | Output some preformatted text.+preformatted :: HtmlDocument d => Maybe String -> d -> d+preformatted cl = withTag "div" [("class", classes cl)]+ where+ classes (Just cls) = "preformatted " ++ cls+ classes (Nothing) = "preformatted"++-- | Render a proof index relative to a theory path constructor.+proofIndex :: HtmlDocument d+ => (ProofPath -> TheoryPath) -- ^ Relative addressing function+ -> Proof (Maybe Sequent, Bool) -- ^ The annotated incremental proof+ -> d+proofIndex mkPath = + prettyProofWith ppStep ppCase . insertPaths+ where+ isSolved = snd . fst . psInfo+ isAnnotated = isJust . fst . fst . psInfo++ isSorry ps+ | Sorry _ <- psMethod ps = True+ | otherwise = False++ markSolved = withTag "span" [("class", "hl_solved")]++ ppStep ps+ | not (isAnnotated ps) = superfluousStep ps+ | isSolved ps = (markSolved $ linkToStep ["solved"] ps) <> removeStep ps+ | isSorry ps = linkToStep ["unsolved", "sorry-step"] ps + | otherwise = linkToStep ["unsolved"] ps <> removeStep ps++ removeStep ps = linkToPath+ (mkPath $ snd $ psInfo ps) ["remove-step"] emptyDoc++ ppCase ps+ | isSolved ps = markSolved + | otherwise = id ++ superfluousStep ps = withTag "span"+ [("class","hl_superfluous unsolved")] + (prettyProofMethod $ psMethod ps)+ + linkToStep cls ps = linkToPath+ (mkPath $ snd $ psInfo ps) ("proof-step" : cls)+ (prettyProofMethod $ psMethod ps)++-- | Render the indexing links for a single lemma+lemmaIndex :: HtmlDocument d+ => (ProofPath -> TheoryPath) -- ^ Relative addressing function+ -> Lemma IncrementalProof -- ^ The lemma+ -> d+lemmaIndex mkPath l =+ markSolved (kwLemmaModulo "E" <-> prettyLemmaName l <> colon) <->+ (linkToPath (TheoryLemma $ get lName l) ["edit-link"] editPng <->+ linkToPath (TheoryLemma $ get lName l) ["delete-link"] deletePng) $-$+ nest 2 (markSolved $ doubleQuotes $ prettyFormulaE $ get lFormulaE l) $-$+ proofIndex mkPath annotatedProof+ where+ editPng = png "/static/img/edit.png"+ deletePng = png "/static/img/delete.png" + png path = closedTag "img" [("class","icon"),("src",path)]++ annotatedProof = annotateProof $ get lProof l++ markSolved doc+ | solved = withTag "span" [("class", "hl_solved")] doc+ | otherwise = doc+ where+ solved = snd $ psInfo $ root annotatedProof++-- | Render the theory index.+theoryIndex :: HtmlDocument d => ClosedTheory -> d+theoryIndex thy = foldr1 ($-$)+ [ kwTheoryHeader $ get thyName thy+ , text ""+ , messageLink+ , text ""+ , ruleLink+ , text ""+ , reqCasesLink "Untyped case distinctions" UntypedCaseDist+ , text ""+ , reqCasesLink "Typed case distinctions " TypedCaseDist+ , text ""+ , vcat $ intersperse (text "") lemmas+ , text ""+ , kwEnd+ ]+ where+ mkPath path lemma = path $ get lName lemma+ lemmaIndex' lemma = lemmaIndex (mkPath TheoryProof lemma) lemma++ lemmas = map lemmaIndex' (getLemmas thy)+ rules = getClassifiedRules thy+ rulesInfo = parens $ int $ length $ get crProtocol rules+ casesInfo kind =+ parens $ nCases <> comma <-> text chainInfo+ where + cases = getCaseDistinction kind thy+ nChains = sum $ map (sum . unsolvedChainConstraints) cases+ nCases = int (length cases) <-> text "cases"+ chainInfo | nChains == 0 = "all chains solved"+ | otherwise = show nChains ++ " chains left"+ + bold = withTag "strong" [] . text+ overview n info p = linkToPath p [] (bold n <-> info)+ messageLink = overview "Message theory" (text "") TheoryMessage+ ruleLink = overview "Multiset rewriting rules" rulesInfo TheoryRules+ reqCasesLink name k = overview name (casesInfo k) (TheoryCaseDist k 0 0)++{-+-- | A snippet that explains a sequent using a rendered graph and the pretty+-- printed sequent.+sequentSnippet :: HtmlDocument d+ => Sequent -- ^ Sequent to pretty print.+ -> TheoryPath -- ^ The sequents path (NOT the path to its PNG)+ -> d+sequentSnippet se path = refDotPath path $-$ preformatted Nothing (prettySequent se)+-}++-- | A snippet that explains a sub-proof by displaying its proof state, the+-- open-goals, and the new cases.+subProofSnippet :: HtmlDocument d+ => ClosedTheory -- ^ The theory context.+ -> (ProofPath -> TheoryPath) -- ^ Relative proof adressing+ -> (Int -> TheoryPath) -- ^ Relative proof method addressing+ -> IncrementalProof -- ^ The sub-proof.+ -> d+subProofSnippet thy mkProofPath mkPrfMethodPath prf = + case psInfo $ root prf of+ Nothing -> text $ "no annotated sequent / " ++ nCases ++ " sub-case(s)"+ Just se -> vcat $+ [ withTag "h3" [] (text "Graph Part of Sequent")+ , refDotPath (mkProofPath [])+ , text ""+ , withTag "h3" [] (text "Applicable Proof Methods")+ , preformatted (Just "methods") (numbered' $ proofMethods se)+ , withTag "h3" [] (text "Pretty-Printed Sequent")+ , preformatted (Just "sequent") (prettyNonGraphSequent se)+ , withTag "h3" [] (text $ nCases ++ " sub-case(s)")+ ] ++ + subCases+ where+ prettyPM (i, m) = linkToPath+ (mkPrfMethodPath i) ["proof-method"] (prettyProofMethod m)++ nCases = show $ M.size $ children prf+ proofMethods = map prettyPM . zip [1..] . applicableProofMethods thy+ subCases = concatMap refSubCase $ M.toList $ children prf + refSubCase (name, prf') = + [ withTag "h4" [] (text "Case" <-> text name)+ , maybe (text "no proof state available")+ (const $ refDotPath $ mkProofPath [name])+ (psInfo $ root prf') + ]++-- | A Html document representing the requires case splitting theorem.+htmlCaseDistinction :: HtmlDocument d + => CaseDistKind -> (Int, CaseDistinction) -> d+htmlCaseDistinction kind (j, th) =+ if null cases+ then withTag "h2" [] ppHeader $-$ withTag "h3" [] (text "No cases.")+ else vcat $ withTag "h2" [] ppHeader : cases+ where+ cases = concatMap ppCase $ zip [1..] $ getDisj $ get cdCases th+ wrapP = withTag "p" [("class","monospace cases")]+ nCases = int $ length $ getDisj $ get cdCases th+ ppPrem = nest 2 $ doubleQuotes $ prettyBigStepGoal $ get cdGoal th+ ppHeader = hsep + [ text "Sources of" <-> ppPrem+ , parens $ nCases <-> text "cases"+ ]+ ppCase (i, (names, (conc, se))) = + [ withTag "h3" [] $ fsep [ text "Source", int i, text "of", nCases+ , text " / named ", doubleQuotes (text name) ]+ , refDotPath (TheoryCaseDist kind j i)+ , withTag "p" [] $ ppPrem <-> text "provided by conclusion" <-> prettyNodeConc conc+ , wrapP $ prettyNonGraphSequent se+ ]+ where+ name = intercalate "_" names++-- | Build the Html document showing the source cases distinctions.+reqCasesSnippet :: HtmlDocument d => CaseDistKind -> ClosedTheory -> d+reqCasesSnippet kind thy = vcat $ + htmlCaseDistinction kind <$> zip [1..] (getCaseDistinction kind thy)++-- | Build the Html document showing the rules of the theory.+rulesSnippet :: HtmlDocument d => ClosedTheory -> d+rulesSnippet thy = vcat+ [ ppRules "Multiset Rewriting Rules" crProtocol+ ] + where+ rules = getClassifiedRules thy+ ppRules header l =+ withTag "h2" [] (text header) $$ withTag "p"+ [("class","monospace rules")]+ (vcat (intersperse (text "") $ map prettyRuleAC $ get l rules))++-- | Build the Html document showing the message theory.+messageSnippet :: HtmlDocument d => ClosedTheory -> d+messageSnippet thy = vcat+ [ ppSection "Signature" [prettySignatureWithMaude (get thySignature thy)]+ , ppSection "Construction Rules" (ppRules crConstruct)+ , ppSection "Destruction Rules" (ppRules crDestruct)+-- , ppSection "Special Rules" (ppRules crSpecial)+ ]+ where+ ppRules l = map prettyRuleAC $ get l $ getClassifiedRules thy+ ppSection header s =+ withTag "h2" [] (text header) $$ withTag "p"+ [("class","monospace rules")]+ (vcat (intersperse (text "") $ s))++-- | Render the item in the given theory given by the supplied path.+htmlThyPath :: HtmlDocument d+ => ClosedTheory -- ^ The theory to render+ -> TheoryPath -- ^ Path to render+ -> d+htmlThyPath thy path = go path+ where+ go TheoryRules = rulesSnippet thy+ go TheoryMessage = messageSnippet thy+ go (TheoryCaseDist kind _ _) = reqCasesSnippet kind thy+ go (TheoryProof l p) = fromMaybe+ (text "No such lemma or proof path.")+ (subProofSnippet thy+ (mkProofPath l p)+ (TheoryMethod l p)+ <$> resolveProofPath thy l p)+ go (TheoryLemma _) = text "Implement theory item pretty printing!"+ go _ = text "Unhandled theory path. This is a bug."++ mkProofPath lemma path' subPath = TheoryProof lemma (path' ++ subPath)++-- | Render debug information for the item in the theory given by the path.+htmlThyDbgPath :: HtmlDocument d+ => ClosedTheory -- ^ The theory to render+ -> TheoryPath -- ^ Path to render+ -> Maybe d+htmlThyDbgPath thy path = go path+ where+ go (TheoryProof l p) = do+ proof <- resolveProofPath thy l p+ prettySequent <$> psInfo (root proof)+ go _ = Nothing++-- | Render the image corresponding to the given theory path.+pngThyPath :: FilePath -> (Sequent -> D.Dot ()) -> ClosedTheory+ -> TheoryPath -> IO FilePath+pngThyPath dir compact thy path = go path+ where+ go (TheoryCaseDist k i j) = renderDotCode (casesDotCode k i j)+ go (TheoryProof l p) = renderDotCode (proofPathDotCode l p)+ go _ = error "Unhandled theory path. This is a bug."+ + -- Get dot code for required cases+ casesDotCode k i j = D.showDot $+ compact $ snd $ snd $ cases !! (i-1) !! (j-1)+ where+ cases = map (getDisj . get cdCases) (getCaseDistinction k thy)++ -- Get dot code for proof path in lemma+ proofPathDotCode lemma proofPath =+ D.showDot $ fromMaybe (return ()) $ do+ subProof <- resolveProofPath thy lemma proofPath+ sequent <- psInfo $ root subProof+ return $ compact sequent++ -- Render a piece of dot code+ renderDotCode code = do+ let dotPath = dir </> getDotPath code+ pngPath = addExtension dotPath "png"++ pngGenerated <-+ firstSuccess [ doesFileExist pngPath+ , writeFile dotPath code >> dotToPng "dot" dotPath pngPath+ , dotToPng "fdp" dotPath pngPath ]+ return (if pngGenerated then pngPath else imageDir ++ "/img/delete.png")++ dotToPng dotCmd dotFile pngFile = do+ (ecode,_out,err) <- readProcessWithExitCode dotCmd ["-Tpng","-o",pngFile,dotFile] ""+ case ecode of+ ExitSuccess -> return True+ ExitFailure i -> do+ putStrLn $ "dotToPng: "++dotCmd++" failed with code "+ ++show i++" for file "++dotFile++":\n"++err+ return False++ firstSuccess [] = return False+ firstSuccess (m:ms) = do+ s <- m+ if s then return True else firstSuccess ms+++-- | Get title to display for a given proof path.+titleThyPath :: ClosedTheory -> TheoryPath -> String +titleThyPath thy path = go path+ where+ go TheoryRules = "Rewriting rules"+ go TheoryMessage = "Message theory"+ go (TheoryCaseDist UntypedCaseDist _ _) = "Untyped case distinctions"+ go (TheoryCaseDist TypedCaseDist _ _) = "Typed case distinctions"+ go (TheoryLemma l) = "Lemma: " ++ l+ go (TheoryProof l []) = "Lemma: " ++ l+ go (TheoryProof l p)+ | null (last p) = "Method: " ++ methodName l p + | otherwise = "Case: " ++ last p+ go _ = "Unhandled theory path"++ methodName l p =+ case resolveProofPath thy l p of+ Nothing -> "None"+ Just proof -> renderHtmlDoc $ prettyProofMethod $ psMethod $ root proof++-- | Resolve a proof path.+resolveProofPath :: ClosedTheory -- ^ Theory to resolve in+ -> String -- ^ Name of lemma+ -> ProofPath -- ^ Path to resolve+ -> Maybe IncrementalProof+resolveProofPath thy lemmaName path = do+ lemma <- lookupLemma lemmaName thy+ get lProof lemma `atPath` path+++------------------------------------------------------------------------------+-- Moving to next/prev proof path+------------------------------------------------------------------------------++-- | Get 'next' theory path.+nextThyPath :: ClosedTheory -> TheoryPath -> TheoryPath+nextThyPath thy = go+ where+ go TheoryMain = TheoryMessage+ go TheoryMessage = TheoryRules+ go TheoryRules = TheoryCaseDist UntypedCaseDist 0 0+ go (TheoryCaseDist UntypedCaseDist _ _) = TheoryCaseDist TypedCaseDist 0 0+ go (TheoryCaseDist TypedCaseDist _ _) = fromMaybe TheoryMain firstLemma+ go (TheoryLemma lemma) = TheoryProof lemma []+ go (TheoryProof l p)+ | Just nextPath <- getNextPath l p = TheoryProof l nextPath+ | Just nextLemma <- getNextLemma l = TheoryProof nextLemma []+ | otherwise = TheoryMain+ go _ = TheoryMain++ lemmas = map (\l -> (get lName l, l)) $ getLemmas thy+ firstLemma = flip TheoryProof [] . fst <$> listToMaybe lemmas++ getNextPath lemmaName path = do+ lemma <- lookupLemma lemmaName thy+ let paths = map fst $ getProofPaths $ get lProof lemma+ getNextElement (== path) paths++ getNextLemma lemmaName = getNextElement (== lemmaName) (map fst lemmas)++-- | Get 'prev' theory path.+prevThyPath :: ClosedTheory -> TheoryPath -> TheoryPath+prevThyPath thy = go+ where+ go TheoryMessage = TheoryMain+ go TheoryRules = TheoryMessage+ go (TheoryCaseDist UntypedCaseDist _ _) = TheoryRules+ go (TheoryCaseDist TypedCaseDist _ _) = TheoryCaseDist UntypedCaseDist 0 0+ go (TheoryLemma l)+ | Just prevLemma <- getPrevLemma l = TheoryProof prevLemma (lastPath prevLemma)+ | otherwise = TheoryCaseDist TypedCaseDist 0 0+ go (TheoryProof l p)+ | Just prevPath <- getPrevPath l p = TheoryProof l prevPath+ | Just prevLemma <- getPrevLemma l = TheoryProof prevLemma (lastPath prevLemma)+ | otherwise = TheoryCaseDist TypedCaseDist 0 0+ go _ = TheoryMain++ lemmas = map (\l -> (get lName l, l)) $ getLemmas thy++ getPrevPath lemmaName path = do+ lemma <- lookupLemma lemmaName thy+ let paths = map fst $ getProofPaths $ get lProof lemma+ getPrevElement (== path) paths++ lastPath lemmaName = last $ map fst $ getProofPaths $+ get lProof $ fromJust $ lookupLemma lemmaName thy++ getPrevLemma lemmaName = getPrevElement (== lemmaName) (map fst lemmas)++-- Get 'next' smart theory path.+nextSmartThyPath :: ClosedTheory -> TheoryPath -> TheoryPath+nextSmartThyPath thy = go+ where+ go TheoryMain = TheoryMessage+ go TheoryMessage = TheoryRules+ go TheoryRules = TheoryCaseDist UntypedCaseDist 0 0+ go (TheoryCaseDist UntypedCaseDist _ _) = TheoryCaseDist TypedCaseDist 0 0+ go (TheoryCaseDist TypedCaseDist _ _) = fromMaybe TheoryMain firstLemma+ go (TheoryLemma lemma) = TheoryProof lemma []+ go (TheoryProof l p)+ | Just nextPath <- getNextPath l p = TheoryProof l nextPath+ | Just nextLemma <- getNextLemma l = TheoryProof nextLemma []+ | otherwise = TheoryMain+ go _ = TheoryMain++ lemmas = map (\l -> (get lName l, l)) $ getLemmas thy+ firstLemma = flip TheoryProof [] . fst <$> listToMaybe lemmas++ getNextPath lemmaName path = do+ lemma <- lookupLemma lemmaName thy+ let paths = getProofPaths $ get lProof lemma+ let nextSteps = snd $ break ((== path) . fst) paths+ if null nextSteps+ then Nothing+ else listToMaybe $ map fst $ filter snd $ tail nextSteps++ getNextLemma lemmaName = getNextElement (== lemmaName) (map fst lemmas)++-- Get 'prev' smart theory path.+prevSmartThyPath :: ClosedTheory -> TheoryPath -> TheoryPath+prevSmartThyPath thy = go+ where+ go TheoryMessage = TheoryMain+ go TheoryRules = TheoryMessage+ go (TheoryCaseDist UntypedCaseDist _ _) = TheoryRules+ go (TheoryCaseDist TypedCaseDist _ _) = TheoryCaseDist UntypedCaseDist 0 0+ go (TheoryLemma l)+ | Just prevLemma <- getPrevLemma l = TheoryProof prevLemma (lastPath prevLemma)+ | otherwise = TheoryCaseDist TypedCaseDist 0 0+ go (TheoryProof l p)+ | Just prevPath <- getPrevPath l p = TheoryProof l prevPath+ | Just firstPath <- getFirstPath l p = TheoryProof l firstPath+ | Just prevLemma <- getPrevLemma l = TheoryProof prevLemma (lastPath prevLemma)+ | otherwise = TheoryCaseDist TypedCaseDist 0 0+ go _ = TheoryMain++ lemmas = map (\l -> (get lName l, l)) $ getLemmas thy++ getFirstPath lemmaName current = do+ lemma <- lookupLemma lemmaName thy+ let paths = map fst $ getProofPaths $ get lProof lemma+ if null paths || (head paths == current)+ then Nothing+ else Just $ head paths++ getPrevPath lemmaName path = do+ lemma <- lookupLemma lemmaName thy+ let paths = getProofPaths $ get lProof lemma+ let prevSteps = filter snd $ fst $ break ((== path) . fst) paths+ if null prevSteps+ then Nothing+ else Just $ fst $ last prevSteps++ lastPath lemmaName = last $ map fst $ getProofPaths $+ get lProof $ fromJust $ lookupLemma lemmaName thy++ getPrevLemma lemmaName = getPrevElement (== lemmaName) (map fst lemmas)++-- | Extract proof paths out of a proof.+-- Boolean value in tuple indicates if path is sorry step.+getProofPaths :: LTree CaseName (ProofStep a) -> [([String], Bool)]+getProofPaths proof = ([], isSorry proof) : go proof+ where+ go = concatMap paths . M.toList . children+ paths (lbl, prf) = ([lbl], isSorry prf) : map (first (lbl:)) (go prf)++ isSorry ps+ | Sorry _ <- psMethod (root ps) = True+ | otherwise = False++-- | Get element _after_ the matching element in the list.+getNextElement :: (a -> Bool) -> [a] -> Maybe a+getNextElement _ [] = Nothing+getNextElement f (x:xs)+ | f x = listToMaybe xs+ | otherwise = getNextElement f xs++-- | Get element _before_ the matching element in the list.+getPrevElement :: (a -> Bool) -> [a] -> Maybe a+getPrevElement _ [] = Nothing+getPrevElement f (x:xs) = go x xs+ where+ go _ [] = Nothing+ go old (z:zs)+ | f z = Just old+ | otherwise = go z zs++-- | Annotate a proof for pretty printing.+-- The boolean flag indicates that the given proof step's children+-- are (a) all annotated and (b) contain no sorry steps.+annotateProof :: Proof (Maybe Sequent) -> Proof (Maybe Sequent, Bool)+annotateProof (LNode (ProofStep method sequent) children')+ | Nothing <- sequent = LNode (proofStep False) annotatedChildren+ | Sorry _ <- method = LNode (proofStep False) annotatedChildren+ | otherwise = LNode (proofStep checkChildren) annotatedChildren+ where+ annotatedChildren = M.map annotateProof children'+ proofStep bool = ProofStep method (sequent, bool)+ checkChildren = all (snd . psInfo . root . snd) $ M.toList annotatedChildren+++------------------------------------------------------------------------------+-- Html file generation+------------------------------------------------------------------------------++{- TO BE REDONE, once interactive visualization is finished. Corresponds to+ - a pre-rendering of all relevant data.++data Viewport = LeftView | MainView | DebugView | PopupView+ deriving( Eq, Ord, Show )++type Link = (Viewport, HtmlSnippetId)+type LinkId = Int+type HtmlSnippet = String+type HtmlSnippetId = Int+type DotCode = String++data ThHtmlState = ThHtmlState+ { _thsDots :: M.Map FilePath DotCode+ , _thsSnippets :: M.Map HtmlSnippet HtmlSnippetId+ , _thsLinks :: M.Map LinkId [Link]+ }+ deriving( Eq, Ord, Show )++emptyThHtmlState :: ThHtmlState+emptyThHtmlState = ThHtmlState M.empty M.empty M.empty++$(mkLabels [''ThHtmlState])++type ThHtml = ReaderT (Sequent -> Sequent) (StateT ThHtmlState Fresh)++runThHtml :: (Sequent -> Sequent) -> ThHtml a -> (a, ThHtmlState)+runThHtml compress = + (`evalFresh` nothingUsed) + . (`runStateT` emptyThHtmlState) + . (`runReaderT` compress)++instance JSON Viewport where+ readJSON (JSString name) = case fromJSString name of + "Left" -> return LeftView+ "Main" -> return MainView+ "Debug" -> return DebugView+ "Popup" -> return PopupView+ cs -> Error $ "readJSSON (Viewport): " ++ cs+ readJSON _ = Error "readJSSon (Viewport)"++ showJSON LeftView = JSString $ toJSString "Left"+ showJSON MainView = JSString $ toJSString "Main"+ showJSON DebugView = JSString $ toJSString "Debug"+ showJSON PopupView = JSString $ toJSString "Popup"+++-- | Input for generation process that needs to be supplied from a caller of+-- @theoryToHtml@.+data GenerationInput = GenerationInput {+ giHeader :: String -- ^ Arbitrary html for the header+ , giTime :: UTCTime -- ^ Generation time.+ , giSystem :: String -- ^ Description of the system we run on.+ , giInputFile :: FilePath -- ^ Path to input file.+ , giTemplate :: FilePath -- ^ Path to template index.+ , giOutDir :: FilePath -- ^ Path to the output directory.+ , giTheory :: ClosedTheory -- ^ Theory to output.+ , giCmdLine :: String -- ^ The command line that was used in this call to+ -- tamarin.+ , giCompress :: Bool -- ^ True if sequents should be compressed+ -- before visualization by unsoundly dropping+ -- information.+ }+ deriving( Show )++-- | Information about various paths relevant for generating the HTML output.+data PathInfo = PathInfo {+ inputFileCopy :: FilePath -- ^ Path of input file copy.+ , proofScriptFile :: FilePath -- ^ Path of generated Isabelle proof script.+ , outDir :: FilePath -- ^ Output directory.+ , filesDir :: FilePath -- ^ Relative directory for input and output files.+ }+ deriving( Show )++-- | Compute the path info from the generation input.+pathInfo :: GenerationInput -> PathInfo+pathInfo input = info+ where+ info = PathInfo+ { inputFileCopy = extendBaseName "_original"+ , proofScriptFile = extendBaseName "_processed"+ , outDir = giOutDir input+ , filesDir = "files"+ }++ extendBaseName ext = + filesDir info </> + addExtension (takeBaseName (giInputFile input) ++ ext) "spthy"++-- | Make a path that is specified relative to the output directory absolute.+mkAbsolute :: PathInfo -> FilePath -> FilePath+mkAbsolute info = (outDir info </>)++-- | Compute the list of absolute paths to directories required for generating+-- this HTML output.+requiredDirs :: PathInfo -> [FilePath]+requiredDirs info = map (mkAbsolute info) [".", imageDir, filesDir info]++-- | Prepare information gathered during the generation of the resulting+-- theories for exporting as JSON.+jsGenerationInfo :: GenerationInput+ -> NominalDiffTime -- ^ Proof script generation time.+ -> JSObject JSValue+jsGenerationInfo input genTime = toJSObject $+ [ ("header", showJSON . toJSString $ giHeader input)+ , ("time", showJSON . toJSString . show $ giTime input)+ , ("system", showJSON . toJSString $ giSystem input)+ , ("inputFile", showJSON . fileLink $ inputFileCopy paths)+ , ("proofScript", showJSON . fileLink $ proofScriptFile paths)+ , ("commandLine", showJSON . toJSString $ giCmdLine input)+ , ("certificateStatus", showJSON . toJSString $ genTimeString) + ] + where+ paths = pathInfo input+ fileLink file = (toJSString (takeFileName file), toJSString file)+ genTimeString = "generated in " ++ show genTime++-- | Convert a security protocol theory to a HTML file visualizing it.+theoryToHtml :: GenerationInput -> IO ()+theoryToHtml input = do+ putStrLn ""+ putStrLn $ " copying template to output directory: " ++ outDir paths+ mapM_ (createDirectoryIfMissing True) $ requiredDirs paths+ copyTemplate (giTemplate input) $ outDir paths+ copyFile (giInputFile input) (mkAbsolute paths $ inputFileCopy paths)+ -- timed proof script generation+ putStr " generating proof script: " >> hFlush stdout+ genTime <- timed_ $ writeAbsolute (proofScriptFile paths) + (render $ prettyClosedTheory $ giTheory input)+ putStrLn $ show genTime+ -- json output+ let thyJSON = mkThyJSON (jsGenerationInfo input genTime)+ writeAbsolute "theory.js"+ (("scytherP_theory_JSON = "++) . show $ showJSObject thyJSON "")+ -- graph generation+ putStrLn " generating visualizations using GraphViz:"+ parMkGraphs $ M.toList $ get thsDots thSt+ where+ paths = pathInfo input+ writeAbsolute = writeFile . mkAbsolute paths++ compress | giCompress input = compressSequent+ | otherwise = id++ (thId, thSt) = runThHtml compress $ do+ thy <- htmlTheory $ giTheory input+ return $ renderHtmlDoc thy++ mkThyJSON :: JSObject JSValue -> JSObject JSValue+ mkThyJSON genInfo = toJSObject+ [ ("theory", showJSON $ thId )+ , ("generationInfo", showJSON $ genInfo )+ , ("snippets", showJSON $ invertMap $ get thsSnippets thSt )+ , ("links", showJSON $ get thsLinks thSt )+ ]++ invertMap = M.fromList . map (uncurry $ flip (,)) . M.toList++ -- create the graph corresponding to the given formula+ mkGraph (path, dotCode) msgChan = do+ let outFile = mkAbsolute paths path+ pngFile = addExtension outFile "png"+ ifM (doesFileExist pngFile) + (writeChan msgChan $ "using cached file: " ++ pngFile) + (do writeFile outFile dotCode+ graphvizDotToPng outFile pngFile msgChan+ removeFile outFile)++ -- | Convert a list of dot strings in parallel to png files, using the number of+ -- cores+1 parallel executions of the dot tool.+ parMkGraphs = + parCmd_ display . map mkGraph+ where+ display n i msg = + hPutStrLn stdout $ " ["++showPadded i++" of "++show n++"] "++msg+ where + showPadded x = flushRight (length (show n)) (show x)++-- | Copy all the files referenced in the template index file to the output+-- directory.+copyTemplate :: FilePath -- ^ Path of template index file.+ -> FilePath -- ^ Output directory.+ -> IO ()+copyTemplate templateFile targetDir = do+ let templateDir = takeDirectory templateFile+ template <- readFile templateFile+ let files = filter (not.null) $ lines template+ copy file = do+ let outPath = targetDir </> file+ createDirectoryIfMissing True (takeDirectory outPath)+ copyFile (templateDir </> file) outPath+ mapM_ copy files++-}+
@@ -0,0 +1,344 @@+{- |+Module : Types.hs+Description : Central data type and Yesod typeclass instances.+Copyright : (c) 2011 Cedric Staub+License : GPL-3++Maintainer : Cedric Staub <cstaub@ethz.ch>+Stability : experimental+Portability : non-portable+-}++{-# LANGUAGE+ OverloadedStrings, Rank2Types, QuasiQuotes,+ TypeFamilies, TemplateHaskell, CPP #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++module Web.Types+ ( WebUI(..)+ , WebUIRoute (..)+ , resourcesWebUI+ , TheoryInfo(..)+ , TheoryPath(..)+ , TheoryOrigin(..)+ , JsonResponse(..)+ , renderPath+ , parsePath+ , joinPath'+ , TheoryIdx+ , TheoryMap+ , ThreadMap+ , GenericHandler+ , Handler+ , GenericWidget+ , Widget+ ) +where++import Theory++import Yesod.Core+import Yesod.Helpers.Static++import Text.Hamlet+import Text.Printf++import Data.Monoid (mconcat)+import Data.List (intercalate)+import Data.Maybe (listToMaybe)+import Data.Ord (comparing)+import Data.Char (ord, isAlphaNum)+import Data.Time.LocalTime+import Data.Label+import Control.Concurrent++import qualified Data.Map as M+import qualified Data.Text as T++import Control.Monad.IO.Class+import Control.Applicative++------------------------------------------------------------------------------+-- Types+------------------------------------------------------------------------------++-- | Type synonym for a generic handler inside our site.+type GenericHandler m = GGHandler WebUI WebUI m+type Handler a = GHandler WebUI WebUI a++-- | Type synonym for a generic widget inside our site.+type GenericWidget m = GGWidget WebUI (GenericHandler m)+type Widget a = GWidget WebUI WebUI a++-- | Type synonym representing a numeric index for a theory.+type TheoryIdx = Int++-- | Type synonym representing a map of theories.+type TheoryMap = M.Map TheoryIdx TheoryInfo++-- | Type synonym representing a map of threads.+type ThreadMap = M.Map T.Text ThreadId++-- | The so-called site argument for our application, which can hold various+-- information that can use to keep info that needs to be available to the +-- handler functions.+data WebUI = WebUI+ { getStatic :: Static+ -- ^ Settings for static file serving.+ , workDir :: FilePath+ -- ^ The working directory (for storing/loading theories).+ , parseThy :: MonadIO m => String -> GenericHandler m ClosedTheory+ -- ^ Parse a closed theory according to command-line arguments.+ , closeThy :: OpenTheory -> IO ClosedTheory+ -- ^ Close an open theory according to command-line arguments.+ , theoryVar :: MVar TheoryMap+ -- ^ MVar that holds the theory map+ , threadVar :: MVar ThreadMap+ -- ^ MVar that holds the thread map+ , autosaveProofstate :: Bool+ -- ^ Automatically store theory map+ , debug :: Bool+ -- ^ Output debug messages+ }++-- | Simple data type for generating JSON responses.+data JsonResponse+ = JsonHtml T.Text Content -- ^ Title and HTML content+ | JsonAlert T.Text -- ^ Alert/dialog box with message+ | JsonRedirect T.Text -- ^ Redirect to given URL++-- | Data type representing origin of theory.+-- Command line with file path, upload with filename (not path),+-- or created by interactive mode (e.g. through editing).+data TheoryOrigin = Local FilePath | Upload String | Interactive+ deriving (Show, Eq, Ord)++-- | Data type containg both the theory and it's index, making it easier to +-- pass the two around (since they are always tied to each other). We also+-- keep some extra bookkeeping information.+data TheoryInfo = TheoryInfo+ { tiIndex :: TheoryIdx -- ^ Index of theory.+ , tiTheory :: ClosedTheory -- ^ The closed theory.+ , tiTime :: ZonedTime -- ^ Time theory was loaded.+ , tiParent :: Maybe TheoryIdx -- ^ Prev theory in history+ , tiPrimary :: Bool -- ^ This is the orginally loaded theory.+ , tiOrigin :: TheoryOrigin -- ^ Origin of theory.+ }++-- | We use the ordering in order to display loaded theories to the user.+-- We first compare by name, then by time loaded, and then by source: Theories+-- that were loaded from the command-line are displayed earlier then+-- interactively loaded ones.+compareTI :: TheoryInfo -> TheoryInfo -> Ordering+compareTI (TheoryInfo _ i1 t1 p1 a1 o1) (TheoryInfo _ i2 t2 p2 a2 o2) =+ mconcat+ [ comparing (get thyName) i1 i2+ , comparing zonedTimeToUTC t1 t2+ , compare a1 a2+ , compare p1 p2+ , compare o1 o2+ ]++instance Eq TheoryInfo where+ (==) t1 t2 = compareTI t1 t2 == EQ++instance Ord TheoryInfo where+ compare = compareTI++-- Adapted from the output of 'derive'.+instance Read CaseDistKind where+ readsPrec p0 r+ = readParen (p0 > 10)+ (\ r0 ->+ [(UntypedCaseDist, r1) | ("untyped", r1) <- lex r0])+ r+ +++ readParen (p0 > 10)+ (\ r0 -> [(TypedCaseDist, r1) | ("typed", r1) <- lex r0])+ r++-- | Simple data type for specifying a path to a specific+-- item within a theory.+data TheoryPath+ = TheoryMain -- ^ The main view (info about theory)+ | TheoryLemma String -- ^ Theory lemma with given name+ | TheoryIntrVar Int -- ^ Intruder variant (n'th from start)+ | TheoryCaseDist CaseDistKind Int Int -- ^ Required cases (i'th source, j'th case) + | TheoryProof String ProofPath -- ^ Proof path within proof for given lemma+ | TheoryMethod String ProofPath Int -- ^ Apply the proof method to proof path+ | TheoryRules -- ^ Theory rules+ | TheoryMessage -- ^ Theory message deduction+ deriving (Eq, Show, Read)++-- | Render a theory path to a list of strings.+renderPath :: TheoryPath -> [String]+renderPath TheoryMain = ["main"]+renderPath TheoryRules = ["rules"]+renderPath TheoryMessage = ["message"]+renderPath (TheoryLemma name) = ["lemma", name]+renderPath (TheoryIntrVar i) = ["variant", show i]+renderPath (TheoryCaseDist k i j) = ["cases", show k, show i, show j]+renderPath (TheoryProof lemma path) = "proof" : lemma : path+renderPath (TheoryMethod lemma path idx) = "method" : lemma : show idx : path++-- | Parse a list of strings into a theory path.+parsePath :: [String] -> Maybe TheoryPath+parsePath [] = Nothing+parsePath (x:xs) = case x of+ "main" -> Just TheoryMain+ "rules" -> Just TheoryRules+ "message" -> Just TheoryMessage+ "lemma" -> parseLemma xs+ "cases" -> parseCases xs+ "variant" -> parseVariant xs+ "proof" -> parseProof xs+ "method" -> parseMethod xs+ _ -> Nothing + where+ safeRead = listToMaybe . map fst . reads++ parseLemma ys = TheoryLemma <$> listToMaybe ys++ parseProof (y:ys) = Just (TheoryProof y ys)+ parseProof _ = Nothing ++ parseMethod (y:z:zs) = safeRead z >>= Just . TheoryMethod y zs+ parseMethod _ = Nothing++ parseVariant (y:_) = safeRead y >>= Just . TheoryIntrVar+ parseVariant _ = Nothing++ parseCases (kind:y:z:_) = do+ k <- case kind of "typed" -> return TypedCaseDist + "untyped" -> return UntypedCaseDist+ _ -> Nothing+ m <- safeRead y+ n <- safeRead z+ return (TheoryCaseDist k m n)+ parseCases _ = Nothing+++-- | Join a path (list of strings) into a single string.+-- This functions also performs escaping of special characters.+joinPath' :: [String] -> String+joinPath' = intercalate "/" . map escape+ where+ escape [] = []+ escape (x:xs)+ | isAlphaNum x = x : escape xs+ | otherwise = printf "%%%02x" (ord x) ++ escape xs++------------------------------------------------------------------------------+-- Routing+------------------------------------------------------------------------------++-- Quasi-quotation syntax changed from GHC 6 to 7,+-- so we need this switch in order to support both.+#if __GLASGOW_HASKELL__ >= 700+#define HAMLET hamlet+#define PARSE_ROUTES parseRoutes+#else+#define HAMLET $hamlet+#define PARSE_ROUTES $parseRoutes+#endif++-- This is a hack we need to work around a bug (?) in the+-- C pre-processor. In order to define multi-pieces we need+-- the asterisk symbol, but the C pre-processor always chokes+-- on them thinking that they are somehow comments. This can+-- be removed once the CPP language ext is disabled, but it's+-- currently needed for GHC < 7 support.+#define MP(x) *x++-- | Static routing for our application.+-- Note that handlers ending in R are general handlers,+-- whereas handlers ending in MR are for the main view+-- and the ones ending in DR are for the debug view.+mkYesodData "WebUI" [PARSE_ROUTES|+/ RootR GET POST+/thy/#Int/overview OverviewR GET+/thy/#Int/source TheorySourceR GET+/thy/#Int/variants TheoryVariantsR GET+/thy/#Int/message TheoryMessageDeductionR GET+/thy/#Int/main/MP(TheoryPath) TheoryPathMR GET+/thy/#Int/debug/MP(TheoryPath) TheoryPathDR GET+/thy/#Int/graph/MP(TheoryPath) TheoryGraphR GET+/thy/#Int/autoprove/MP(TheoryPath) AutoProverR GET+/thy/#Int/next/#String/MP(TheoryPath) NextTheoryPathR GET+/thy/#Int/prev/#String/MP(TheoryPath) PrevTheoryPathR GET+/thy/#Int/save SaveTheoryR GET+/thy/#Int/download/#String DownloadTheoryR GET+/thy/#Int/edit/source EditTheoryR GET POST+/thy/#Int/edit/path/MP(TheoryPath) EditPathR GET POST+/thy/#Int/del/path/MP(TheoryPath) DeleteStepR GET+/thy/#Int/unload UnloadTheoryR GET+/kill KillThreadR GET+/threads ThreadsR GET+/robots.txt RobotsR GET+/favicon.ico FaviconR GET+/static StaticR Static getStatic+|]++-- | MultiPiece instance for TheoryPath.+instance MultiPiece TheoryPath where+ toMultiPiece = map T.pack . renderPath+ fromMultiPiece = parsePath . map T.unpack++-- Instance of the Yesod typeclass.+instance Yesod WebUI where+ -- | The approot. We can leave this empty because the+ -- application is always served from the root of the server.+ approot _ = T.empty++ -- | The default layout for rendering.+ defaultLayout = defaultLayout'++ -- | The path cleaning function. We make sure empty strings+ -- are not scrubbed from the end of the list. The default+ -- cleanPath function forces canonical URLs.+ cleanPath _ = Right+++------------------------------------------------------------------------------+-- Default layout+------------------------------------------------------------------------------++-- | Our application's default layout template.+-- Note: We define the default layout here even tough it doesn't really+-- belong in the "types" module in order to avoid mutually recursive modules.+defaultLayout' :: (Yesod master, Route master ~ WebUIRoute) + => GWidget sub master () -- ^ Widget to embed in layout+ -> GHandler sub master RepHtml+defaultLayout' w = do+ page <- widgetToPageContent w+ message <- getMessage+ hamletToRepHtml [HAMLET|+ !!!+ <html>+ <head>+ <title>#{pageTitle page}+ <link rel=stylesheet href=/static/css/tamarin-prover-ui.css>+ <link rel=stylesheet href=/static/css/jquery-contextmenu.css>+ <link rel=stylesheet href=/static/css/smoothness/jquery-ui.css>+ <script src=/static/js/jquery.js></script>+ <script src=/static/js/jquery-ui.js></script>+ <script src=/static/js/jquery-layout.js></script>+ <script src=/static/js/jquery-cookie.js></script>+ <script src=/static/js/jquery-superfish.js></script>+ <script src=/static/js/jquery-contextmenu.js></script>+ <script src=/static/js/tamarin-prover-ui.js></script>+ ^{pageHead page}+ <body>+ $maybe msg <- message+ <p.message>#{msg}+ <p.loading>+ Loading, please wait...+ \ <a id=cancel href='#'>Cancel</a>+ ^{pageBody page}+ <div#dialog>+ <ul#contextMenu>+ <li.autoprove>+ <a href="#autoprove">Autoprove</a>+ <li.delstep>+ <a href="#del/path">Remove step</a>+ |]
@@ -0,0 +1,219 @@+cabal-version: >= 1.8+build-type: Simple+name: tamarin-prover+version: 0.1.0.0+license: GPL+license-file: LICENSE+category: Theorem Provers+author: Benedikt Schmidt <benedikt.schmidt@inf.ethz.ch>,+ Simon Meier <simon.meier@inf.ethz.ch>+maintainer: Simon Meier <simon.meier@inf.ethz.ch>+copyright: Benedikt Schmidt, Simon Meier, ETH Zurich, 2010-2012+synopsis: The tamarin prover for security protocol analysis.+description: ++ The @tamarin@ prover is a tool for the analysis of security protocols. It+ implements a constraint solving algorithm that supports both falsification+ and verification of security protocols with respect to an unbounded number+ of sessions. The underlying security protocol model uses multiset+ rewriting to specify protocols and adversary capabilities, a guarded+ fragment of first-order logic to specify security properties, and+ equational theories to model the algebraic properties of cryptographic+ operators.+ .+ The paper describing the theory underlying the @tamarin@ prover is+ currently under submission to CSF 2012. Drop us (simon.meier\@inf.ethz.ch+ or benedikt.schmidt\@inf.ethz.ch) a mail, if you would like to obtain a+ copy of the paper.+ .+ The @tamarin@ prover supports both a batch analysis mode and the+ interactive construction of security proofs using a GUI. Example protocols+ and the user guide are installed together with the prover. Just call the+ @tamarin-prover@ executable without any arguments to get more information.+ .+ The @tamarin@ prover uses maude (<http://maude.cs.uiuc.edu/>) as a+ unification backend and GraphViz (<http://www.graphviz.org/>) to visualize+ constraint systems. Detailed instructions for installing the `tamarin`+ prover are given here:+ <http://www.infsec.ethz.ch/research/software#TAMARIN>++homepage: http://www.infsec.ethz.ch/research/software#TAMARIN+++--------------+-- extra files+--------------++data-dir: data+data-files:+ LICENSE+ AUTHORS++ -- cached intruder variants for DH-exponentiation+ intruder_variants_dh.spthy++ -- files for the web-frontend+ img/*.ico+ img/*.gif+ img/*.png+ js/*.js+ css/*.css+ css/smoothness/*.css+ css/smoothness/images/*.png++ -- vim syntax highlighting+ etc/spthy.vim+ etc/filetype.vim++ -- example files+ examples/UserGuide.spthy+ examples/TLS.spthy+ -- examples/Typing_Invariant_Example.spthy++ -- CSF'12 case studies+ examples/csf12/Artificial.spthy++ examples/csf12/KEA_plus_KI_KCI.spthy+ examples/csf12/KEA_plus_KI_KCI_wPFS.spthy+ examples/csf12/KEA_plus_eCK.spthy++ examples/csf12/NAXOS_eCK_PFS.spthy+ examples/csf12/NAXOS_eCK.spthy++ examples/csf12/UM_eCK.spthy+ examples/csf12/UM_eCK_noKCI.spthy+ examples/csf12/UM_PFS.spthy+ examples/csf12/UM_wPFS.spthy+ examples/csf12/UM_PFS.spthy++ examples/csf12/SignedDH_PFS.spthy+ examples/csf12/SignedDH_eCK.spthy++ examples/csf12/STS-MAC.spthy+ examples/csf12/STS-MAC-fix1.spthy+ examples/csf12/STS-MAC-fix2.spthy++ examples/csf12/JKL_TS1_2004-KI.spthy+ examples/csf12/JKL_TS1_2008-KI_wPFS.spthy+ examples/csf12/JKL_TS1_2008-KI.spthy+ examples/csf12/JKL_TS2_2004-KI_wPFS.spthy+ examples/csf12/JKL_TS2_2004-KI.spthy+ examples/csf12/JKL_TS2_2008-KI_wPFS.spthy+ examples/csf12/JKL_TS2_2008-KI.spthy+ examples/csf12/JKL_TS3_2004-KI_wPFS.spthy-nonterm+ examples/csf12/JKL_TS3_2008-KI_wPFS.spthy-nonterm++extra-source-files:+ .ghci+ interactive-only-src/Paths_tamarin_prover.hs+ interactive-only-src/Lexer.x++ README+ CHANGES+++--------------+-- build flags+--------------++flag threaded+ default: True+ description: Build with support for multithreaded execution++flag test-coverage+ default: True+ description: Build with test coverage support++Flag build-tests+ default: False+ description: Build unit test driver+++----------------------+-- executables stanzas+----------------------++executable tamarin-prover+ build-depends:+ base == 4.*+ , array == 0.3.*+ , deepseq == 1.1.*+ , containers >= 0.3 && < 0.4.2+ , mtl == 2.0.*+ , cmdargs == 0.6.* && >= 0.6.8+ , filepath >= 1.1 && < 1.3+ , directory >= 1.0 && < 1.2+ , process == 1.0.*+ , parsec == 3.1.*+ , bytestring == 0.9.*+ , safe >= 0.2 && < 0.4+ , transformers == 0.2.*+ , fclabels == 1.0.*+ , uniplate == 1.6.*+ , syb == 0.3.* && >= 0.3.3+ , binary == 0.5.*+ , derive == 2.5.*+ , time == 1.2.*+ , threads == 0.4.*+ , http-types == 0.6.*+ , blaze-builder == 0.3.*+ , yesod-core == 0.8.*+ , yesod-json == 0.1.*+ , yesod-static == 0.1.*+ , yesod-form == 0.1.*+ , text == 0.11.*+ , wai == 0.4.*+ , hamlet == 0.8.*+ , warp == 0.4.*+ , aeson == 0.3.*+ , old-locale == 1.0.*+ , monad-control == 0.2.*+ , parallel == 3.2.*++ , tamarin-prover-utils == 0.1.*+ , tamarin-prover-term == 0.1.*++ -- extra deps to get it building on GHC 7.0.3 without the new modular+ --solver of cabal-install, activated with flag --solver=modular+ if impl(ghc <= 7.2)+ build-depends:+ template-haskell == 2.5.*+ , data-default == 0.2.*+ , wai-extra == 0.4.3++ if flag(threaded)+ ghc-options: -threaded++ ghc-options: -Wall -funbox-strict-fields -fwarn-tabs -rtsopts+ main-is: Main.hs+ hs-source-dirs: src++ other-modules:+ Theory.Pretty+ Theory.Fact+ Theory.Atom+ Theory.Formula+ Theory.Rule+ Theory.IntruderRules+ Theory.Proof.Guarded+ Theory.Proof.Types+ Theory.Proof.EquationStore+ Theory.Proof.SolveGuarded+ Theory.Proof.Sequent+ Theory.Proof.Sequent.Dot+ Theory.Proof.CaseDistinctions+ Theory.Proof+ Theory.RuleVariants+ Theory.Signature+ Theory+ Theory.Lexer+ Theory.Parser+ Theory.Wellformedness++ Web.Settings+ Web.Types+ Web.Theory+ Web.Hamlet+ Web.Instances+ Web.Handler+ Web.Dispatch