summaryrefslogtreecommitdiff
path: root/libgpl
diff options
context:
space:
mode:
Diffstat (limited to 'libgpl')
-rw-r--r--libgpl/CHANGELOG39
-rw-r--r--libgpl/LICENSE671
-rw-r--r--libgpl/README8
-rw-r--r--libgpl/caldav/caldav-client.php468
-rw-r--r--libgpl/caldav/caldav_sync.php284
-rw-r--r--libgpl/caldav/vobject_sanitize.php110
-rw-r--r--libgpl/contextmenu/jquery.contextMenu.js1686
-rw-r--r--libgpl/contextmenu/jquery.ui.position.js497
-rw-r--r--libgpl/date/date.js335
-rw-r--r--libgpl/dialogextend/jquery.dialogextend.js509
-rw-r--r--libgpl/dialogextend/jquery.dialogextend.min.js2
-rw-r--r--libgpl/encryption/encryption.php166
-rw-r--r--libgpl/fancybox/blank.gifbin0 -> 43 bytes
-rw-r--r--libgpl/fancybox/fancy_close.pngbin0 -> 1517 bytes
-rw-r--r--libgpl/fancybox/fancy_closebox.pngbin0 -> 1910 bytes
-rw-r--r--libgpl/fancybox/fancy_left.pngbin0 -> 1623 bytes
-rw-r--r--libgpl/fancybox/fancy_loading.pngbin0 -> 10195 bytes
-rw-r--r--libgpl/fancybox/fancy_nav_left.pngbin0 -> 1446 bytes
-rw-r--r--libgpl/fancybox/fancy_nav_right.pngbin0 -> 1454 bytes
-rw-r--r--libgpl/fancybox/fancy_progress.pngbin0 -> 12412 bytes
-rw-r--r--libgpl/fancybox/fancy_right.pngbin0 -> 1645 bytes
-rw-r--r--libgpl/fancybox/fancy_shadow_e.pngbin0 -> 107 bytes
-rw-r--r--libgpl/fancybox/fancy_shadow_n.pngbin0 -> 106 bytes
-rw-r--r--libgpl/fancybox/fancy_shadow_ne.pngbin0 -> 347 bytes
-rw-r--r--libgpl/fancybox/fancy_shadow_nw.pngbin0 -> 324 bytes
-rw-r--r--libgpl/fancybox/fancy_shadow_s.pngbin0 -> 111 bytes
-rw-r--r--libgpl/fancybox/fancy_shadow_se.pngbin0 -> 352 bytes
-rw-r--r--libgpl/fancybox/fancy_shadow_sw.pngbin0 -> 340 bytes
-rw-r--r--libgpl/fancybox/fancy_shadow_w.pngbin0 -> 103 bytes
-rw-r--r--libgpl/fancybox/fancy_title_left.pngbin0 -> 503 bytes
-rw-r--r--libgpl/fancybox/fancy_title_main.pngbin0 -> 96 bytes
-rw-r--r--libgpl/fancybox/fancy_title_over.pngbin0 -> 70 bytes
-rw-r--r--libgpl/fancybox/fancy_title_right.pngbin0 -> 506 bytes
-rw-r--r--libgpl/fancybox/fancybox-x.pngbin0 -> 203 bytes
-rw-r--r--libgpl/fancybox/fancybox-y.pngbin0 -> 176 bytes
-rw-r--r--libgpl/fancybox/fancybox.pngbin0 -> 15287 bytes
-rw-r--r--libgpl/fancybox/jquery.easing-1.3.pack.js72
-rw-r--r--libgpl/fancybox/jquery.fancybox-1.3.4.css359
-rw-r--r--libgpl/fancybox/jquery.fancybox-1.3.4.js1156
-rw-r--r--libgpl/fancybox/jquery.fancybox-1.3.4.pack.js46
-rw-r--r--libgpl/fancybox/jquery.mousewheel-3.0.4.pack.js14
-rw-r--r--libgpl/flashclipboard/clipboard.swfbin0 -> 1071 bytes
-rw-r--r--libgpl/flashclipboard/flashclipboard_libgpl.js309
-rw-r--r--libgpl/flashclipboard/flashclipboard_moreuserinfo.js290
-rw-r--r--libgpl/gibberish/GibberishAES.php213
-rw-r--r--libgpl/gibberish/gibberish-aes.js36
-rw-r--r--libgpl/gibberish/gibberish-aes.js.comp.src1017
-rw-r--r--libgpl/http_request/class.http.php1190
-rw-r--r--libgpl/ical/ical_sync.php144
-rw-r--r--libgpl/jquery_migrate/jquery.migrate.js521
-rw-r--r--libgpl/libcalendaring/libcalendaring.js676
-rw-r--r--libgpl/libgpl.php189
-rw-r--r--libgpl/localization/cs_CZ.inc48
-rw-r--r--libgpl/localization/en_US.inc36
-rw-r--r--libgpl/localization/es_ES.inc48
-rw-r--r--libgpl/localization/fi_FI.inc48
-rw-r--r--libgpl/localization/fr_FR.inc51
-rw-r--r--libgpl/localization/revision.inc.php11
-rw-r--r--libgpl/package.xml22
-rw-r--r--libgpl/password/password.js36
-rw-r--r--libgpl/qtip/qtip.css1
-rw-r--r--libgpl/qtip/qtip.js68
-rw-r--r--libgpl/querystring/querystring.js34
-rw-r--r--libgpl/skins/classic/calendar.css4
-rw-r--r--libgpl/skins/classic/images/convert.pngbin0 -> 709 bytes
-rw-r--r--libgpl/skins/classic/images/delete.pngbin0 -> 536 bytes
-rw-r--r--libgpl/skins/classic/images/door.pngbin0 -> 412 bytes
-rw-r--r--libgpl/skins/classic/images/edit.pngbin0 -> 618 bytes
-rw-r--r--libgpl/skins/classic/images/message.pngbin0 -> 376 bytes
-rw-r--r--libgpl/skins/classic/images/note.pngbin0 -> 844 bytes
-rw-r--r--libgpl/skins/classic/images/task.pngbin0 -> 684 bytes
-rw-r--r--libgpl/skins/classic/images/ui-bg_highlight-hard_75_f8f8f8_1x100.pngbin0 -> 88 bytes
-rw-r--r--libgpl/skins/classic/images/ui-bg_highlight-hard_90_e6e6e7_1x100.pngbin0 -> 101 bytes
-rw-r--r--libgpl/skins/classic/images/ui-bg_highlight-soft_90_e4e4e4_1x100.pngbin0 -> 111 bytes
-rw-r--r--libgpl/skins/classic/images/ui-icons_004458_256x240.pngbin0 -> 4369 bytes
-rw-r--r--libgpl/skins/classic/jquery.contextMenu.css141
-rw-r--r--libgpl/skins/classic/timepicker2.css10
-rw-r--r--libgpl/skins/larry/calendar.css6
-rw-r--r--libgpl/skins/larry/images/ui-bg_highlight-hard_75_f8f8f8_1x100.pngbin0 -> 88 bytes
-rw-r--r--libgpl/skins/larry/images/ui-bg_highlight-soft_90_e4e4e4_1x100.pngbin0 -> 111 bytes
-rw-r--r--libgpl/skins/larry/images/ui-icons_004458_256x240.pngbin0 -> 4369 bytes
-rw-r--r--libgpl/skins/larry/jquery.contextMenu.css154
-rw-r--r--libgpl/skins/larry/timepicker2.css13
-rw-r--r--libgpl/timepicker/jquery.timepicker.css72
-rw-r--r--libgpl/timepicker/jquery.timepicker.js1149
-rw-r--r--libgpl/timepicker/jquery.timepicker.min.js7
-rw-r--r--libgpl/timepicker2/jquery.timepicker.js2223
87 files changed, 15189 insertions, 0 deletions
diff --git a/libgpl/CHANGELOG b/libgpl/CHANGELOG
new file mode 100644
index 0000000..9defcc5
--- /dev/null
+++ b/libgpl/CHANGELOG
@@ -0,0 +1,39 @@
+VERSION COMMENT
+----------------------------------------------------------------------------------
+1.0 - Initial release
+1.0.1 - Added log option to CalDAV client
+1.0.2 - Added date.js toolbox
+ (http://www.mattkruse.com/javascript/date)
+1.0.3 - Added sync interval property to caldav sync client
+1.0.4 - Moved ical_sync to libgpl
+1.0.5 - Include querystring.js for tasklist
+1.0.6 - Replace the big close button in jquery dialogs
+1.0.7 - 1.0.9 - Fetch reminders almost immediately after page
+ initialization and not with a delay of 1 minute
+1.0.10 - 1.0.12 - Include jquery contexmenu
+ (http://medialize.github.io/jQuery-contextMenu/demo.html)
+1.0.13 - Include date.js for sticky_notes
+1.0.14 - Larry skin improvements
+1.0.15 - Implement contextmenu for sticky_notes
+1.0.16 - Include fancybox
+1.0.17 - Re-organize folder structure
+1.0.18 - Clean up larry skin images
+1.0.19 - Include jquery timepicker
+1.0.20 - Include http_request
+1.0.21 - Make sure jqueryui plugin is loaded first of all
+1.0.22 - 1.0.23 - Include qtip
+1.0.24 - Fix javascript error in libcalendaring.js if date format
+ is undefined
+1.0.25 - Move label overwrites to libgpl
+1.0.26 - Add password.js overwrite
+1.0.27 - CalDAV: Send User-Agent header
+1.0.28 - 1.0.29 - Implement gzip decompression in ical driver
+1.0.30 - css fix: min-width for jqueryui dialogs (calendar/
+ carddav plugins)
+1.0.31 - CalDAV: Implemented digest authentication
+1.0.32 - 1.0.33 - CardDAV: Overwrite default subscribed label
+1.0.34 - Header User-Agent: MyRoundcube-SabreDAV
+1.0.35 - Move SabreDAV components to libcalendaring plugin
+1.0.36 - CalDAV: Don't use gmdate for UTC timezone conversion
+1.0.37 - CalDAV: Make cURL verify host configurable
+1.0.38 - CalDAV: Implement DELETE request \ No newline at end of file
diff --git a/libgpl/LICENSE b/libgpl/LICENSE
new file mode 100644
index 0000000..56c3b5b
--- /dev/null
+++ b/libgpl/LICENSE
@@ -0,0 +1,671 @@
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+dev-team [at] myroundcube [dot] com
+http://myroundcube.com
+
+--- LICENSE DETAILS ---
+
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU Affero General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+<http://www.gnu.org/licenses/>.
diff --git a/libgpl/README b/libgpl/README
new file mode 100644
index 0000000..df9059f
--- /dev/null
+++ b/libgpl/README
@@ -0,0 +1,8 @@
+libgpl
+------
+Documentation:
+http://myroundcube.com/myroundcube-plugins/
+
+
+MyRoundcube Dev Team
+www.myroundcube.com \ No newline at end of file
diff --git a/libgpl/caldav/caldav-client.php b/libgpl/caldav/caldav-client.php
new file mode 100644
index 0000000..417c42b
--- /dev/null
+++ b/libgpl/caldav/caldav-client.php
@@ -0,0 +1,468 @@
+<?php
+
+/**
+ * CalDAV Client
+ *
+ * @version @package_version@
+ * @author Daniel Morlock <daniel.morlock@awesome-it.de>
+ *
+ * Copyright (C) 2013, Awesome IT GbR <info@awesome-it.de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+require_once (dirname(__FILE__).'/../../libcalendaring/SabreDAV/vendor/autoload.php');
+require_once (dirname(__FILE__).'/vobject_sanitize.php');
+
+
+class caldav_client extends Sabre\DAV\Client
+{
+ const CLARK_GETCTAG = '{http://calendarserver.org/ns/}getctag';
+ const CLARK_GETETAG = '{DAV:}getetag';
+ const CLARK_CALDATA = '{urn:ietf:params:xml:ns:caldav}calendar-data';
+
+ public $base_uri;
+ public $path;
+ private $libvcal;
+ private $rc;
+ private $user_agent;
+
+ /**
+ * Default constructor for CalDAV client.
+ *
+ * @param string Caldav URI to appropriate calendar.
+ * @param string Username for HTTP basic auth.
+ * @param string Password for HTTP basic auth.
+ * @param boolean Verify SSL cert. // Mod by Rosali (https://gitlab.awesome-it.de/kolab/roundcube-plugins/issues/1)
+ */
+ public function __construct($uri, $user = null, $pass = null, $verifySSL = array(true, true)) // Mod by Rosali (https://gitlab.awesome-it.de/kolab/roundcube-plugins/issues/1)
+ {
+ $this->user_agent = 'MyRoundcube-SabreDAV/' . Sabre\DAV\Version::VERSION;
+
+ // Include libvcalendar on demand ...
+ if(!class_exists("libvcalendar"))
+ require_once (dirname(__FILE__).'/../../libcalendaring/libvcalendar.php');
+
+ $this->libvcal = new libvcalendar();
+ $this->rc = rcube::get_instance();
+
+ $tokens = parse_url($uri);
+ $this->base_uri = $tokens['scheme']."://".$tokens['host'].($tokens['port'] ? ":".$tokens['port'] : null);
+ $this->path = $tokens['path'].($tokens['query'] ? "?".$tokens['query'] : null);
+ $settings = array(
+ 'baseUri' => $this->base_uri,
+ 'authType' => Sabre\DAV\Client::AUTH_BASIC
+ );
+
+ if ($user) $settings['userName'] = $user;
+ if ($pass) $settings['password'] = $pass;
+
+ parent::__construct($settings);
+
+ $this->verifyPeer = $verifySSL[0];
+ $this->verifyHost = $verifySSL[1];
+ $this->authType = CURLAUTH_BASIC | CURLAUTH_ANY;
+ }
+
+ /**
+ * Fetches calendar ctag.
+ *
+ * @see http://code.google.com/p/sabredav/wiki/BuildingACalDAVClient#Retrieving_calendar_information
+ * @return Calendar ctag or null on error.
+ */
+ public function get_ctag()
+ {
+ try
+ {
+ $arr = $this->propFind($this->path, array(self::CLARK_GETCTAG));
+
+ if (isset($arr[self::CLARK_GETCTAG]))
+ return $arr[self::CLARK_GETCTAG];
+ }
+ catch(Sabre\DAV\Exception $err)
+ {
+ rcube::raise_error(array(
+ 'code' => $err->getHTTPCode(),
+ 'type' => 'DAV',
+ 'file' => $err->getFile(),
+ 'line' => $err->getLine(),
+ 'message' => $err->getMessage()
+ ), true, false);
+ }
+
+ return null;
+ }
+
+ /**
+ * Fetches event etags and urls.
+ *
+ * @see http://code.google.com/p/sabredav/wiki/BuildingACalDAVClient#Finding_out_if_anything_changed
+ *
+ * @param array Optional list of relative event URL's to retrieve specific etags. If not specified, all etags of the current calendar are returned.
+ * @return array List of etag properties with keys:
+ * url: Event ical path relative to the calendar URL.
+ * etag: Current event etag.
+ */
+ public function get_etags(array $event_urls = array())
+ {
+ $etags = array();
+
+ try
+ {
+ $arr = $this->prop_report($this->path, array(self::CLARK_GETETAG), $event_urls);
+ foreach ($arr as $path => $data)
+ {
+ // Some caldav server return an empty calendar as event where etag is missing. Skip this!
+ if($data[self::CLARK_GETETAG])
+ {
+ array_push($etags, array(
+ "url" => $path,
+ "etag" => str_replace('"', null, $data[self::CLARK_GETETAG])
+ ));
+ }
+ }
+ }
+ catch(Sabre\DAV\Exception $err)
+ {
+ rcube::raise_error(array(
+ 'code' => $err->getHTTPCode(),
+ 'type' => 'DAV',
+ 'file' => $err->getFile(),
+ 'line' => $err->getLine(),
+ 'message' => $err->getMessage()
+ ), true, false);
+ }
+
+ return $etags;
+ }
+
+ /**
+ * Fetches calendar events.
+ *
+ * @see http://code.google.com/p/sabredav/wiki/BuildingACalDAVClient#Downloading_objects
+ * @param array $urls = array() Optional list of event URL's to fetch. If non is specified, all
+ * events from the appropriate calendar will be fetched.
+ * @return Array hash list that maps the events URL to the appropriate event properties.
+ */
+ public function get_events($urls = array())
+ {
+ $events = array();
+
+ try
+ {
+ $vcals = $this->prop_report($this->path, array(
+ self::CLARK_GETETAG,
+ self::CLARK_CALDATA
+ ), $urls);
+
+ foreach ($vcals as $path => $response)
+ {
+ $vcal = $response[self::CLARK_CALDATA];
+ $vobject_sanitize = new vobject_sanitize($vcal, array('CATEGORIES'), 'serialize');
+ $vcal = $vobject_sanitize->vobject;
+ $vobject_sanitize = new vobject_sanitize($vcal, array('RDATE'), 'unserialize');
+ $vcal = $vobject_sanitize->vobject;
+ foreach ($this->libvcal->import($vcal) as $event) {
+ $events[$path] = $event;
+ }
+ }
+ }
+ catch(Sabre\DAV\Exception $err)
+ {
+ rcube::raise_error(array(
+ 'code' => $err->getHTTPCode(),
+ 'type' => 'DAV',
+ 'file' => $err->getFile(),
+ 'line' => $err->getLine(),
+ 'message' => $err->getMessage()
+ ), true, false);
+ }
+ return $events;
+ }
+
+ /**
+ * Does a REPORT request
+ *
+ * @param string $url
+ * @param array $properties List of requested properties must be specified as an array, in clark
+ * notation.
+ * @param array $event_urls If specified, a multiget report request will be initiated with the
+ * specified event urls.
+ * @param int $depth = 1 Depth should be either 0 or 1. A depth of 1 will cause a request to be
+ * made to the server to also return all child resources.
+ * @return array Hash with ics event path as key and a hash array with properties and appropriate values.
+ */
+ public function prop_report($url, array $properties, array $event_urls = array(), $depth = 1)
+ {
+ $url = slashify($url); // iCloud
+
+ $parent_tag = sizeof($event_urls) > 0 ? "c:calendar-multiget" : "d:propfind";
+ $method = sizeof($event_urls) > 0 ? 'REPORT' : 'PROPFIND';
+
+ $body = '<?xml version="1.0"?>'."\n".'<'.$parent_tag.' xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav">'."\n";
+
+ $body .= ' <d:prop>'."\n";
+ foreach ($properties as $property)
+ {
+
+ list($namespace, $elementName) = Sabre\DAV\XMLUtil::parseClarkNotation($property);
+
+ if ($namespace === 'DAV:')
+ {
+ $body .= ' <d:'.$elementName.' />'."\n";
+ }
+ else
+ {
+ $body .= ' <x:'.$elementName.' xmlns:x="'.$namespace.'"/>'."\n";
+ }
+ }
+ $body .= ' </d:prop>'."\n";
+
+ // http://tools.ietf.org/html/rfc4791#page-90
+ // http://www.bedework.org/trac/bedework/wiki/Bedework/DevDocs/Filters
+ /*
+ if($start && $end)
+ {
+ $body.= ' <c:filter>'."\n".
+ ' <c:comp-filter name="VCALENDAR">'."\n".
+ ' <c:comp-filter name="VEVENT">'."\n".
+ ' <c:time-range start="'.$start.'" end="'.$end.'" />'."\n".
+ ' </c:comp-filter>'."\n".
+ ' </c:comp-filter>'."\n".
+ ' </c:filter>' . "\n";
+ }
+ */
+
+ foreach ($event_urls as $event_url)
+ {
+ $body .= '<d:href>'.$event_url.'</d:href>'."\n";
+ }
+
+ $body .= '</'.$parent_tag.'>';
+
+ $response = $this->request($method, $url, $body, array(
+ 'Depth' => $depth,
+ 'Content-Type' => 'application/xml',
+ 'User-Agent' => $this->user_agent
+ ));
+
+ $result = $this->parseMultiStatus($response['body']);
+
+ // If depth was 0, we only return the top item
+ if ($depth === 0)
+ {
+ reset($result);
+ $result = current($result);
+ return isset($result[200]) ? $result[200] : array();
+ }
+
+ $new_result = array();
+ foreach ($result as $href => $status_list)
+ {
+ $new_result[$href] = isset($status_list[200]) ? $status_list[200] : array();
+ }
+
+ return $new_result;
+ }
+
+ /**
+ * Updates or creates a calendar event.
+ *
+ * @see http://code.google.com/p/sabredav/wiki/BuildingACalDAVClient#Updating_a_calendar_object
+ * @param string Event ics path for the event.
+ * @param array Hash array with event properties.
+ * @param string Current event etag to match against server data. Pass null for new events.
+ * @return True on success, -1 if precondition failed i.e. local etag is not up to date, false on error.
+ */
+ public function put_event($path, $event, $etag = null)
+ {
+ try
+ {
+ $headers = array(
+ 'Content-Type' => 'text/calendar; charset=utf-8',
+ 'User-Agent' => $this->user_agent
+ );
+ if ($etag) $headers["If-Match"] = '"'.$etag.'"';
+
+ // Temporarily disable error reporting since libvcal seems not checking array key properly.
+ // TODO: Remove this todo if we could ensure that those errors come not from incomplete event properties.
+ //$err_rep = error_reporting(E_ERROR);
+ $vcal = $this->libvcal->export(array($event));
+ if (is_array($vcal))
+ $vcal = array_shift($vcal);
+
+ //error_reporting($err_rep);
+ $response = $this->request('PUT', $path, $vcal, $headers);
+
+ // Following http://code.google.com/p/sabredav/wiki/BuildingACalDAVClient#Creating_a_calendar_object, the
+ // caldav server must not always return the new etag.
+
+ return $response["statusCode"] == 201 || // 201 (created, successfully created)
+ $response["statusCode"] == 204; // 204 (no content, successfully updated)
+ }
+ catch(Sabre\DAV\Exception\PreconditionFailed $err)
+ {
+ // Event tag not up to date, must be updated first ...
+ return -1;
+ }
+ catch(Sabre\DAV\Exception $err)
+ {
+ rcube::raise_error(array(
+ 'code' => $err->getHTTPCode(),
+ 'type' => 'DAV',
+ 'file' => $err->getFile(),
+ 'line' => $err->getLine(),
+ 'message' => $err->getMessage()
+ ), true, false);
+ }
+ return false;
+ }
+
+ /**
+ * Removes event of given URL.
+ *
+ * @see http://code.google.com/p/sabredav/wiki/BuildingACalDAVClient#Deleting_a_calendar_object
+ * @param string Event ics path for the event.
+ * @param string Current event etag to match against server data. Pass null to force removing the event.
+ * @return True on success, -1 if precondition failed i.e. local etag is not up to date, false on error.
+ **/
+ public function remove_event($path, $etag = null)
+ {
+ return $this->delete_request($path, $etag);
+ }
+
+ /**
+ * Fires a DELETE request to a given URL.
+ *
+ * @see http://code.google.com/p/sabredav/wiki/BuildingACalDAVClient#Deleting_a_calendar_object
+ * @param string Path.
+ * @param string Current etag to match against server data or null.
+ * @return True on success, -1 if precondition failed i.e. local etag is not up to date, false on error.
+ **/
+ public function delete_request($path, $etag = null)
+ {
+ try
+ {
+ $headers = array(
+ 'Content-Type' => 'text/calendar; charset=utf-8',
+ 'User-Agent' => $this->user_agent
+ );
+ if ($etag) $headers["If-Match"] = '"'.$etag.'"';
+
+ $response = $this->request('DELETE', $path, null, $headers);
+ return $response["statusCode"] == 204; // 204 (no content, successfully deleted);
+ }
+ catch(Sabre\DAV\Exception\PreconditionFailed $err)
+ {
+ // Event tag not up to date, must be updated first ...
+ return -1;
+ }
+ catch(Sabre\DAV\Exception $err)
+ {
+ rcube::raise_error(array(
+ 'code' => $err->getHTTPCode(),
+ 'type' => 'DAV',
+ 'file' => $err->getFile(),
+ 'line' => $err->getLine(),
+ 'message' => $err->getMessage()
+ ), true, false);
+ }
+ return false;
+ }
+
+ /**
+ * Make a propFind query to caldav server
+ * @param string $path absolute or relative URL to Resource
+ * @param array $props list of properties to use for the query. Properties must have clark-notation.
+ * @param int $depth 0 means no recurse while 1 means recurse
+ * @param boolean $log log exception
+ * @return array
+ */
+ public function prop_find($path, $props, $depth, $log = true)
+ {
+ try {
+ $response = $this->propFind($path, $props, $depth);
+ }
+ catch(Sabre\DAV\Exception $err)
+ {
+ rcube::raise_error(array(
+ 'code' => $err->getHTTPCode(),
+ 'type' => 'DAV',
+ 'file' => $err->getFile(),
+ 'line' => $err->getLine(),
+ 'message' => $err->getMessage()
+ ), $log, false);
+ }
+ return $response;
+ }
+
+ /**
+ * Add a caldendar collection
+ * @param string collection URL
+ * @parma string displayname
+ * @param string resource type
+ * @param string namespace
+ * @return array response
+ */
+ public function add_collection($url, $displayname, $resourcetype, $namespace)
+ {
+ $body = '<?xml version="1.0" encoding="utf-8" ?>' .
+ '<D:mkcol xmlns:D="DAV:"xmlns:C="urn:ietf:params:xml:ns:' . $namespace . '">' .
+ ' <D:set>' .
+ ' <D:prop>' .
+ ' <D:resourcetype>' .
+ ' <D:collection/> ' .
+ ' <C:' . $resourcetype . '/>' .
+ ' </D:resourcetype>' .
+ ' <D:displayname>' . $displayname . '</D:displayname>' .
+ ' </D:prop>' .
+ ' </D:set>' .
+ ' </D:mkcol>';
+
+ try {
+ $response = $this->request('MKCOL', $url, $body, array(
+ 'Content-Type' => 'application/xml',
+ 'User-Agent' => $this->user_agent
+ ));
+ }
+ catch(Sabre\DAV\Exception $err)
+ {
+ return false;
+ }
+ return $response;
+ }
+
+ /**
+ * Freebusy request for a given user
+ * @param string username
+ * @param path relative path to base uri
+ * @param integer unix timestamp
+ * @param integer unix timestamp
+ * @retrun array List of busy timeslots within the requested range
+ */
+ public function freebusy($user, $path, $start, $end)
+ {
+ $body = '<?xml version="1.0" encoding="utf-8" ?>' .
+ '<C:free-busy-query xmlns:C="urn:ietf:params:xml:ns:caldav">' .
+ '<C:time-range start="' . gmdate("Ymd\THis\Z", $start) . '"' .
+ ' end="' . gmdate("Ymd\THis\Z", $end) . '"/>' .
+ '</C:free-busy-query>';
+ return $this->request('REPORT', $path, $body, array(
+ 'Content-Type' => 'application/xml',
+ 'Depth' => 1,
+ 'User-Agent' => $this->user_agent
+ ));
+ }
+};
+?>
diff --git a/libgpl/caldav/caldav_sync.php b/libgpl/caldav/caldav_sync.php
new file mode 100644
index 0000000..0266af4
--- /dev/null
+++ b/libgpl/caldav/caldav_sync.php
@@ -0,0 +1,284 @@
+<?php
+/**
+ * CalDAV sync for the Calendar plugin
+ *
+ * @version @package_version@
+ * @author Daniel Morlock <daniel.morlock@awesome-it.de>
+ *
+ * Copyright (C) 2013, Awesome IT GbR <info@awesome-it.de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+require_once (dirname(__FILE__) . '/caldav-client.php');
+
+class caldav_sync
+{
+ const ACTION_NONE = 1;
+ const ACTION_UPDATE = 2;
+ const ACTION_CREATE = 4;
+
+ private $cal_id = null;
+ private $ctag = null;
+ private $user = null;
+ private $pass = null;
+ private $url = null;
+ private $env;
+
+ public $sync = 0;
+
+ /**
+ * Default constructor for calendar synchronization adapter.
+ *
+ * @param int Calendar id.
+ * @param array Hash array with caldav properties:
+ * url: Caldav calendar URL.
+ * user: Caldav http basic auth user.
+ * pass: Password für caldav user.
+ * ctag: Caldav ctag for calendar.
+ * @param boolean verify SSL Cert // Mod by Rosali (https://gitlab.awesome-it.de/kolab/roundcube-plugins/issues/1)
+ */
+ public function __construct($cal_id, $props, $verifySSL, $env)
+ {
+ $this->env = $env;
+ $this->cal_id = $cal_id;
+
+ $this->url = $props["url"];
+ $this->ctag = isset($props["tag"]) ? $props["tag"] : null;
+ $this->user = isset($props["user"]) ? $props["user"] : null;
+ $this->pass = isset($props["pass"]) ? $props["pass"] : null;
+ $this->sync = isset($props["sync"]) ? $props["sync"] : 0;
+
+ $this->caldav = new caldav_client($this->url, $this->user, $this->pass, $verifySSL); // Mod by Rosali (https://gitlab.awesome-it.de/kolab/roundcube-plugins/issues/1)
+ }
+
+ /**
+ * Getter for current calendar ctag.
+ * @return string
+ */
+ public function get_ctag()
+ {
+ return $this->ctag;
+ }
+
+ /**
+ * Determines whether current calendar needs to be synced
+ * regarding the CalDAV ctag.
+ *
+ * @return True if the current calendar ctag differs from the CalDAV tag which
+ * indicates that there are changes that must be synched. Returns false
+ * if the calendar is up to date, no sync necesarry.
+ */
+ public function is_synced($force = false)
+ {
+ $is_synced = $this->ctag == $this->caldav->get_ctag() && $this->ctag;
+ $env = $this->env;
+ $env::debug_log("Ctag indicates that calendar \"$this->cal_id\" ".($is_synced ? "is synced." : "needs update!"));
+
+ return $is_synced;
+ }
+
+ /**
+ * Synchronizes given events with caldav server and returns updates.
+ *
+ * @param array List of local events.
+ * @param array List of caldav properties for each event.
+ * @return array Tuple containing the following lists:
+ *
+ * Caldav properties for events to be created or to be updated with the keys:
+ * url: Event ical URL relative to calendar URL
+ * etag: Remote etag of the event
+ * local_event: The local event in case of an update.
+ * remote_event: The current event retrieved from caldav server.
+ *
+ * A list of event ids that are in sync.
+ */
+ public function get_updates($events, $caldav_props)
+ {
+ $ctag = $this->caldav->get_ctag();
+
+ if($ctag)
+ {
+ $this->ctag = $ctag;
+ $etags = $this->caldav->get_etags();
+ list($updates, $synced_event_ids) = $this->_get_event_updates($events, $caldav_props, $etags);
+ return array($this->_get_event_data($updates), $synced_event_ids);
+ }
+ else
+ {
+ $env = $this->env;
+ $env::debug_log("Unkown error while fetching calendar ctag for calendar \"$this->cal_id\"!");
+ }
+
+ return null;
+ }
+
+ /**
+ * Determines sync status and requried updates for the given events using given list of etags.
+ *
+ * @param array List of local events.
+ * @param array List of caldav properties for each event.
+ * @param array List of current remote etags.
+ * @return array Tuple containing the following lists:
+ *
+ * Caldav properties for events to be created or to be updated with the keys:
+ * url: Event ical URL relative to calendar URL
+ * etag: Remote etag of the event
+ * local_event: The local event in case of an update.
+ *
+ * A list of event ids that are in sync.
+ */
+ private function _get_event_updates($events, $caldav_props, $etags)
+ {
+ $updates = array();
+ $in_sync = array();
+
+ foreach ($etags as $etag)
+ {
+ $url = $etag["url"];
+ $etag = $etag["etag"];
+ $event_found = false;
+ for($i = 0; $i < sizeof($events); $i ++)
+ {
+ if ($caldav_props[$i]["url"] == $url)
+ {
+ $event_found = true;
+
+ if ($caldav_props[$i]["tag"] != $etag)
+ {
+ $env = $this->env;
+ $env::debug_log("Event ".$events[$i]["uid"]." needs update.");
+
+ array_push($updates, array(
+ "local_event" => $events[$i],
+ "etag" => $etag,
+ "url" => $url
+ ));
+ }
+ else
+ {
+ array_push($in_sync, $events[$i]["id"]);
+ }
+ }
+ }
+
+ if (!$event_found)
+ {
+ $env = $this->env;
+ $env::debug_log("Found new event ".$url);
+
+ array_push($updates, array(
+ "url" => $url,
+ "etag" => $etag
+ ));
+ }
+ }
+
+ return array($updates, $in_sync);
+ }
+
+ /**
+ * Fetches event data and attaches it to the given update properties.
+ *
+ * @param $updates List of update properties.
+ * @return array List of update properties with additional key "remote_event" containing the current caldav event.
+ */
+ private function _get_event_data($updates)
+ {
+ $urls = array();
+
+ foreach ($updates as $update)
+ {
+ array_push($urls, $update["url"]);
+ }
+
+ $events = $this->caldav->get_events($urls);
+
+ foreach($updates as &$update)
+ {
+ // Attach remote events to the appropriate updates.
+ // Note that this assumes unique event URL's!
+ $url = $update["url"];
+ if($events[$url]) {
+ $update["remote_event"] = $events[$url];
+ $update["remote_event"]["calendar"] = $this->cal_id;
+ }
+ }
+
+ return $updates;
+ }
+
+ /**
+ * Creates the given event on the caldav server.
+ *
+ * @param array Hash array with event properties.
+ * @return Caldav properties with created URL on success, false on error.
+ */
+ public function create_event($event)
+ {
+ $props = array(
+ "url" => parse_url($this->url, PHP_URL_PATH)."/".$event["uid"].".ics",
+ "tag" => null
+ );
+
+ $env = $this->env;
+ $env::debug_log("Push new event to url ".$props["url"]);
+ $result = $this->caldav->put_event($props["url"], $event);
+
+ if($result == false || $result < 0) return false;
+ return $props;
+ }
+
+ /**
+ * Updates the given event on the caldav server.
+ *
+ * @param array Hash array with event properties to update.
+ * @param array Hash array with caldav properties "url" and "tag" for the event.
+ * @return True on success, false on error, -1 if the given event/etag is not up to date.
+ */
+ public function update_event($event, $props)
+ {
+ $env = $this->env;
+ $env::debug_log("Updating event uid \"".$event["uid"]."\".");
+ return $this->caldav->put_event($props["url"], $event, $props["tag"]);
+ }
+
+ /**
+ * Removes the given event from the caldav server.
+ *
+ * @param array Hash array with caldav properties "url" and "tag" for the event.
+ * @return True on success, false on error.
+ */
+ public function remove_event($props)
+ {
+ $env = $this->env;
+ $env::debug_log("Removing event url \"".$props["url"]."\".");
+ return $this->caldav->remove_event($props["url"]);
+ }
+
+ /**
+ * Freebusy request for a given user.
+ *
+ * @param string username
+ * @param string relative path to caldav base uri
+ * @param integer unix timestamp
+ * @param integer unix timestamp
+ * @retrun array List of busy timeslots within the requested range
+ */
+ public function freebusy($user, $path, $start, $end)
+ {
+ return $this->caldav->freebusy($user, $path, $start, $end);
+ }
+};
+?> \ No newline at end of file
diff --git a/libgpl/caldav/vobject_sanitize.php b/libgpl/caldav/vobject_sanitize.php
new file mode 100644
index 0000000..9db4b41
--- /dev/null
+++ b/libgpl/caldav/vobject_sanitize.php
@@ -0,0 +1,110 @@
+<?php
+class vobject_sanitize
+{
+ public $vobject;
+ private $components = array('VEVENT', 'VTODO', 'VJOURNAL', 'VFREEBUSY', 'VTIMEZONE', 'VCARD', 'VALARM');
+ private $properties = array();
+
+ public function __construct($vobject, $properties = array(), $method = 'serialize')
+ {
+ $this->vobject = $vobject;
+ $this->properties = (array) $properties;
+ $this->_unfoald();
+ $this->_eol();
+ switch($method){
+ case 'serialize':
+ $this->_serialize();
+ break;
+ case 'unserialize':
+ $this->_unserialize();
+ break;
+ }
+ }
+
+ private function _unfoald()
+ {
+ $data = array();
+ $content = explode("\n", $this->vobject);
+ for($i = 0; $i < count($content); $i++){
+ $line = rtrim($content[$i]);
+ while(isset($content[$i + 1]) && strlen($content[$i + 1]) > 0 && ($content[$i+1]{0} == ' ' || $content[$i + 1]{0} == "\t" )){
+ $line .= rtrim(substr($content[++$i], 1));
+ }
+ $data[] = $line;
+ }
+ $this->vobject = implode(PHP_EOL, $data);
+ }
+
+ private function _eol()
+ {
+ $this->vobject = preg_replace('/\s\s+/', PHP_EOL, $this->vobject);
+ }
+
+ private function _serialize()
+ {
+ $tokens = array();
+ foreach($this->components as $component){
+ $regex = '#BEGIN:' . $component . '(?:(?!BEGIN:' . $component . ').)*?END:' . $component . '#si';
+ preg_match_all($regex, $this->vobject, $matches);
+ foreach($matches as $part){
+ foreach($part as $match){
+ $token = md5($match);
+ $tokens[$token] = $match;
+ $this->vobject = str_replace($match, '***' . $token . '***', $this->vobject);
+ }
+ }
+ foreach($tokens as $token => $content){
+ foreach($this->properties as $property){
+ $content = preg_replace('#' . PHP_EOL . $property . ':#i', PHP_EOL . 'X-ICAL-SANITIZE-' . $property . ':', $content, 1);
+ $content = preg_replace('#' . PHP_EOL . $property . ':#i', ',', $content);
+ $content = str_replace(PHP_EOL . 'X-ICAL-SANITIZE-' . $property . ':', PHP_EOL . $property . ':', $content);
+ $this->vobject = str_replace('***' . $token . '***', $content, $this->vobject);
+ }
+ }
+ }
+ }
+
+ private function _unserialize()
+ {
+ foreach($this->properties as $property){
+ preg_match_all('#' . PHP_EOL . $property . '.*:.*,.*' . PHP_EOL . '#i', $this->vobject, $matches);
+ $content = $this->vobject;
+ if(is_array($matches)){
+ foreach($matches[0] as $match){
+ $temp = explode(':', $match, 2);
+ $field = $temp[0];
+ $values = $temp[1];
+ $properties = explode(';', $field);
+ $tz = false;
+ foreach($properties as $idx => $property){
+ if(strtolower(substr($property, 0, 5)) == 'tzid='){
+ $temp = explode('=', $property, 2);
+ $tz = $temp[1];
+ unset($properties[$idx]);
+ }
+ if(strtolower(substr($property, 0, 6)) == 'value='){
+ $temp = explode('=', $property, 2);
+ $daot = $temp[1];
+ }
+ }
+ $field = implode(';', $properties);
+ $values = explode(',', $values);
+ $line = '';
+ foreach($values as $value){
+ if($tz){
+ $datetime = new DateTime($value, new DateTimeZone($tz));
+ if(strtolower($daot) == 'date-time'){
+ $ts = $datetime->format('U');
+ $value = gmdate('Ymd\THis\Z', $ts);
+ }
+ }
+ $line .= $field . ':' . $value . PHP_EOL;
+ }
+ $content = preg_replace('/\s\s+/', PHP_EOL, str_replace($match, $line, $content));
+ }
+ }
+ $this->vobject = $content;
+ }
+ }
+}
+?> \ No newline at end of file
diff --git a/libgpl/contextmenu/jquery.contextMenu.js b/libgpl/contextmenu/jquery.contextMenu.js
new file mode 100644
index 0000000..103a585
--- /dev/null
+++ b/libgpl/contextmenu/jquery.contextMenu.js
@@ -0,0 +1,1686 @@
+/*!
+ * jQuery contextMenu - Plugin for simple contextMenu handling
+ *
+ * Version: git-master
+ *
+ * Authors: Rodney Rehm, Addy Osmani (patches for FF)
+ * Web: http://medialize.github.com/jQuery-contextMenu/
+ *
+ * Licensed under
+ * MIT License http://www.opensource.org/licenses/mit-license
+ * GPL v3 http://opensource.org/licenses/GPL-3.0
+ *
+ */
+
+(function($, undefined){
+
+ // TODO: -
+ // ARIA stuff: menuitem, menuitemcheckbox und menuitemradio
+ // create <menu> structure if $.support[htmlCommand || htmlMenuitem] and !opt.disableNative
+
+// determine html5 compatibility
+$.support.htmlMenuitem = ('HTMLMenuItemElement' in window);
+$.support.htmlCommand = ('HTMLCommandElement' in window);
+$.support.eventSelectstart = ("onselectstart" in document.documentElement);
+/* // should the need arise, test for css user-select
+$.support.cssUserSelect = (function(){
+ var t = false,
+ e = document.createElement('div');
+
+ $.each('Moz|Webkit|Khtml|O|ms|Icab|'.split('|'), function(i, prefix) {
+ var propCC = prefix + (prefix ? 'U' : 'u') + 'serSelect',
+ prop = (prefix ? ('-' + prefix.toLowerCase() + '-') : '') + 'user-select';
+
+ e.style.cssText = prop + ': text;';
+ if (e.style[propCC] == 'text') {
+ t = true;
+ return false;
+ }
+
+ return true;
+ });
+
+ return t;
+})();
+*/
+
+if (!$.ui || !$.ui.widget) {
+ // duck punch $.cleanData like jQueryUI does to get that remove event
+ // https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.widget.js#L16-24
+ var _cleanData = $.cleanData;
+ $.cleanData = function( elems ) {
+ for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
+ try {
+ $( elem ).triggerHandler( "remove" );
+ // http://bugs.jquery.com/ticket/8235
+ } catch( e ) {}
+ }
+ _cleanData( elems );
+ };
+}
+
+var // currently active contextMenu trigger
+ $currentTrigger = null,
+ // is contextMenu initialized with at least one menu?
+ initialized = false,
+ // window handle
+ $win = $(window),
+ // number of registered menus
+ counter = 0,
+ // mapping selector to namespace
+ namespaces = {},
+ // mapping namespace to options
+ menus = {},
+ // custom command type handlers
+ types = {},
+ // default values
+ defaults = {
+ // selector of contextMenu trigger
+ selector: null,
+ // where to append the menu to
+ appendTo: null,
+ // method to trigger context menu ["right", "left", "hover"]
+ trigger: "right",
+ // hide menu when mouse leaves trigger / menu elements
+ autoHide: false,
+ // ms to wait before showing a hover-triggered context menu
+ delay: 200,
+ // flag denoting if a second trigger should simply move (true) or rebuild (false) an open menu
+ // as long as the trigger happened on one of the trigger-element's child nodes
+ reposition: true,
+ // determine position to show menu at
+ determinePosition: function($menu) {
+ // position to the lower middle of the trigger element
+ if ($.ui && $.ui.position) {
+ // .position() is provided as a jQuery UI utility
+ // (...and it won't work on hidden elements)
+ $menu.css('display', 'block').position({
+ my: "center top",
+ at: "center bottom",
+ of: this,
+ offset: "0 5",
+ collision: "fit"
+ }).css('display', 'none');
+ } else {
+ // determine contextMenu position
+ var offset = this.offset();
+ offset.top += this.outerHeight();
+ offset.left += this.outerWidth() / 2 - $menu.outerWidth() / 2;
+ $menu.css(offset);
+ }
+ },
+ // position menu
+ position: function(opt, x, y) {
+ var $this = this,
+ offset;
+ // determine contextMenu position
+ if (!x && !y) {
+ opt.determinePosition.call(this, opt.$menu);
+ return;
+ } else if (x === "maintain" && y === "maintain") {
+ // x and y must not be changed (after re-show on command click)
+ offset = opt.$menu.position();
+ } else {
+ // x and y are given (by mouse event)
+ offset = {top: y, left: x};
+ }
+
+ // correct offset if viewport demands it
+ var bottom = $win.scrollTop() + $win.height(),
+ right = $win.scrollLeft() + $win.width(),
+ height = opt.$menu.height(),
+ width = opt.$menu.width();
+
+ if (offset.top + height > bottom) {
+ offset.top -= height;
+ }
+
+ if (offset.left + width > right) {
+ offset.left -= width;
+ }
+
+ opt.$menu.css(offset);
+ },
+ // position the sub-menu
+ positionSubmenu: function($menu) {
+ if ($.ui && $.ui.position) {
+ // .position() is provided as a jQuery UI utility
+ // (...and it won't work on hidden elements)
+ $menu.css('display', 'block').position({
+ my: "left top",
+ at: "right top",
+ of: this,
+ collision: "flipfit fit"
+ }).css('display', '');
+ } else {
+ // determine contextMenu position
+ var offset = {
+ top: 0,
+ left: this.outerWidth()
+ };
+ $menu.css(offset);
+ }
+ },
+ // offset to add to zIndex
+ zIndex: 1,
+ // show hide animation settings
+ animation: {
+ duration: 50,
+ show: 'slideDown',
+ hide: 'slideUp'
+ },
+ // events
+ events: {
+ show: $.noop,
+ hide: $.noop
+ },
+ // default callback
+ callback: null,
+ // list of contextMenu items
+ items: {}
+ },
+ // mouse position for hover activation
+ hoveract = {
+ timer: null,
+ pageX: null,
+ pageY: null
+ },
+ // determine zIndex
+ zindex = function($t) {
+ var zin = 0,
+ $tt = $t;
+
+ while (true) {
+ zin = Math.max(zin, parseInt($tt.css('z-index'), 10) || 0);
+ $tt = $tt.parent();
+ if (!$tt || !$tt.length || "html body".indexOf($tt.prop('nodeName').toLowerCase()) > -1 ) {
+ break;
+ }
+ }
+
+ return zin;
+ },
+ // event handlers
+ handle = {
+ // abort anything
+ abortevent: function(e){
+ e.preventDefault();
+ e.stopImmediatePropagation();
+ },
+
+ // contextmenu show dispatcher
+ contextmenu: function(e) {
+ var $this = $(this);
+
+ // disable actual context-menu
+ e.preventDefault();
+ e.stopImmediatePropagation();
+
+ // abort native-triggered events unless we're triggering on right click
+ if (e.data.trigger != 'right' && e.originalEvent) {
+ return;
+ }
+
+ // abort event if menu is visible for this trigger
+ if ($this.hasClass('context-menu-active')) {
+ return;
+ }
+
+ if (!$this.hasClass('context-menu-disabled')) {
+ // theoretically need to fire a show event at <menu>
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/interactive-elements.html#context-menus
+ // var evt = jQuery.Event("show", { data: data, pageX: e.pageX, pageY: e.pageY, relatedTarget: this });
+ // e.data.$menu.trigger(evt);
+
+ $currentTrigger = $this;
+ if (e.data.build) {
+ var built = e.data.build($currentTrigger, e);
+ // abort if build() returned false
+ if (built === false) {
+ return;
+ }
+
+ // dynamically build menu on invocation
+ e.data = $.extend(true, {}, defaults, e.data, built || {});
+
+ // abort if there are no items to display
+ if (!e.data.items || $.isEmptyObject(e.data.items)) {
+ // Note: jQuery captures and ignores errors from event handlers
+ if (window.console) {
+ (console.error || console.log)("No items specified to show in contextMenu");
+ }
+
+ throw new Error('No Items specified');
+ }
+
+ // backreference for custom command type creation
+ e.data.$trigger = $currentTrigger;
+
+ op.create(e.data);
+ }
+ // show menu
+ op.show.call($this, e.data, e.pageX, e.pageY);
+ }
+ },
+ // contextMenu left-click trigger
+ click: function(e) {
+ e.preventDefault();
+ e.stopImmediatePropagation();
+ $(this).trigger($.Event("contextmenu", { data: e.data, pageX: e.pageX, pageY: e.pageY }));
+ },
+ // contextMenu right-click trigger
+ mousedown: function(e) {
+ // register mouse down
+ var $this = $(this);
+
+ // hide any previous menus
+ if ($currentTrigger && $currentTrigger.length && !$currentTrigger.is($this)) {
+ $currentTrigger.data('contextMenu').$menu.trigger('contextmenu:hide');
+ }
+
+ // activate on right click
+ if (e.button == 2) {
+ $currentTrigger = $this.data('contextMenuActive', true);
+ }
+ },
+ // contextMenu right-click trigger
+ mouseup: function(e) {
+ // show menu
+ var $this = $(this);
+ if ($this.data('contextMenuActive') && $currentTrigger && $currentTrigger.length && $currentTrigger.is($this) && !$this.hasClass('context-menu-disabled')) {
+ e.preventDefault();
+ e.stopImmediatePropagation();
+ $currentTrigger = $this;
+ $this.trigger($.Event("contextmenu", { data: e.data, pageX: e.pageX, pageY: e.pageY }));
+ }
+
+ $this.removeData('contextMenuActive');
+ },
+ // contextMenu hover trigger
+ mouseenter: function(e) {
+ var $this = $(this),
+ $related = $(e.relatedTarget),
+ $document = $(document);
+
+ // abort if we're coming from a menu
+ if ($related.is('.context-menu-list') || $related.closest('.context-menu-list').length) {
+ return;
+ }
+
+ // abort if a menu is shown
+ if ($currentTrigger && $currentTrigger.length) {
+ return;
+ }
+
+ hoveract.pageX = e.pageX;
+ hoveract.pageY = e.pageY;
+ hoveract.data = e.data;
+ $document.on('mousemove.contextMenuShow', handle.mousemove);
+ hoveract.timer = setTimeout(function() {
+ hoveract.timer = null;
+ $document.off('mousemove.contextMenuShow');
+ $currentTrigger = $this;
+ $this.trigger($.Event("contextmenu", { data: hoveract.data, pageX: hoveract.pageX, pageY: hoveract.pageY }));
+ }, e.data.delay );
+ },
+ // contextMenu hover trigger
+ mousemove: function(e) {
+ hoveract.pageX = e.pageX;
+ hoveract.pageY = e.pageY;
+ },
+ // contextMenu hover trigger
+ mouseleave: function(e) {
+ // abort if we're leaving for a menu
+ var $related = $(e.relatedTarget);
+ if ($related.is('.context-menu-list') || $related.closest('.context-menu-list').length) {
+ return;
+ }
+
+ try {
+ clearTimeout(hoveract.timer);
+ } catch(e) {}
+
+ hoveract.timer = null;
+ },
+
+ // click on layer to hide contextMenu
+ layerClick: function(e) {
+ var $this = $(this),
+ root = $this.data('contextMenuRoot'),
+ mouseup = false,
+ button = e.button,
+ x = e.pageX,
+ y = e.pageY,
+ target,
+ offset,
+ selectors;
+
+ e.preventDefault();
+ e.stopImmediatePropagation();
+
+ setTimeout(function() {
+ var $window, hideshow, possibleTarget;
+ var triggerAction = ((root.trigger == 'left' && button === 0) || (root.trigger == 'right' && button === 2));
+
+ // find the element that would've been clicked, wasn't the layer in the way
+ if (document.elementFromPoint) {
+ root.$layer.hide();
+ target = document.elementFromPoint(x - $win.scrollLeft(), y - $win.scrollTop());
+ root.$layer.show();
+ }
+
+ if (root.reposition && triggerAction) {
+ if (document.elementFromPoint) {
+ if (root.$trigger.is(target) || root.$trigger.has(target).length) {
+ root.position.call(root.$trigger, root, x, y);
+ return;
+ }
+ } else {
+ offset = root.$trigger.offset();
+ $window = $(window);
+ // while this looks kinda awful, it's the best way to avoid
+ // unnecessarily calculating any positions
+ offset.top += $window.scrollTop();
+ if (offset.top <= e.pageY) {
+ offset.left += $window.scrollLeft();
+ if (offset.left <= e.pageX) {
+ offset.bottom = offset.top + root.$trigger.outerHeight();
+ if (offset.bottom >= e.pageY) {
+ offset.right = offset.left + root.$trigger.outerWidth();
+ if (offset.right >= e.pageX) {
+ // reposition
+ root.position.call(root.$trigger, root, x, y);
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (target && triggerAction) {
+ root.$trigger.one('contextmenu:hidden', function() {
+ $(target).contextMenu({x: x, y: y});
+ });
+ }
+
+ root.$menu.trigger('contextmenu:hide');
+ }, 50);
+ },
+ // key handled :hover
+ keyStop: function(e, opt) {
+ if (!opt.isInput) {
+ e.preventDefault();
+ }
+
+ e.stopPropagation();
+ },
+ key: function(e) {
+ var opt = $currentTrigger.data('contextMenu') || {};
+
+ switch (e.keyCode) {
+ case 9:
+ case 38: // up
+ handle.keyStop(e, opt);
+ // if keyCode is [38 (up)] or [9 (tab) with shift]
+ if (opt.isInput) {
+ if (e.keyCode == 9 && e.shiftKey) {
+ e.preventDefault();
+ opt.$selected && opt.$selected.find('input, textarea, select').blur();
+ opt.$menu.trigger('prevcommand');
+ return;
+ } else if (e.keyCode == 38 && opt.$selected.find('input, textarea, select').prop('type') == 'checkbox') {
+ // checkboxes don't capture this key
+ e.preventDefault();
+ return;
+ }
+ } else if (e.keyCode != 9 || e.shiftKey) {
+ opt.$menu.trigger('prevcommand');
+ return;
+ }
+ // omitting break;
+
+ // case 9: // tab - reached through omitted break;
+ case 40: // down
+ handle.keyStop(e, opt);
+ if (opt.isInput) {
+ if (e.keyCode == 9) {
+ e.preventDefault();
+ opt.$selected && opt.$selected.find('input, textarea, select').blur();
+ opt.$menu.trigger('nextcommand');
+ return;
+ } else if (e.keyCode == 40 && opt.$selected.find('input, textarea, select').prop('type') == 'checkbox') {
+ // checkboxes don't capture this key
+ e.preventDefault();
+ return;
+ }
+ } else {
+ opt.$menu.trigger('nextcommand');
+ return;
+ }
+ break;
+
+ case 37: // left
+ handle.keyStop(e, opt);
+ if (opt.isInput || !opt.$selected || !opt.$selected.length) {
+ break;
+ }
+
+ if (!opt.$selected.parent().hasClass('context-menu-root')) {
+ var $parent = opt.$selected.parent().parent();
+ opt.$selected.trigger('contextmenu:blur');
+ opt.$selected = $parent;
+ return;
+ }
+ break;
+
+ case 39: // right
+ handle.keyStop(e, opt);
+ if (opt.isInput || !opt.$selected || !opt.$selected.length) {
+ break;
+ }
+
+ var itemdata = opt.$selected.data('contextMenu') || {};
+ if (itemdata.$menu && opt.$selected.hasClass('context-menu-submenu')) {
+ opt.$selected = null;
+ itemdata.$selected = null;
+ itemdata.$menu.trigger('nextcommand');
+ return;
+ }
+ break;
+
+ case 35: // end
+ case 36: // home
+ if (opt.$selected && opt.$selected.find('input, textarea, select').length) {
+ return;
+ } else {
+ (opt.$selected && opt.$selected.parent() || opt.$menu)
+ .children(':not(.disabled, .not-selectable)')[e.keyCode == 36 ? 'first' : 'last']()
+ .trigger('contextmenu:focus');
+ e.preventDefault();
+ return;
+ }
+ break;
+
+ case 13: // enter
+ handle.keyStop(e, opt);
+ if (opt.isInput) {
+ if (opt.$selected && !opt.$selected.is('textarea, select')) {
+ e.preventDefault();
+ return;
+ }
+ break;
+ }
+ opt.$selected && opt.$selected.trigger('mouseup');
+ return;
+
+ case 32: // space
+ case 33: // page up
+ case 34: // page down
+ // prevent browser from scrolling down while menu is visible
+ handle.keyStop(e, opt);
+ return;
+
+ case 27: // esc
+ handle.keyStop(e, opt);
+ opt.$menu.trigger('contextmenu:hide');
+ return;
+
+ default: // 0-9, a-z
+ var k = (String.fromCharCode(e.keyCode)).toUpperCase();
+ if (opt.accesskeys[k]) {
+ // according to the specs accesskeys must be invoked immediately
+ opt.accesskeys[k].$node.trigger(opt.accesskeys[k].$menu
+ ? 'contextmenu:focus'
+ : 'mouseup'
+ );
+ return;
+ }
+ break;
+ }
+ // pass event to selected item,
+ // stop propagation to avoid endless recursion
+ e.stopPropagation();
+ opt.$selected && opt.$selected.trigger(e);
+ },
+
+ // select previous possible command in menu
+ prevItem: function(e) {
+ e.stopPropagation();
+ var opt = $(this).data('contextMenu') || {};
+
+ // obtain currently selected menu
+ if (opt.$selected) {
+ var $s = opt.$selected;
+ opt = opt.$selected.parent().data('contextMenu') || {};
+ opt.$selected = $s;
+ }
+
+ var $children = opt.$menu.children(),
+ $prev = !opt.$selected || !opt.$selected.prev().length ? $children.last() : opt.$selected.prev(),
+ $round = $prev;
+
+ // skip disabled
+ while ($prev.hasClass('disabled') || $prev.hasClass('not-selectable')) {
+ if ($prev.prev().length) {
+ $prev = $prev.prev();
+ } else {
+ $prev = $children.last();
+ }
+ if ($prev.is($round)) {
+ // break endless loop
+ return;
+ }
+ }
+
+ // leave current
+ if (opt.$selected) {
+ handle.itemMouseleave.call(opt.$selected.get(0), e);
+ }
+
+ // activate next
+ handle.itemMouseenter.call($prev.get(0), e);
+
+ // focus input
+ var $input = $prev.find('input, textarea, select');
+ if ($input.length) {
+ $input.focus();
+ }
+ },
+ // select next possible command in menu
+ nextItem: function(e) {
+ e.stopPropagation();
+ var opt = $(this).data('contextMenu') || {};
+
+ // obtain currently selected menu
+ if (opt.$selected) {
+ var $s = opt.$selected;
+ opt = opt.$selected.parent().data('contextMenu') || {};
+ opt.$selected = $s;
+ }
+
+ var $children = opt.$menu.children(),
+ $next = !opt.$selected || !opt.$selected.next().length ? $children.first() : opt.$selected.next(),
+ $round = $next;
+
+ // skip disabled
+ while ($next.hasClass('disabled') || $next.hasClass('not-selectable')) {
+ if ($next.next().length) {
+ $next = $next.next();
+ } else {
+ $next = $children.first();
+ }
+ if ($next.is($round)) {
+ // break endless loop
+ return;
+ }
+ }
+
+ // leave current
+ if (opt.$selected) {
+ handle.itemMouseleave.call(opt.$selected.get(0), e);
+ }
+
+ // activate next
+ handle.itemMouseenter.call($next.get(0), e);
+
+ // focus input
+ var $input = $next.find('input, textarea, select');
+ if ($input.length) {
+ $input.focus();
+ }
+ },
+
+ // flag that we're inside an input so the key handler can act accordingly
+ focusInput: function(e) {
+ var $this = $(this).closest('.context-menu-item'),
+ data = $this.data(),
+ opt = data.contextMenu,
+ root = data.contextMenuRoot;
+
+ root.$selected = opt.$selected = $this;
+ root.isInput = opt.isInput = true;
+ },
+ // flag that we're inside an input so the key handler can act accordingly
+ blurInput: function(e) {
+ var $this = $(this).closest('.context-menu-item'),
+ data = $this.data(),
+ opt = data.contextMenu,
+ root = data.contextMenuRoot;
+
+ root.isInput = opt.isInput = false;
+ },
+
+ // :hover on menu
+ menuMouseenter: function(e) {
+ var root = $(this).data().contextMenuRoot;
+ root.hovering = true;
+ },
+ // :hover on menu
+ menuMouseleave: function(e) {
+ var root = $(this).data().contextMenuRoot;
+ if (root.$layer && root.$layer.is(e.relatedTarget)) {
+ root.hovering = false;
+ }
+ },
+
+ // :hover done manually so key handling is possible
+ itemMouseenter: function(e) {
+ var $this = $(this),
+ data = $this.data(),
+ opt = data.contextMenu,
+ root = data.contextMenuRoot;
+
+ root.hovering = true;
+
+ // abort if we're re-entering
+ if (e && root.$layer && root.$layer.is(e.relatedTarget)) {
+ e.preventDefault();
+ e.stopImmediatePropagation();
+ }
+
+ // make sure only one item is selected
+ (opt.$menu ? opt : root).$menu
+ .children('.hover').trigger('contextmenu:blur');
+
+ if ($this.hasClass('disabled') || $this.hasClass('not-selectable')) {
+ opt.$selected = null;
+ return;
+ }
+
+ $this.trigger('contextmenu:focus');
+ },
+ // :hover done manually so key handling is possible
+ itemMouseleave: function(e) {
+ var $this = $(this),
+ data = $this.data(),
+ opt = data.contextMenu,
+ root = data.contextMenuRoot;
+
+ if (root !== opt && root.$layer && root.$layer.is(e.relatedTarget)) {
+ root.$selected && root.$selected.trigger('contextmenu:blur');
+ e.preventDefault();
+ e.stopImmediatePropagation();
+ root.$selected = opt.$selected = opt.$node;
+ return;
+ }
+
+ $this.trigger('contextmenu:blur');
+ },
+ // contextMenu item click
+ itemClick: function(e) {
+ var $this = $(this),
+ data = $this.data(),
+ opt = data.contextMenu,
+ root = data.contextMenuRoot,
+ key = data.contextMenuKey,
+ callback;
+
+ // abort if the key is unknown or disabled or is a menu
+ if (!opt.items[key] || $this.is('.disabled, .context-menu-submenu, .context-menu-separator, .not-selectable')) {
+ return;
+ }
+
+ e.preventDefault();
+ e.stopImmediatePropagation();
+
+ if ($.isFunction(root.callbacks[key]) && Object.prototype.hasOwnProperty.call(root.callbacks, key)) {
+ // item-specific callback
+ callback = root.callbacks[key];
+ } else if ($.isFunction(root.callback)) {
+ // default callback
+ callback = root.callback;
+ } else {
+ // no callback, no action
+ return;
+ }
+
+ // hide menu if callback doesn't stop that
+ if (callback.call(root.$trigger, key, root) !== false) {
+ root.$menu.trigger('contextmenu:hide');
+ } else if (root.$menu.parent().length) {
+ op.update.call(root.$trigger, root);
+ }
+ },
+ // ignore click events on input elements
+ inputClick: function(e) {
+ e.stopImmediatePropagation();
+ },
+
+ // hide <menu>
+ hideMenu: function(e, data) {
+ var root = $(this).data('contextMenuRoot');
+ op.hide.call(root.$trigger, root, data && data.force);
+ },
+ // focus <command>
+ focusItem: function(e) {
+ e.stopPropagation();
+ var $this = $(this),
+ data = $this.data(),
+ opt = data.contextMenu,
+ root = data.contextMenuRoot;
+
+ $this.addClass('hover')
+ .siblings('.hover').trigger('contextmenu:blur');
+
+ // remember selected
+ opt.$selected = root.$selected = $this;
+
+ // position sub-menu - do after show so dumb $.ui.position can keep up
+ if (opt.$node) {
+ root.positionSubmenu.call(opt.$node, opt.$menu);
+ }
+ },
+ // blur <command>
+ blurItem: function(e) {
+ e.stopPropagation();
+ var $this = $(this),
+ data = $this.data(),
+ opt = data.contextMenu,
+ root = data.contextMenuRoot;
+
+ $this.removeClass('hover');
+ opt.$selected = null;
+ }
+ },
+ // operations
+ op = {
+ show: function(opt, x, y) {
+ var $trigger = $(this),
+ offset,
+ css = {};
+
+ // hide any open menus
+ $('#context-menu-layer').trigger('mousedown');
+
+ // backreference for callbacks
+ opt.$trigger = $trigger;
+
+ // show event
+ if (opt.events.show.call($trigger, opt) === false) {
+ $currentTrigger = null;
+ return;
+ }
+
+ // create or update context menu
+ op.update.call($trigger, opt);
+
+ // position menu
+ opt.position.call($trigger, opt, x, y);
+
+ // make sure we're in front
+ if (opt.zIndex) {
+ css.zIndex = zindex($trigger) + opt.zIndex;
+ }
+
+ // add layer
+ op.layer.call(opt.$menu, opt, css.zIndex);
+
+ // adjust sub-menu zIndexes
+ opt.$menu.find('ul').css('zIndex', css.zIndex + 1);
+
+ // position and show context menu
+ opt.$menu.css( css )[opt.animation.show](opt.animation.duration, function() {
+ $trigger.trigger('contextmenu:visible');
+ });
+ // make options available and set state
+ $trigger
+ .data('contextMenu', opt)
+ .addClass("context-menu-active");
+
+ // register key handler
+ $(document).off('keydown.contextMenu').on('keydown.contextMenu', handle.key);
+ // register autoHide handler
+ if (opt.autoHide) {
+ // mouse position handler
+ $(document).on('mousemove.contextMenuAutoHide', function(e) {
+ // need to capture the offset on mousemove,
+ // since the page might've been scrolled since activation
+ var pos = $trigger.offset();
+ pos.right = pos.left + $trigger.outerWidth();
+ pos.bottom = pos.top + $trigger.outerHeight();
+
+ if (opt.$layer && !opt.hovering && (!(e.pageX >= pos.left && e.pageX <= pos.right) || !(e.pageY >= pos.top && e.pageY <= pos.bottom))) {
+ // if mouse in menu...
+ opt.$menu.trigger('contextmenu:hide');
+ }
+ });
+ }
+ },
+ hide: function(opt, force) {
+ var $trigger = $(this);
+ if (!opt) {
+ opt = $trigger.data('contextMenu') || {};
+ }
+
+ // hide event
+ if (!force && opt.events && opt.events.hide.call($trigger, opt) === false) {
+ return;
+ }
+
+ // remove options and revert state
+ $trigger
+ .removeData('contextMenu')
+ .removeClass("context-menu-active");
+
+ if (opt.$layer) {
+ // keep layer for a bit so the contextmenu event can be aborted properly by opera
+ setTimeout((function($layer) {
+ return function(){
+ $layer.remove();
+ };
+ })(opt.$layer), 10);
+
+ try {
+ delete opt.$layer;
+ } catch(e) {
+ opt.$layer = null;
+ }
+ }
+
+ // remove handle
+ $currentTrigger = null;
+ // remove selected
+ opt.$menu.find('.hover').trigger('contextmenu:blur');
+ opt.$selected = null;
+ // unregister key and mouse handlers
+ //$(document).off('.contextMenuAutoHide keydown.contextMenu'); // http://bugs.jquery.com/ticket/10705
+ $(document).off('.contextMenuAutoHide').off('keydown.contextMenu');
+ // hide menu
+ opt.$menu && opt.$menu[opt.animation.hide](opt.animation.duration, function (){
+ // tear down dynamically built menu after animation is completed.
+ if (opt.build) {
+ opt.$menu.remove();
+ $.each(opt, function(key, value) {
+ switch (key) {
+ case 'ns':
+ case 'selector':
+ case 'build':
+ case 'trigger':
+ return true;
+
+ default:
+ opt[key] = undefined;
+ try {
+ delete opt[key];
+ } catch (e) {}
+ return true;
+ }
+ });
+ }
+
+ setTimeout(function() {
+ $trigger.trigger('contextmenu:hidden');
+ }, 10);
+ });
+ },
+ create: function(opt, root) {
+ if (root === undefined) {
+ root = opt;
+ }
+ // create contextMenu
+ opt.$menu = $('<ul class="context-menu-list"></ul>').addClass(opt.className || "").data({
+ 'contextMenu': opt,
+ 'contextMenuRoot': root
+ });
+
+ $.each(['callbacks', 'commands', 'inputs'], function(i,k){
+ opt[k] = {};
+ if (!root[k]) {
+ root[k] = {};
+ }
+ });
+
+ root.accesskeys || (root.accesskeys = {});
+
+ // create contextMenu items
+ $.each(opt.items, function(key, item){
+ var $t = $('<li class="context-menu-item"></li>').addClass(item.className || ""),
+ $label = null,
+ $input = null;
+
+ // iOS needs to see a click-event bound to an element to actually
+ // have the TouchEvents infrastructure trigger the click event
+ $t.on('click', $.noop);
+
+ item.$node = $t.data({
+ 'contextMenu': opt,
+ 'contextMenuRoot': root,
+ 'contextMenuKey': key
+ });
+
+ // register accesskey
+ // NOTE: the accesskey attribute should be applicable to any element, but Safari5 and Chrome13 still can't do that
+ if (item.accesskey) {
+ var aks = splitAccesskey(item.accesskey);
+ for (var i=0, ak; ak = aks[i]; i++) {
+ if (!root.accesskeys[ak]) {
+ root.accesskeys[ak] = item;
+ item._name = item.name.replace(new RegExp('(' + ak + ')', 'i'), '<span class="context-menu-accesskey">$1</span>');
+ break;
+ }
+ }
+ }
+
+ if (typeof item == "string") {
+ $t.addClass('context-menu-separator not-selectable');
+ } else if (item.type && types[item.type]) {
+ // run custom type handler
+ types[item.type].call($t, item, opt, root);
+ // register commands
+ $.each([opt, root], function(i,k){
+ k.commands[key] = item;
+ if ($.isFunction(item.callback)) {
+ k.callbacks[key] = item.callback;
+ }
+ });
+ } else {
+ // add label for input
+ if (item.type == 'html') {
+ $t.addClass('context-menu-html not-selectable');
+ } else if (item.type) {
+ $label = $('<label></label>').appendTo($t);
+ $('<span></span>').html(item._name || item.name).appendTo($label);
+ $t.addClass('context-menu-input');
+ opt.hasTypes = true;
+ $.each([opt, root], function(i,k){
+ k.commands[key] = item;
+ k.inputs[key] = item;
+ });
+ } else if (item.items) {
+ item.type = 'sub';
+ }
+
+ switch (item.type) {
+ case 'text':
+ $input = $('<input type="text" value="1" name="" value="">')
+ .attr('name', 'context-menu-input-' + key)
+ .val(item.value || "")
+ .appendTo($label);
+ break;
+
+ case 'textarea':
+ $input = $('<textarea name=""></textarea>')
+ .attr('name', 'context-menu-input-' + key)
+ .val(item.value || "")
+ .appendTo($label);
+
+ if (item.height) {
+ $input.height(item.height);
+ }
+ break;
+
+ case 'checkbox':
+ $input = $('<input type="checkbox" value="1" name="" value="">')
+ .attr('name', 'context-menu-input-' + key)
+ .val(item.value || "")
+ .prop("checked", !!item.selected)
+ .prependTo($label);
+ break;
+
+ case 'radio':
+ $input = $('<input type="radio" value="1" name="" value="">')
+ .attr('name', 'context-menu-input-' + item.radio)
+ .val(item.value || "")
+ .prop("checked", !!item.selected)
+ .prependTo($label);
+ break;
+
+ case 'select':
+ $input = $('<select name="">')
+ .attr('name', 'context-menu-input-' + key)
+ .appendTo($label);
+ if (item.options) {
+ $.each(item.options, function(value, text) {
+ $('<option></option>').val(value).text(text).appendTo($input);
+ });
+ $input.val(item.selected);
+ }
+ break;
+
+ case 'sub':
+ // FIXME: shouldn't this .html() be a .text()?
+ $('<span></span>').html(item._name || item.name).appendTo($t);
+ item.appendTo = item.$node;
+ op.create(item, root);
+ $t.data('contextMenu', item).addClass('context-menu-submenu');
+ item.callback = null;
+ break;
+
+ case 'html':
+ $(item.html).appendTo($t);
+ break;
+
+ default:
+ $.each([opt, root], function(i,k){
+ k.commands[key] = item;
+ if ($.isFunction(item.callback)) {
+ k.callbacks[key] = item.callback;
+ }
+ });
+ // FIXME: shouldn't this .html() be a .text()?
+ $('<span></span>').html(item._name || item.name || "").appendTo($t);
+ break;
+ }
+
+ // disable key listener in <input>
+ if (item.type && item.type != 'sub' && item.type != 'html') {
+ $input
+ .on('focus', handle.focusInput)
+ .on('blur', handle.blurInput);
+
+ if (item.events) {
+ $input.on(item.events, opt);
+ }
+ }
+
+ // add icons
+ if (item.icon) {
+ $t.addClass("icon icon-" + item.icon);
+ }
+ }
+
+ // cache contained elements
+ item.$input = $input;
+ item.$label = $label;
+
+ // attach item to menu
+ $t.appendTo(opt.$menu);
+
+ // Disable text selection
+ if (!opt.hasTypes && $.support.eventSelectstart) {
+ // browsers support user-select: none,
+ // IE has a special event for text-selection
+ // browsers supporting neither will not be preventing text-selection
+ $t.on('selectstart.disableTextSelect', handle.abortevent);
+ }
+ });
+ // attach contextMenu to <body> (to bypass any possible overflow:hidden issues on parents of the trigger element)
+ if (!opt.$node) {
+ opt.$menu.css('display', 'none').addClass('context-menu-root');
+ }
+ opt.$menu.appendTo(opt.appendTo || document.body);
+ },
+ resize: function($menu, nested) {
+ // determine widths of submenus, as CSS won't grow them automatically
+ // position:absolute within position:absolute; min-width:100; max-width:200; results in width: 100;
+ // kinda sucks hard...
+
+ // determine width of absolutely positioned element
+ $menu.css({position: 'absolute', display: 'block'});
+ // don't apply yet, because that would break nested elements' widths
+ // add a pixel to circumvent word-break issue in IE9 - #80
+ $menu.data('width', Math.ceil($menu.width()) + 1);
+ // reset styles so they allow nested elements to grow/shrink naturally
+ $menu.css({
+ position: 'static',
+ minWidth: '0px',
+ maxWidth: '100000px'
+ });
+ // identify width of nested menus
+ $menu.find('> li > ul').each(function() {
+ op.resize($(this), true);
+ });
+ // reset and apply changes in the end because nested
+ // elements' widths wouldn't be calculatable otherwise
+ if (!nested) {
+ $menu.find('ul').andSelf().css({
+ position: '',
+ display: '',
+ minWidth: '',
+ maxWidth: ''
+ }).width(function() {
+ return $(this).data('width');
+ });
+ }
+ },
+ update: function(opt, root) {
+ var $trigger = this;
+ if (root === undefined) {
+ root = opt;
+ op.resize(opt.$menu);
+ }
+ // re-check disabled for each item
+ opt.$menu.children().each(function(){
+ var $item = $(this),
+ key = $item.data('contextMenuKey'),
+ item = opt.items[key],
+ disabled = ($.isFunction(item.disabled) && item.disabled.call($trigger, key, root)) || item.disabled === true;
+
+ // dis- / enable item
+ $item[disabled ? 'addClass' : 'removeClass']('disabled');
+
+ if (item.type) {
+ // dis- / enable input elements
+ $item.find('input, select, textarea').prop('disabled', disabled);
+
+ // update input states
+ switch (item.type) {
+ case 'text':
+ case 'textarea':
+ item.$input.val(item.value || "");
+ break;
+
+ case 'checkbox':
+ case 'radio':
+ item.$input.val(item.value || "").prop('checked', !!item.selected);
+ break;
+
+ case 'select':
+ item.$input.val(item.selected || "");
+ break;
+ }
+ }
+
+ if (item.$menu) {
+ // update sub-menu
+ op.update.call($trigger, item, root);
+ }
+ });
+ },
+ layer: function(opt, zIndex) {
+ // add transparent layer for click area
+ // filter and background for Internet Explorer, Issue #23
+ var $layer = opt.$layer = $('<div id="context-menu-layer" style="position:fixed; z-index:' + zIndex + '; top:0; left:0; opacity: 0; filter: alpha(opacity=0); background-color: #000;"></div>')
+ .css({height: $win.height(), width: $win.width(), display: 'block'})
+ .data('contextMenuRoot', opt)
+ .insertBefore(this)
+ .on('contextmenu', handle.abortevent)
+ .on('mousedown', handle.layerClick);
+
+ // IE6 doesn't know position:fixed;
+ if (!$.support.fixedPosition) {
+ $layer.css({
+ 'position' : 'absolute',
+ 'height' : $(document).height()
+ });
+ }
+
+ return $layer;
+ }
+ };
+
+// split accesskey according to http://www.whatwg.org/specs/web-apps/current-work/multipage/editing.html#assigned-access-key
+function splitAccesskey(val) {
+ var t = val.split(/\s+/),
+ keys = [];
+
+ for (var i=0, k; k = t[i]; i++) {
+ k = k[0].toUpperCase(); // first character only
+ // theoretically non-accessible characters should be ignored, but different systems, different keyboard layouts, ... screw it.
+ // a map to look up already used access keys would be nice
+ keys.push(k);
+ }
+
+ return keys;
+}
+
+// handle contextMenu triggers
+$.fn.contextMenu = function(operation) {
+ if (operation === undefined) {
+ this.first().trigger('contextmenu');
+ } else if (operation.x && operation.y) {
+ this.first().trigger($.Event("contextmenu", {pageX: operation.x, pageY: operation.y}));
+ } else if (operation === "hide") {
+ var $menu = this.data('contextMenu').$menu;
+ $menu && $menu.trigger('contextmenu:hide');
+ } else if (operation === "destroy") {
+ $.contextMenu("destroy", {context: this});
+ } else if ($.isPlainObject(operation)) {
+ operation.context = this;
+ $.contextMenu("create", operation);
+ } else if (operation) {
+ this.removeClass('context-menu-disabled');
+ } else if (!operation) {
+ this.addClass('context-menu-disabled');
+ }
+
+ return this;
+};
+
+// manage contextMenu instances
+$.contextMenu = function(operation, options) {
+ if (typeof operation != 'string') {
+ options = operation;
+ operation = 'create';
+ }
+
+ if (typeof options == 'string') {
+ options = {selector: options};
+ } else if (options === undefined) {
+ options = {};
+ }
+
+ // merge with default options
+ var o = $.extend(true, {}, defaults, options || {});
+ var $document = $(document);
+ var $context = $document;
+ var _hasContext = false;
+
+ if (!o.context || !o.context.length) {
+ o.context = document;
+ } else {
+ // you never know what they throw at you...
+ $context = $(o.context).first();
+ o.context = $context.get(0);
+ _hasContext = o.context !== document;
+ }
+
+ switch (operation) {
+ case 'create':
+ // no selector no joy
+ if (!o.selector) {
+ throw new Error('No selector specified');
+ }
+ // make sure internal classes are not bound to
+ if (o.selector.match(/.context-menu-(list|item|input)($|\s)/)) {
+ throw new Error('Cannot bind to selector "' + o.selector + '" as it contains a reserved className');
+ }
+ if (!o.build && (!o.items || $.isEmptyObject(o.items))) {
+ throw new Error('No Items specified');
+ }
+ counter ++;
+ o.ns = '.contextMenu' + counter;
+ if (!_hasContext) {
+ namespaces[o.selector] = o.ns;
+ }
+ menus[o.ns] = o;
+
+ // default to right click
+ if (!o.trigger) {
+ o.trigger = 'right';
+ }
+
+ if (!initialized) {
+ // make sure item click is registered first
+ $document
+ .on({
+ 'contextmenu:hide.contextMenu': handle.hideMenu,
+ 'prevcommand.contextMenu': handle.prevItem,
+ 'nextcommand.contextMenu': handle.nextItem,
+ 'contextmenu.contextMenu': handle.abortevent,
+ 'mouseenter.contextMenu': handle.menuMouseenter,
+ 'mouseleave.contextMenu': handle.menuMouseleave
+ }, '.context-menu-list')
+ .on('mouseup.contextMenu', '.context-menu-input', handle.inputClick)
+ .on({
+ 'mouseup.contextMenu': handle.itemClick,
+ 'contextmenu:focus.contextMenu': handle.focusItem,
+ 'contextmenu:blur.contextMenu': handle.blurItem,
+ 'contextmenu.contextMenu': handle.abortevent,
+ 'mouseenter.contextMenu': handle.itemMouseenter,
+ 'mouseleave.contextMenu': handle.itemMouseleave
+ }, '.context-menu-item');
+
+ initialized = true;
+ }
+
+ // engage native contextmenu event
+ $context
+ .on('contextmenu' + o.ns, o.selector, o, handle.contextmenu);
+
+ if (_hasContext) {
+ // add remove hook, just in case
+ $context.on('remove' + o.ns, function() {
+ $(this).contextMenu("destroy");
+ });
+ }
+
+ switch (o.trigger) {
+ case 'hover':
+ $context
+ .on('mouseenter' + o.ns, o.selector, o, handle.mouseenter)
+ .on('mouseleave' + o.ns, o.selector, o, handle.mouseleave);
+ break;
+
+ case 'left':
+ $context.on('click' + o.ns, o.selector, o, handle.click);
+ break;
+ /*
+ default:
+ // http://www.quirksmode.org/dom/events/contextmenu.html
+ $document
+ .on('mousedown' + o.ns, o.selector, o, handle.mousedown)
+ .on('mouseup' + o.ns, o.selector, o, handle.mouseup);
+ break;
+ */
+ }
+
+ // create menu
+ if (!o.build) {
+ op.create(o);
+ }
+ break;
+
+ case 'destroy':
+ var $visibleMenu;
+ if (_hasContext) {
+ // get proper options
+ var context = o.context;
+ $.each(menus, function(ns, o) {
+ if (o.context !== context) {
+ return true;
+ }
+
+ $visibleMenu = $('.context-menu-list').filter(':visible');
+ if ($visibleMenu.length && $visibleMenu.data().contextMenuRoot.$trigger.is($(o.context).find(o.selector))) {
+ $visibleMenu.trigger('contextmenu:hide', {force: true});
+ }
+
+ try {
+ if (menus[o.ns].$menu) {
+ menus[o.ns].$menu.remove();
+ }
+
+ delete menus[o.ns];
+ } catch(e) {
+ menus[o.ns] = null;
+ }
+
+ $(o.context).off(o.ns);
+
+ return true;
+ });
+ } else if (!o.selector) {
+ $document.off('.contextMenu .contextMenuAutoHide');
+ $.each(menus, function(ns, o) {
+ $(o.context).off(o.ns);
+ });
+
+ namespaces = {};
+ menus = {};
+ counter = 0;
+ initialized = false;
+
+ $('#context-menu-layer, .context-menu-list').remove();
+ } else if (namespaces[o.selector]) {
+ $visibleMenu = $('.context-menu-list').filter(':visible');
+ if ($visibleMenu.length && $visibleMenu.data().contextMenuRoot.$trigger.is(o.selector)) {
+ $visibleMenu.trigger('contextmenu:hide', {force: true});
+ }
+
+ try {
+ if (menus[namespaces[o.selector]].$menu) {
+ menus[namespaces[o.selector]].$menu.remove();
+ }
+
+ delete menus[namespaces[o.selector]];
+ } catch(e) {
+ menus[namespaces[o.selector]] = null;
+ }
+
+ $document.off(namespaces[o.selector]);
+ }
+ break;
+
+ case 'html5':
+ // if <command> or <menuitem> are not handled by the browser,
+ // or options was a bool true,
+ // initialize $.contextMenu for them
+ if ((!$.support.htmlCommand && !$.support.htmlMenuitem) || (typeof options == "boolean" && options)) {
+ $('menu[type="context"]').each(function() {
+ if (this.id) {
+ $.contextMenu({
+ selector: '[contextmenu=' + this.id +']',
+ items: $.contextMenu.fromMenu(this)
+ });
+ }
+ }).css('display', 'none');
+ }
+ break;
+
+ default:
+ throw new Error('Unknown operation "' + operation + '"');
+ }
+
+ return this;
+};
+
+// import values into <input> commands
+$.contextMenu.setInputValues = function(opt, data) {
+ if (data === undefined) {
+ data = {};
+ }
+
+ $.each(opt.inputs, function(key, item) {
+ switch (item.type) {
+ case 'text':
+ case 'textarea':
+ item.value = data[key] || "";
+ break;
+
+ case 'checkbox':
+ item.selected = data[key] ? true : false;
+ break;
+
+ case 'radio':
+ item.selected = (data[item.radio] || "") == item.value ? true : false;
+ break;
+
+ case 'select':
+ item.selected = data[key] || "";
+ break;
+ }
+ });
+};
+
+// export values from <input> commands
+$.contextMenu.getInputValues = function(opt, data) {
+ if (data === undefined) {
+ data = {};
+ }
+
+ $.each(opt.inputs, function(key, item) {
+ switch (item.type) {
+ case 'text':
+ case 'textarea':
+ case 'select':
+ data[key] = item.$input.val();
+ break;
+
+ case 'checkbox':
+ data[key] = item.$input.prop('checked');
+ break;
+
+ case 'radio':
+ if (item.$input.prop('checked')) {
+ data[item.radio] = item.value;
+ }
+ break;
+ }
+ });
+
+ return data;
+};
+
+// find <label for="xyz">
+function inputLabel(node) {
+ return (node.id && $('label[for="'+ node.id +'"]').val()) || node.name;
+}
+
+// convert <menu> to items object
+function menuChildren(items, $children, counter) {
+ if (!counter) {
+ counter = 0;
+ }
+
+ $children.each(function() {
+ var $node = $(this),
+ node = this,
+ nodeName = this.nodeName.toLowerCase(),
+ label,
+ item;
+
+ // extract <label><input>
+ if (nodeName == 'label' && $node.find('input, textarea, select').length) {
+ label = $node.text();
+ $node = $node.children().first();
+ node = $node.get(0);
+ nodeName = node.nodeName.toLowerCase();
+ }
+
+ /*
+ * <menu> accepts flow-content as children. that means <embed>, <canvas> and such are valid menu items.
+ * Not being the sadistic kind, $.contextMenu only accepts:
+ * <command>, <menuitem>, <hr>, <span>, <p> <input [text, radio, checkbox]>, <textarea>, <select> and of course <menu>.
+ * Everything else will be imported as an html node, which is not interfaced with contextMenu.
+ */
+
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/commands.html#concept-command
+ switch (nodeName) {
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/interactive-elements.html#the-menu-element
+ case 'menu':
+ item = {name: $node.attr('label'), items: {}};
+ counter = menuChildren(item.items, $node.children(), counter);
+ break;
+
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/commands.html#using-the-a-element-to-define-a-command
+ case 'a':
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/commands.html#using-the-button-element-to-define-a-command
+ case 'button':
+ item = {
+ name: $node.text(),
+ disabled: !!$node.attr('disabled'),
+ callback: (function(){ return function(){ $node.click(); }; })()
+ };
+ break;
+
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/commands.html#using-the-command-element-to-define-a-command
+
+ case 'menuitem':
+ case 'command':
+ switch ($node.attr('type')) {
+ case undefined:
+ case 'command':
+ case 'menuitem':
+ item = {
+ name: $node.attr('label'),
+ disabled: !!$node.attr('disabled'),
+ callback: (function(){ return function(){ $node.click(); }; })()
+ };
+ break;
+
+ case 'checkbox':
+ item = {
+ type: 'checkbox',
+ disabled: !!$node.attr('disabled'),
+ name: $node.attr('label'),
+ selected: !!$node.attr('checked')
+ };
+ break;
+
+ case 'radio':
+ item = {
+ type: 'radio',
+ disabled: !!$node.attr('disabled'),
+ name: $node.attr('label'),
+ radio: $node.attr('radiogroup'),
+ value: $node.attr('id'),
+ selected: !!$node.attr('checked')
+ };
+ break;
+
+ default:
+ item = undefined;
+ }
+ break;
+
+ case 'hr':
+ item = '-------';
+ break;
+
+ case 'input':
+ switch ($node.attr('type')) {
+ case 'text':
+ item = {
+ type: 'text',
+ name: label || inputLabel(node),
+ disabled: !!$node.attr('disabled'),
+ value: $node.val()
+ };
+ break;
+
+ case 'checkbox':
+ item = {
+ type: 'checkbox',
+ name: label || inputLabel(node),
+ disabled: !!$node.attr('disabled'),
+ selected: !!$node.attr('checked')
+ };
+ break;
+
+ case 'radio':
+ item = {
+ type: 'radio',
+ name: label || inputLabel(node),
+ disabled: !!$node.attr('disabled'),
+ radio: !!$node.attr('name'),
+ value: $node.val(),
+ selected: !!$node.attr('checked')
+ };
+ break;
+
+ default:
+ item = undefined;
+ break;
+ }
+ break;
+
+ case 'select':
+ item = {
+ type: 'select',
+ name: label || inputLabel(node),
+ disabled: !!$node.attr('disabled'),
+ selected: $node.val(),
+ options: {}
+ };
+ $node.children().each(function(){
+ item.options[this.value] = $(this).text();
+ });
+ break;
+
+ case 'textarea':
+ item = {
+ type: 'textarea',
+ name: label || inputLabel(node),
+ disabled: !!$node.attr('disabled'),
+ value: $node.val()
+ };
+ break;
+
+ case 'label':
+ break;
+
+ default:
+ item = {type: 'html', html: $node.clone(true)};
+ break;
+ }
+
+ if (item) {
+ counter++;
+ items['key' + counter] = item;
+ }
+ });
+
+ return counter;
+}
+
+// convert html5 menu
+$.contextMenu.fromMenu = function(element) {
+ var $this = $(element),
+ items = {};
+
+ menuChildren(items, $this.children());
+
+ return items;
+};
+
+// make defaults accessible
+$.contextMenu.defaults = defaults;
+$.contextMenu.types = types;
+// export internal functions - undocumented, for hacking only!
+$.contextMenu.handle = handle;
+$.contextMenu.op = op;
+$.contextMenu.menus = menus;
+
+})(jQuery);
diff --git a/libgpl/contextmenu/jquery.ui.position.js b/libgpl/contextmenu/jquery.ui.position.js
new file mode 100644
index 0000000..08ce445
--- /dev/null
+++ b/libgpl/contextmenu/jquery.ui.position.js
@@ -0,0 +1,497 @@
+/*!
+ * jQuery UI Position v1.10.0
+ * http://jqueryui.com
+ *
+ * Copyright 2013 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/position/
+ */
+(function( $, undefined ) {
+
+$.ui = $.ui || {};
+
+var cachedScrollbarWidth,
+ max = Math.max,
+ abs = Math.abs,
+ round = Math.round,
+ rhorizontal = /left|center|right/,
+ rvertical = /top|center|bottom/,
+ roffset = /[\+\-]\d+%?/,
+ rposition = /^\w+/,
+ rpercent = /%$/,
+ _position = $.fn.position;
+
+function getOffsets( offsets, width, height ) {
+ return [
+ parseInt( offsets[ 0 ], 10 ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
+ parseInt( offsets[ 1 ], 10 ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
+ ];
+}
+
+function parseCss( element, property ) {
+ return parseInt( $.css( element, property ), 10 ) || 0;
+}
+
+function getDimensions( elem ) {
+ var raw = elem[0];
+ if ( raw.nodeType === 9 ) {
+ return {
+ width: elem.width(),
+ height: elem.height(),
+ offset: { top: 0, left: 0 }
+ };
+ }
+ if ( $.isWindow( raw ) ) {
+ return {
+ width: elem.width(),
+ height: elem.height(),
+ offset: { top: elem.scrollTop(), left: elem.scrollLeft() }
+ };
+ }
+ if ( raw.preventDefault ) {
+ return {
+ width: 0,
+ height: 0,
+ offset: { top: raw.pageY, left: raw.pageX }
+ };
+ }
+ return {
+ width: elem.outerWidth(),
+ height: elem.outerHeight(),
+ offset: elem.offset()
+ };
+}
+
+$.position = {
+ scrollbarWidth: function() {
+ if ( cachedScrollbarWidth !== undefined ) {
+ return cachedScrollbarWidth;
+ }
+ var w1, w2,
+ div = $( "<div style='display:block;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ),
+ innerDiv = div.children()[0];
+
+ $( "body" ).append( div );
+ w1 = innerDiv.offsetWidth;
+ div.css( "overflow", "scroll" );
+
+ w2 = innerDiv.offsetWidth;
+
+ if ( w1 === w2 ) {
+ w2 = div[0].clientWidth;
+ }
+
+ div.remove();
+
+ return (cachedScrollbarWidth = w1 - w2);
+ },
+ getScrollInfo: function( within ) {
+ var overflowX = within.isWindow ? "" : within.element.css( "overflow-x" ),
+ overflowY = within.isWindow ? "" : within.element.css( "overflow-y" ),
+ hasOverflowX = overflowX === "scroll" ||
+ ( overflowX === "auto" && within.width < within.element[0].scrollWidth ),
+ hasOverflowY = overflowY === "scroll" ||
+ ( overflowY === "auto" && within.height < within.element[0].scrollHeight );
+ return {
+ width: hasOverflowX ? $.position.scrollbarWidth() : 0,
+ height: hasOverflowY ? $.position.scrollbarWidth() : 0
+ };
+ },
+ getWithinInfo: function( element ) {
+ var withinElement = $( element || window ),
+ isWindow = $.isWindow( withinElement[0] );
+ return {
+ element: withinElement,
+ isWindow: isWindow,
+ offset: withinElement.offset() || { left: 0, top: 0 },
+ scrollLeft: withinElement.scrollLeft(),
+ scrollTop: withinElement.scrollTop(),
+ width: isWindow ? withinElement.width() : withinElement.outerWidth(),
+ height: isWindow ? withinElement.height() : withinElement.outerHeight()
+ };
+ }
+};
+
+$.fn.position = function( options ) {
+ if ( !options || !options.of ) {
+ return _position.apply( this, arguments );
+ }
+
+ // make a copy, we don't want to modify arguments
+ options = $.extend( {}, options );
+
+ var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,
+ target = $( options.of ),
+ within = $.position.getWithinInfo( options.within ),
+ scrollInfo = $.position.getScrollInfo( within ),
+ collision = ( options.collision || "flip" ).split( " " ),
+ offsets = {};
+
+ dimensions = getDimensions( target );
+ if ( target[0].preventDefault ) {
+ // force left top to allow flipping
+ options.at = "left top";
+ }
+ targetWidth = dimensions.width;
+ targetHeight = dimensions.height;
+ targetOffset = dimensions.offset;
+ // clone to reuse original targetOffset later
+ basePosition = $.extend( {}, targetOffset );
+
+ // force my and at to have valid horizontal and vertical positions
+ // if a value is missing or invalid, it will be converted to center
+ $.each( [ "my", "at" ], function() {
+ var pos = ( options[ this ] || "" ).split( " " ),
+ horizontalOffset,
+ verticalOffset;
+
+ if ( pos.length === 1) {
+ pos = rhorizontal.test( pos[ 0 ] ) ?
+ pos.concat( [ "center" ] ) :
+ rvertical.test( pos[ 0 ] ) ?
+ [ "center" ].concat( pos ) :
+ [ "center", "center" ];
+ }
+ pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
+ pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";
+
+ // calculate offsets
+ horizontalOffset = roffset.exec( pos[ 0 ] );
+ verticalOffset = roffset.exec( pos[ 1 ] );
+ offsets[ this ] = [
+ horizontalOffset ? horizontalOffset[ 0 ] : 0,
+ verticalOffset ? verticalOffset[ 0 ] : 0
+ ];
+
+ // reduce to just the positions without the offsets
+ options[ this ] = [
+ rposition.exec( pos[ 0 ] )[ 0 ],
+ rposition.exec( pos[ 1 ] )[ 0 ]
+ ];
+ });
+
+ // normalize collision option
+ if ( collision.length === 1 ) {
+ collision[ 1 ] = collision[ 0 ];
+ }
+
+ if ( options.at[ 0 ] === "right" ) {
+ basePosition.left += targetWidth;
+ } else if ( options.at[ 0 ] === "center" ) {
+ basePosition.left += targetWidth / 2;
+ }
+
+ if ( options.at[ 1 ] === "bottom" ) {
+ basePosition.top += targetHeight;
+ } else if ( options.at[ 1 ] === "center" ) {
+ basePosition.top += targetHeight / 2;
+ }
+
+ atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
+ basePosition.left += atOffset[ 0 ];
+ basePosition.top += atOffset[ 1 ];
+
+ return this.each(function() {
+ var collisionPosition, using,
+ elem = $( this ),
+ elemWidth = elem.outerWidth(),
+ elemHeight = elem.outerHeight(),
+ marginLeft = parseCss( this, "marginLeft" ),
+ marginTop = parseCss( this, "marginTop" ),
+ collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width,
+ collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height,
+ position = $.extend( {}, basePosition ),
+ myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );
+
+ if ( options.my[ 0 ] === "right" ) {
+ position.left -= elemWidth;
+ } else if ( options.my[ 0 ] === "center" ) {
+ position.left -= elemWidth / 2;
+ }
+
+ if ( options.my[ 1 ] === "bottom" ) {
+ position.top -= elemHeight;
+ } else if ( options.my[ 1 ] === "center" ) {
+ position.top -= elemHeight / 2;
+ }
+
+ position.left += myOffset[ 0 ];
+ position.top += myOffset[ 1 ];
+
+ // if the browser doesn't support fractions, then round for consistent results
+ if ( !$.support.offsetFractions ) {
+ position.left = round( position.left );
+ position.top = round( position.top );
+ }
+
+ collisionPosition = {
+ marginLeft: marginLeft,
+ marginTop: marginTop
+ };
+
+ $.each( [ "left", "top" ], function( i, dir ) {
+ if ( $.ui.position[ collision[ i ] ] ) {
+ $.ui.position[ collision[ i ] ][ dir ]( position, {
+ targetWidth: targetWidth,
+ targetHeight: targetHeight,
+ elemWidth: elemWidth,
+ elemHeight: elemHeight,
+ collisionPosition: collisionPosition,
+ collisionWidth: collisionWidth,
+ collisionHeight: collisionHeight,
+ offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
+ my: options.my,
+ at: options.at,
+ within: within,
+ elem : elem
+ });
+ }
+ });
+
+ if ( options.using ) {
+ // adds feedback as second argument to using callback, if present
+ using = function( props ) {
+ var left = targetOffset.left - position.left,
+ right = left + targetWidth - elemWidth,
+ top = targetOffset.top - position.top,
+ bottom = top + targetHeight - elemHeight,
+ feedback = {
+ target: {
+ element: target,
+ left: targetOffset.left,
+ top: targetOffset.top,
+ width: targetWidth,
+ height: targetHeight
+ },
+ element: {
+ element: elem,
+ left: position.left,
+ top: position.top,
+ width: elemWidth,
+ height: elemHeight
+ },
+ horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
+ vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
+ };
+ if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
+ feedback.horizontal = "center";
+ }
+ if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
+ feedback.vertical = "middle";
+ }
+ if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
+ feedback.important = "horizontal";
+ } else {
+ feedback.important = "vertical";
+ }
+ options.using.call( this, props, feedback );
+ };
+ }
+
+ elem.offset( $.extend( position, { using: using } ) );
+ });
+};
+
+$.ui.position = {
+ fit: {
+ left: function( position, data ) {
+ var within = data.within,
+ withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
+ outerWidth = within.width,
+ collisionPosLeft = position.left - data.collisionPosition.marginLeft,
+ overLeft = withinOffset - collisionPosLeft,
+ overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
+ newOverRight;
+
+ // element is wider than within
+ if ( data.collisionWidth > outerWidth ) {
+ // element is initially over the left side of within
+ if ( overLeft > 0 && overRight <= 0 ) {
+ newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset;
+ position.left += overLeft - newOverRight;
+ // element is initially over right side of within
+ } else if ( overRight > 0 && overLeft <= 0 ) {
+ position.left = withinOffset;
+ // element is initially over both left and right sides of within
+ } else {
+ if ( overLeft > overRight ) {
+ position.left = withinOffset + outerWidth - data.collisionWidth;
+ } else {
+ position.left = withinOffset;
+ }
+ }
+ // too far left -> align with left edge
+ } else if ( overLeft > 0 ) {
+ position.left += overLeft;
+ // too far right -> align with right edge
+ } else if ( overRight > 0 ) {
+ position.left -= overRight;
+ // adjust based on position and margin
+ } else {
+ position.left = max( position.left - collisionPosLeft, position.left );
+ }
+ },
+ top: function( position, data ) {
+ var within = data.within,
+ withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
+ outerHeight = data.within.height,
+ collisionPosTop = position.top - data.collisionPosition.marginTop,
+ overTop = withinOffset - collisionPosTop,
+ overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
+ newOverBottom;
+
+ // element is taller than within
+ if ( data.collisionHeight > outerHeight ) {
+ // element is initially over the top of within
+ if ( overTop > 0 && overBottom <= 0 ) {
+ newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset;
+ position.top += overTop - newOverBottom;
+ // element is initially over bottom of within
+ } else if ( overBottom > 0 && overTop <= 0 ) {
+ position.top = withinOffset;
+ // element is initially over both top and bottom of within
+ } else {
+ if ( overTop > overBottom ) {
+ position.top = withinOffset + outerHeight - data.collisionHeight;
+ } else {
+ position.top = withinOffset;
+ }
+ }
+ // too far up -> align with top
+ } else if ( overTop > 0 ) {
+ position.top += overTop;
+ // too far down -> align with bottom edge
+ } else if ( overBottom > 0 ) {
+ position.top -= overBottom;
+ // adjust based on position and margin
+ } else {
+ position.top = max( position.top - collisionPosTop, position.top );
+ }
+ }
+ },
+ flip: {
+ left: function( position, data ) {
+ var within = data.within,
+ withinOffset = within.offset.left + within.scrollLeft,
+ outerWidth = within.width,
+ offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
+ collisionPosLeft = position.left - data.collisionPosition.marginLeft,
+ overLeft = collisionPosLeft - offsetLeft,
+ overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
+ myOffset = data.my[ 0 ] === "left" ?
+ -data.elemWidth :
+ data.my[ 0 ] === "right" ?
+ data.elemWidth :
+ 0,
+ atOffset = data.at[ 0 ] === "left" ?
+ data.targetWidth :
+ data.at[ 0 ] === "right" ?
+ -data.targetWidth :
+ 0,
+ offset = -2 * data.offset[ 0 ],
+ newOverRight,
+ newOverLeft;
+
+ if ( overLeft < 0 ) {
+ newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset;
+ if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
+ position.left += myOffset + atOffset + offset;
+ }
+ }
+ else if ( overRight > 0 ) {
+ newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft;
+ if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
+ position.left += myOffset + atOffset + offset;
+ }
+ }
+ },
+ top: function( position, data ) {
+ var within = data.within,
+ withinOffset = within.offset.top + within.scrollTop,
+ outerHeight = within.height,
+ offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
+ collisionPosTop = position.top - data.collisionPosition.marginTop,
+ overTop = collisionPosTop - offsetTop,
+ overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
+ top = data.my[ 1 ] === "top",
+ myOffset = top ?
+ -data.elemHeight :
+ data.my[ 1 ] === "bottom" ?
+ data.elemHeight :
+ 0,
+ atOffset = data.at[ 1 ] === "top" ?
+ data.targetHeight :
+ data.at[ 1 ] === "bottom" ?
+ -data.targetHeight :
+ 0,
+ offset = -2 * data.offset[ 1 ],
+ newOverTop,
+ newOverBottom;
+ if ( overTop < 0 ) {
+ newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset;
+ if ( ( position.top + myOffset + atOffset + offset) > overTop && ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) ) {
+ position.top += myOffset + atOffset + offset;
+ }
+ }
+ else if ( overBottom > 0 ) {
+ newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop;
+ if ( ( position.top + myOffset + atOffset + offset) > overBottom && ( newOverTop > 0 || abs( newOverTop ) < overBottom ) ) {
+ position.top += myOffset + atOffset + offset;
+ }
+ }
+ }
+ },
+ flipfit: {
+ left: function() {
+ $.ui.position.flip.left.apply( this, arguments );
+ $.ui.position.fit.left.apply( this, arguments );
+ },
+ top: function() {
+ $.ui.position.flip.top.apply( this, arguments );
+ $.ui.position.fit.top.apply( this, arguments );
+ }
+ }
+};
+
+// fraction support test
+(function () {
+ var testElement, testElementParent, testElementStyle, offsetLeft, i,
+ body = document.getElementsByTagName( "body" )[ 0 ],
+ div = document.createElement( "div" );
+
+ //Create a "fake body" for testing based on method used in jQuery.support
+ testElement = document.createElement( body ? "div" : "body" );
+ testElementStyle = {
+ visibility: "hidden",
+ width: 0,
+ height: 0,
+ border: 0,
+ margin: 0,
+ background: "none"
+ };
+ if ( body ) {
+ $.extend( testElementStyle, {
+ position: "absolute",
+ left: "-1000px",
+ top: "-1000px"
+ });
+ }
+ for ( i in testElementStyle ) {
+ testElement.style[ i ] = testElementStyle[ i ];
+ }
+ testElement.appendChild( div );
+ testElementParent = body || document.documentElement;
+ testElementParent.insertBefore( testElement, testElementParent.firstChild );
+
+ div.style.cssText = "position: absolute; left: 10.7432222px;";
+
+ offsetLeft = $( div ).offset().left;
+ $.support.offsetFractions = offsetLeft > 10 && offsetLeft < 11;
+
+ testElement.innerHTML = "";
+ testElementParent.removeChild( testElement );
+})();
+
+}( jQuery ) );
diff --git a/libgpl/date/date.js b/libgpl/date/date.js
new file mode 100644
index 0000000..984adb5
--- /dev/null
+++ b/libgpl/date/date.js
@@ -0,0 +1,335 @@
+// ===================================================================
+// Author: Matt Kruse <matt@mattkruse.com>
+// WWW: http://www.mattkruse.com/
+//
+// NOTICE: You may use this code for any purpose, commercial or
+// private, without any further permission from the author. You may
+// remove this notice from your final code if you wish, however it is
+// appreciated by the author if at least my web site address is kept.
+//
+// You may *NOT* re-distribute this code in any way except through its
+// use. That means, you can include it in your product, or your web
+// site, or any other form where the code is actually being used. You
+// may not put the plain javascript up on your site for download or
+// include it in your javascript libraries for download.
+// If you wish to share this code with others, please just point them
+// to the URL instead.
+// Please DO NOT link directly to my .js files from your site. Copy
+// the files to your server and use them there. Thank you.
+// ===================================================================
+
+// HISTORY
+// ------------------------------------------------------------------
+// May 17, 2003: Fixed bug in parseDate() for dates <1970
+// March 11, 2003: Added parseDate() function
+// March 11, 2003: Added "NNN" formatting option. Doesn't match up
+// perfectly with SimpleDateFormat formats, but
+// backwards-compatability was required.
+
+// ------------------------------------------------------------------
+// These functions use the same 'format' strings as the
+// java.text.SimpleDateFormat class, with minor exceptions.
+// The format string consists of the following abbreviations:
+//
+// Field | Full Form | Short Form
+// -------------+--------------------+-----------------------
+// Year | yyyy (4 digits) | yy (2 digits), y (2 or 4 digits)
+// Month | MMM (name or abbr.)| MM (2 digits), M (1 or 2 digits)
+// | NNN (abbr.) |
+// Day of Month | dd (2 digits) | d (1 or 2 digits)
+// Day of Week | EE (name) | E (abbr)
+// Hour (1-12) | hh (2 digits) | h (1 or 2 digits)
+// Hour (0-23) | HH (2 digits) | H (1 or 2 digits)
+// Hour (0-11) | KK (2 digits) | K (1 or 2 digits)
+// Hour (1-24) | kk (2 digits) | k (1 or 2 digits)
+// Minute | mm (2 digits) | m (1 or 2 digits)
+// Second | ss (2 digits) | s (1 or 2 digits)
+// AM/PM | a |
+//
+// NOTE THE DIFFERENCE BETWEEN MM and mm! Month=MM, not mm!
+// Examples:
+// "MMM d, y" matches: January 01, 2000
+// Dec 1, 1900
+// Nov 20, 00
+// "M/d/yy" matches: 01/20/00
+// 9/2/00
+// "MMM dd, yyyy hh:mm:ssa" matches: "January 01, 2000 12:30:45AM"
+// ------------------------------------------------------------------
+
+var MONTH_NAMES=new Array('January','February','March','April','May','June','July','August','September','October','November','December','Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
+var DAY_NAMES=new Array('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sun','Mon','Tue','Wed','Thu','Fri','Sat');
+function LZ(x) {return(x<0||x>9?"":"0")+x}
+
+// ------------------------------------------------------------------
+// isDate ( date_string, format_string )
+// Returns true if date string matches format of format string and
+// is a valid date. Else returns false.
+// It is recommended that you trim whitespace around the value before
+// passing it to this function, as whitespace is NOT ignored!
+// ------------------------------------------------------------------
+function isDate(val,format) {
+ var date=getDateFromFormat(val,format);
+ if (date==0) { return false; }
+ return true;
+ }
+
+// -------------------------------------------------------------------
+// compareDates(date1,date1format,date2,date2format)
+// Compare two date strings to see which is greater.
+// Returns:
+// 1 if date1 is greater than date2
+// 0 if date2 is greater than date1 of if they are the same
+// -1 if either of the dates is in an invalid format
+// -------------------------------------------------------------------
+function compareDates(date1,dateformat1,date2,dateformat2) {
+ var d1=getDateFromFormat(date1,dateformat1);
+ var d2=getDateFromFormat(date2,dateformat2);
+ if (d1==0 || d2==0) {
+ return -1;
+ }
+ else if (d1 > d2) {
+ return 1;
+ }
+ return 0;
+ }
+
+// ------------------------------------------------------------------
+// formatDate (date_object, format)
+// Returns a date in the output format specified.
+// The format string uses the same abbreviations as in getDateFromFormat()
+// ------------------------------------------------------------------
+function formatDate(date,format) {
+ format=format+"";
+ var result="";
+ var i_format=0;
+ var c="";
+ var token="";
+ var y=date.getYear()+"";
+ var M=date.getMonth()+1;
+ var d=date.getDate();
+ var E=date.getDay();
+ var H=date.getHours();
+ var m=date.getMinutes();
+ var s=date.getSeconds();
+ var yyyy,yy,MMM,MM,dd,hh,h,mm,ss,ampm,HH,H,KK,K,kk,k;
+ // Convert real date parts into formatted versions
+ var value=new Object();
+ if (y.length < 4) {y=""+(y-0+1900);}
+ value["y"]=""+y;
+ value["yyyy"]=y;
+ value["yy"]=y.substring(2,4);
+ value["M"]=M;
+ value["MM"]=LZ(M);
+ value["MMM"]=MONTH_NAMES[M-1];
+ value["NNN"]=MONTH_NAMES[M+11];
+ value["d"]=d;
+ value["dd"]=LZ(d);
+ value["E"]=DAY_NAMES[E+7];
+ value["EE"]=DAY_NAMES[E];
+ value["H"]=H;
+ value["HH"]=LZ(H);
+ if (H==0){value["h"]=12;}
+ else if (H>12){value["h"]=H-12;}
+ else {value["h"]=H;}
+ value["hh"]=LZ(value["h"]);
+ if (H>11){value["K"]=H-12;} else {value["K"]=H;}
+ value["k"]=H+1;
+ value["KK"]=LZ(value["K"]);
+ value["kk"]=LZ(value["k"]);
+ if (H > 11) { value["a"]="PM"; }
+ else { value["a"]="AM"; }
+ value["m"]=m;
+ value["mm"]=LZ(m);
+ value["s"]=s;
+ value["ss"]=LZ(s);
+ while (i_format < format.length) {
+ c=format.charAt(i_format);
+ token="";
+ while ((format.charAt(i_format)==c) && (i_format < format.length)) {
+ token += format.charAt(i_format++);
+ }
+ if (value[token] != null) { result=result + value[token]; }
+ else { result=result + token; }
+ }
+ return result;
+ }
+
+// ------------------------------------------------------------------
+// Utility functions for parsing in getDateFromFormat()
+// ------------------------------------------------------------------
+function _isInteger(val) {
+ var digits="1234567890";
+ for (var i=0; i < val.length; i++) {
+ if (digits.indexOf(val.charAt(i))==-1) { return false; }
+ }
+ return true;
+ }
+function _getInt(str,i,minlength,maxlength) {
+ for (var x=maxlength; x>=minlength; x--) {
+ var token=str.substring(i,i+x);
+ if (token.length < minlength) { return null; }
+ if (_isInteger(token)) { return token; }
+ }
+ return null;
+ }
+
+// ------------------------------------------------------------------
+// getDateFromFormat( date_string , format_string )
+//
+// This function takes a date string and a format string. It matches
+// If the date string matches the format string, it returns the
+// getTime() of the date. If it does not match, it returns 0.
+// ------------------------------------------------------------------
+function getDateFromFormat(val,format) {
+ val=val+"";
+ format=format+"";
+ var i_val=0;
+ var i_format=0;
+ var c="";
+ var token="";
+ var token2="";
+ var x,y;
+ var now=new Date();
+ var year=now.getYear();
+ var month=now.getMonth()+1;
+ var date=1;
+ var hh=now.getHours();
+ var mm=now.getMinutes();
+ var ss=now.getSeconds();
+ var ampm="";
+
+ while (i_format < format.length) {
+ // Get next token from format string
+ c=format.charAt(i_format);
+ token="";
+ while ((format.charAt(i_format)==c) && (i_format < format.length)) {
+ token += format.charAt(i_format++);
+ }
+ // Extract contents of value based on format token
+ if (token=="yyyy" || token=="yy" || token=="y") {
+ if (token=="yyyy") { x=4;y=4; }
+ if (token=="yy") { x=2;y=2; }
+ if (token=="y") { x=2;y=4; }
+ year=_getInt(val,i_val,x,y);
+ if (year==null) { return 0; }
+ i_val += year.length;
+ if (year.length==2) {
+ if (year > 70) { year=1900+(year-0); }
+ else { year=2000+(year-0); }
+ }
+ }
+ else if (token=="MMM"||token=="NNN"){
+ month=0;
+ for (var i=0; i<MONTH_NAMES.length; i++) {
+ var month_name=MONTH_NAMES[i];
+ if (val.substring(i_val,i_val+month_name.length).toLowerCase()==month_name.toLowerCase()) {
+ if (token=="MMM"||(token=="NNN"&&i>11)) {
+ month=i+1;
+ if (month>12) { month -= 12; }
+ i_val += month_name.length;
+ break;
+ }
+ }
+ }
+ if ((month < 1)||(month>12)){return 0;}
+ }
+ else if (token=="EE"||token=="E"){
+ for (var i=0; i<DAY_NAMES.length; i++) {
+ var day_name=DAY_NAMES[i];
+ if (val.substring(i_val,i_val+day_name.length).toLowerCase()==day_name.toLowerCase()) {
+ i_val += day_name.length;
+ break;
+ }
+ }
+ }
+ else if (token=="MM"||token=="M") {
+ month=_getInt(val,i_val,token.length,2);
+ if(month==null||(month<1)||(month>12)){return 0;}
+ i_val+=month.length;}
+ else if (token=="dd"||token=="d") {
+ date=_getInt(val,i_val,token.length,2);
+ if(date==null||(date<1)||(date>31)){return 0;}
+ i_val+=date.length;}
+ else if (token=="hh"||token=="h") {
+ hh=_getInt(val,i_val,token.length,2);
+ if(hh==null||(hh<1)||(hh>12)){return 0;}
+ i_val+=hh.length;}
+ else if (token=="HH"||token=="H") {
+ hh=_getInt(val,i_val,token.length,2);
+ if(hh==null||(hh<0)||(hh>23)){return 0;}
+ i_val+=hh.length;}
+ else if (token=="KK"||token=="K") {
+ hh=_getInt(val,i_val,token.length,2);
+ if(hh==null||(hh<0)||(hh>11)){return 0;}
+ i_val+=hh.length;}
+ else if (token=="kk"||token=="k") {
+ hh=_getInt(val,i_val,token.length,2);
+ if(hh==null||(hh<1)||(hh>24)){return 0;}
+ i_val+=hh.length;hh--;}
+ else if (token=="mm"||token=="m") {
+ mm=_getInt(val,i_val,token.length,2);
+ if(mm==null||(mm<0)||(mm>59)){return 0;}
+ i_val+=mm.length;}
+ else if (token=="ss"||token=="s") {
+ ss=_getInt(val,i_val,token.length,2);
+ if(ss==null||(ss<0)||(ss>59)){return 0;}
+ i_val+=ss.length;}
+ else if (token=="a") {
+ if (val.substring(i_val,i_val+2).toLowerCase()=="am") {ampm="AM";}
+ else if (val.substring(i_val,i_val+2).toLowerCase()=="pm") {ampm="PM";}
+ else {return 0;}
+ i_val+=2;}
+ else {
+ if (val.substring(i_val,i_val+token.length)!=token) {return 0;}
+ else {i_val+=token.length;}
+ }
+ }
+ // If there are any trailing characters left in the value, it doesn't match
+ if (i_val != val.length) { return 0; }
+ // Is date valid for month?
+ if (month==2) {
+ // Check for leap year
+ if ( ( (year%4==0)&&(year%100 != 0) ) || (year%400==0) ) { // leap year
+ if (date > 29){ return 0; }
+ }
+ else { if (date > 28) { return 0; } }
+ }
+ if ((month==4)||(month==6)||(month==9)||(month==11)) {
+ if (date > 30) { return 0; }
+ }
+ // Correct hours value
+ if (hh<12 && ampm=="PM") { hh=hh-0+12; }
+ else if (hh>11 && ampm=="AM") { hh-=12; }
+ var newdate=new Date(year,month-1,date,hh,mm,ss);
+ return newdate.getTime();
+ }
+
+// ------------------------------------------------------------------
+// parseDate( date_string [, prefer_euro_format] )
+//
+// This function takes a date string and tries to match it to a
+// number of possible date formats to get the value. It will try to
+// match against the following international formats, in this order:
+// y-M-d MMM d, y MMM d,y y-MMM-d d-MMM-y MMM d
+// M/d/y M-d-y M.d.y MMM-d M/d M-d
+// d/M/y d-M-y d.M.y d-MMM d/M d-M
+// A second argument may be passed to instruct the method to search
+// for formats like d/M/y (european format) before M/d/y (American).
+// Returns a Date object or null if no patterns match.
+// ------------------------------------------------------------------
+function parseDate(val) {
+ var preferEuro=(arguments.length==2)?arguments[1]:false;
+ generalFormats=new Array('y-M-d','MMM d, y','MMM d,y','y-MMM-d','d-MMM-y','MMM d');
+ monthFirst=new Array('M/d/y','M-d-y','M.d.y','MMM-d','M/d','M-d');
+ dateFirst =new Array('d/M/y','d-M-y','d.M.y','d-MMM','d/M','d-M');
+ var checkList=new Array('generalFormats',preferEuro?'dateFirst':'monthFirst',preferEuro?'monthFirst':'dateFirst');
+ var d=null;
+ for (var i=0; i<checkList.length; i++) {
+ var l=window[checkList[i]];
+ for (var j=0; j<l.length; j++) {
+ d=getDateFromFormat(val,l[j]);
+ if (d!=0) { return new Date(d); }
+ }
+ }
+ return null;
+ } \ No newline at end of file
diff --git a/libgpl/dialogextend/jquery.dialogextend.js b/libgpl/dialogextend/jquery.dialogextend.js
new file mode 100644
index 0000000..f633829
--- /dev/null
+++ b/libgpl/dialogextend/jquery.dialogextend.js
@@ -0,0 +1,509 @@
+(function() {
+ var $;
+
+ $ = jQuery;
+
+ $.widget("ui.dialogExtend", {
+ version: "2.0.0",
+ modes: {},
+ options: {
+ "closable": true,
+ "dblclick": false,
+ "titlebar": false,
+ "icons": {
+ "close": "ui-icon-closethick",
+ "restore": "ui-icon-newwin"
+ },
+ "load": null,
+ "beforeRestore": null,
+ "restore": null
+ },
+ _create: function() {
+ this._state = "normal";
+ if (!$(this.element[0]).data("ui-dialog")) {
+ $.error("jQuery.dialogExtend Error : Only jQuery UI Dialog element is accepted");
+ }
+ this._verifyOptions();
+ this._initStyles();
+ this._initButtons();
+ this._initTitleBar();
+ this._setState("normal");
+ this._on("load", function(e) {
+ return console.log("test", e);
+ });
+ return this._trigger("load");
+ },
+ _setState: function(state) {
+ $(this.element[0]).removeClass("ui-dialog-" + this._state).addClass("ui-dialog-" + state);
+ return this._state = state;
+ },
+ _verifyOptions: function() {
+ var name, _ref, _results;
+
+ if (this.options.dblclick && !(this.options.dblclick in this.modes)) {
+ $.error("jQuery.dialogExtend Error : Invalid <dblclick> value '" + this.options.dblclick + "'");
+ this.options.dblclick = false;
+ }
+ if (this.options.titlebar && ((_ref = this.options.titlebar) !== "none" && _ref !== "transparent")) {
+ $.error("jQuery.dialogExtend Error : Invalid <titlebar> value '" + this.options.titlebar + "'");
+ this.options.titlebar = false;
+ }
+ _results = [];
+ for (name in this.modes) {
+ if (this["_verifyOptions_" + name]) {
+ _results.push(this["_verifyOptions_" + name]());
+ } else {
+ _results.push(void 0);
+ }
+ }
+ return _results;
+ },
+ _initStyles: function() {
+ var name, style, _results;
+
+ if (!$(".dialog-extend-css").length) {
+ style = '';
+ style += '<style class="dialog-extend-css" type="text/css">';
+ style += '.ui-dialog .ui-dialog-titlebar-buttonpane>a { float: right; }';
+ style += '.ui-dialog .ui-dialog-titlebar-restore { width: 19px; height: 18px; }';
+ style += '.ui-dialog .ui-dialog-titlebar-restore span { display: block; margin: 1px; }';
+ style += '.ui-dialog .ui-dialog-titlebar-restore:hover,';
+ style += '.ui-dialog .ui-dialog-titlebar-restore:focus { padding: 0; }';
+ style += '.ui-dialog .ui-dialog-titlebar ::selection { background-color: transparent; }';
+ style += '</style>';
+ $(style).appendTo("body");
+ }
+ _results = [];
+ for (name in this.modes) {
+ _results.push(this["_initStyles_" + name]());
+ }
+ return _results;
+ },
+ _initButtons: function() {
+ var buttonPane, mode, name, titlebar, _ref,
+ _this = this;
+
+ titlebar = $(this.element[0]).dialog("widget").find(".ui-dialog-titlebar");
+ buttonPane = $('<div class="ui-dialog-titlebar-buttonpane"></div>').appendTo(titlebar);
+ buttonPane.css({
+ "position": "absolute",
+ "top": "50%",
+ "right": "0.3em",
+ "margin-top": "-10px",
+ "height": "18px"
+ });
+ titlebar.find(".ui-dialog-titlebar-close").css({
+ "position": "relative",
+ "float": "right",
+ "top": "auto",
+ "right": "auto",
+ "margin": 0
+ }).find(".ui-icon").removeClass("ui-icon-closethick").addClass(this.options.icons.close).end().appendTo(buttonPane).end();
+ buttonPane.append('<a class="ui-dialog-titlebar-restore ui-corner-all ui-state-default" href="#"><span class="ui-icon ' + this.options.icons.restore + '" title="restore">restore</span></a>').find('.ui-dialog-titlebar-restore').attr("role", "button").mouseover(function() {
+ return $(this).addClass("ui-state-hover");
+ }).mouseout(function() {
+ return $(this).removeClass("ui-state-hover");
+ }).focus(function() {
+ return $(this).addClass("ui-state-focus");
+ }).blur(function() {
+ return $(this).removeClass("ui-state-focus");
+ }).end().find(".ui-dialog-titlebar-close").toggle(this.options.closable).end().find(".ui-dialog-titlebar-restore").hide().click(function(e) {
+ e.preventDefault();
+ return _this.restore();
+ }).end();
+ _ref = this.modes;
+ for (name in _ref) {
+ mode = _ref[name];
+ this._initModuleButton(name, mode);
+ }
+ return titlebar.dblclick(function(evt) {
+ if (_this.options.dblclick) {
+ if (_this._state !== "normal") {
+ return _this.restore();
+ } else {
+ return _this[_this.options.dblclick]();
+ }
+ }
+ }).select(function() {
+ return false;
+ });
+ },
+ _initModuleButton: function(name, mode) {
+ var buttonPane,
+ _this = this;
+
+ buttonPane = $(this.element[0]).dialog("widget").find('.ui-dialog-titlebar-buttonpane');
+ return buttonPane.append('<a class="ui-dialog-titlebar-' + name + ' ui-corner-all ui-state-default" href="#" title="' + name + '"><span class="ui-icon ' + this.options.icons[name] + '">' + name + '</span></a>').find(".ui-dialog-titlebar-" + name).attr("role", "button").mouseover(function() {
+ return $(this).addClass("ui-state-hover");
+ }).mouseout(function() {
+ return $(this).removeClass("ui-state-hover");
+ }).focus(function() {
+ return $(this).addClass("ui-state-focus");
+ }).blur(function() {
+ return $(this).removeClass("ui-state-focus");
+ }).end().find(".ui-dialog-titlebar-" + name).toggle(this.options[mode.option]).click(function(e) {
+ e.preventDefault();
+ return _this[name]();
+ }).end();
+ },
+ _initTitleBar: function() {
+ var handle;
+
+ switch (this.options.titlebar) {
+ case false:
+ return 0;
+ case "none":
+ if ($(this.element[0]).dialog("option", "draggable")) {
+ handle = $("<div />").addClass("ui-dialog-draggable-handle").css("cursor", "move").height(5);
+ $(this.element[0]).dialog("widget").prepend(handle).draggable("option", "handle", handle);
+ }
+ return $(this.element[0]).dialog("widget").find(".ui-dialog-titlebar").find(".ui-dialog-title").html("&nbsp;").end().css({
+ "background-color": "transparent",
+ "background-image": "none",
+ "border": 0,
+ "position": "absolute",
+ "right": 0,
+ "top": 0,
+ "z-index": 9999
+ }).end();
+ case "transparent":
+ return $(this.element[0]).dialog("widget").find(".ui-dialog-titlebar").css({
+ "background-color": "transparent",
+ "background-image": "none",
+ "border": 0
+ });
+ default:
+ return $.error("jQuery.dialogExtend Error : Invalid <titlebar> value '" + this.options.titlebar + "'");
+ }
+ },
+ state: function() {
+ return this._state;
+ },
+ restore: function() {
+ this._trigger("beforeRestore");
+ this._restore();
+ this._toggleButtons();
+ return this._trigger("restore");
+ },
+ _restore: function() {
+ if (this._state !== "normal") {
+ this["_restore_" + this._state]();
+ this._setState("normal");
+ return $(this.element[0]).dialog("widget").focus();
+ }
+ },
+ _saveSnapshot: function() {
+ if (this._state === "normal") {
+ this.original_config_resizable = $(this.element[0]).dialog("option", "resizable");
+ this.original_config_draggable = $(this.element[0]).dialog("option", "draggable");
+ this.original_size_height = $(this.element[0]).dialog("widget").outerHeight();
+ this.original_size_width = $(this.element[0]).dialog("option", "width");
+ this.original_size_maxHeight = $(this.element[0]).dialog("option", "maxHeight");
+ this.original_position_mode = $(this.element[0]).dialog("widget").css("position");
+ this.original_position_left = $(this.element[0]).dialog("widget").offset().left - $('body').scrollLeft();
+ this.original_position_top = $(this.element[0]).dialog("widget").offset().top - $('body').scrollTop();
+ return this.original_titlebar_wrap = $(this.element[0]).dialog("widget").find(".ui-dialog-titlebar").css("white-space");
+ }
+ },
+ _loadSnapshot: function() {
+ return {
+ "config": {
+ "resizable": this.original_config_resizable,
+ "draggable": this.original_config_draggable
+ },
+ "size": {
+ "height": this.original_size_height,
+ "width": this.original_size_width,
+ "maxHeight": this.original_size_maxHeight
+ },
+ "position": {
+ "mode": this.original_position_mode,
+ "left": this.original_position_left,
+ "top": this.original_position_top
+ },
+ "titlebar": {
+ "wrap": this.original_titlebar_wrap
+ }
+ };
+ },
+ _toggleButtons: function(newstate) {
+ var mode, name, state, _ref, _ref1, _results;
+
+ state = newstate || this._state;
+ $(this.element[0]).dialog("widget").find(".ui-dialog-titlebar-restore").toggle(state !== "normal").css({
+ "right": "1.4em"
+ }).end();
+ _ref = this.modes;
+ for (name in _ref) {
+ mode = _ref[name];
+ $(this.element[0]).dialog("widget").find(".ui-dialog-titlebar-" + name).toggle(state !== mode.state && this.options[mode.option]);
+ }
+ _ref1 = this.modes;
+ _results = [];
+ for (name in _ref1) {
+ mode = _ref1[name];
+ if (mode.state === state) {
+ _results.push($(this.element[0]).dialog("widget").find(".ui-dialog-titlebar-restore").insertAfter($(this.element[0]).dialog("widget").find(".ui-dialog-titlebar-" + name)).end());
+ } else {
+ _results.push(void 0);
+ }
+ }
+ return _results;
+ }
+ });
+
+}).call(this);
+
+(function() {
+ var $;
+
+ $ = jQuery;
+
+ $.extend(true, $.ui.dialogExtend.prototype, {
+ modes: {
+ "collapse": {
+ option: "collapsable",
+ state: "collapsed"
+ }
+ },
+ options: {
+ "collapsable": false,
+ "icons": {
+ "collapse": "ui-icon-triangle-1-s"
+ },
+ "beforeCollapse": null,
+ "collapse": null
+ },
+ collapse: function() {
+ var newHeight, pos;
+
+ newHeight = $(this.element[0]).dialog("widget").find(".ui-dialog-titlebar").height() + 15;
+ this._trigger("beforeCollapse");
+ if (this._state !== "normal") {
+ this._restore();
+ }
+ this._saveSnapshot();
+ pos = $(this.element[0]).dialog("widget").position();
+ $(this.element[0]).dialog("option", {
+ "resizable": false,
+ "height": newHeight,
+ "maxHeight": newHeight,
+ "position": [pos.left - $(document).scrollLeft(), pos.top - $(document).scrollTop()]
+ }).on('dialogclose', this._collapse_restore).hide().dialog("widget").find(".ui-dialog-buttonpane:visible").hide().end().find(".ui-dialog-titlebar").css("white-space", "nowrap").end().find(".ui-dialog-content");
+ this._setState("collapsed");
+ this._toggleButtons();
+ return this._trigger("collapse");
+ },
+ _restore_collapsed: function() {
+ var original;
+
+ original = this._loadSnapshot();
+ return $(this.element[0]).show().dialog("widget").find(".ui-dialog-buttonpane:hidden").show().end().find(".ui-dialog-titlebar").css("white-space", original.titlebar.wrap).end().find(".ui-dialog-content").dialog("option", {
+ "resizable": original.config.resizable,
+ "height": original.size.height,
+ "maxHeight": original.size.maxHeight
+ }).off('dialogclose', this._collapse_restore);
+ },
+ _initStyles_collapse: function() {
+ var style;
+
+ if (!$(".dialog-extend-collapse-css").length) {
+ style = '';
+ style += '<style class="dialog-extend-collapse-css" type="text/css">';
+ style += '.ui-dialog .ui-dialog-titlebar-collapse { width: 19px; height: 18px; }';
+ style += '.ui-dialog .ui-dialog-titlebar-collapse span { display: block; margin: 1px; }';
+ style += '.ui-dialog .ui-dialog-titlebar-collapse:hover,';
+ style += '.ui-dialog .ui-dialog-titlebar-collapse:focus { padding: 0; }';
+ style += '</style>';
+ return $(style).appendTo("body");
+ }
+ },
+ _collapse_restore: function() {
+ return $(this).dialogExtend("restore");
+ }
+ });
+
+}).call(this);
+
+(function() {
+ var $;
+
+ $ = jQuery;
+
+ $.extend(true, $.ui.dialogExtend.prototype, {
+ modes: {
+ "maximize": {
+ option: "maximizable",
+ state: "maximized"
+ }
+ },
+ options: {
+ "maximizable": false,
+ "icons": {
+ "maximize": "ui-icon-extlink"
+ },
+ "beforeMaximize": null,
+ "maximize": null
+ },
+ maximize: function() {
+ var newHeight, newWidth;
+
+ newHeight = $(window).height() - 11;
+ newWidth = $(window).width() - 11;
+ this._trigger("beforeMaximize");
+ if (this._state !== "normal") {
+ this._restore();
+ }
+ this._saveSnapshot();
+ if ($(this.element[0]).dialog("option", "draggable")) {
+ $(this.element[0]).dialog("widget").draggable("option", "handle", null).find(".ui-dialog-draggable-handle").css("cursor", "text").end();
+ }
+ $(this.element[0]).dialog("widget").css("position", "fixed").find(".ui-dialog-content").show().dialog("widget").find(".ui-dialog-buttonpane").show().end().find(".ui-dialog-content").dialog("option", {
+ "resizable": false,
+ "draggable": false,
+ "height": newHeight,
+ "width": newWidth,
+ "position": {
+ my: "left top",
+ at: "left top",
+ of: window
+ }
+ });
+ this._setState("maximized");
+ this._toggleButtons();
+ return this._trigger("maximize");
+ },
+ _restore_maximized: function() {
+ var original;
+
+ original = this._loadSnapshot();
+ $(this.element[0]).dialog("widget").css("position", original.position.mode).find(".ui-dialog-titlebar").css("white-space", original.titlebar.wrap).end().find(".ui-dialog-content").dialog("option", {
+ "resizable": original.config.resizable,
+ "draggable": original.config.draggable,
+ "height": original.size.height,
+ "width": original.size.width,
+ "maxHeight": original.size.maxHeight,
+ "position": {
+ my: "left top",
+ at: "left+" + original.position.left + " top+" + original.position.top,
+ of: window
+ }
+ });
+ if ($(this.element[0]).dialog("option", "draggable")) {
+ return $(this.element[0]).dialog("widget").draggable("option", "handle", $(this.element[0]).dialog("widget").find(".ui-dialog-draggable-handle").length ? $(this.element[0]).dialog("widget").find(".ui-dialog-draggable-handle") : ".ui-dialog-titlebar").find(".ui-dialog-draggable-handle").css("cursor", "move");
+ }
+ },
+ _initStyles_maximize: function() {
+ var style;
+
+ if (!$(".dialog-extend-maximize-css").length) {
+ style = '';
+ style += '<style class="dialog-extend-maximize-css" type="text/css">';
+ style += '.ui-dialog .ui-dialog-titlebar-maximize { width: 19px; height: 18px; }';
+ style += '.ui-dialog .ui-dialog-titlebar-maximize span { display: block; margin: 1px; }';
+ style += '.ui-dialog .ui-dialog-titlebar-maximize:hover,';
+ style += '.ui-dialog .ui-dialog-titlebar-maximize:focus { padding: 0; }';
+ style += '</style>';
+ return $(style).appendTo("body");
+ }
+ }
+ });
+
+}).call(this);
+
+(function() {
+ var $;
+
+ $ = jQuery;
+
+ $.extend(true, $.ui.dialogExtend.prototype, {
+ modes: {
+ "minimize": {
+ option: "minimizable",
+ state: "minimized"
+ }
+ },
+ options: {
+ "minimizable": false,
+ "minimizeLocation": "left",
+ "icons": {
+ "minimize": "ui-icon-minus"
+ },
+ "beforeMinimize": null,
+ "minimize": null
+ },
+ minimize: function() {
+ var dialogcontrols, fixedContainer, newWidth;
+
+ this._trigger("beforeMinimize");
+ if (this._state !== "normal") {
+ this._restore();
+ }
+ newWidth = 200;
+ if ($("#dialog-extend-fixed-container").length) {
+ fixedContainer = $("#dialog-extend-fixed-container");
+ } else {
+ fixedContainer = $('<div id="dialog-extend-fixed-container"></div>').appendTo("body");
+ fixedContainer.css({
+ "position": "fixed",
+ "bottom": 1,
+ "left": 1,
+ "right": 1,
+ "z-index": 9999
+ });
+ }
+ this._toggleButtons("minimized");
+ dialogcontrols = $(this.element[0]).dialog("widget").clone().children().remove().end();
+ $(this.element[0]).dialog("widget").find('.ui-dialog-titlebar').clone(true, true).appendTo(dialogcontrols);
+ dialogcontrols.css({
+ "float": this.options.minimizeLocation,
+ "margin": 1
+ });
+ fixedContainer.append(dialogcontrols);
+ $(this.element[0]).data("dialog-extend-minimize-controls", dialogcontrols);
+ if ($(this.element[0]).dialog("option", "draggable")) {
+ dialogcontrols.removeClass("ui-draggable");
+ }
+ dialogcontrols.css({
+ "height": "auto",
+ "width": newWidth,
+ "position": "static"
+ });
+ $(this.element[0]).on('dialogbeforeclose', this._minimize_restoreOnClose).dialog("widget").hide();
+ this._setState("minimized");
+ return this._trigger("minimize");
+ },
+ _restore_minimized: function() {
+ $(this.element[0]).dialog("widget").show();
+ $(this.element[0]).off('dialogbeforeclose', this._minimize_restoreOnClose);
+ $(this.element[0]).data("dialog-extend-minimize-controls").remove();
+ return $(this.element[0]).removeData("dialog-extend-minimize-controls");
+ },
+ _initStyles_minimize: function() {
+ var style;
+
+ if (!$(".dialog-extend-minimize-css").length) {
+ style = '';
+ style += '<style class="dialog-extend-minimize-css" type="text/css">';
+ style += '.ui-dialog .ui-dialog-titlebar-minimize { width: 19px; height: 18px; }';
+ style += '.ui-dialog .ui-dialog-titlebar-minimize span { display: block; margin: 1px; }';
+ style += '.ui-dialog .ui-dialog-titlebar-minimize:hover,';
+ style += '.ui-dialog .ui-dialog-titlebar-minimize:focus { padding: 0; }';
+ style += '</style>';
+ return $(style).appendTo("body");
+ }
+ },
+ _verifyOptions_minimize: function() {
+ var _ref;
+
+ if (!this.options.minimizeLocation || ((_ref = this.options.minimizeLocation) !== 'left' && _ref !== 'right')) {
+ $.error("jQuery.dialogExtend Error : Invalid <minimizeLocation> value '" + this.options.minimizeLocation + "'");
+ return this.options.minimizeLocation = "left";
+ }
+ },
+ _minimize_restoreOnClose: function() {
+ return $(this).dialogExtend("restore");
+ }
+ });
+
+}).call(this);
diff --git a/libgpl/dialogextend/jquery.dialogextend.min.js b/libgpl/dialogextend/jquery.dialogextend.min.js
new file mode 100644
index 0000000..0d943a1
--- /dev/null
+++ b/libgpl/dialogextend/jquery.dialogextend.min.js
@@ -0,0 +1,2 @@
+/*! jquery-dialogextend 2.0.3 2014-07-08 */
+(function(){var i;i=jQuery,i.widget("ui.dialogExtend",{version:"2.0.0",modes:{},options:{closable:!0,dblclick:!1,titlebar:!1,icons:{close:"ui-icon-closethick",restore:"ui-icon-newwin"},load:null,beforeRestore:null,restore:null},_create:function(){return this._state="normal",i(this.element[0]).data("ui-dialog")||i.error("jQuery.dialogExtend Error : Only jQuery UI Dialog element is accepted"),this._verifyOptions(),this._initStyles(),this._initButtons(),this._initTitleBar(),this._setState("normal"),this._on("load",function(i){return console.log("test",i)}),this._trigger("load")},_setState:function(t){return i(this.element[0]).removeClass("ui-dialog-"+this._state).addClass("ui-dialog-"+t),this._state=t},_verifyOptions:function(){var t,e,o;!this.options.dblclick||this.options.dblclick in this.modes||(i.error("jQuery.dialogExtend Error : Invalid <dblclick> value '"+this.options.dblclick+"'"),this.options.dblclick=!1),this.options.titlebar&&"none"!==(e=this.options.titlebar)&&"transparent"!==e&&(i.error("jQuery.dialogExtend Error : Invalid <titlebar> value '"+this.options.titlebar+"'"),this.options.titlebar=!1),o=[];for(t in this.modes)this["_verifyOptions_"+t]?o.push(this["_verifyOptions_"+t]()):o.push(void 0);return o},_initStyles:function(){var t,e,o;i(".dialog-extend-css").length||(e="",e+='<style class="dialog-extend-css" type="text/css">',e+=".ui-dialog .ui-dialog-titlebar-buttonpane>a { float: right; }",e+=".ui-dialog .ui-dialog-titlebar-restore { width: 19px; height: 18px; }",e+=".ui-dialog .ui-dialog-titlebar-restore span { display: block; margin: 1px; }",e+=".ui-dialog .ui-dialog-titlebar-restore:hover,",e+=".ui-dialog .ui-dialog-titlebar-restore:focus { padding: 0; }",e+=".ui-dialog .ui-dialog-titlebar ::selection { background-color: transparent; }",e+="</style>",i(e).appendTo("body")),o=[];for(t in this.modes)o.push(this["_initStyles_"+t]());return o},_initButtons:function(){var t,e,o,n,a,l=this;n=i(this.element[0]).dialog("widget").find(".ui-dialog-titlebar"),t=i('<div class="ui-dialog-titlebar-buttonpane"></div>').appendTo(n),t.css({position:"absolute",top:"50%",right:"0.3em","margin-top":"-10px",height:"18px"}),n.find(".ui-dialog-titlebar-close").css({position:"relative","float":"right",top:"auto",right:"auto",margin:0}).find(".ui-icon").removeClass("ui-icon-closethick").addClass(this.options.icons.close).end().appendTo(t).end(),t.append('<a class="ui-dialog-titlebar-restore ui-corner-all ui-state-default" href="#"><span class="ui-icon '+this.options.icons.restore+'" title="restore">restore</span></a>').find(".ui-dialog-titlebar-restore").attr("role","button").mouseover(function(){return i(this).addClass("ui-state-hover")}).mouseout(function(){return i(this).removeClass("ui-state-hover")}).focus(function(){return i(this).addClass("ui-state-focus")}).blur(function(){return i(this).removeClass("ui-state-focus")}).end().find(".ui-dialog-titlebar-close").toggle(this.options.closable).end().find(".ui-dialog-titlebar-restore").hide().click(function(i){return i.preventDefault(),l.restore()}).end(),a=this.modes;for(o in a)e=a[o],this._initModuleButton(o,e);return n.dblclick(function(){return l.options.dblclick?"normal"!==l._state?l.restore():l[l.options.dblclick]():void 0}).select(function(){return!1})},_initModuleButton:function(t,e){var o,n=this;return o=i(this.element[0]).dialog("widget").find(".ui-dialog-titlebar-buttonpane"),o.append('<a class="ui-dialog-titlebar-'+t+' ui-corner-all ui-state-default" href="#" title="'+t+'"><span class="ui-icon '+this.options.icons[t]+'">'+t+"</span></a>").find(".ui-dialog-titlebar-"+t).attr("role","button").mouseover(function(){return i(this).addClass("ui-state-hover")}).mouseout(function(){return i(this).removeClass("ui-state-hover")}).focus(function(){return i(this).addClass("ui-state-focus")}).blur(function(){return i(this).removeClass("ui-state-focus")}).end().find(".ui-dialog-titlebar-"+t).toggle(this.options[e.option]).click(function(i){return i.preventDefault(),n[t]()}).end()},_initTitleBar:function(){var t;switch(this.options.titlebar){case!1:return 0;case"none":return i(this.element[0]).dialog("option","draggable")&&(t=i("<div />").addClass("ui-dialog-draggable-handle").css("cursor","move").height(5),i(this.element[0]).dialog("widget").prepend(t).draggable("option","handle",t)),i(this.element[0]).dialog("widget").find(".ui-dialog-titlebar").find(".ui-dialog-title").html("&nbsp;").end().css({"background-color":"transparent","background-image":"none",border:0,position:"absolute",right:0,top:0,"z-index":9999}).end();case"transparent":return i(this.element[0]).dialog("widget").find(".ui-dialog-titlebar").css({"background-color":"transparent","background-image":"none",border:0});default:return i.error("jQuery.dialogExtend Error : Invalid <titlebar> value '"+this.options.titlebar+"'")}},state:function(){return this._state},restore:function(){return this._trigger("beforeRestore"),this._restore(),this._toggleButtons(),this._trigger("restore")},_restore:function(){return"normal"!==this._state?(this["_restore_"+this._state](),this._setState("normal"),i(this.element[0]).dialog("widget").focus()):void 0},_saveSnapshot:function(){return"normal"===this._state?(this.original_config_resizable=i(this.element[0]).dialog("option","resizable"),this.original_config_draggable=i(this.element[0]).dialog("option","draggable"),this.original_size_height=i(this.element[0]).dialog("widget").outerHeight(),this.original_size_width=i(this.element[0]).dialog("option","width"),this.original_size_maxHeight=i(this.element[0]).dialog("option","maxHeight"),this.original_position_mode=i(this.element[0]).dialog("widget").css("position"),this.original_position_left=i(this.element[0]).dialog("widget").offset().left-i("body").scrollLeft(),this.original_position_top=i(this.element[0]).dialog("widget").offset().top-i("body").scrollTop(),this.original_titlebar_wrap=i(this.element[0]).dialog("widget").find(".ui-dialog-titlebar").css("white-space")):void 0},_loadSnapshot:function(){return{config:{resizable:this.original_config_resizable,draggable:this.original_config_draggable},size:{height:this.original_size_height,width:this.original_size_width,maxHeight:this.original_size_maxHeight},position:{mode:this.original_position_mode,left:this.original_position_left,top:this.original_position_top},titlebar:{wrap:this.original_titlebar_wrap}}},_toggleButtons:function(t){var e,o,n,a,l,s;n=t||this._state,i(this.element[0]).dialog("widget").find(".ui-dialog-titlebar-restore").toggle("normal"!==n).css({right:"1.4em"}).end(),a=this.modes;for(o in a)e=a[o],i(this.element[0]).dialog("widget").find(".ui-dialog-titlebar-"+o).toggle(n!==e.state&&this.options[e.option]);l=this.modes,s=[];for(o in l)e=l[o],e.state===n?s.push(i(this.element[0]).dialog("widget").find(".ui-dialog-titlebar-restore").insertAfter(i(this.element[0]).dialog("widget").find(".ui-dialog-titlebar-"+o)).end()):s.push(void 0);return s}})}).call(this),function(){var i;i=jQuery,i.extend(!0,i.ui.dialogExtend.prototype,{modes:{collapse:{option:"collapsable",state:"collapsed"}},options:{collapsable:!1,icons:{collapse:"ui-icon-triangle-1-s"},beforeCollapse:null,collapse:null},collapse:function(){var t,e;return t=i(this.element[0]).dialog("widget").find(".ui-dialog-titlebar").height()+15,this._trigger("beforeCollapse"),"normal"!==this._state&&this._restore(),this._saveSnapshot(),e=i(this.element[0]).dialog("widget").position(),i(this.element[0]).dialog("option",{resizable:!1,height:t,maxHeight:t,position:[e.left-i(document).scrollLeft(),e.top-i(document).scrollTop()]}).on("dialogclose",this._collapse_restore).hide().dialog("widget").find(".ui-dialog-buttonpane:visible").hide().end().find(".ui-dialog-titlebar").css("white-space","nowrap").end().find(".ui-dialog-content"),this._setState("collapsed"),this._toggleButtons(),this._trigger("collapse")},_restore_collapsed:function(){var t;return t=this._loadSnapshot(),i(this.element[0]).show().dialog("widget").find(".ui-dialog-buttonpane:hidden").show().end().find(".ui-dialog-titlebar").css("white-space",t.titlebar.wrap).end().find(".ui-dialog-content").dialog("option",{resizable:t.config.resizable,height:t.size.height,maxHeight:t.size.maxHeight}).off("dialogclose",this._collapse_restore)},_initStyles_collapse:function(){var t;return i(".dialog-extend-collapse-css").length?void 0:(t="",t+='<style class="dialog-extend-collapse-css" type="text/css">',t+=".ui-dialog .ui-dialog-titlebar-collapse { width: 19px; height: 18px; }",t+=".ui-dialog .ui-dialog-titlebar-collapse span { display: block; margin: 1px; }",t+=".ui-dialog .ui-dialog-titlebar-collapse:hover,",t+=".ui-dialog .ui-dialog-titlebar-collapse:focus { padding: 0; }",t+="</style>",i(t).appendTo("body"))},_collapse_restore:function(){return i(this).dialogExtend("restore")}})}.call(this),function(){var i;i=jQuery,i.extend(!0,i.ui.dialogExtend.prototype,{modes:{maximize:{option:"maximizable",state:"maximized"}},options:{maximizable:!1,icons:{maximize:"ui-icon-extlink"},beforeMaximize:null,maximize:null},maximize:function(){var t,e;return t=i(window).height()-11,e=i(window).width()-11,this._trigger("beforeMaximize"),"normal"!==this._state&&this._restore(),this._saveSnapshot(),i(this.element[0]).dialog("option","draggable")&&i(this.element[0]).dialog("widget").draggable("option","handle",null).find(".ui-dialog-draggable-handle").css("cursor","text").end(),i(this.element[0]).dialog("widget").css("position","fixed").find(".ui-dialog-content").show().dialog("widget").find(".ui-dialog-buttonpane").show().end().find(".ui-dialog-content").dialog("option",{resizable:!1,draggable:!1,height:t,width:e,position:{my:"left top",at:"left top",of:window}}),this._setState("maximized"),this._toggleButtons(),this._trigger("maximize")},_restore_maximized:function(){var t;return t=this._loadSnapshot(),i(this.element[0]).dialog("widget").css("position",t.position.mode).find(".ui-dialog-titlebar").css("white-space",t.titlebar.wrap).end().find(".ui-dialog-content").dialog("option",{resizable:t.config.resizable,draggable:t.config.draggable,height:t.size.height,width:t.size.width,maxHeight:t.size.maxHeight,position:{my:"left top",at:"left+"+t.position.left+" top+"+t.position.top,of:window}}),i(this.element[0]).dialog("option","draggable")?i(this.element[0]).dialog("widget").draggable("option","handle",i(this.element[0]).dialog("widget").find(".ui-dialog-draggable-handle").length?i(this.element[0]).dialog("widget").find(".ui-dialog-draggable-handle"):".ui-dialog-titlebar").find(".ui-dialog-draggable-handle").css("cursor","move"):void 0},_initStyles_maximize:function(){var t;return i(".dialog-extend-maximize-css").length?void 0:(t="",t+='<style class="dialog-extend-maximize-css" type="text/css">',t+=".ui-dialog .ui-dialog-titlebar-maximize { width: 19px; height: 18px; }",t+=".ui-dialog .ui-dialog-titlebar-maximize span { display: block; margin: 1px; }",t+=".ui-dialog .ui-dialog-titlebar-maximize:hover,",t+=".ui-dialog .ui-dialog-titlebar-maximize:focus { padding: 0; }",t+="</style>",i(t).appendTo("body"))}})}.call(this),function(){var i;i=jQuery,i.extend(!0,i.ui.dialogExtend.prototype,{modes:{minimize:{option:"minimizable",state:"minimized"}},options:{minimizable:!1,minimizeLocation:"left",icons:{minimize:"ui-icon-minus"},beforeMinimize:null,minimize:null},minimize:function(){var t,e,o;return this._trigger("beforeMinimize"),"normal"!==this._state&&this._restore(),o=200,i("#dialog-extend-fixed-container").length?e=i("#dialog-extend-fixed-container"):(e=i('<div id="dialog-extend-fixed-container"></div>').appendTo("body"),e.css({position:"fixed",bottom:1,left:1,right:1,"z-index":9999})),this._toggleButtons("minimized"),t=i(this.element[0]).dialog("widget").clone().children().remove().end(),i(this.element[0]).dialog("widget").find(".ui-dialog-titlebar").clone(!0,!0).appendTo(t),t.css({"float":this.options.minimizeLocation,margin:1}),e.append(t),i(this.element[0]).data("dialog-extend-minimize-controls",t),i(this.element[0]).dialog("option","draggable")&&t.removeClass("ui-draggable"),t.css({height:"auto",width:o,position:"static"}),i(this.element[0]).on("dialogbeforeclose",this._minimize_restoreOnClose).dialog("widget").hide(),this._setState("minimized"),this._trigger("minimize")},_restore_minimized:function(){return i(this.element[0]).dialog("widget").show(),i(this.element[0]).off("dialogbeforeclose",this._minimize_restoreOnClose),i(this.element[0]).data("dialog-extend-minimize-controls").remove(),i(this.element[0]).removeData("dialog-extend-minimize-controls")},_initStyles_minimize:function(){var t;return i(".dialog-extend-minimize-css").length?void 0:(t="",t+='<style class="dialog-extend-minimize-css" type="text/css">',t+=".ui-dialog .ui-dialog-titlebar-minimize { width: 19px; height: 18px; }",t+=".ui-dialog .ui-dialog-titlebar-minimize span { display: block; margin: 1px; }",t+=".ui-dialog .ui-dialog-titlebar-minimize:hover,",t+=".ui-dialog .ui-dialog-titlebar-minimize:focus { padding: 0; }",t+="</style>",i(t).appendTo("body"))},_verifyOptions_minimize:function(){var t;return!this.options.minimizeLocation||"left"!==(t=this.options.minimizeLocation)&&"right"!==t?(i.error("jQuery.dialogExtend Error : Invalid <minimizeLocation> value '"+this.options.minimizeLocation+"'"),this.options.minimizeLocation="left"):void 0},_minimize_restoreOnClose:function(){return i(this).dialogExtend("restore")}})}.call(this); \ No newline at end of file
diff --git a/libgpl/encryption/encryption.php b/libgpl/encryption/encryption.php
new file mode 100644
index 0000000..c503109
--- /dev/null
+++ b/libgpl/encryption/encryption.php
@@ -0,0 +1,166 @@
+<?php
+/**
+ * A class to handle secure encryption and decryption of arbitrary data
+ * Copyright http://stackoverflow.com/users/338665/ircmaxell
+ * http://stackoverflow.com/questions/5089841/php-2-way-encryption-i-need-to-store-passwords-that-can-be-retrieved
+ *
+ *
+ * Note that this is not just straight encryption. It also has a few other
+ * features in it to make the encrypted data far more secure. Note that any
+ * other implementations used to decrypt data will have to do the same exact
+ * operations.
+ *
+ * Security Benefits:
+ *
+ * - Uses Key stretching
+ * - Hides the Initialization Vector
+ * - Does HMAC verification of source data
+ *
+ */
+class Encryption {
+
+ /**
+ * @var string $cipher The mcrypt cipher to use for this instance
+ */
+ protected $cipher = '';
+
+ /**
+ * @var int $mode The mcrypt cipher mode to use
+ */
+ protected $mode = '';
+
+ /**
+ * @var int $rounds The number of rounds to feed into PBKDF2 for key generation
+ */
+ protected $rounds = 100;
+
+ /**
+ * Constructor!
+ *
+ * @param string $cipher The MCRYPT_* cypher to use for this instance
+ * @param int $mode The MCRYPT_MODE_* mode to use for this instance
+ * @param int $rounds The number of PBKDF2 rounds to do on the key
+ */
+ public function __construct($cipher, $mode, $rounds = 100) {
+ $this->cipher = $cipher;
+ $this->mode = $mode;
+ $this->rounds = (int) $rounds;
+ }
+
+ /**
+ * Decrypt the data with the provided key
+ *
+ * @param string $data The encrypted datat to decrypt
+ * @param string $key The key to use for decryption
+ *
+ * @returns string|false The returned string if decryption is successful
+ * false if it is not
+ */
+ public function decrypt($data, $key) {
+ $salt = substr($data, 0, 128);
+ $enc = substr($data, 128, -64);
+ $mac = substr($data, -64);
+
+ list ($cipherKey, $macKey, $iv) = $this->getKeys($salt, $key);
+
+ if ($mac !== hash_hmac('sha512', $enc, $macKey, true)) {
+ return false;
+ }
+
+ $dec = mcrypt_decrypt($this->cipher, $cipherKey, $enc, $this->mode, $iv);
+
+ $data = $this->unpad($dec);
+
+ return $data;
+ }
+
+ /**
+ * Encrypt the supplied data using the supplied key
+ *
+ * @param string $data The data to encrypt
+ * @param string $key The key to encrypt with
+ *
+ * @returns string The encrypted data
+ */
+ public function encrypt($data, $key) {
+ $salt = mcrypt_create_iv(128, MCRYPT_DEV_URANDOM);
+ list ($cipherKey, $macKey, $iv) = $this->getKeys($salt, $key);
+
+ $data = $this->pad($data);
+
+ $enc = mcrypt_encrypt($this->cipher, $cipherKey, $data, $this->mode, $iv);
+
+ $mac = hash_hmac('sha512', $enc, $macKey, true);
+ return $salt . $enc . $mac;
+ }
+
+ /**
+ * Generates a set of keys given a random salt and a master key
+ *
+ * @param string $salt A random string to change the keys each encryption
+ * @param string $key The supplied key to encrypt with
+ *
+ * @returns array An array of keys (a cipher key, a mac key, and a IV)
+ */
+ protected function getKeys($salt, $key) {
+ $ivSize = mcrypt_get_iv_size($this->cipher, $this->mode);
+ $keySize = mcrypt_get_key_size($this->cipher, $this->mode);
+ $length = 2 * $keySize + $ivSize;
+
+ $key = $this->pbkdf2('sha512', $key, $salt, $this->rounds, $length);
+
+ $cipherKey = substr($key, 0, $keySize);
+ $macKey = substr($key, $keySize, $keySize);
+ $iv = substr($key, 2 * $keySize);
+ return array($cipherKey, $macKey, $iv);
+ }
+
+ /**
+ * Stretch the key using the PBKDF2 algorithm
+ *
+ * @see http://en.wikipedia.org/wiki/PBKDF2
+ *
+ * @param string $algo The algorithm to use
+ * @param string $key The key to stretch
+ * @param string $salt A random salt
+ * @param int $rounds The number of rounds to derive
+ * @param int $length The length of the output key
+ *
+ * @returns string The derived key.
+ */
+ protected function pbkdf2($algo, $key, $salt, $rounds, $length) {
+ $size = strlen(hash($algo, '', true));
+ $len = ceil($length / $size);
+ $result = '';
+ for ($i = 1; $i <= $len; $i++) {
+ $tmp = hash_hmac($algo, $salt . pack('N', $i), $key, true);
+ $res = $tmp;
+ for ($j = 1; $j < $rounds; $j++) {
+ $tmp = hash_hmac($algo, $tmp, $key, true);
+ $res ^= $tmp;
+ }
+ $result .= $res;
+ }
+ return substr($result, 0, $length);
+ }
+
+ protected function pad($data) {
+ $length = mcrypt_get_block_size($this->cipher, $this->mode);
+ $padAmount = $length - strlen($data) % $length;
+ if ($padAmount == 0) {
+ $padAmount = $length;
+ }
+ return $data . str_repeat(chr($padAmount), $padAmount);
+ }
+
+ protected function unpad($data) {
+ $length = mcrypt_get_block_size($this->cipher, $this->mode);
+ $last = ord($data[strlen($data) - 1]);
+ if ($last > $length) return false;
+ if (substr($data, -1 * $last) !== str_repeat(chr($last), $last)) {
+ return false;
+ }
+ return substr($data, 0, -1 * $last);
+ }
+}
+?>
diff --git a/libgpl/fancybox/blank.gif b/libgpl/fancybox/blank.gif
new file mode 100644
index 0000000..35d42e8
--- /dev/null
+++ b/libgpl/fancybox/blank.gif
Binary files differ
diff --git a/libgpl/fancybox/fancy_close.png b/libgpl/fancybox/fancy_close.png
new file mode 100644
index 0000000..0703530
--- /dev/null
+++ b/libgpl/fancybox/fancy_close.png
Binary files differ
diff --git a/libgpl/fancybox/fancy_closebox.png b/libgpl/fancybox/fancy_closebox.png
new file mode 100644
index 0000000..4de4396
--- /dev/null
+++ b/libgpl/fancybox/fancy_closebox.png
Binary files differ
diff --git a/libgpl/fancybox/fancy_left.png b/libgpl/fancybox/fancy_left.png
new file mode 100644
index 0000000..61494e6
--- /dev/null
+++ b/libgpl/fancybox/fancy_left.png
Binary files differ
diff --git a/libgpl/fancybox/fancy_loading.png b/libgpl/fancybox/fancy_loading.png
new file mode 100644
index 0000000..2503017
--- /dev/null
+++ b/libgpl/fancybox/fancy_loading.png
Binary files differ
diff --git a/libgpl/fancybox/fancy_nav_left.png b/libgpl/fancybox/fancy_nav_left.png
new file mode 100644
index 0000000..ebaa6a4
--- /dev/null
+++ b/libgpl/fancybox/fancy_nav_left.png
Binary files differ
diff --git a/libgpl/fancybox/fancy_nav_right.png b/libgpl/fancybox/fancy_nav_right.png
new file mode 100644
index 0000000..873294e
--- /dev/null
+++ b/libgpl/fancybox/fancy_nav_right.png
Binary files differ
diff --git a/libgpl/fancybox/fancy_progress.png b/libgpl/fancybox/fancy_progress.png
new file mode 100644
index 0000000..06b7c89
--- /dev/null
+++ b/libgpl/fancybox/fancy_progress.png
Binary files differ
diff --git a/libgpl/fancybox/fancy_right.png b/libgpl/fancybox/fancy_right.png
new file mode 100644
index 0000000..0a56042
--- /dev/null
+++ b/libgpl/fancybox/fancy_right.png
Binary files differ
diff --git a/libgpl/fancybox/fancy_shadow_e.png b/libgpl/fancybox/fancy_shadow_e.png
new file mode 100644
index 0000000..2eda089
--- /dev/null
+++ b/libgpl/fancybox/fancy_shadow_e.png
Binary files differ
diff --git a/libgpl/fancybox/fancy_shadow_n.png b/libgpl/fancybox/fancy_shadow_n.png
new file mode 100644
index 0000000..69aa10e
--- /dev/null
+++ b/libgpl/fancybox/fancy_shadow_n.png
Binary files differ
diff --git a/libgpl/fancybox/fancy_shadow_ne.png b/libgpl/fancybox/fancy_shadow_ne.png
new file mode 100644
index 0000000..79f6980
--- /dev/null
+++ b/libgpl/fancybox/fancy_shadow_ne.png
Binary files differ
diff --git a/libgpl/fancybox/fancy_shadow_nw.png b/libgpl/fancybox/fancy_shadow_nw.png
new file mode 100644
index 0000000..7182cd9
--- /dev/null
+++ b/libgpl/fancybox/fancy_shadow_nw.png
Binary files differ
diff --git a/libgpl/fancybox/fancy_shadow_s.png b/libgpl/fancybox/fancy_shadow_s.png
new file mode 100644
index 0000000..d8858bf
--- /dev/null
+++ b/libgpl/fancybox/fancy_shadow_s.png
Binary files differ
diff --git a/libgpl/fancybox/fancy_shadow_se.png b/libgpl/fancybox/fancy_shadow_se.png
new file mode 100644
index 0000000..541e3ff
--- /dev/null
+++ b/libgpl/fancybox/fancy_shadow_se.png
Binary files differ
diff --git a/libgpl/fancybox/fancy_shadow_sw.png b/libgpl/fancybox/fancy_shadow_sw.png
new file mode 100644
index 0000000..b451689
--- /dev/null
+++ b/libgpl/fancybox/fancy_shadow_sw.png
Binary files differ
diff --git a/libgpl/fancybox/fancy_shadow_w.png b/libgpl/fancybox/fancy_shadow_w.png
new file mode 100644
index 0000000..8a4e4a8
--- /dev/null
+++ b/libgpl/fancybox/fancy_shadow_w.png
Binary files differ
diff --git a/libgpl/fancybox/fancy_title_left.png b/libgpl/fancybox/fancy_title_left.png
new file mode 100644
index 0000000..6049223
--- /dev/null
+++ b/libgpl/fancybox/fancy_title_left.png
Binary files differ
diff --git a/libgpl/fancybox/fancy_title_main.png b/libgpl/fancybox/fancy_title_main.png
new file mode 100644
index 0000000..8044271
--- /dev/null
+++ b/libgpl/fancybox/fancy_title_main.png
Binary files differ
diff --git a/libgpl/fancybox/fancy_title_over.png b/libgpl/fancybox/fancy_title_over.png
new file mode 100644
index 0000000..d9f458f
--- /dev/null
+++ b/libgpl/fancybox/fancy_title_over.png
Binary files differ
diff --git a/libgpl/fancybox/fancy_title_right.png b/libgpl/fancybox/fancy_title_right.png
new file mode 100644
index 0000000..e36d9db
--- /dev/null
+++ b/libgpl/fancybox/fancy_title_right.png
Binary files differ
diff --git a/libgpl/fancybox/fancybox-x.png b/libgpl/fancybox/fancybox-x.png
new file mode 100644
index 0000000..c2130f8
--- /dev/null
+++ b/libgpl/fancybox/fancybox-x.png
Binary files differ
diff --git a/libgpl/fancybox/fancybox-y.png b/libgpl/fancybox/fancybox-y.png
new file mode 100644
index 0000000..7ef399b
--- /dev/null
+++ b/libgpl/fancybox/fancybox-y.png
Binary files differ
diff --git a/libgpl/fancybox/fancybox.png b/libgpl/fancybox/fancybox.png
new file mode 100644
index 0000000..65e14f6
--- /dev/null
+++ b/libgpl/fancybox/fancybox.png
Binary files differ
diff --git a/libgpl/fancybox/jquery.easing-1.3.pack.js b/libgpl/fancybox/jquery.easing-1.3.pack.js
new file mode 100644
index 0000000..9028179
--- /dev/null
+++ b/libgpl/fancybox/jquery.easing-1.3.pack.js
@@ -0,0 +1,72 @@
+/*
+ * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/
+ *
+ * Uses the built in easing capabilities added In jQuery 1.1
+ * to offer multiple easing options
+ *
+ * TERMS OF USE - jQuery Easing
+ *
+ * Open source under the BSD License.
+ *
+ * Copyright © 2008 George McGinley Smith
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * Neither the name of the author nor the names of contributors may be used to endorse
+ * or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+*/
+
+// t: current time, b: begInnIng value, c: change In value, d: duration
+eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('h.i[\'1a\']=h.i[\'z\'];h.O(h.i,{y:\'D\',z:9(x,t,b,c,d){6 h.i[h.i.y](x,t,b,c,d)},17:9(x,t,b,c,d){6 c*(t/=d)*t+b},D:9(x,t,b,c,d){6-c*(t/=d)*(t-2)+b},13:9(x,t,b,c,d){e((t/=d/2)<1)6 c/2*t*t+b;6-c/2*((--t)*(t-2)-1)+b},X:9(x,t,b,c,d){6 c*(t/=d)*t*t+b},U:9(x,t,b,c,d){6 c*((t=t/d-1)*t*t+1)+b},R:9(x,t,b,c,d){e((t/=d/2)<1)6 c/2*t*t*t+b;6 c/2*((t-=2)*t*t+2)+b},N:9(x,t,b,c,d){6 c*(t/=d)*t*t*t+b},M:9(x,t,b,c,d){6-c*((t=t/d-1)*t*t*t-1)+b},L:9(x,t,b,c,d){e((t/=d/2)<1)6 c/2*t*t*t*t+b;6-c/2*((t-=2)*t*t*t-2)+b},K:9(x,t,b,c,d){6 c*(t/=d)*t*t*t*t+b},J:9(x,t,b,c,d){6 c*((t=t/d-1)*t*t*t*t+1)+b},I:9(x,t,b,c,d){e((t/=d/2)<1)6 c/2*t*t*t*t*t+b;6 c/2*((t-=2)*t*t*t*t+2)+b},G:9(x,t,b,c,d){6-c*8.C(t/d*(8.g/2))+c+b},15:9(x,t,b,c,d){6 c*8.n(t/d*(8.g/2))+b},12:9(x,t,b,c,d){6-c/2*(8.C(8.g*t/d)-1)+b},Z:9(x,t,b,c,d){6(t==0)?b:c*8.j(2,10*(t/d-1))+b},Y:9(x,t,b,c,d){6(t==d)?b+c:c*(-8.j(2,-10*t/d)+1)+b},W:9(x,t,b,c,d){e(t==0)6 b;e(t==d)6 b+c;e((t/=d/2)<1)6 c/2*8.j(2,10*(t-1))+b;6 c/2*(-8.j(2,-10*--t)+2)+b},V:9(x,t,b,c,d){6-c*(8.o(1-(t/=d)*t)-1)+b},S:9(x,t,b,c,d){6 c*8.o(1-(t=t/d-1)*t)+b},Q:9(x,t,b,c,d){e((t/=d/2)<1)6-c/2*(8.o(1-t*t)-1)+b;6 c/2*(8.o(1-(t-=2)*t)+1)+b},P:9(x,t,b,c,d){f s=1.l;f p=0;f a=c;e(t==0)6 b;e((t/=d)==1)6 b+c;e(!p)p=d*.3;e(a<8.w(c)){a=c;f s=p/4}m f s=p/(2*8.g)*8.r(c/a);6-(a*8.j(2,10*(t-=1))*8.n((t*d-s)*(2*8.g)/p))+b},H:9(x,t,b,c,d){f s=1.l;f p=0;f a=c;e(t==0)6 b;e((t/=d)==1)6 b+c;e(!p)p=d*.3;e(a<8.w(c)){a=c;f s=p/4}m f s=p/(2*8.g)*8.r(c/a);6 a*8.j(2,-10*t)*8.n((t*d-s)*(2*8.g)/p)+c+b},T:9(x,t,b,c,d){f s=1.l;f p=0;f a=c;e(t==0)6 b;e((t/=d/2)==2)6 b+c;e(!p)p=d*(.3*1.5);e(a<8.w(c)){a=c;f s=p/4}m f s=p/(2*8.g)*8.r(c/a);e(t<1)6-.5*(a*8.j(2,10*(t-=1))*8.n((t*d-s)*(2*8.g)/p))+b;6 a*8.j(2,-10*(t-=1))*8.n((t*d-s)*(2*8.g)/p)*.5+c+b},F:9(x,t,b,c,d,s){e(s==u)s=1.l;6 c*(t/=d)*t*((s+1)*t-s)+b},E:9(x,t,b,c,d,s){e(s==u)s=1.l;6 c*((t=t/d-1)*t*((s+1)*t+s)+1)+b},16:9(x,t,b,c,d,s){e(s==u)s=1.l;e((t/=d/2)<1)6 c/2*(t*t*(((s*=(1.B))+1)*t-s))+b;6 c/2*((t-=2)*t*(((s*=(1.B))+1)*t+s)+2)+b},A:9(x,t,b,c,d){6 c-h.i.v(x,d-t,0,c,d)+b},v:9(x,t,b,c,d){e((t/=d)<(1/2.k)){6 c*(7.q*t*t)+b}m e(t<(2/2.k)){6 c*(7.q*(t-=(1.5/2.k))*t+.k)+b}m e(t<(2.5/2.k)){6 c*(7.q*(t-=(2.14/2.k))*t+.11)+b}m{6 c*(7.q*(t-=(2.18/2.k))*t+.19)+b}},1b:9(x,t,b,c,d){e(t<d/2)6 h.i.A(x,t*2,0,c,d)*.5+b;6 h.i.v(x,t*2-d,0,c,d)*.5+c*.5+b}});',62,74,'||||||return||Math|function|||||if|var|PI|jQuery|easing|pow|75|70158|else|sin|sqrt||5625|asin|||undefined|easeOutBounce|abs||def|swing|easeInBounce|525|cos|easeOutQuad|easeOutBack|easeInBack|easeInSine|easeOutElastic|easeInOutQuint|easeOutQuint|easeInQuint|easeInOutQuart|easeOutQuart|easeInQuart|extend|easeInElastic|easeInOutCirc|easeInOutCubic|easeOutCirc|easeInOutElastic|easeOutCubic|easeInCirc|easeInOutExpo|easeInCubic|easeOutExpo|easeInExpo||9375|easeInOutSine|easeInOutQuad|25|easeOutSine|easeInOutBack|easeInQuad|625|984375|jswing|easeInOutBounce'.split('|'),0,{}))
+
+/*
+ *
+ * TERMS OF USE - EASING EQUATIONS
+ *
+ * Open source under the BSD License.
+ *
+ * Copyright © 2001 Robert Penner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * Neither the name of the author nor the names of contributors may be used to endorse
+ * or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
diff --git a/libgpl/fancybox/jquery.fancybox-1.3.4.css b/libgpl/fancybox/jquery.fancybox-1.3.4.css
new file mode 100644
index 0000000..6f53d8f
--- /dev/null
+++ b/libgpl/fancybox/jquery.fancybox-1.3.4.css
@@ -0,0 +1,359 @@
+/*
+ * FancyBox - jQuery Plugin
+ * Simple and fancy lightbox alternative
+ *
+ * Examples and documentation at: http://fancybox.net
+ *
+ * Copyright (c) 2008 - 2010 Janis Skarnelis
+ * That said, it is hardly a one-person project. Many people have submitted bugs, code, and offered their advice freely. Their support is greatly appreciated.
+ *
+ * Version: 1.3.4 (11/11/2010)
+ * Requires: jQuery v1.3+
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ */
+
+#fancybox-loading {
+ position: fixed;
+ top: 50%;
+ left: 50%;
+ width: 40px;
+ height: 40px;
+ margin-top: -20px;
+ margin-left: -20px;
+ cursor: pointer;
+ overflow: hidden;
+ z-index: 1104;
+ display: none;
+}
+
+#fancybox-loading div {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 40px;
+ height: 480px;
+ background-image: url('fancybox.png');
+}
+
+#fancybox-overlay {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ z-index: 1100;
+ display: none;
+}
+
+#fancybox-tmp {
+ padding: 0;
+ margin: 0;
+ border: 0;
+ overflow: auto;
+ display: none;
+}
+
+#fancybox-wrap {
+ position: absolute;
+ top: 0;
+ left: 0;
+ padding: 20px;
+ z-index: 1101;
+ outline: none;
+ display: none;
+}
+
+#fancybox-outer {
+ position: relative;
+ width: 100%;
+ height: 100%;
+ background: #fff;
+}
+
+#fancybox-content {
+ width: 0;
+ height: 0;
+ padding: 0;
+ outline: none;
+ position: relative;
+ overflow: hidden;
+ z-index: 1102;
+ border: 0px solid #fff;
+}
+
+#fancybox-hide-sel-frame {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: transparent;
+ z-index: 1101;
+}
+
+#fancybox-close {
+ position: absolute;
+ top: -15px;
+ right: -15px;
+ width: 30px;
+ height: 30px;
+ background: transparent url('fancybox.png') -40px 0px;
+ cursor: pointer;
+ z-index: 1103;
+ display: none;
+}
+
+#fancybox-error {
+ color: #444;
+ font: normal 12px/20px Arial;
+ padding: 14px;
+ margin: 0;
+}
+
+#fancybox-img {
+ width: 100%;
+ height: 100%;
+ padding: 0;
+ margin: 0;
+ border: none;
+ outline: none;
+ line-height: 0;
+ vertical-align: top;
+}
+
+#fancybox-frame {
+ width: 100%;
+ height: 100%;
+ border: none;
+ display: block;
+}
+
+#fancybox-left, #fancybox-right {
+ position: absolute;
+ bottom: 0px;
+ height: 100%;
+ width: 35%;
+ cursor: pointer;
+ outline: none;
+ background: transparent url('blank.gif');
+ z-index: 1102;
+ display: none;
+}
+
+#fancybox-left {
+ left: 0px;
+}
+
+#fancybox-right {
+ right: 0px;
+}
+
+#fancybox-left-ico, #fancybox-right-ico {
+ position: absolute;
+ top: 50%;
+ left: -9999px;
+ width: 30px;
+ height: 30px;
+ margin-top: -15px;
+ cursor: pointer;
+ z-index: 1102;
+ display: block;
+}
+
+#fancybox-left-ico {
+ background-image: url('fancybox.png');
+ background-position: -40px -30px;
+}
+
+#fancybox-right-ico {
+ background-image: url('fancybox.png');
+ background-position: -40px -60px;
+}
+
+#fancybox-left:hover, #fancybox-right:hover {
+ visibility: visible; /* IE6 */
+}
+
+#fancybox-left:hover span {
+ left: 20px;
+}
+
+#fancybox-right:hover span {
+ left: auto;
+ right: 20px;
+}
+
+.fancybox-bg {
+ position: absolute;
+ padding: 0;
+ margin: 0;
+ border: 0;
+ width: 20px;
+ height: 20px;
+ z-index: 1001;
+}
+
+#fancybox-bg-n {
+ top: -20px;
+ left: 0;
+ width: 100%;
+ background-image: url('fancybox-x.png');
+}
+
+#fancybox-bg-ne {
+ top: -20px;
+ right: -20px;
+ background-image: url('fancybox.png');
+ background-position: -40px -162px;
+}
+
+#fancybox-bg-e {
+ top: 0;
+ right: -20px;
+ height: 100%;
+ background-image: url('fancybox-y.png');
+ background-position: -20px 0px;
+}
+
+#fancybox-bg-se {
+ bottom: -20px;
+ right: -20px;
+ background-image: url('fancybox.png');
+ background-position: -40px -182px;
+}
+
+#fancybox-bg-s {
+ bottom: -20px;
+ left: 0;
+ width: 100%;
+ background-image: url('fancybox-x.png');
+ background-position: 0px -20px;
+}
+
+#fancybox-bg-sw {
+ bottom: -20px;
+ left: -20px;
+ background-image: url('fancybox.png');
+ background-position: -40px -142px;
+}
+
+#fancybox-bg-w {
+ top: 0;
+ left: -20px;
+ height: 100%;
+ background-image: url('fancybox-y.png');
+}
+
+#fancybox-bg-nw {
+ top: -20px;
+ left: -20px;
+ background-image: url('fancybox.png');
+ background-position: -40px -122px;
+}
+
+#fancybox-title {
+ font-family: Helvetica;
+ font-size: 12px;
+ z-index: 1102;
+}
+
+.fancybox-title-inside {
+ padding-bottom: 10px;
+ text-align: center;
+ color: #333;
+ background: #fff;
+ position: relative;
+}
+
+.fancybox-title-outside {
+ padding-top: 10px;
+ color: #fff;
+}
+
+.fancybox-title-over {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ color: #FFF;
+ text-align: left;
+}
+
+#fancybox-title-over {
+ padding: 10px;
+ background-image: url('fancy_title_over.png');
+ display: block;
+}
+
+.fancybox-title-float {
+ position: absolute;
+ left: 0;
+ bottom: -20px;
+ height: 32px;
+}
+
+#fancybox-title-float-wrap {
+ border: none;
+ border-collapse: collapse;
+ width: auto;
+}
+
+#fancybox-title-float-wrap td {
+ border: none;
+ white-space: nowrap;
+}
+
+#fancybox-title-float-left {
+ padding: 0 0 0 15px;
+ background: url('fancybox.png') -40px -90px no-repeat;
+}
+
+#fancybox-title-float-main {
+ color: #FFF;
+ line-height: 29px;
+ font-weight: bold;
+ padding: 0 0 3px 0;
+ background: url('fancybox-x.png') 0px -40px;
+}
+
+#fancybox-title-float-right {
+ padding: 0 0 0 15px;
+ background: url('fancybox.png') -55px -90px no-repeat;
+}
+
+/* IE6 */
+
+.fancybox-ie6 #fancybox-close { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_close.png', sizingMethod='scale'); }
+
+.fancybox-ie6 #fancybox-left-ico { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_nav_left.png', sizingMethod='scale'); }
+.fancybox-ie6 #fancybox-right-ico { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_nav_right.png', sizingMethod='scale'); }
+
+.fancybox-ie6 #fancybox-title-over { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_over.png', sizingMethod='scale'); zoom: 1; }
+.fancybox-ie6 #fancybox-title-float-left { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_left.png', sizingMethod='scale'); }
+.fancybox-ie6 #fancybox-title-float-main { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_main.png', sizingMethod='scale'); }
+.fancybox-ie6 #fancybox-title-float-right { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_right.png', sizingMethod='scale'); }
+
+.fancybox-ie6 #fancybox-bg-w, .fancybox-ie6 #fancybox-bg-e, .fancybox-ie6 #fancybox-left, .fancybox-ie6 #fancybox-right, #fancybox-hide-sel-frame {
+ height: expression(this.parentNode.clientHeight + "px");
+}
+
+#fancybox-loading.fancybox-ie6 {
+ position: absolute; margin-top: 0;
+ top: expression( (-20 + (document.documentElement.clientHeight ? document.documentElement.clientHeight/2 : document.body.clientHeight/2 ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop )) + 'px');
+}
+
+#fancybox-loading.fancybox-ie6 div { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_loading.png', sizingMethod='scale'); }
+
+/* IE6, IE7, IE8 */
+
+.fancybox-ie .fancybox-bg { background: transparent !important; }
+
+.fancybox-ie #fancybox-bg-n { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_n.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-ne { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_ne.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-e { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_e.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-se { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_se.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-s { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_s.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-sw { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_sw.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-w { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_w.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-nw { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_nw.png', sizingMethod='scale'); } \ No newline at end of file
diff --git a/libgpl/fancybox/jquery.fancybox-1.3.4.js b/libgpl/fancybox/jquery.fancybox-1.3.4.js
new file mode 100644
index 0000000..be77275
--- /dev/null
+++ b/libgpl/fancybox/jquery.fancybox-1.3.4.js
@@ -0,0 +1,1156 @@
+/*
+ * FancyBox - jQuery Plugin
+ * Simple and fancy lightbox alternative
+ *
+ * Examples and documentation at: http://fancybox.net
+ *
+ * Copyright (c) 2008 - 2010 Janis Skarnelis
+ * That said, it is hardly a one-person project. Many people have submitted bugs, code, and offered their advice freely. Their support is greatly appreciated.
+ *
+ * Version: 1.3.4 (11/11/2010)
+ * Requires: jQuery v1.3+
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ */
+
+;(function($) {
+ var tmp, loading, overlay, wrap, outer, content, close, title, nav_left, nav_right,
+
+ selectedIndex = 0, selectedOpts = {}, selectedArray = [], currentIndex = 0, currentOpts = {}, currentArray = [],
+
+ ajaxLoader = null, imgPreloader = new Image(), imgRegExp = /\.(jpg|gif|png|bmp|jpeg)(.*)?$/i, swfRegExp = /[^\.]\.(swf)\s*$/i,
+
+ loadingTimer, loadingFrame = 1,
+
+ titleHeight = 0, titleStr = '', start_pos, final_pos, busy = false, fx = $.extend($('<div/>')[0], { prop: 0 }),
+
+ isIE6 = $.browser.msie && $.browser.version < 7 && !window.XMLHttpRequest,
+
+ /*
+ * Private methods
+ */
+
+ _abort = function() {
+ loading.hide();
+
+ imgPreloader.onerror = imgPreloader.onload = null;
+
+ if (ajaxLoader) {
+ ajaxLoader.abort();
+ }
+
+ tmp.empty();
+ },
+
+ _error = function() {
+ if (false === selectedOpts.onError(selectedArray, selectedIndex, selectedOpts)) {
+ loading.hide();
+ busy = false;
+ return;
+ }
+
+ selectedOpts.titleShow = false;
+
+ selectedOpts.width = 'auto';
+ selectedOpts.height = 'auto';
+
+ tmp.html( '<p id="fancybox-error">The requested content cannot be loaded.<br />Please try again later.</p>' );
+
+ _process_inline();
+ },
+
+ _start = function() {
+ var obj = selectedArray[ selectedIndex ],
+ href,
+ type,
+ title,
+ str,
+ emb,
+ ret;
+
+ _abort();
+
+ selectedOpts = $.extend({}, $.fn.fancybox.defaults, (typeof $(obj).data('fancybox') == 'undefined' ? selectedOpts : $(obj).data('fancybox')));
+
+ ret = selectedOpts.onStart(selectedArray, selectedIndex, selectedOpts);
+
+ if (ret === false) {
+ busy = false;
+ return;
+ } else if (typeof ret == 'object') {
+ selectedOpts = $.extend(selectedOpts, ret);
+ }
+
+ title = selectedOpts.title || (obj.nodeName ? $(obj).attr('title') : obj.title) || '';
+
+ if (obj.nodeName && !selectedOpts.orig) {
+ selectedOpts.orig = $(obj).children("img:first").length ? $(obj).children("img:first") : $(obj);
+ }
+
+ if (title === '' && selectedOpts.orig && selectedOpts.titleFromAlt) {
+ title = selectedOpts.orig.attr('alt');
+ }
+
+ href = selectedOpts.href || (obj.nodeName ? $(obj).attr('href') : obj.href) || null;
+
+ if ((/^(?:javascript)/i).test(href) || href == '#') {
+ href = null;
+ }
+
+ if (selectedOpts.type) {
+ type = selectedOpts.type;
+
+ if (!href) {
+ href = selectedOpts.content;
+ }
+
+ } else if (selectedOpts.content) {
+ type = 'html';
+
+ } else if (href) {
+ if (href.match(imgRegExp)) {
+ type = 'image';
+
+ } else if (href.match(swfRegExp)) {
+ type = 'swf';
+
+ } else if ($(obj).hasClass("iframe")) {
+ type = 'iframe';
+
+ } else if (href.indexOf("#") === 0) {
+ type = 'inline';
+
+ } else {
+ type = 'ajax';
+ }
+ }
+
+ if (!type) {
+ _error();
+ return;
+ }
+
+ if (type == 'inline') {
+ obj = href.substr(href.indexOf("#"));
+ type = $(obj).length > 0 ? 'inline' : 'ajax';
+ }
+
+ selectedOpts.type = type;
+ selectedOpts.href = href;
+ selectedOpts.title = title;
+
+ if (selectedOpts.autoDimensions) {
+ if (selectedOpts.type == 'html' || selectedOpts.type == 'inline' || selectedOpts.type == 'ajax') {
+ selectedOpts.width = 'auto';
+ selectedOpts.height = 'auto';
+ } else {
+ selectedOpts.autoDimensions = false;
+ }
+ }
+
+ if (selectedOpts.modal) {
+ selectedOpts.overlayShow = true;
+ selectedOpts.hideOnOverlayClick = false;
+ selectedOpts.hideOnContentClick = false;
+ selectedOpts.enableEscapeButton = false;
+ selectedOpts.showCloseButton = false;
+ }
+
+ selectedOpts.padding = parseInt(selectedOpts.padding, 10);
+ selectedOpts.margin = parseInt(selectedOpts.margin, 10);
+
+ tmp.css('padding', (selectedOpts.padding + selectedOpts.margin));
+
+ $('.fancybox-inline-tmp').unbind('fancybox-cancel').bind('fancybox-change', function() {
+ $(this).replaceWith(content.children());
+ });
+
+ switch (type) {
+ case 'html' :
+ tmp.html( selectedOpts.content );
+ _process_inline();
+ break;
+
+ case 'inline' :
+ if ( $(obj).parent().is('#fancybox-content') === true) {
+ busy = false;
+ return;
+ }
+
+ $('<div class="fancybox-inline-tmp" />')
+ .hide()
+ .insertBefore( $(obj) )
+ .bind('fancybox-cleanup', function() {
+ $(this).replaceWith(content.children());
+ }).bind('fancybox-cancel', function() {
+ $(this).replaceWith(tmp.children());
+ });
+
+ $(obj).appendTo(tmp);
+
+ _process_inline();
+ break;
+
+ case 'image':
+ busy = false;
+
+ $.fancybox.showActivity();
+
+ imgPreloader = new Image();
+
+ imgPreloader.onerror = function() {
+ _error();
+ };
+
+ imgPreloader.onload = function() {
+ busy = true;
+
+ imgPreloader.onerror = imgPreloader.onload = null;
+
+ _process_image();
+ };
+
+ imgPreloader.src = href;
+ break;
+
+ case 'swf':
+ selectedOpts.scrolling = 'no';
+
+ str = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="' + selectedOpts.width + '" height="' + selectedOpts.height + '"><param name="movie" value="' + href + '"></param>';
+ emb = '';
+
+ $.each(selectedOpts.swf, function(name, val) {
+ str += '<param name="' + name + '" value="' + val + '"></param>';
+ emb += ' ' + name + '="' + val + '"';
+ });
+
+ str += '<embed src="' + href + '" type="application/x-shockwave-flash" width="' + selectedOpts.width + '" height="' + selectedOpts.height + '"' + emb + '></embed></object>';
+
+ tmp.html(str);
+
+ _process_inline();
+ break;
+
+ case 'ajax':
+ busy = false;
+
+ $.fancybox.showActivity();
+
+ selectedOpts.ajax.win = selectedOpts.ajax.success;
+
+ ajaxLoader = $.ajax($.extend({}, selectedOpts.ajax, {
+ url : href,
+ data : selectedOpts.ajax.data || {},
+ error : function(XMLHttpRequest, textStatus, errorThrown) {
+ if ( XMLHttpRequest.status > 0 ) {
+ _error();
+ }
+ },
+ success : function(data, textStatus, XMLHttpRequest) {
+ var o = typeof XMLHttpRequest == 'object' ? XMLHttpRequest : ajaxLoader;
+ if (o.status == 200) {
+ if ( typeof selectedOpts.ajax.win == 'function' ) {
+ ret = selectedOpts.ajax.win(href, data, textStatus, XMLHttpRequest);
+
+ if (ret === false) {
+ loading.hide();
+ return;
+ } else if (typeof ret == 'string' || typeof ret == 'object') {
+ data = ret;
+ }
+ }
+
+ tmp.html( data );
+ _process_inline();
+ }
+ }
+ }));
+
+ break;
+
+ case 'iframe':
+ _show();
+ break;
+ }
+ },
+
+ _process_inline = function() {
+ var
+ w = selectedOpts.width,
+ h = selectedOpts.height;
+
+ if (w.toString().indexOf('%') > -1) {
+ w = parseInt( ($(window).width() - (selectedOpts.margin * 2)) * parseFloat(w) / 100, 10) + 'px';
+
+ } else {
+ w = w == 'auto' ? 'auto' : w + 'px';
+ }
+
+ if (h.toString().indexOf('%') > -1) {
+ h = parseInt( ($(window).height() - (selectedOpts.margin * 2)) * parseFloat(h) / 100, 10) + 'px';
+
+ } else {
+ h = h == 'auto' ? 'auto' : h + 'px';
+ }
+
+ tmp.wrapInner('<div style="width:' + w + ';height:' + h + ';overflow: ' + (selectedOpts.scrolling == 'auto' ? 'auto' : (selectedOpts.scrolling == 'yes' ? 'scroll' : 'hidden')) + ';position:relative;"></div>');
+
+ selectedOpts.width = tmp.width();
+ selectedOpts.height = tmp.height();
+
+ _show();
+ },
+
+ _process_image = function() {
+ selectedOpts.width = imgPreloader.width;
+ selectedOpts.height = imgPreloader.height;
+
+ $("<img />").attr({
+ 'id' : 'fancybox-img',
+ 'src' : imgPreloader.src,
+ 'alt' : selectedOpts.title
+ }).appendTo( tmp );
+
+ _show();
+ },
+
+ _show = function() {
+ var pos, equal;
+
+ loading.hide();
+
+ if (wrap.is(":visible") && false === currentOpts.onCleanup(currentArray, currentIndex, currentOpts)) {
+ $.event.trigger('fancybox-cancel');
+
+ busy = false;
+ return;
+ }
+
+ busy = true;
+
+ $(content.add( overlay )).unbind();
+
+ $(window).unbind("resize.fb scroll.fb");
+ $(document).unbind('keydown.fb');
+
+ if (wrap.is(":visible") && currentOpts.titlePosition !== 'outside') {
+ wrap.css('height', wrap.height());
+ }
+
+ currentArray = selectedArray;
+ currentIndex = selectedIndex;
+ currentOpts = selectedOpts;
+
+ if (currentOpts.overlayShow) {
+ overlay.css({
+ 'background-color' : currentOpts.overlayColor,
+ 'opacity' : currentOpts.overlayOpacity,
+ 'cursor' : currentOpts.hideOnOverlayClick ? 'pointer' : 'auto',
+ 'height' : $(document).height()
+ });
+
+ if (!overlay.is(':visible')) {
+ if (isIE6) {
+ $('select:not(#fancybox-tmp select)').filter(function() {
+ return this.style.visibility !== 'hidden';
+ }).css({'visibility' : 'hidden'}).one('fancybox-cleanup', function() {
+ this.style.visibility = 'inherit';
+ });
+ }
+
+ overlay.show();
+ }
+ } else {
+ overlay.hide();
+ }
+
+ final_pos = _get_zoom_to();
+
+ _process_title();
+
+ if (wrap.is(":visible")) {
+ $( close.add( nav_left ).add( nav_right ) ).hide();
+
+ pos = wrap.position(),
+
+ start_pos = {
+ top : pos.top,
+ left : pos.left,
+ width : wrap.width(),
+ height : wrap.height()
+ };
+
+ equal = (start_pos.width == final_pos.width && start_pos.height == final_pos.height);
+
+ content.fadeTo(currentOpts.changeFade, 0.3, function() {
+ var finish_resizing = function() {
+ content.html( tmp.contents() ).fadeTo(currentOpts.changeFade, 1, _finish);
+ };
+
+ $.event.trigger('fancybox-change');
+
+ content
+ .empty()
+ .removeAttr('filter')
+ .css({
+ 'border-width' : currentOpts.padding,
+ 'width' : final_pos.width - currentOpts.padding * 2,
+ 'height' : selectedOpts.autoDimensions ? 'auto' : final_pos.height - titleHeight - currentOpts.padding * 2
+ });
+
+ if (equal) {
+ finish_resizing();
+
+ } else {
+ fx.prop = 0;
+
+ $(fx).animate({prop: 1}, {
+ duration : currentOpts.changeSpeed,
+ easing : currentOpts.easingChange,
+ step : _draw,
+ complete : finish_resizing
+ });
+ }
+ });
+
+ return;
+ }
+
+ wrap.removeAttr("style");
+
+ content.css('border-width', currentOpts.padding);
+
+ if (currentOpts.transitionIn == 'elastic') {
+ start_pos = _get_zoom_from();
+
+ content.html( tmp.contents() );
+
+ wrap.show();
+
+ if (currentOpts.opacity) {
+ final_pos.opacity = 0;
+ }
+
+ fx.prop = 0;
+
+ $(fx).animate({prop: 1}, {
+ duration : currentOpts.speedIn,
+ easing : currentOpts.easingIn,
+ step : _draw,
+ complete : _finish
+ });
+
+ return;
+ }
+
+ if (currentOpts.titlePosition == 'inside' && titleHeight > 0) {
+ title.show();
+ }
+
+ content
+ .css({
+ 'width' : final_pos.width - currentOpts.padding * 2,
+ 'height' : selectedOpts.autoDimensions ? 'auto' : final_pos.height - titleHeight - currentOpts.padding * 2
+ })
+ .html( tmp.contents() );
+
+ wrap
+ .css(final_pos)
+ .fadeIn( currentOpts.transitionIn == 'none' ? 0 : currentOpts.speedIn, _finish );
+ },
+
+ _format_title = function(title) {
+ if (title && title.length) {
+ if (currentOpts.titlePosition == 'float') {
+ return '<table id="fancybox-title-float-wrap" cellpadding="0" cellspacing="0"><tr><td id="fancybox-title-float-left"></td><td id="fancybox-title-float-main">' + title + '</td><td id="fancybox-title-float-right"></td></tr></table>';
+ }
+
+ return '<div id="fancybox-title-' + currentOpts.titlePosition + '">' + title + '</div>';
+ }
+
+ return false;
+ },
+
+ _process_title = function() {
+ titleStr = currentOpts.title || '';
+ titleHeight = 0;
+
+ title
+ .empty()
+ .removeAttr('style')
+ .removeClass();
+
+ if (currentOpts.titleShow === false) {
+ title.hide();
+ return;
+ }
+
+ titleStr = $.isFunction(currentOpts.titleFormat) ? currentOpts.titleFormat(titleStr, currentArray, currentIndex, currentOpts) : _format_title(titleStr);
+
+ if (!titleStr || titleStr === '') {
+ title.hide();
+ return;
+ }
+
+ title
+ .addClass('fancybox-title-' + currentOpts.titlePosition)
+ .html( titleStr )
+ .appendTo( 'body' )
+ .show();
+
+ switch (currentOpts.titlePosition) {
+ case 'inside':
+ title
+ .css({
+ 'width' : final_pos.width - (currentOpts.padding * 2),
+ 'marginLeft' : currentOpts.padding,
+ 'marginRight' : currentOpts.padding
+ });
+
+ titleHeight = title.outerHeight(true);
+
+ title.appendTo( outer );
+
+ final_pos.height += titleHeight;
+ break;
+
+ case 'over':
+ title
+ .css({
+ 'marginLeft' : currentOpts.padding,
+ 'width' : final_pos.width - (currentOpts.padding * 2),
+ 'bottom' : currentOpts.padding
+ })
+ .appendTo( outer );
+ break;
+
+ case 'float':
+ title
+ .css('left', parseInt((title.width() - final_pos.width - 40)/ 2, 10) * -1)
+ .appendTo( wrap );
+ break;
+
+ default:
+ title
+ .css({
+ 'width' : final_pos.width - (currentOpts.padding * 2),
+ 'paddingLeft' : currentOpts.padding,
+ 'paddingRight' : currentOpts.padding
+ })
+ .appendTo( wrap );
+ break;
+ }
+
+ title.hide();
+ },
+
+ _set_navigation = function() {
+ if (currentOpts.enableEscapeButton || currentOpts.enableKeyboardNav) {
+ $(document).bind('keydown.fb', function(e) {
+ if (e.keyCode == 27 && currentOpts.enableEscapeButton) {
+ e.preventDefault();
+ $.fancybox.close();
+
+ } else if ((e.keyCode == 37 || e.keyCode == 39) && currentOpts.enableKeyboardNav && e.target.tagName !== 'INPUT' && e.target.tagName !== 'TEXTAREA' && e.target.tagName !== 'SELECT') {
+ e.preventDefault();
+ $.fancybox[ e.keyCode == 37 ? 'prev' : 'next']();
+ }
+ });
+ }
+
+ if (!currentOpts.showNavArrows) {
+ nav_left.hide();
+ nav_right.hide();
+ return;
+ }
+
+ if ((currentOpts.cyclic && currentArray.length > 1) || currentIndex !== 0) {
+ nav_left.show();
+ }
+
+ if ((currentOpts.cyclic && currentArray.length > 1) || currentIndex != (currentArray.length -1)) {
+ nav_right.show();
+ }
+ },
+
+ _finish = function () {
+ if (!$.support.opacity) {
+ content.get(0).style.removeAttribute('filter');
+ wrap.get(0).style.removeAttribute('filter');
+ }
+
+ if (selectedOpts.autoDimensions) {
+ content.css('height', 'auto');
+ }
+
+ wrap.css('height', 'auto');
+
+ if (titleStr && titleStr.length) {
+ title.show();
+ }
+
+ if (currentOpts.showCloseButton) {
+ close.show();
+ }
+
+ _set_navigation();
+
+ if (currentOpts.hideOnContentClick) {
+ content.bind('click', $.fancybox.close);
+ }
+
+ if (currentOpts.hideOnOverlayClick) {
+ overlay.bind('click', $.fancybox.close);
+ }
+
+ $(window).bind("resize.fb", $.fancybox.resize);
+
+ if (currentOpts.centerOnScroll) {
+ $(window).bind("scroll.fb", $.fancybox.center);
+ }
+
+ if (currentOpts.type == 'iframe') {
+ $('<iframe id="fancybox-frame" name="fancybox-frame' + new Date().getTime() + '" frameborder="0" hspace="0" ' + ($.browser.msie ? 'allowtransparency="true""' : '') + ' scrolling="' + selectedOpts.scrolling + '" src="' + currentOpts.href + '"></iframe>').appendTo(content);
+ }
+
+ wrap.show();
+
+ busy = false;
+
+ $.fancybox.center();
+
+ currentOpts.onComplete(currentArray, currentIndex, currentOpts);
+
+ _preload_images();
+ },
+
+ _preload_images = function() {
+ var href,
+ objNext;
+
+ if ((currentArray.length -1) > currentIndex) {
+ href = currentArray[ currentIndex + 1 ].href;
+
+ if (typeof href !== 'undefined' && href.match(imgRegExp)) {
+ objNext = new Image();
+ objNext.src = href;
+ }
+ }
+
+ if (currentIndex > 0) {
+ href = currentArray[ currentIndex - 1 ].href;
+
+ if (typeof href !== 'undefined' && href.match(imgRegExp)) {
+ objNext = new Image();
+ objNext.src = href;
+ }
+ }
+ },
+
+ _draw = function(pos) {
+ var dim = {
+ width : parseInt(start_pos.width + (final_pos.width - start_pos.width) * pos, 10),
+ height : parseInt(start_pos.height + (final_pos.height - start_pos.height) * pos, 10),
+
+ top : parseInt(start_pos.top + (final_pos.top - start_pos.top) * pos, 10),
+ left : parseInt(start_pos.left + (final_pos.left - start_pos.left) * pos, 10)
+ };
+
+ if (typeof final_pos.opacity !== 'undefined') {
+ dim.opacity = pos < 0.5 ? 0.5 : pos;
+ }
+
+ wrap.css(dim);
+
+ content.css({
+ 'width' : dim.width - currentOpts.padding * 2,
+ 'height' : dim.height - (titleHeight * pos) - currentOpts.padding * 2
+ });
+ },
+
+ _get_viewport = function() {
+ return [
+ $(window).width() - (currentOpts.margin * 2),
+ $(window).height() - (currentOpts.margin * 2),
+ $(document).scrollLeft() + currentOpts.margin,
+ $(document).scrollTop() + currentOpts.margin
+ ];
+ },
+
+ _get_zoom_to = function () {
+ var view = _get_viewport(),
+ to = {},
+ resize = currentOpts.autoScale,
+ double_padding = currentOpts.padding * 2,
+ ratio;
+
+ if (currentOpts.width.toString().indexOf('%') > -1) {
+ to.width = parseInt((view[0] * parseFloat(currentOpts.width)) / 100, 10);
+ } else {
+ to.width = currentOpts.width + double_padding;
+ }
+
+ if (currentOpts.height.toString().indexOf('%') > -1) {
+ to.height = parseInt((view[1] * parseFloat(currentOpts.height)) / 100, 10);
+ } else {
+ to.height = currentOpts.height + double_padding;
+ }
+
+ if (resize && (to.width > view[0] || to.height > view[1])) {
+ if (selectedOpts.type == 'image' || selectedOpts.type == 'swf') {
+ ratio = (currentOpts.width ) / (currentOpts.height );
+
+ if ((to.width ) > view[0]) {
+ to.width = view[0];
+ to.height = parseInt(((to.width - double_padding) / ratio) + double_padding, 10);
+ }
+
+ if ((to.height) > view[1]) {
+ to.height = view[1];
+ to.width = parseInt(((to.height - double_padding) * ratio) + double_padding, 10);
+ }
+
+ } else {
+ to.width = Math.min(to.width, view[0]);
+ to.height = Math.min(to.height, view[1]);
+ }
+ }
+
+ to.top = parseInt(Math.max(view[3] - 20, view[3] + ((view[1] - to.height - 40) * 0.5)), 10);
+ to.left = parseInt(Math.max(view[2] - 20, view[2] + ((view[0] - to.width - 40) * 0.5)), 10);
+
+ return to;
+ },
+
+ _get_obj_pos = function(obj) {
+ var pos = obj.offset();
+
+ pos.top += parseInt( obj.css('paddingTop'), 10 ) || 0;
+ pos.left += parseInt( obj.css('paddingLeft'), 10 ) || 0;
+
+ pos.top += parseInt( obj.css('border-top-width'), 10 ) || 0;
+ pos.left += parseInt( obj.css('border-left-width'), 10 ) || 0;
+
+ pos.width = obj.width();
+ pos.height = obj.height();
+
+ return pos;
+ },
+
+ _get_zoom_from = function() {
+ var orig = selectedOpts.orig ? $(selectedOpts.orig) : false,
+ from = {},
+ pos,
+ view;
+
+ if (orig && orig.length) {
+ pos = _get_obj_pos(orig);
+
+ from = {
+ width : pos.width + (currentOpts.padding * 2),
+ height : pos.height + (currentOpts.padding * 2),
+ top : pos.top - currentOpts.padding - 20,
+ left : pos.left - currentOpts.padding - 20
+ };
+
+ } else {
+ view = _get_viewport();
+
+ from = {
+ width : currentOpts.padding * 2,
+ height : currentOpts.padding * 2,
+ top : parseInt(view[3] + view[1] * 0.5, 10),
+ left : parseInt(view[2] + view[0] * 0.5, 10)
+ };
+ }
+
+ return from;
+ },
+
+ _animate_loading = function() {
+ if (!loading.is(':visible')){
+ clearInterval(loadingTimer);
+ return;
+ }
+
+ $('div', loading).css('top', (loadingFrame * -40) + 'px');
+
+ loadingFrame = (loadingFrame + 1) % 12;
+ };
+
+ /*
+ * Public methods
+ */
+
+ $.fn.fancybox = function(options) {
+ if (!$(this).length) {
+ return this;
+ }
+
+ $(this)
+ .data('fancybox', $.extend({}, options, ($.metadata ? $(this).metadata() : {})))
+ .unbind('click.fb')
+ .bind('click.fb', function(e) {
+ e.preventDefault();
+
+ if (busy) {
+ return;
+ }
+
+ busy = true;
+
+ $(this).blur();
+
+ selectedArray = [];
+ selectedIndex = 0;
+
+ var rel = $(this).attr('rel') || '';
+
+ if (!rel || rel == '' || rel === 'nofollow') {
+ selectedArray.push(this);
+
+ } else {
+ selectedArray = $("a[rel=" + rel + "], area[rel=" + rel + "]");
+ selectedIndex = selectedArray.index( this );
+ }
+
+ _start();
+
+ return;
+ });
+
+ return this;
+ };
+
+ $.fancybox = function(obj) {
+ var opts;
+
+ if (busy) {
+ return;
+ }
+
+ busy = true;
+ opts = typeof arguments[1] !== 'undefined' ? arguments[1] : {};
+
+ selectedArray = [];
+ selectedIndex = parseInt(opts.index, 10) || 0;
+
+ if ($.isArray(obj)) {
+ for (var i = 0, j = obj.length; i < j; i++) {
+ if (typeof obj[i] == 'object') {
+ $(obj[i]).data('fancybox', $.extend({}, opts, obj[i]));
+ } else {
+ obj[i] = $({}).data('fancybox', $.extend({content : obj[i]}, opts));
+ }
+ }
+
+ selectedArray = jQuery.merge(selectedArray, obj);
+
+ } else {
+ if (typeof obj == 'object') {
+ $(obj).data('fancybox', $.extend({}, opts, obj));
+ } else {
+ obj = $({}).data('fancybox', $.extend({content : obj}, opts));
+ }
+
+ selectedArray.push(obj);
+ }
+
+ if (selectedIndex > selectedArray.length || selectedIndex < 0) {
+ selectedIndex = 0;
+ }
+
+ _start();
+ };
+
+ $.fancybox.showActivity = function() {
+ clearInterval(loadingTimer);
+
+ loading.show();
+ loadingTimer = setInterval(_animate_loading, 66);
+ };
+
+ $.fancybox.hideActivity = function() {
+ loading.hide();
+ };
+
+ $.fancybox.next = function() {
+ return $.fancybox.pos( currentIndex + 1);
+ };
+
+ $.fancybox.prev = function() {
+ return $.fancybox.pos( currentIndex - 1);
+ };
+
+ $.fancybox.pos = function(pos) {
+ if (busy) {
+ return;
+ }
+
+ pos = parseInt(pos);
+
+ selectedArray = currentArray;
+
+ if (pos > -1 && pos < currentArray.length) {
+ selectedIndex = pos;
+ _start();
+
+ } else if (currentOpts.cyclic && currentArray.length > 1) {
+ selectedIndex = pos >= currentArray.length ? 0 : currentArray.length - 1;
+ _start();
+ }
+
+ return;
+ };
+
+ $.fancybox.cancel = function() {
+ if (busy) {
+ return;
+ }
+
+ busy = true;
+
+ $.event.trigger('fancybox-cancel');
+
+ _abort();
+
+ selectedOpts.onCancel(selectedArray, selectedIndex, selectedOpts);
+
+ busy = false;
+ };
+
+ // Note: within an iframe use - parent.$.fancybox.close();
+ $.fancybox.close = function() {
+ if (busy || wrap.is(':hidden')) {
+ return;
+ }
+
+ busy = true;
+
+ if (currentOpts && false === currentOpts.onCleanup(currentArray, currentIndex, currentOpts)) {
+ busy = false;
+ return;
+ }
+
+ _abort();
+
+ $(close.add( nav_left ).add( nav_right )).hide();
+
+ $(content.add( overlay )).unbind();
+
+ $(window).unbind("resize.fb scroll.fb");
+ $(document).unbind('keydown.fb');
+
+ content.find('iframe').attr('src', isIE6 && /^https/i.test(window.location.href || '') ? 'javascript:void(false)' : 'about:blank');
+
+ if (currentOpts.titlePosition !== 'inside') {
+ title.empty();
+ }
+
+ wrap.stop();
+
+ function _cleanup() {
+ overlay.fadeOut('fast');
+
+ title.empty().hide();
+ wrap.hide();
+
+ $.event.trigger('fancybox-cleanup');
+
+ content.empty();
+
+ currentOpts.onClosed(currentArray, currentIndex, currentOpts);
+
+ currentArray = selectedOpts = [];
+ currentIndex = selectedIndex = 0;
+ currentOpts = selectedOpts = {};
+
+ busy = false;
+ }
+
+ if (currentOpts.transitionOut == 'elastic') {
+ start_pos = _get_zoom_from();
+
+ var pos = wrap.position();
+
+ final_pos = {
+ top : pos.top ,
+ left : pos.left,
+ width : wrap.width(),
+ height : wrap.height()
+ };
+
+ if (currentOpts.opacity) {
+ final_pos.opacity = 1;
+ }
+
+ title.empty().hide();
+
+ fx.prop = 1;
+
+ $(fx).animate({ prop: 0 }, {
+ duration : currentOpts.speedOut,
+ easing : currentOpts.easingOut,
+ step : _draw,
+ complete : _cleanup
+ });
+
+ } else {
+ wrap.fadeOut( currentOpts.transitionOut == 'none' ? 0 : currentOpts.speedOut, _cleanup);
+ }
+ };
+
+ $.fancybox.resize = function() {
+ if (overlay.is(':visible')) {
+ overlay.css('height', $(document).height());
+ }
+
+ $.fancybox.center(true);
+ };
+
+ $.fancybox.center = function() {
+ var view, align;
+
+ if (busy) {
+ return;
+ }
+
+ align = arguments[0] === true ? 1 : 0;
+ view = _get_viewport();
+
+ if (!align && (wrap.width() > view[0] || wrap.height() > view[1])) {
+ return;
+ }
+
+ wrap
+ .stop()
+ .animate({
+ 'top' : parseInt(Math.max(view[3] - 20, view[3] + ((view[1] - content.height() - 40) * 0.5) - currentOpts.padding)),
+ 'left' : parseInt(Math.max(view[2] - 20, view[2] + ((view[0] - content.width() - 40) * 0.5) - currentOpts.padding))
+ }, typeof arguments[0] == 'number' ? arguments[0] : 200);
+ };
+
+ $.fancybox.init = function() {
+ if ($("#fancybox-wrap").length) {
+ return;
+ }
+
+ $('body').append(
+ tmp = $('<div id="fancybox-tmp"></div>'),
+ loading = $('<div id="fancybox-loading"><div></div></div>'),
+ overlay = $('<div id="fancybox-overlay"></div>'),
+ wrap = $('<div id="fancybox-wrap"></div>')
+ );
+
+ outer = $('<div id="fancybox-outer"></div>')
+ .append('<div class="fancybox-bg" id="fancybox-bg-n"></div><div class="fancybox-bg" id="fancybox-bg-ne"></div><div class="fancybox-bg" id="fancybox-bg-e"></div><div class="fancybox-bg" id="fancybox-bg-se"></div><div class="fancybox-bg" id="fancybox-bg-s"></div><div class="fancybox-bg" id="fancybox-bg-sw"></div><div class="fancybox-bg" id="fancybox-bg-w"></div><div class="fancybox-bg" id="fancybox-bg-nw"></div>')
+ .appendTo( wrap );
+
+ outer.append(
+ content = $('<div id="fancybox-content"></div>'),
+ close = $('<a id="fancybox-close"></a>'),
+ title = $('<div id="fancybox-title"></div>'),
+
+ nav_left = $('<a href="javascript:;" id="fancybox-left"><span class="fancy-ico" id="fancybox-left-ico"></span></a>'),
+ nav_right = $('<a href="javascript:;" id="fancybox-right"><span class="fancy-ico" id="fancybox-right-ico"></span></a>')
+ );
+
+ close.click($.fancybox.close);
+ loading.click($.fancybox.cancel);
+
+ nav_left.click(function(e) {
+ e.preventDefault();
+ $.fancybox.prev();
+ });
+
+ nav_right.click(function(e) {
+ e.preventDefault();
+ $.fancybox.next();
+ });
+
+ if ($.fn.mousewheel) {
+ wrap.bind('mousewheel.fb', function(e, delta) {
+ if (busy) {
+ e.preventDefault();
+
+ } else if ($(e.target).get(0).clientHeight == 0 || $(e.target).get(0).scrollHeight === $(e.target).get(0).clientHeight) {
+ e.preventDefault();
+ $.fancybox[ delta > 0 ? 'prev' : 'next']();
+ }
+ });
+ }
+
+ if (!$.support.opacity) {
+ wrap.addClass('fancybox-ie');
+ }
+
+ if (isIE6) {
+ loading.addClass('fancybox-ie6');
+ wrap.addClass('fancybox-ie6');
+
+ $('<iframe id="fancybox-hide-sel-frame" src="' + (/^https/i.test(window.location.href || '') ? 'javascript:void(false)' : 'about:blank' ) + '" scrolling="no" border="0" frameborder="0" tabindex="-1"></iframe>').prependTo(outer);
+ }
+ };
+
+ $.fn.fancybox.defaults = {
+ padding : 10,
+ margin : 40,
+ opacity : false,
+ modal : false,
+ cyclic : false,
+ scrolling : 'auto', // 'auto', 'yes' or 'no'
+
+ width : 560,
+ height : 340,
+
+ autoScale : true,
+ autoDimensions : true,
+ centerOnScroll : false,
+
+ ajax : {},
+ swf : { wmode: 'transparent' },
+
+ hideOnOverlayClick : true,
+ hideOnContentClick : false,
+
+ overlayShow : true,
+ overlayOpacity : 0.7,
+ overlayColor : '#777',
+
+ titleShow : true,
+ titlePosition : 'float', // 'float', 'outside', 'inside' or 'over'
+ titleFormat : null,
+ titleFromAlt : false,
+
+ transitionIn : 'fade', // 'elastic', 'fade' or 'none'
+ transitionOut : 'fade', // 'elastic', 'fade' or 'none'
+
+ speedIn : 300,
+ speedOut : 300,
+
+ changeSpeed : 300,
+ changeFade : 'fast',
+
+ easingIn : 'swing',
+ easingOut : 'swing',
+
+ showCloseButton : true,
+ showNavArrows : true,
+ enableEscapeButton : true,
+ enableKeyboardNav : true,
+
+ onStart : function(){},
+ onCancel : function(){},
+ onComplete : function(){},
+ onCleanup : function(){},
+ onClosed : function(){},
+ onError : function(){}
+ };
+
+ $(document).ready(function() {
+ $.fancybox.init();
+ });
+
+})(jQuery); \ No newline at end of file
diff --git a/libgpl/fancybox/jquery.fancybox-1.3.4.pack.js b/libgpl/fancybox/jquery.fancybox-1.3.4.pack.js
new file mode 100644
index 0000000..1373ed0
--- /dev/null
+++ b/libgpl/fancybox/jquery.fancybox-1.3.4.pack.js
@@ -0,0 +1,46 @@
+/*
+ * FancyBox - jQuery Plugin
+ * Simple and fancy lightbox alternative
+ *
+ * Examples and documentation at: http://fancybox.net
+ *
+ * Copyright (c) 2008 - 2010 Janis Skarnelis
+ * That said, it is hardly a one-person project. Many people have submitted bugs, code, and offered their advice freely. Their support is greatly appreciated.
+ *
+ * Version: 1.3.4 (11/11/2010)
+ * Requires: jQuery v1.3+
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ */
+
+;(function(b){var m,t,u,f,D,j,E,n,z,A,q=0,e={},o=[],p=0,d={},l=[],G=null,v=new Image,J=/\.(jpg|gif|png|bmp|jpeg)(.*)?$/i,W=/[^\.]\.(swf)\s*$/i,K,L=1,y=0,s="",r,i,h=false,B=b.extend(b("<div/>")[0],{prop:0}),M=b.browser.msie&&b.browser.version<7&&!window.XMLHttpRequest,N=function(){t.hide();v.onerror=v.onload=null;G&&G.abort();m.empty()},O=function(){if(false===e.onError(o,q,e)){t.hide();h=false}else{e.titleShow=false;e.width="auto";e.height="auto";m.html('<p id="fancybox-error">The requested content cannot be loaded.<br />Please try again later.</p>');
+F()}},I=function(){var a=o[q],c,g,k,C,P,w;N();e=b.extend({},b.fn.fancybox.defaults,typeof b(a).data("fancybox")=="undefined"?e:b(a).data("fancybox"));w=e.onStart(o,q,e);if(w===false)h=false;else{if(typeof w=="object")e=b.extend(e,w);k=e.title||(a.nodeName?b(a).attr("title"):a.title)||"";if(a.nodeName&&!e.orig)e.orig=b(a).children("img:first").length?b(a).children("img:first"):b(a);if(k===""&&e.orig&&e.titleFromAlt)k=e.orig.attr("alt");c=e.href||(a.nodeName?b(a).attr("href"):a.href)||null;if(/^(?:javascript)/i.test(c)||
+c=="#")c=null;if(e.type){g=e.type;if(!c)c=e.content}else if(e.content)g="html";else if(c)g=c.match(J)?"image":c.match(W)?"swf":b(a).hasClass("iframe")?"iframe":c.indexOf("#")===0?"inline":"ajax";if(g){if(g=="inline"){a=c.substr(c.indexOf("#"));g=b(a).length>0?"inline":"ajax"}e.type=g;e.href=c;e.title=k;if(e.autoDimensions)if(e.type=="html"||e.type=="inline"||e.type=="ajax"){e.width="auto";e.height="auto"}else e.autoDimensions=false;if(e.modal){e.overlayShow=true;e.hideOnOverlayClick=false;e.hideOnContentClick=
+false;e.enableEscapeButton=false;e.showCloseButton=false}e.padding=parseInt(e.padding,10);e.margin=parseInt(e.margin,10);m.css("padding",e.padding+e.margin);b(".fancybox-inline-tmp").unbind("fancybox-cancel").bind("fancybox-change",function(){b(this).replaceWith(j.children())});switch(g){case "html":m.html(e.content);F();break;case "inline":if(b(a).parent().is("#fancybox-content")===true){h=false;break}b('<div class="fancybox-inline-tmp" />').hide().insertBefore(b(a)).bind("fancybox-cleanup",function(){b(this).replaceWith(j.children())}).bind("fancybox-cancel",
+function(){b(this).replaceWith(m.children())});b(a).appendTo(m);F();break;case "image":h=false;b.fancybox.showActivity();v=new Image;v.onerror=function(){O()};v.onload=function(){h=true;v.onerror=v.onload=null;e.width=v.width;e.height=v.height;b("<img />").attr({id:"fancybox-img",src:v.src,alt:e.title}).appendTo(m);Q()};v.src=c;break;case "swf":e.scrolling="no";C='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="'+e.width+'" height="'+e.height+'"><param name="movie" value="'+c+
+'"></param>';P="";b.each(e.swf,function(x,H){C+='<param name="'+x+'" value="'+H+'"></param>';P+=" "+x+'="'+H+'"'});C+='<embed src="'+c+'" type="application/x-shockwave-flash" width="'+e.width+'" height="'+e.height+'"'+P+"></embed></object>";m.html(C);F();break;case "ajax":h=false;b.fancybox.showActivity();e.ajax.win=e.ajax.success;G=b.ajax(b.extend({},e.ajax,{url:c,data:e.ajax.data||{},error:function(x){x.status>0&&O()},success:function(x,H,R){if((typeof R=="object"?R:G).status==200){if(typeof e.ajax.win==
+"function"){w=e.ajax.win(c,x,H,R);if(w===false){t.hide();return}else if(typeof w=="string"||typeof w=="object")x=w}m.html(x);F()}}}));break;case "iframe":Q()}}else O()}},F=function(){var a=e.width,c=e.height;a=a.toString().indexOf("%")>-1?parseInt((b(window).width()-e.margin*2)*parseFloat(a)/100,10)+"px":a=="auto"?"auto":a+"px";c=c.toString().indexOf("%")>-1?parseInt((b(window).height()-e.margin*2)*parseFloat(c)/100,10)+"px":c=="auto"?"auto":c+"px";m.wrapInner('<div style="width:'+a+";height:"+c+
+";overflow: "+(e.scrolling=="auto"?"auto":e.scrolling=="yes"?"scroll":"hidden")+';position:relative;"></div>');e.width=m.width();e.height=m.height();Q()},Q=function(){var a,c;t.hide();if(f.is(":visible")&&false===d.onCleanup(l,p,d)){b.event.trigger("fancybox-cancel");h=false}else{h=true;b(j.add(u)).unbind();b(window).unbind("resize.fb scroll.fb");b(document).unbind("keydown.fb");f.is(":visible")&&d.titlePosition!=="outside"&&f.css("height",f.height());l=o;p=q;d=e;if(d.overlayShow){u.css({"background-color":d.overlayColor,
+opacity:d.overlayOpacity,cursor:d.hideOnOverlayClick?"pointer":"auto",height:b(document).height()});if(!u.is(":visible")){M&&b("select:not(#fancybox-tmp select)").filter(function(){return this.style.visibility!=="hidden"}).css({visibility:"hidden"}).one("fancybox-cleanup",function(){this.style.visibility="inherit"});u.show()}}else u.hide();i=X();s=d.title||"";y=0;n.empty().removeAttr("style").removeClass();if(d.titleShow!==false){if(b.isFunction(d.titleFormat))a=d.titleFormat(s,l,p,d);else a=s&&s.length?
+d.titlePosition=="float"?'<table id="fancybox-title-float-wrap" cellpadding="0" cellspacing="0"><tr><td id="fancybox-title-float-left"></td><td id="fancybox-title-float-main">'+s+'</td><td id="fancybox-title-float-right"></td></tr></table>':'<div id="fancybox-title-'+d.titlePosition+'">'+s+"</div>":false;s=a;if(!(!s||s==="")){n.addClass("fancybox-title-"+d.titlePosition).html(s).appendTo("body").show();switch(d.titlePosition){case "inside":n.css({width:i.width-d.padding*2,marginLeft:d.padding,marginRight:d.padding});
+y=n.outerHeight(true);n.appendTo(D);i.height+=y;break;case "over":n.css({marginLeft:d.padding,width:i.width-d.padding*2,bottom:d.padding}).appendTo(D);break;case "float":n.css("left",parseInt((n.width()-i.width-40)/2,10)*-1).appendTo(f);break;default:n.css({width:i.width-d.padding*2,paddingLeft:d.padding,paddingRight:d.padding}).appendTo(f)}}}n.hide();if(f.is(":visible")){b(E.add(z).add(A)).hide();a=f.position();r={top:a.top,left:a.left,width:f.width(),height:f.height()};c=r.width==i.width&&r.height==
+i.height;j.fadeTo(d.changeFade,0.3,function(){var g=function(){j.html(m.contents()).fadeTo(d.changeFade,1,S)};b.event.trigger("fancybox-change");j.empty().removeAttr("filter").css({"border-width":d.padding,width:i.width-d.padding*2,height:e.autoDimensions?"auto":i.height-y-d.padding*2});if(c)g();else{B.prop=0;b(B).animate({prop:1},{duration:d.changeSpeed,easing:d.easingChange,step:T,complete:g})}})}else{f.removeAttr("style");j.css("border-width",d.padding);if(d.transitionIn=="elastic"){r=V();j.html(m.contents());
+f.show();if(d.opacity)i.opacity=0;B.prop=0;b(B).animate({prop:1},{duration:d.speedIn,easing:d.easingIn,step:T,complete:S})}else{d.titlePosition=="inside"&&y>0&&n.show();j.css({width:i.width-d.padding*2,height:e.autoDimensions?"auto":i.height-y-d.padding*2}).html(m.contents());f.css(i).fadeIn(d.transitionIn=="none"?0:d.speedIn,S)}}}},Y=function(){if(d.enableEscapeButton||d.enableKeyboardNav)b(document).bind("keydown.fb",function(a){if(a.keyCode==27&&d.enableEscapeButton){a.preventDefault();b.fancybox.close()}else if((a.keyCode==
+37||a.keyCode==39)&&d.enableKeyboardNav&&a.target.tagName!=="INPUT"&&a.target.tagName!=="TEXTAREA"&&a.target.tagName!=="SELECT"){a.preventDefault();b.fancybox[a.keyCode==37?"prev":"next"]()}});if(d.showNavArrows){if(d.cyclic&&l.length>1||p!==0)z.show();if(d.cyclic&&l.length>1||p!=l.length-1)A.show()}else{z.hide();A.hide()}},S=function(){if(!b.support.opacity){j.get(0).style.removeAttribute("filter");f.get(0).style.removeAttribute("filter")}e.autoDimensions&&j.css("height","auto");f.css("height","auto");
+s&&s.length&&n.show();d.showCloseButton&&E.show();Y();d.hideOnContentClick&&j.bind("click",b.fancybox.close);d.hideOnOverlayClick&&u.bind("click",b.fancybox.close);b(window).bind("resize.fb",b.fancybox.resize);d.centerOnScroll&&b(window).bind("scroll.fb",b.fancybox.center);if(d.type=="iframe")b('<iframe id="fancybox-frame" name="fancybox-frame'+(new Date).getTime()+'" frameborder="0" hspace="0" '+(b.browser.msie?'allowtransparency="true""':"")+' scrolling="'+e.scrolling+'" src="'+d.href+'"></iframe>').appendTo(j);
+f.show();h=false;b.fancybox.center();d.onComplete(l,p,d);var a,c;if(l.length-1>p){a=l[p+1].href;if(typeof a!=="undefined"&&a.match(J)){c=new Image;c.src=a}}if(p>0){a=l[p-1].href;if(typeof a!=="undefined"&&a.match(J)){c=new Image;c.src=a}}},T=function(a){var c={width:parseInt(r.width+(i.width-r.width)*a,10),height:parseInt(r.height+(i.height-r.height)*a,10),top:parseInt(r.top+(i.top-r.top)*a,10),left:parseInt(r.left+(i.left-r.left)*a,10)};if(typeof i.opacity!=="undefined")c.opacity=a<0.5?0.5:a;f.css(c);
+j.css({width:c.width-d.padding*2,height:c.height-y*a-d.padding*2})},U=function(){return[b(window).width()-d.margin*2,b(window).height()-d.margin*2,b(document).scrollLeft()+d.margin,b(document).scrollTop()+d.margin]},X=function(){var a=U(),c={},g=d.autoScale,k=d.padding*2;c.width=d.width.toString().indexOf("%")>-1?parseInt(a[0]*parseFloat(d.width)/100,10):d.width+k;c.height=d.height.toString().indexOf("%")>-1?parseInt(a[1]*parseFloat(d.height)/100,10):d.height+k;if(g&&(c.width>a[0]||c.height>a[1]))if(e.type==
+"image"||e.type=="swf"){g=d.width/d.height;if(c.width>a[0]){c.width=a[0];c.height=parseInt((c.width-k)/g+k,10)}if(c.height>a[1]){c.height=a[1];c.width=parseInt((c.height-k)*g+k,10)}}else{c.width=Math.min(c.width,a[0]);c.height=Math.min(c.height,a[1])}c.top=parseInt(Math.max(a[3]-20,a[3]+(a[1]-c.height-40)*0.5),10);c.left=parseInt(Math.max(a[2]-20,a[2]+(a[0]-c.width-40)*0.5),10);return c},V=function(){var a=e.orig?b(e.orig):false,c={};if(a&&a.length){c=a.offset();c.top+=parseInt(a.css("paddingTop"),
+10)||0;c.left+=parseInt(a.css("paddingLeft"),10)||0;c.top+=parseInt(a.css("border-top-width"),10)||0;c.left+=parseInt(a.css("border-left-width"),10)||0;c.width=a.width();c.height=a.height();c={width:c.width+d.padding*2,height:c.height+d.padding*2,top:c.top-d.padding-20,left:c.left-d.padding-20}}else{a=U();c={width:d.padding*2,height:d.padding*2,top:parseInt(a[3]+a[1]*0.5,10),left:parseInt(a[2]+a[0]*0.5,10)}}return c},Z=function(){if(t.is(":visible")){b("div",t).css("top",L*-40+"px");L=(L+1)%12}else clearInterval(K)};
+b.fn.fancybox=function(a){if(!b(this).length)return this;b(this).data("fancybox",b.extend({},a,b.metadata?b(this).metadata():{})).unbind("click.fb").bind("click.fb",function(c){c.preventDefault();if(!h){h=true;b(this).blur();o=[];q=0;c=b(this).attr("rel")||"";if(!c||c==""||c==="nofollow")o.push(this);else{o=b("a[rel="+c+"], area[rel="+c+"]");q=o.index(this)}I()}});return this};b.fancybox=function(a,c){var g;if(!h){h=true;g=typeof c!=="undefined"?c:{};o=[];q=parseInt(g.index,10)||0;if(b.isArray(a)){for(var k=
+0,C=a.length;k<C;k++)if(typeof a[k]=="object")b(a[k]).data("fancybox",b.extend({},g,a[k]));else a[k]=b({}).data("fancybox",b.extend({content:a[k]},g));o=jQuery.merge(o,a)}else{if(typeof a=="object")b(a).data("fancybox",b.extend({},g,a));else a=b({}).data("fancybox",b.extend({content:a},g));o.push(a)}if(q>o.length||q<0)q=0;I()}};b.fancybox.showActivity=function(){clearInterval(K);t.show();K=setInterval(Z,66)};b.fancybox.hideActivity=function(){t.hide()};b.fancybox.next=function(){return b.fancybox.pos(p+
+1)};b.fancybox.prev=function(){return b.fancybox.pos(p-1)};b.fancybox.pos=function(a){if(!h){a=parseInt(a);o=l;if(a>-1&&a<l.length){q=a;I()}else if(d.cyclic&&l.length>1){q=a>=l.length?0:l.length-1;I()}}};b.fancybox.cancel=function(){if(!h){h=true;b.event.trigger("fancybox-cancel");N();e.onCancel(o,q,e);h=false}};b.fancybox.close=function(){function a(){u.fadeOut("fast");n.empty().hide();f.hide();b.event.trigger("fancybox-cleanup");j.empty();d.onClosed(l,p,d);l=e=[];p=q=0;d=e={};h=false}if(!(h||f.is(":hidden"))){h=
+true;if(d&&false===d.onCleanup(l,p,d))h=false;else{N();b(E.add(z).add(A)).hide();b(j.add(u)).unbind();b(window).unbind("resize.fb scroll.fb");b(document).unbind("keydown.fb");j.find("iframe").attr("src",M&&/^https/i.test(window.location.href||"")?"javascript:void(false)":"about:blank");d.titlePosition!=="inside"&&n.empty();f.stop();if(d.transitionOut=="elastic"){r=V();var c=f.position();i={top:c.top,left:c.left,width:f.width(),height:f.height()};if(d.opacity)i.opacity=1;n.empty().hide();B.prop=1;
+b(B).animate({prop:0},{duration:d.speedOut,easing:d.easingOut,step:T,complete:a})}else f.fadeOut(d.transitionOut=="none"?0:d.speedOut,a)}}};b.fancybox.resize=function(){u.is(":visible")&&u.css("height",b(document).height());b.fancybox.center(true)};b.fancybox.center=function(a){var c,g;if(!h){g=a===true?1:0;c=U();!g&&(f.width()>c[0]||f.height()>c[1])||f.stop().animate({top:parseInt(Math.max(c[3]-20,c[3]+(c[1]-j.height()-40)*0.5-d.padding)),left:parseInt(Math.max(c[2]-20,c[2]+(c[0]-j.width()-40)*0.5-
+d.padding))},typeof a=="number"?a:200)}};b.fancybox.init=function(){if(!b("#fancybox-wrap").length){b("body").append(m=b('<div id="fancybox-tmp"></div>'),t=b('<div id="fancybox-loading"><div></div></div>'),u=b('<div id="fancybox-overlay"></div>'),f=b('<div id="fancybox-wrap"></div>'));D=b('<div id="fancybox-outer"></div>').append('<div class="fancybox-bg" id="fancybox-bg-n"></div><div class="fancybox-bg" id="fancybox-bg-ne"></div><div class="fancybox-bg" id="fancybox-bg-e"></div><div class="fancybox-bg" id="fancybox-bg-se"></div><div class="fancybox-bg" id="fancybox-bg-s"></div><div class="fancybox-bg" id="fancybox-bg-sw"></div><div class="fancybox-bg" id="fancybox-bg-w"></div><div class="fancybox-bg" id="fancybox-bg-nw"></div>').appendTo(f);
+D.append(j=b('<div id="fancybox-content"></div>'),E=b('<a id="fancybox-close"></a>'),n=b('<div id="fancybox-title"></div>'),z=b('<a href="javascript:;" id="fancybox-left"><span class="fancy-ico" id="fancybox-left-ico"></span></a>'),A=b('<a href="javascript:;" id="fancybox-right"><span class="fancy-ico" id="fancybox-right-ico"></span></a>'));E.click(b.fancybox.close);t.click(b.fancybox.cancel);z.click(function(a){a.preventDefault();b.fancybox.prev()});A.click(function(a){a.preventDefault();b.fancybox.next()});
+b.fn.mousewheel&&f.bind("mousewheel.fb",function(a,c){if(h)a.preventDefault();else if(b(a.target).get(0).clientHeight==0||b(a.target).get(0).scrollHeight===b(a.target).get(0).clientHeight){a.preventDefault();b.fancybox[c>0?"prev":"next"]()}});b.support.opacity||f.addClass("fancybox-ie");if(M){t.addClass("fancybox-ie6");f.addClass("fancybox-ie6");b('<iframe id="fancybox-hide-sel-frame" src="'+(/^https/i.test(window.location.href||"")?"javascript:void(false)":"about:blank")+'" scrolling="no" border="0" frameborder="0" tabindex="-1"></iframe>').prependTo(D)}}};
+b.fn.fancybox.defaults={padding:10,margin:40,opacity:false,modal:false,cyclic:false,scrolling:"auto",width:560,height:340,autoScale:true,autoDimensions:true,centerOnScroll:false,ajax:{},swf:{wmode:"transparent"},hideOnOverlayClick:true,hideOnContentClick:false,overlayShow:true,overlayOpacity:0.7,overlayColor:"#777",titleShow:true,titlePosition:"float",titleFormat:null,titleFromAlt:false,transitionIn:"fade",transitionOut:"fade",speedIn:300,speedOut:300,changeSpeed:300,changeFade:"fast",easingIn:"swing",
+easingOut:"swing",showCloseButton:true,showNavArrows:true,enableEscapeButton:true,enableKeyboardNav:true,onStart:function(){},onCancel:function(){},onComplete:function(){},onCleanup:function(){},onClosed:function(){},onError:function(){}};b(document).ready(function(){b.fancybox.init()})})(jQuery); \ No newline at end of file
diff --git a/libgpl/fancybox/jquery.mousewheel-3.0.4.pack.js b/libgpl/fancybox/jquery.mousewheel-3.0.4.pack.js
new file mode 100644
index 0000000..cb66588
--- /dev/null
+++ b/libgpl/fancybox/jquery.mousewheel-3.0.4.pack.js
@@ -0,0 +1,14 @@
+/*! Copyright (c) 2010 Brandon Aaron (http://brandonaaron.net)
+* Licensed under the MIT License (LICENSE.txt).
+*
+* Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
+* Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
+* Thanks to: Seamus Leahy for adding deltaX and deltaY
+*
+* Version: 3.0.4
+*
+* Requires: 1.2.2+
+*/
+
+(function(d){function g(a){var b=a||window.event,i=[].slice.call(arguments,1),c=0,h=0,e=0;a=d.event.fix(b);a.type="mousewheel";if(a.wheelDelta)c=a.wheelDelta/120;if(a.detail)c=-a.detail/3;e=c;if(b.axis!==undefined&&b.axis===b.HORIZONTAL_AXIS){e=0;h=-1*c}if(b.wheelDeltaY!==undefined)e=b.wheelDeltaY/120;if(b.wheelDeltaX!==undefined)h=-1*b.wheelDeltaX/120;i.unshift(a,c,h,e);return d.event.handle.apply(this,i)}var f=["DOMMouseScroll","mousewheel"];d.event.special.mousewheel={setup:function(){if(this.addEventListener)for(var a=
+f.length;a;)this.addEventListener(f[--a],g,false);else this.onmousewheel=g},teardown:function(){if(this.removeEventListener)for(var a=f.length;a;)this.removeEventListener(f[--a],g,false);else this.onmousewheel=null}};d.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}})})(jQuery); \ No newline at end of file
diff --git a/libgpl/flashclipboard/clipboard.swf b/libgpl/flashclipboard/clipboard.swf
new file mode 100644
index 0000000..13bf8e3
--- /dev/null
+++ b/libgpl/flashclipboard/clipboard.swf
Binary files differ
diff --git a/libgpl/flashclipboard/flashclipboard_libgpl.js b/libgpl/flashclipboard/flashclipboard_libgpl.js
new file mode 100644
index 0000000..cdbb2ed
--- /dev/null
+++ b/libgpl/flashclipboard/flashclipboard_libgpl.js
@@ -0,0 +1,309 @@
+$(window).load(function(){
+ $(function() {
+ $(".zclip").each(function() {
+ //Create a new clipboard client
+ var clip = new ZeroClipboard.Client();
+
+ clip.glue($(this).get(0));
+
+ var txt = $(this).prev().val();
+ clip.setText(txt);
+
+ clip.addEventListener('complete', function(client, text) {
+ $('#zclipdialog').html(txt);
+ $('#zclipdialog').dialog({ height : 110, width : 'auto' });
+ });
+ });
+ });
+});
+
+// Simple Set Clipboard System
+// Author: Joseph Huckaby
+
+var ZeroClipboard = {
+
+ version: "1.0.4",
+ clients: {}, // registered upload clients on page, indexed by id
+ moviePath: 'plugins/libgpl/flashclipboard/clipboard.swf', // URL to movie
+ nextId: 1, // ID of next movie
+
+ $: function(thingy) {
+ // simple DOM lookup utility function
+ if (typeof(thingy) == 'string') thingy = document.getElementById(thingy);
+ if (!thingy.addClass) {
+ // extend element with a few useful methods
+ thingy.hide = function() { this.style.display = 'none'; };
+ thingy.show = function() { this.style.display = ''; };
+ thingy.addClass = function(name) { this.removeClass(name); this.className += ' ' + name; };
+ thingy.removeClass = function(name) {
+ this.className = this.className.replace( new RegExp("\\s*" + name + "\\s*"), " ").replace(/^\s+/, '').replace(/\s+$/, '');
+ };
+ thingy.hasClass = function(name) {
+ return !!this.className.match( new RegExp("\\s*" + name + "\\s*") );
+ }
+ }
+ return thingy;
+ },
+
+ setMoviePath: function(path) {
+ // set path to ZeroClipboard.swf
+ this.moviePath = path;
+ },
+
+ dispatch: function(id, eventName, args) {
+ // receive event from flash movie, send to client
+ var client = this.clients[id];
+ if (client) {
+ client.receiveEvent(eventName, args);
+ }
+ },
+
+ register: function(id, client) {
+ // register new client to receive events
+ this.clients[id] = client;
+ },
+
+ getDOMObjectPosition: function(obj) {
+ // get absolute coordinates for dom element
+ var info = {
+ left: 0,
+ top: 0,
+ width: obj.width ? obj.width : obj.offsetWidth,
+ height: obj.height ? obj.height : obj.offsetHeight
+ };
+
+ while (obj) {
+ info.left += obj.offsetLeft;
+ info.top += obj.offsetTop;
+ obj = obj.offsetParent;
+ }
+
+ return info;
+ },
+
+ Client: function(elem) {
+ // constructor for new simple upload client
+ this.handlers = {};
+
+ // unique ID
+ this.id = ZeroClipboard.nextId++;
+ this.movieId = 'ZeroClipboardMovie_' + this.id;
+
+ // register client with singleton to receive flash events
+ ZeroClipboard.register(this.id, this);
+
+ // create movie
+ if (elem) this.glue(elem);
+ }
+};
+
+ZeroClipboard.Client.prototype = {
+
+ id: 0, // unique ID for us
+ ready: false, // whether movie is ready to receive events or not
+ movie: null, // reference to movie object
+ clipText: '', // text to copy to clipboard
+ handCursorEnabled: true, // whether to show hand cursor, or default pointer cursor
+ cssEffects: true, // enable CSS mouse effects on dom container
+ handlers: null, // user event handlers
+
+ glue: function(elem) {
+ // glue to DOM element
+ // elem can be ID or actual DOM element object
+ this.domElement = ZeroClipboard.$(elem);
+
+ // float just above object, or zIndex 99 if dom element isn't set
+ var zIndex = 99;
+ if (this.domElement.style.zIndex) {
+ zIndex = parseInt(this.domElement.style.zIndex) + 1;
+ }
+
+ // find X/Y position of domElement
+ var box = ZeroClipboard.getDOMObjectPosition(this.domElement);
+
+ // create floating DIV above element
+ this.div = document.createElement('div');
+ var style = this.div.style;
+ style.position = 'absolute';
+ style.left = '' + box.left + 'px';
+ style.top = '' + box.top + 'px';
+ style.width = '' + box.width + 'px';
+ style.height = '' + box.height + 'px';
+ style.zIndex = zIndex;
+
+ // style.backgroundColor = '#f00'; // debug
+
+ var body = document.getElementsByTagName('body')[0];
+ body.appendChild(this.div);
+
+ this.div.innerHTML = this.getHTML( box.width, box.height );
+ },
+
+ getHTML: function(width, height) {
+ // return HTML for movie
+ var html = '';
+ var flashvars = 'id=' + this.id +
+ '&width=' + width +
+ '&height=' + height;
+
+ if (navigator.userAgent.match(/MSIE/)) {
+ // IE gets an OBJECT tag
+ var protocol = location.href.match(/^https/i) ? 'https://' : 'http://';
+ html += '<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="'+protocol+'download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" width="'+width+'" height="'+height+'" id="'+this.movieId+'" align="middle"><param name="allowScriptAccess" value="always" /><param name="allowFullScreen" value="false" /><param name="movie" value="'+ZeroClipboard.moviePath+'" /><param name="loop" value="false" /><param name="menu" value="false" /><param name="quality" value="best" /><param name="bgcolor" value="#ffffff" /><param name="flashvars" value="'+flashvars+'"/><param name="wmode" value="transparent"/></object>';
+ }
+ else {
+ // all other browsers get an EMBED tag
+ html += '<embed id="'+this.movieId+'" src="'+ZeroClipboard.moviePath+'" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="'+width+'" height="'+height+'" name="'+this.movieId+'" align="middle" allowScriptAccess="always" allowFullScreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="'+flashvars+'" wmode="transparent" />';
+ }
+ return html;
+ },
+
+ hide: function() {
+ // temporarily hide floater offscreen
+ if (this.div) {
+ this.div.style.left = '-2000px';
+ }
+ },
+
+ show: function() {
+ // show ourselves after a call to hide()
+ this.reposition();
+ },
+
+ destroy: function() {
+ // destroy control and floater
+ if (this.domElement && this.div) {
+ this.hide();
+ this.div.innerHTML = '';
+
+ var body = document.getElementsByTagName('body')[0];
+ try { body.removeChild( this.div ); } catch(e) {;}
+
+ this.domElement = null;
+ this.div = null;
+ }
+ },
+
+ reposition: function(elem) {
+ // reposition our floating div, optionally to new container
+ // warning: container CANNOT change size, only position
+ if (elem) {
+ this.domElement = ZeroClipboard.$(elem);
+ if (!this.domElement) this.hide();
+ }
+
+ if (this.domElement && this.div) {
+ var box = ZeroClipboard.getDOMObjectPosition(this.domElement);
+ var style = this.div.style;
+ style.left = '' + box.left + 'px';
+ style.top = '' + box.top + 'px';
+ }
+ },
+
+ setText: function(newText) {
+ // set text to be copied to clipboard
+ this.clipText = newText;
+ if (this.ready) this.movie.setText(newText);
+ },
+
+ addEventListener: function(eventName, func) {
+ // add user event listener for event
+ // event types: load, queueStart, fileStart, fileComplete, queueComplete, progress, error, cancel
+ eventName = eventName.toString().toLowerCase().replace(/^on/, '');
+ if (!this.handlers[eventName]) this.handlers[eventName] = [];
+ this.handlers[eventName].push(func);
+ },
+
+ setHandCursor: function(enabled) {
+ // enable hand cursor (true), or default arrow cursor (false)
+ this.handCursorEnabled = enabled;
+ if (this.ready) this.movie.setHandCursor(enabled);
+ },
+
+ setCSSEffects: function(enabled) {
+ // enable or disable CSS effects on DOM container
+ this.cssEffects = !!enabled;
+ },
+
+ receiveEvent: function(eventName, args) {
+ // receive event from flash
+ eventName = eventName.toString().toLowerCase().replace(/^on/, '');
+
+ // special behavior for certain events
+ switch (eventName) {
+ case 'load':
+ // movie claims it is ready, but in IE this isn't always the case...
+ // bug fix: Cannot extend EMBED DOM elements in Firefox, must use traditional function
+ this.movie = document.getElementById(this.movieId);
+ if (!this.movie) {
+ var self = this;
+ setTimeout( function() { self.receiveEvent('load', null); }, 1 );
+ return;
+ }
+
+ // firefox on pc needs a "kick" in order to set these in certain cases
+ if (!this.ready && navigator.userAgent.match(/Firefox/) && navigator.userAgent.match(/Windows/)) {
+ var self = this;
+ setTimeout( function() { self.receiveEvent('load', null); }, 100 );
+ this.ready = true;
+ return;
+ }
+
+ this.ready = true;
+ this.movie.setText( this.clipText );
+ this.movie.setHandCursor( this.handCursorEnabled );
+ break;
+
+ case 'mouseover':
+ if (this.domElement && this.cssEffects) {
+ this.domElement.addClass('hover');
+ if (this.recoverActive) this.domElement.addClass('active');
+ }
+ break;
+
+ case 'mouseout':
+ if (this.domElement && this.cssEffects) {
+ this.recoverActive = false;
+ if (this.domElement.hasClass('active')) {
+ this.domElement.removeClass('active');
+ this.recoverActive = true;
+ }
+ this.domElement.removeClass('hover');
+ }
+ break;
+
+ case 'mousedown':
+ if (this.domElement && this.cssEffects) {
+ this.domElement.addClass('active');
+ }
+ break;
+
+ case 'mouseup':
+ if (this.domElement && this.cssEffects) {
+ this.domElement.removeClass('active');
+ this.recoverActive = false;
+ }
+ break;
+ } // switch eventName
+
+ if (this.handlers[eventName]) {
+ for (var idx = 0, len = this.handlers[eventName].length; idx < len; idx++) {
+ var func = this.handlers[eventName][idx];
+
+ if (typeof(func) == 'function') {
+ // actual function reference
+ func(this, args);
+ }
+ else if ((typeof(func) == 'object') && (func.length == 2)) {
+ // PHP style object + method, i.e. [myObject, 'myMethod']
+ func[0][ func[1] ](this, args);
+ }
+ else if (typeof(func) == 'string') {
+ // name of function
+ window[func](this, args);
+ }
+ } // foreach event handler defined
+ } // user defined handler for event
+ }
+
+};
diff --git a/libgpl/flashclipboard/flashclipboard_moreuserinfo.js b/libgpl/flashclipboard/flashclipboard_moreuserinfo.js
new file mode 100644
index 0000000..46042c1
--- /dev/null
+++ b/libgpl/flashclipboard/flashclipboard_moreuserinfo.js
@@ -0,0 +1,290 @@
+// Simple Set Clipboard System
+// Author: Joseph Huckaby
+
+var ZeroClipboard = {
+
+ version: "1.0.4",
+ clients: {}, // registered upload clients on page, indexed by id
+ moviePath: 'plugins/libgpl/flashclipboard/clipboard.swf', // URL to movie
+ nextId: 1, // ID of next movie
+
+ $: function(thingy) {
+ // simple DOM lookup utility function
+ if (typeof(thingy) == 'string') thingy = document.getElementById(thingy);
+ if (!thingy.addClass) {
+ // extend element with a few useful methods
+ thingy.hide = function() { this.style.display = 'none'; };
+ thingy.show = function() { this.style.display = ''; };
+ thingy.addClass = function(name) { this.removeClass(name); this.className += ' ' + name; };
+ thingy.removeClass = function(name) {
+ this.className = this.className.replace( new RegExp("\\s*" + name + "\\s*"), " ").replace(/^\s+/, '').replace(/\s+$/, '');
+ };
+ thingy.hasClass = function(name) {
+ return !!this.className.match( new RegExp("\\s*" + name + "\\s*") );
+ }
+ }
+ return thingy;
+ },
+
+ setMoviePath: function(path) {
+ // set path to ZeroClipboard.swf
+ this.moviePath = path;
+ },
+
+ dispatch: function(id, eventName, args) {
+ // receive event from flash movie, send to client
+ var client = this.clients[id];
+ if (client) {
+ client.receiveEvent(eventName, args);
+ }
+ },
+
+ register: function(id, client) {
+ // register new client to receive events
+ this.clients[id] = client;
+ },
+
+ getDOMObjectPosition: function(obj) {
+ // get absolute coordinates for dom element
+ var info = {
+ left: 0,
+ top: 0,
+ width: obj.width ? obj.width : obj.offsetWidth,
+ height: obj.height ? obj.height : obj.offsetHeight
+ };
+
+ while (obj) {
+ info.left += obj.offsetLeft;
+ info.top += obj.offsetTop;
+ obj = obj.offsetParent;
+ }
+
+ return info;
+ },
+
+ Client: function(elem) {
+ // constructor for new simple upload client
+ this.handlers = {};
+
+ // unique ID
+ this.id = ZeroClipboard.nextId++;
+ this.movieId = 'ZeroClipboardMovie_' + this.id;
+
+ // register client with singleton to receive flash events
+ ZeroClipboard.register(this.id, this);
+
+ // create movie
+ if (elem) this.glue(elem);
+ }
+};
+
+ZeroClipboard.Client.prototype = {
+
+ id: 0, // unique ID for us
+ ready: false, // whether movie is ready to receive events or not
+ movie: null, // reference to movie object
+ clipText: '', // text to copy to clipboard
+ handCursorEnabled: true, // whether to show hand cursor, or default pointer cursor
+ cssEffects: true, // enable CSS mouse effects on dom container
+ handlers: null, // user event handlers
+
+ glue: function(elem) {
+ // glue to DOM element
+ // elem can be ID or actual DOM element object
+ this.domElement = ZeroClipboard.$(elem);
+
+ // float just above object, or zIndex 99 if dom element isn't set
+ var zIndex = 99;
+ if (this.domElement.style.zIndex) {
+ zIndex = parseInt(this.domElement.style.zIndex) + 1;
+ }
+
+ // find X/Y position of domElement
+ var box = ZeroClipboard.getDOMObjectPosition(this.domElement);
+
+ // create floating DIV above element
+ this.div = document.createElement('div');
+ var style = this.div.style;
+ style.position = 'absolute';
+ style.left = '' + box.left + 'px';
+ style.top = '' + box.top + 'px';
+ style.width = '' + box.width + 'px';
+ style.height = '' + box.height + 'px';
+ style.zIndex = zIndex;
+
+ // style.backgroundColor = '#f00'; // debug
+
+ var body = document.getElementsByTagName('body')[0];
+ body.appendChild(this.div);
+
+ this.div.innerHTML = this.getHTML( box.width, box.height );
+ },
+
+ getHTML: function(width, height) {
+ // return HTML for movie
+ var html = '';
+ var flashvars = 'id=' + this.id +
+ '&width=' + width +
+ '&height=' + height;
+
+ if (navigator.userAgent.match(/MSIE/)) {
+ // IE gets an OBJECT tag
+ var protocol = location.href.match(/^https/i) ? 'https://' : 'http://';
+ html += '<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="'+protocol+'download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" width="'+width+'" height="'+height+'" id="'+this.movieId+'" align="middle"><param name="allowScriptAccess" value="always" /><param name="allowFullScreen" value="false" /><param name="movie" value="'+ZeroClipboard.moviePath+'" /><param name="loop" value="false" /><param name="menu" value="false" /><param name="quality" value="best" /><param name="bgcolor" value="#ffffff" /><param name="flashvars" value="'+flashvars+'"/><param name="wmode" value="transparent"/></object>';
+ }
+ else {
+ // all other browsers get an EMBED tag
+ html += '<embed id="'+this.movieId+'" src="'+ZeroClipboard.moviePath+'" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="'+width+'" height="'+height+'" name="'+this.movieId+'" align="middle" allowScriptAccess="always" allowFullScreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="'+flashvars+'" wmode="transparent" />';
+ }
+ return html;
+ },
+
+ hide: function() {
+ // temporarily hide floater offscreen
+ if (this.div) {
+ this.div.style.left = '-2000px';
+ }
+ },
+
+ show: function() {
+ // show ourselves after a call to hide()
+ this.reposition();
+ },
+
+ destroy: function() {
+ // destroy control and floater
+ if (this.domElement && this.div) {
+ this.hide();
+ this.div.innerHTML = '';
+
+ var body = document.getElementsByTagName('body')[0];
+ try { body.removeChild( this.div ); } catch(e) {;}
+
+ this.domElement = null;
+ this.div = null;
+ }
+ },
+
+ reposition: function(elem) {
+ // reposition our floating div, optionally to new container
+ // warning: container CANNOT change size, only position
+ if (elem) {
+ this.domElement = ZeroClipboard.$(elem);
+ if (!this.domElement) this.hide();
+ }
+
+ if (this.domElement && this.div) {
+ var box = ZeroClipboard.getDOMObjectPosition(this.domElement);
+ var style = this.div.style;
+ style.left = '' + box.left + 'px';
+ style.top = '' + box.top + 'px';
+ }
+ },
+
+ setText: function(newText) {
+ // set text to be copied to clipboard
+ this.clipText = newText;
+ if (this.ready) this.movie.setText(newText);
+ },
+
+ addEventListener: function(eventName, func) {
+ // add user event listener for event
+ // event types: load, queueStart, fileStart, fileComplete, queueComplete, progress, error, cancel
+ eventName = eventName.toString().toLowerCase().replace(/^on/, '');
+ if (!this.handlers[eventName]) this.handlers[eventName] = [];
+ this.handlers[eventName].push(func);
+ },
+
+ setHandCursor: function(enabled) {
+ // enable hand cursor (true), or default arrow cursor (false)
+ this.handCursorEnabled = enabled;
+ if (this.ready) this.movie.setHandCursor(enabled);
+ },
+
+ setCSSEffects: function(enabled) {
+ // enable or disable CSS effects on DOM container
+ this.cssEffects = !!enabled;
+ },
+
+ receiveEvent: function(eventName, args) {
+ // receive event from flash
+ eventName = eventName.toString().toLowerCase().replace(/^on/, '');
+
+ // special behavior for certain events
+ switch (eventName) {
+ case 'load':
+ // movie claims it is ready, but in IE this isn't always the case...
+ // bug fix: Cannot extend EMBED DOM elements in Firefox, must use traditional function
+ this.movie = document.getElementById(this.movieId);
+ if (!this.movie) {
+ var self = this;
+ setTimeout( function() { self.receiveEvent('load', null); }, 1 );
+ return;
+ }
+
+ // firefox on pc needs a "kick" in order to set these in certain cases
+ if (!this.ready && navigator.userAgent.match(/Firefox/) && navigator.userAgent.match(/Windows/)) {
+ var self = this;
+ setTimeout( function() { self.receiveEvent('load', null); }, 100 );
+ this.ready = true;
+ return;
+ }
+
+ this.ready = true;
+ this.movie.setText( this.clipText );
+ this.movie.setHandCursor( this.handCursorEnabled );
+ break;
+
+ case 'mouseover':
+ if (this.domElement && this.cssEffects) {
+ this.domElement.addClass('hover');
+ if (this.recoverActive) this.domElement.addClass('active');
+ }
+ break;
+
+ case 'mouseout':
+ if (this.domElement && this.cssEffects) {
+ this.recoverActive = false;
+ if (this.domElement.hasClass('active')) {
+ this.domElement.removeClass('active');
+ this.recoverActive = true;
+ }
+ this.domElement.removeClass('hover');
+ }
+ break;
+
+ case 'mousedown':
+ if (this.domElement && this.cssEffects) {
+ this.domElement.addClass('active');
+ }
+ break;
+
+ case 'mouseup':
+ if (this.domElement && this.cssEffects) {
+ this.domElement.removeClass('active');
+ this.recoverActive = false;
+ }
+ break;
+ } // switch eventName
+
+ if (this.handlers[eventName]) {
+ for (var idx = 0, len = this.handlers[eventName].length; idx < len; idx++) {
+ var func = this.handlers[eventName][idx];
+
+ if (typeof(func) == 'function') {
+ // actual function reference
+ func(this, args);
+ }
+ else if ((typeof(func) == 'object') && (func.length == 2)) {
+ // PHP style object + method, i.e. [myObject, 'myMethod']
+ func[0][ func[1] ](this, args);
+ }
+ else if (typeof(func) == 'string') {
+ // name of function
+ window[func](this, args);
+ }
+ } // foreach event handler defined
+ } // user defined handler for event
+ }
+
+};
diff --git a/libgpl/gibberish/GibberishAES.php b/libgpl/gibberish/GibberishAES.php
new file mode 100644
index 0000000..8ce069a
--- /dev/null
+++ b/libgpl/gibberish/GibberishAES.php
@@ -0,0 +1,213 @@
+<?php
+
+/**
+ * Gibberish AES, a PHP Implementation
+ *
+ * @author Ivan Tcholakov <ivantcholakov@gmail.com>, 2012-2013.
+ * @link https://github.com/ivantcholakov/gibberish-aes-php
+ *
+ * @license The MIT License (MIT)
+ * @link http://opensource.org/licenses/MIT
+ *
+ * This class is based on initial code proposed by nbari at dalmp dot com
+ * @link http://www.php.net/manual/en/function.openssl-decrypt.php#107210
+ *
+ * See also Gibberish AES javascript encryption library
+ * @link https://github.com/mdp/gibberish-aes
+ *
+ * Requirements:
+ *
+ * OpenSSL functions installed and PHP version >= 5.3.3 (preferred case)
+ * or
+ * Mcrypt functions installed.
+ *
+ * Usage:
+ *
+ * // This is a secret key, keep it in a safe place and don't loose it.
+ * $key = 'my secret key';
+ *
+ * // The string to be encrypted.
+ * $string = 'my secret message';
+ *
+ * // This is the result after encryption of the given string.
+ * $encrypted_string = GibberishAES::enc($string, $key);
+ *
+ * // This is the result after decryption of the previously encrypted string.
+ * // $decrypted_string == $string (should be).
+ * $decrypted_string = GibberishAES::dec($encrypted_string, $key);
+ *
+ */
+
+class GibberishAES {
+
+ protected static $openssl_random_pseudo_bytes_exists;
+ protected static $openssl_encrypt_exists;
+ protected static $openssl_decrypt_exists;
+
+ // This is a static class, instances are disabled.
+ final private function __construct() {}
+ final private function __clone() {}
+
+ /**
+ * Crypt AES 256
+ *
+ * @param data $string
+ * @param string $pass
+ * @return base64 encrypted string
+ */
+ public static function enc($string, $pass) {
+
+ // Set a random salt.
+ $salt = self::random_pseudo_bytes(8);
+
+ $salted = '';
+ $dx = '';
+
+ // Salt the key(32) and iv(16) = 48
+ while (strlen($salted) < 48) {
+ $dx = md5($dx.$pass.$salt, true);
+ $salted .= $dx;
+ }
+
+ $key = substr($salted, 0, 32);
+ $iv = substr($salted, 32, 16);
+
+ return base64_encode('Salted__' . $salt . self::aes_256_cbc_encrypt($string, $key, $iv));
+ }
+
+ /**
+ * Decrypt AES 256
+ *
+ * @param data $string
+ * @param string $pass
+ * @return dencrypted string
+ */
+ public static function dec($string, $pass) {
+
+ $data = base64_decode($string);
+ $salt = substr($data, 8, 8);
+ $ct = substr($data, 16);
+
+ /**
+ * From https://github.com/mdp/gibberish-aes
+ *
+ * Number of rounds depends on the size of the AES in use
+ * 3 rounds for 256
+ * 2 rounds for the key, 1 for the IV
+ * 2 rounds for 128
+ * 1 round for the key, 1 round for the IV
+ * 3 rounds for 192 since it's not evenly divided by 128 bits
+ */
+ $rounds = 3;
+ $data00 = $pass.$salt;
+ $md5_hash = array();
+ $md5_hash[0] = md5($data00, true);
+ $result = $md5_hash[0];
+ for ($i = 1; $i < $rounds; $i++) {
+ $md5_hash[$i] = md5($md5_hash[$i - 1].$data00, true);
+ $result .= $md5_hash[$i];
+ }
+ $key = substr($result, 0, 32);
+ $iv = substr($result, 32, 16);
+
+ return self::aes_256_cbc_decrypt($ct, $key, $iv);
+ }
+
+ // Non-public methods ------------------------------------------------------
+
+ protected static function random_pseudo_bytes($length) {
+
+ if (!isset(self::$openssl_random_pseudo_bytes_exists)) {
+ self::$openssl_random_pseudo_bytes_exists = function_exists('openssl_random_pseudo_bytes');
+ }
+
+ if (self::$openssl_random_pseudo_bytes_exists) {
+ return openssl_random_pseudo_bytes($length);
+ }
+
+ // Borrowed from http://phpseclib.com/
+ $rnd = '';
+ for ($i = 0; $i < $length; $i++) {
+ $sha = hash('sha256', mt_rand());
+ $char = mt_rand(0, 30);
+ $rnd .= chr(hexdec($sha[$char].$sha[$char + 1]));
+ }
+ return $rnd;
+ }
+
+ protected static function aes_256_cbc_encrypt($string, $key, $iv) {
+
+ if (!isset(self::$openssl_encrypt_exists)) {
+ self::$openssl_encrypt_exists = function_exists('openssl_encrypt')
+ && version_compare(PHP_VERSION, '5.3.3', '>='); // We need $iv parameter.
+ }
+
+ if (self::$openssl_encrypt_exists) {
+ return openssl_encrypt($string, 'aes-256-cbc', $key, true, $iv);
+ }
+
+ // Info: http://www.chilkatsoft.com/p/php_aes.asp
+ $cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
+
+ if (mcrypt_generic_init($cipher, $key, $iv) != -1) {
+ $encrypted = mcrypt_generic($cipher, self::pkcs7_pad($string));
+ mcrypt_generic_deinit($cipher);
+ mcrypt_module_close($cipher);
+ return $encrypted;
+ }
+
+ return false;
+ }
+
+ protected static function aes_256_cbc_decrypt($crypted, $key, $iv) {
+
+ if (!isset(self::$openssl_decrypt_exists)) {
+ self::$openssl_decrypt_exists = function_exists('openssl_decrypt')
+ && version_compare(PHP_VERSION, '5.3.3', '>='); // We need $iv parameter.
+ }
+
+ if (self::$openssl_decrypt_exists) {
+ return openssl_decrypt($crypted, 'aes-256-cbc', $key, true, $iv);
+ }
+
+ $cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
+
+ if (mcrypt_generic_init($cipher, $key, $iv) != -1) {
+ $decrypted = mdecrypt_generic($cipher, $crypted);
+ mcrypt_generic_deinit($cipher);
+ mcrypt_module_close($cipher);
+ return self::remove_pkcs7_pad($decrypted);
+ }
+
+ return false;
+ }
+
+ // See http://www.php.net/manual/en/function.mcrypt-decrypt.php#105985
+ protected static function pkcs7_pad($string) {
+
+ $blocksize = 16; // 128 bits: $blocksize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
+ $pad = $blocksize - (strlen($string) % $blocksize);
+ return $string.str_repeat(chr($pad), $pad);
+ }
+
+ protected static function remove_pkcs7_pad($string) {
+
+ $blocksize = 16; // 128 bits: $blocksize = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
+ $len = strlen($string);
+ $pad = ord($string[$len - 1]);
+ if ($pad > 0 && $pad <= $blocksize) {
+ $valid_pad = true;
+ for ($i = 1; $i <= $pad; $i++) {
+ if (ord($string[$len - $i]) != $pad) {
+ $valid_pad = false;
+ break;
+ }
+ }
+ if ($valid_pad) {
+ $string = substr($string, 0, $len - $pad);
+ }
+ }
+ return $string;
+ }
+
+} \ No newline at end of file
diff --git a/libgpl/gibberish/gibberish-aes.js b/libgpl/gibberish/gibberish-aes.js
new file mode 100644
index 0000000..f1b836b
--- /dev/null
+++ b/libgpl/gibberish/gibberish-aes.js
@@ -0,0 +1,36 @@
+/*
+ Gibberish-AES
+ A lightweight Javascript Libray for OpenSSL compatible AES CBC encryption.
+
+ Author: Mark Percival
+ Email: mark@mpercival.com
+ Copyright: Mark Percival - http://mpercival.com 2008
+
+ With thanks to:
+ Josh Davis - http://www.josh-davis.org/ecmaScrypt
+ Chris Veness - http://www.movable-type.co.uk/scripts/aes.html
+ Michel I. Gallant - http://www.jensign.com/
+ Jean-Luc Cooke <jlcooke@certainkey.com> 2012-07-12: added strhex + invertArr to compress G2X/G3X/G9X/GBX/GEX/SBox/SBoxInv/Rcon saving over 7KB, and added encString, decString, also made the MD5 routine more easlier compressible using yuicompressor.
+
+ License: MIT
+
+ Usage: GibberishAES.enc("secret", "password")
+ Outputs: AES Encrypted text encoded in Base64
+*/
+(function(r,n){"object"===typeof exports?module.exports=n():"function"===typeof define&&define.amd?define(n):r.GibberishAES=n()})(this,function(){var r=14,n=8,u=!1,O=function(a,d){var b="",c,k;if(d){c=a[15];if(16<c)throw"Decryption error: Maybe bad key";if(16===c)return"";for(k=0;k<16-c;k++)b+=String.fromCharCode(a[k])}else for(k=0;16>k;k++)b+=String.fromCharCode(a[k]);return b},z=function(a,d){var b=[],c;if(!d)try{a=unescape(encodeURIComponent(a))}catch(k){throw"Error on UTF-8 encode";}for(c=0;c<
+a.length;c++)b[c]=a.charCodeAt(c);return b},K=function(a,d){var b=12<=r?3:2,c=[],k=[],c=[],k=[],m=a.concat(d),p;c[0]=J(m);k=c[0];for(p=1;p<b;p++)c[p]=J(c[p-1].concat(m)),k=k.concat(c[p]);c=k.slice(0,4*n);k=k.slice(4*n,4*n+16);return{key:c,iv:k}},Q=function(a,d,b){d=L(d);var c=Math.ceil(a.length/16),k=[],m,p=[];for(m=0;m<c;m++){var j=k,t=m,n=a.slice(16*m,16*m+16),s=[],q=void 0,q=void 0;16>n.length&&(q=16-n.length,s=[q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q]);for(q=0;q<n.length;q++)s[q]=n[q];j[t]=s}0===a.length%
+16&&k.push([16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16]);for(m=0;m<k.length;m++)k[m]=0===m?A(k[m],b):A(k[m],p[m-1]),p[m]=P(k[m],d);return p},S=function(a,d,b,c){d=L(d);var k=a.length/16,m=[],p,j=[],t="";for(p=0;p<k;p++)m.push(a.slice(16*p,16*(p+1)));for(p=m.length-1;0<=p;p--)j[p]=R(m[p],d),j[p]=0===p?A(j[p],b):A(j[p],m[p-1]);for(p=0;p<k-1;p++)t+=O(j[p]);var t=t+O(j[p],!0),n;if(c)n=t;else try{n=decodeURIComponent(escape(t))}catch(s){throw"Bad Key";}return n},P=function(a,d){u=!1;var b=B(a,d,0),
+c;for(c=1;c<r+1;c++)b=T(b),b=U(b),c<r&&(b=V(b)),b=B(b,d,c);return b},R=function(a,d){u=!0;var b=B(a,d,r),c;for(c=r-1;-1<c;c--)b=U(b),b=T(b),b=B(b,d,c),0<c&&(b=V(b));return b},T=function(a){var d=u?W:M,b=[],c;for(c=0;16>c;c++)b[c]=d[a[c]];return b},U=function(a){var d=[],b=u?[0,13,10,7,4,1,14,11,8,5,2,15,12,9,6,3]:[0,5,10,15,4,9,14,3,8,13,2,7,12,1,6,11],c;for(c=0;16>c;c++)d[c]=a[b[c]];return d},V=function(a){var d=[],b;if(u)for(b=0;4>b;b++)d[4*b]=C[a[4*b]]^D[a[1+4*b]]^E[a[2+4*b]]^F[a[3+4*b]],d[1+4*
+b]=F[a[4*b]]^C[a[1+4*b]]^D[a[2+4*b]]^E[a[3+4*b]],d[2+4*b]=E[a[4*b]]^F[a[1+4*b]]^C[a[2+4*b]]^D[a[3+4*b]],d[3+4*b]=D[a[4*b]]^E[a[1+4*b]]^F[a[2+4*b]]^C[a[3+4*b]];else for(b=0;4>b;b++)d[4*b]=G[a[4*b]]^H[a[1+4*b]]^a[2+4*b]^a[3+4*b],d[1+4*b]=a[4*b]^G[a[1+4*b]]^H[a[2+4*b]]^a[3+4*b],d[2+4*b]=a[4*b]^a[1+4*b]^G[a[2+4*b]]^H[a[3+4*b]],d[3+4*b]=H[a[4*b]]^a[1+4*b]^a[2+4*b]^G[a[3+4*b]];return d},B=function(a,d,b){var c=[],k;for(k=0;16>k;k++)c[k]=a[k]^d[b][k];return c},A=function(a,d){var b=[],c;for(c=0;16>c;c++)b[c]=
+a[c]^d[c];return b},L=function(a){var d=[],b=[],c,k,m=[];for(c=0;c<n;c++)k=[a[4*c],a[4*c+1],a[4*c+2],a[4*c+3]],d[c]=k;for(c=n;c<4*(r+1);c++){d[c]=[];for(a=0;4>a;a++)b[a]=d[c-1][a];if(0===c%n){a=b[0];k=void 0;for(k=0;3>k;k++)b[k]=b[k+1];b[3]=a;b=X(b);b[0]^=$[c/n-1]}else 6<n&&4===c%n&&(b=X(b));for(a=0;4>a;a++)d[c][a]=d[c-n][a]^b[a]}for(c=0;c<r+1;c++){m[c]=[];for(b=0;4>b;b++)m[c].push(d[4*c+b][0],d[4*c+b][1],d[4*c+b][2],d[4*c+b][3])}return m},X=function(a){for(var d=0;4>d;d++)a[d]=M[a[d]];return a},
+N=function(a,d){var b,c=[];for(b=0;b<a.length;b+=d)c[b/d]=parseInt(a.substr(b,d),16);return c},v=function(a){var d,b=[];for(d=0;256>d;d++){for(var c=b,k=d,m=a,p=d,j=void 0,n=void 0,j=n=0;8>j;j++)n=1===(p&1)?n^m:n,m=127<m?283^m<<1:m<<1,p>>>=1;c[k]=n}return b},M=N("637c777bf26b6fc53001672bfed7ab76ca82c97dfa5947f0add4a2af9ca472c0b7fd9326363ff7cc34a5e5f171d8311504c723c31896059a071280e2eb27b27509832c1a1b6e5aa0523bd6b329e32f8453d100ed20fcb15b6acbbe394a4c58cfd0efaafb434d338545f9027f503c9fa851a3408f929d38f5bcb6da2110fff3d2cd0c13ec5f974417c4a77e3d645d197360814fdc222a908846eeb814de5e0bdbe0323a0a4906245cc2d3ac629195e479e7c8376d8dd54ea96c56f4ea657aae08ba78252e1ca6b4c6e8dd741f4bbd8b8a703eb5664803f60e613557b986c11d9ee1f8981169d98e949b1e87e9ce5528df8ca1890dbfe6426841992d0fb054bb16",
+2),W,Y=M,x,Z=[];for(x=0;x<Y.length;x++)Z[Y[x]]=x;W=Z;var $=N("01020408102040801b366cd8ab4d9a2f5ebc63c697356ad4b37dfaefc591",2),G=v(2),H=v(3),F=v(9),D=v(11),E=v(13),C=v(14),J=function(a){function d(a,b){var c,d,e,g,f;e=a&2147483648;g=b&2147483648;c=a&1073741824;d=b&1073741824;f=(a&1073741823)+(b&1073741823);return c&d?f^2147483648^e^g:c|d?f&1073741824?f^3221225472^e^g:f^1073741824^e^g:f^e^g}function b(a,b,c,e,f,g,h){a=d(a,d(d(b&c|~b&e,f),h));return d(a<<g|a>>>32-g,b)}function c(a,b,c,e,g,f,h){a=d(a,
+d(d(b&e|c&~e,g),h));return d(a<<f|a>>>32-f,b)}function k(a,b,c,e,f,g,h){a=d(a,d(d(b^c^e,f),h));return d(a<<g|a>>>32-g,b)}function m(a,b,c,e,g,f,h){a=d(a,d(d(c^(b|~e),g),h));return d(a<<f|a>>>32-f,b)}function p(a){var b,c,d=[];for(c=0;3>=c;c++)b=a>>>8*c&255,d=d.concat(b);return d}var j=[],n,r,s,q,e,g,f,h,l=N("67452301efcdab8998badcfe10325476d76aa478e8c7b756242070dbc1bdceeef57c0faf4787c62aa8304613fd469501698098d88b44f7afffff5bb1895cd7be6b901122fd987193a679438e49b40821f61e2562c040b340265e5a51e9b6c7aad62f105d02441453d8a1e681e7d3fbc821e1cde6c33707d6f4d50d87455a14eda9e3e905fcefa3f8676f02d98d2a4c8afffa39428771f6816d9d6122fde5380ca4beea444bdecfa9f6bb4b60bebfbc70289b7ec6eaa127fad4ef308504881d05d9d4d039e6db99e51fa27cf8c4ac5665f4292244432aff97ab9423a7fc93a039655b59c38f0ccc92ffeff47d85845dd16fa87e4ffe2ce6e0a30143144e0811a1f7537e82bd3af2352ad7d2bbeb86d391",
+8),j=a.length;n=j+8;r=16*((n-n%64)/64+1);s=[];for(e=q=0;e<j;)n=(e-e%4)/4,q=8*(e%4),s[n]|=a[e]<<q,e++;n=(e-e%4)/4;s[n]|=128<<8*(e%4);s[r-2]=j<<3;s[r-1]=j>>>29;j=s;e=l[0];g=l[1];f=l[2];h=l[3];for(a=0;a<j.length;a+=16)n=e,r=g,s=f,q=h,e=b(e,g,f,h,j[a+0],7,l[4]),h=b(h,e,g,f,j[a+1],12,l[5]),f=b(f,h,e,g,j[a+2],17,l[6]),g=b(g,f,h,e,j[a+3],22,l[7]),e=b(e,g,f,h,j[a+4],7,l[8]),h=b(h,e,g,f,j[a+5],12,l[9]),f=b(f,h,e,g,j[a+6],17,l[10]),g=b(g,f,h,e,j[a+7],22,l[11]),e=b(e,g,f,h,j[a+8],7,l[12]),h=b(h,e,g,f,j[a+9],
+12,l[13]),f=b(f,h,e,g,j[a+10],17,l[14]),g=b(g,f,h,e,j[a+11],22,l[15]),e=b(e,g,f,h,j[a+12],7,l[16]),h=b(h,e,g,f,j[a+13],12,l[17]),f=b(f,h,e,g,j[a+14],17,l[18]),g=b(g,f,h,e,j[a+15],22,l[19]),e=c(e,g,f,h,j[a+1],5,l[20]),h=c(h,e,g,f,j[a+6],9,l[21]),f=c(f,h,e,g,j[a+11],14,l[22]),g=c(g,f,h,e,j[a+0],20,l[23]),e=c(e,g,f,h,j[a+5],5,l[24]),h=c(h,e,g,f,j[a+10],9,l[25]),f=c(f,h,e,g,j[a+15],14,l[26]),g=c(g,f,h,e,j[a+4],20,l[27]),e=c(e,g,f,h,j[a+9],5,l[28]),h=c(h,e,g,f,j[a+14],9,l[29]),f=c(f,h,e,g,j[a+3],14,l[30]),
+g=c(g,f,h,e,j[a+8],20,l[31]),e=c(e,g,f,h,j[a+13],5,l[32]),h=c(h,e,g,f,j[a+2],9,l[33]),f=c(f,h,e,g,j[a+7],14,l[34]),g=c(g,f,h,e,j[a+12],20,l[35]),e=k(e,g,f,h,j[a+5],4,l[36]),h=k(h,e,g,f,j[a+8],11,l[37]),f=k(f,h,e,g,j[a+11],16,l[38]),g=k(g,f,h,e,j[a+14],23,l[39]),e=k(e,g,f,h,j[a+1],4,l[40]),h=k(h,e,g,f,j[a+4],11,l[41]),f=k(f,h,e,g,j[a+7],16,l[42]),g=k(g,f,h,e,j[a+10],23,l[43]),e=k(e,g,f,h,j[a+13],4,l[44]),h=k(h,e,g,f,j[a+0],11,l[45]),f=k(f,h,e,g,j[a+3],16,l[46]),g=k(g,f,h,e,j[a+6],23,l[47]),e=k(e,g,
+f,h,j[a+9],4,l[48]),h=k(h,e,g,f,j[a+12],11,l[49]),f=k(f,h,e,g,j[a+15],16,l[50]),g=k(g,f,h,e,j[a+2],23,l[51]),e=m(e,g,f,h,j[a+0],6,l[52]),h=m(h,e,g,f,j[a+7],10,l[53]),f=m(f,h,e,g,j[a+14],15,l[54]),g=m(g,f,h,e,j[a+5],21,l[55]),e=m(e,g,f,h,j[a+12],6,l[56]),h=m(h,e,g,f,j[a+3],10,l[57]),f=m(f,h,e,g,j[a+10],15,l[58]),g=m(g,f,h,e,j[a+1],21,l[59]),e=m(e,g,f,h,j[a+8],6,l[60]),h=m(h,e,g,f,j[a+15],10,l[61]),f=m(f,h,e,g,j[a+6],15,l[62]),g=m(g,f,h,e,j[a+13],21,l[63]),e=m(e,g,f,h,j[a+4],6,l[64]),h=m(h,e,g,f,j[a+
+11],10,l[65]),f=m(f,h,e,g,j[a+2],15,l[66]),g=m(g,f,h,e,j[a+9],21,l[67]),e=d(e,n),g=d(g,r),f=d(f,s),h=d(h,q);return p(e).concat(p(g),p(f),p(h))},I,w="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",y=w.split("");"function"===typeof Array.indexOf&&(w=y);I={encode:function(a){var d=[],b="",c;for(c=0;c<16*a.length;c++)d.push(a[Math.floor(c/16)][c%16]);for(c=0;c<d.length;c+=3)b+=y[d[c]>>2],b+=y[(d[c]&3)<<4|d[c+1]>>4],b=void 0!==d[c+1]?b+y[(d[c+1]&15)<<2|d[c+2]>>6]:b+"=",b=void 0!==d[c+
+2]?b+y[d[c+2]&63]:b+"=";a=b.slice(0,64)+"\n";for(c=1;c<Math.ceil(b.length/64);c++)a+=b.slice(64*c,64*c+64)+(Math.ceil(b.length/64)===c+1?"":"\n");return a},decode:function(a){a=a.replace(/\n/g,"");var d=[],b=[],c=[],k;for(k=0;k<a.length;k+=4)b[0]=w.indexOf(a.charAt(k)),b[1]=w.indexOf(a.charAt(k+1)),b[2]=w.indexOf(a.charAt(k+2)),b[3]=w.indexOf(a.charAt(k+3)),c[0]=b[0]<<2|b[1]>>4,c[1]=(b[1]&15)<<4|b[2]>>2,c[2]=(b[2]&3)<<6|b[3],d.push(c[0],c[1],c[2]);return d=d.slice(0,d.length-d.length%16)}};return{size:function(a){switch(a){case 128:r=
+10;n=4;break;case 192:r=12;n=6;break;case 256:r=14;n=8;break;default:throw"Invalid Key Size Specified:"+a;}},h2a:function(a){var d=[];a.replace(/(..)/g,function(a){d.push(parseInt(a,16))});return d},expandKey:L,encryptBlock:P,decryptBlock:R,Decrypt:u,s2a:z,rawEncrypt:Q,rawDecrypt:S,dec:function(a,d,b){a=I.decode(a);var c=a.slice(8,16),c=K(z(d,b),c);d=c.key;c=c.iv;a=a.slice(16,a.length);return a=S(a,d,c,b)},openSSLKey:K,a2h:function(a){var d="",b;for(b=0;b<a.length;b++)d+=(16>a[b]?"0":"")+a[b].toString(16);
+return d},enc:function(a,d,b){var c;c=[];var k;for(k=0;8>k;k++)c=c.concat(Math.floor(256*Math.random()));k=K(z(d,b),c);d=k.key;k=k.iv;c=[[83,97,108,116,101,100,95,95].concat(c)];a=z(a,b);a=Q(a,d,k);a=c.concat(a);return I.encode(a)},Hash:{MD5:J},Base64:I}}); \ No newline at end of file
diff --git a/libgpl/gibberish/gibberish-aes.js.comp.src b/libgpl/gibberish/gibberish-aes.js.comp.src
new file mode 100644
index 0000000..ca7f01f
--- /dev/null
+++ b/libgpl/gibberish/gibberish-aes.js.comp.src
@@ -0,0 +1,1017 @@
+/**
+* @license Gibberish-AES
+* A lightweight Javascript Libray for OpenSSL compatible AES CBC encryption.
+*
+* Author: Mark Percival
+* Email: mark@mpercival.com
+* Copyright: Mark Percival - http://mpercival.com 2008
+*
+* With thanks to:
+* Josh Davis - http://www.josh-davis.org/ecmaScrypt
+* Chris Veness - http://www.movable-type.co.uk/scripts/aes.html
+* Michel I. Gallant - http://www.jensign.com/
+* Jean-Luc Cooke <jlcooke@certainkey.com> 2012-07-12: added strhex + invertArr to compress G2X/G3X/G9X/GBX/GEX/SBox/SBoxInv/Rcon saving over 7KB, and added encString, decString, also made the MD5 routine more easlier compressible using yuicompressor.
+*
+* License: MIT
+*
+* Usage: GibberishAES.enc("secret", "password")
+* Outputs: AES Encrypted text encoded in Base64
+*/
+
+
+(function (root, factory) {
+ if (typeof exports === 'object') {
+ // Node.
+ module.exports = factory();
+ } else if (typeof define === 'function' && define.amd) {
+ // AMD. Register as an anonymous module.
+ define(factory);
+ } else {
+ // Browser globals (root is window)
+ root.GibberishAES = factory();
+ }
+}(this, function () {
+ 'use strict';
+
+ var Nr = 14,
+ /* Default to 256 Bit Encryption */
+ Nk = 8,
+ Decrypt = false,
+
+ enc_utf8 = function(s)
+ {
+ try {
+ return unescape(encodeURIComponent(s));
+ }
+ catch(e) {
+ throw 'Error on UTF-8 encode';
+ }
+ },
+
+ dec_utf8 = function(s)
+ {
+ try {
+ return decodeURIComponent(escape(s));
+ }
+ catch(e) {
+ throw ('Bad Key');
+ }
+ },
+
+ padBlock = function(byteArr)
+ {
+ var array = [], cpad, i;
+ if (byteArr.length < 16) {
+ cpad = 16 - byteArr.length;
+ array = [cpad, cpad, cpad, cpad, cpad, cpad, cpad, cpad, cpad, cpad, cpad, cpad, cpad, cpad, cpad, cpad];
+ }
+ for (i = 0; i < byteArr.length; i++)
+ {
+ array[i] = byteArr[i];
+ }
+ return array;
+ },
+
+ block2s = function(block, lastBlock)
+ {
+ var string = '', padding, i;
+ if (lastBlock) {
+ padding = block[15];
+ if (padding > 16) {
+ throw ('Decryption error: Maybe bad key');
+ }
+ if (padding === 16) {
+ return '';
+ }
+ for (i = 0; i < 16 - padding; i++) {
+ string += String.fromCharCode(block[i]);
+ }
+ } else {
+ for (i = 0; i < 16; i++) {
+ string += String.fromCharCode(block[i]);
+ }
+ }
+ return string;
+ },
+
+ a2h = function(numArr)
+ {
+ var string = '', i;
+ for (i = 0; i < numArr.length; i++) {
+ string += (numArr[i] < 16 ? '0': '') + numArr[i].toString(16);
+ }
+ return string;
+ },
+
+ h2a = function(s)
+ {
+ var ret = [];
+ s.replace(/(..)/g,
+ function(s) {
+ ret.push(parseInt(s, 16));
+ });
+ return ret;
+ },
+
+ s2a = function(string, binary) {
+ var array = [], i;
+
+ if (! binary) {
+ string = enc_utf8(string);
+ }
+
+ for (i = 0; i < string.length; i++)
+ {
+ array[i] = string.charCodeAt(i);
+ }
+
+ return array;
+ },
+
+ size = function(newsize)
+ {
+ switch (newsize)
+ {
+ case 128:
+ Nr = 10;
+ Nk = 4;
+ break;
+ case 192:
+ Nr = 12;
+ Nk = 6;
+ break;
+ case 256:
+ Nr = 14;
+ Nk = 8;
+ break;
+ default:
+ throw ('Invalid Key Size Specified:' + newsize);
+ }
+ },
+
+ randArr = function(num) {
+ var result = [], i;
+ for (i = 0; i < num; i++) {
+ result = result.concat(Math.floor(Math.random() * 256));
+ }
+ return result;
+ },
+
+ openSSLKey = function(passwordArr, saltArr) {
+ // Number of rounds depends on the size of the AES in use
+ // 3 rounds for 256
+ // 2 rounds for the key, 1 for the IV
+ // 2 rounds for 128
+ // 1 round for the key, 1 round for the IV
+ // 3 rounds for 192 since it's not evenly divided by 128 bits
+ var rounds = Nr >= 12 ? 3: 2,
+ key = [],
+ iv = [],
+ md5_hash = [],
+ result = [],
+ data00 = passwordArr.concat(saltArr),
+ i;
+ md5_hash[0] = MD5(data00);
+ result = md5_hash[0];
+ for (i = 1; i < rounds; i++) {
+ md5_hash[i] = MD5(md5_hash[i - 1].concat(data00));
+ result = result.concat(md5_hash[i]);
+ }
+ key = result.slice(0, 4 * Nk);
+ iv = result.slice(4 * Nk, 4 * Nk + 16);
+ return {
+ key: key,
+ iv: iv
+ };
+ },
+
+ rawEncrypt = function(plaintext, key, iv) {
+ // plaintext, key and iv as byte arrays
+ key = expandKey(key);
+ var numBlocks = Math.ceil(plaintext.length / 16),
+ blocks = [],
+ i,
+ cipherBlocks = [];
+ for (i = 0; i < numBlocks; i++) {
+ blocks[i] = padBlock(plaintext.slice(i * 16, i * 16 + 16));
+ }
+ if (plaintext.length % 16 === 0) {
+ blocks.push([16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16]);
+ // CBC OpenSSL padding scheme
+ numBlocks++;
+ }
+ for (i = 0; i < blocks.length; i++) {
+ blocks[i] = (i === 0) ? xorBlocks(blocks[i], iv) : xorBlocks(blocks[i], cipherBlocks[i - 1]);
+ cipherBlocks[i] = encryptBlock(blocks[i], key);
+ }
+ return cipherBlocks;
+ },
+
+ rawDecrypt = function(cryptArr, key, iv, binary) {
+ // cryptArr, key and iv as byte arrays
+ key = expandKey(key);
+ var numBlocks = cryptArr.length / 16,
+ cipherBlocks = [],
+ i,
+ plainBlocks = [],
+ string = '';
+ for (i = 0; i < numBlocks; i++) {
+ cipherBlocks.push(cryptArr.slice(i * 16, (i + 1) * 16));
+ }
+ for (i = cipherBlocks.length - 1; i >= 0; i--) {
+ plainBlocks[i] = decryptBlock(cipherBlocks[i], key);
+ plainBlocks[i] = (i === 0) ? xorBlocks(plainBlocks[i], iv) : xorBlocks(plainBlocks[i], cipherBlocks[i - 1]);
+ }
+ for (i = 0; i < numBlocks - 1; i++) {
+ string += block2s(plainBlocks[i]);
+ }
+ string += block2s(plainBlocks[i], true);
+ return binary ? string : dec_utf8(string);
+ },
+
+ encryptBlock = function(block, words) {
+ Decrypt = false;
+ var state = addRoundKey(block, words, 0),
+ round;
+ for (round = 1; round < (Nr + 1); round++) {
+ state = subBytes(state);
+ state = shiftRows(state);
+ if (round < Nr) {
+ state = mixColumns(state);
+ }
+ //last round? don't mixColumns
+ state = addRoundKey(state, words, round);
+ }
+
+ return state;
+ },
+
+ decryptBlock = function(block, words) {
+ Decrypt = true;
+ var state = addRoundKey(block, words, Nr),
+ round;
+ for (round = Nr - 1; round > -1; round--) {
+ state = shiftRows(state);
+ state = subBytes(state);
+ state = addRoundKey(state, words, round);
+ if (round > 0) {
+ state = mixColumns(state);
+ }
+ //last round? don't mixColumns
+ }
+
+ return state;
+ },
+
+ subBytes = function(state) {
+ var S = Decrypt ? SBoxInv: SBox,
+ temp = [],
+ i;
+ for (i = 0; i < 16; i++) {
+ temp[i] = S[state[i]];
+ }
+ return temp;
+ },
+
+ shiftRows = function(state) {
+ var temp = [],
+ shiftBy = Decrypt ? [0, 13, 10, 7, 4, 1, 14, 11, 8, 5, 2, 15, 12, 9, 6, 3] : [0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11],
+ i;
+ for (i = 0; i < 16; i++) {
+ temp[i] = state[shiftBy[i]];
+ }
+ return temp;
+ },
+
+ mixColumns = function(state) {
+ var t = [],
+ c;
+ if (!Decrypt) {
+ for (c = 0; c < 4; c++) {
+ t[c * 4] = G2X[state[c * 4]] ^ G3X[state[1 + c * 4]] ^ state[2 + c * 4] ^ state[3 + c * 4];
+ t[1 + c * 4] = state[c * 4] ^ G2X[state[1 + c * 4]] ^ G3X[state[2 + c * 4]] ^ state[3 + c * 4];
+ t[2 + c * 4] = state[c * 4] ^ state[1 + c * 4] ^ G2X[state[2 + c * 4]] ^ G3X[state[3 + c * 4]];
+ t[3 + c * 4] = G3X[state[c * 4]] ^ state[1 + c * 4] ^ state[2 + c * 4] ^ G2X[state[3 + c * 4]];
+ }
+ }else {
+ for (c = 0; c < 4; c++) {
+ t[c*4] = GEX[state[c*4]] ^ GBX[state[1+c*4]] ^ GDX[state[2+c*4]] ^ G9X[state[3+c*4]];
+ t[1+c*4] = G9X[state[c*4]] ^ GEX[state[1+c*4]] ^ GBX[state[2+c*4]] ^ GDX[state[3+c*4]];
+ t[2+c*4] = GDX[state[c*4]] ^ G9X[state[1+c*4]] ^ GEX[state[2+c*4]] ^ GBX[state[3+c*4]];
+ t[3+c*4] = GBX[state[c*4]] ^ GDX[state[1+c*4]] ^ G9X[state[2+c*4]] ^ GEX[state[3+c*4]];
+ }
+ }
+
+ return t;
+ },
+
+ addRoundKey = function(state, words, round) {
+ var temp = [],
+ i;
+ for (i = 0; i < 16; i++) {
+ temp[i] = state[i] ^ words[round][i];
+ }
+ return temp;
+ },
+
+ xorBlocks = function(block1, block2) {
+ var temp = [],
+ i;
+ for (i = 0; i < 16; i++) {
+ temp[i] = block1[i] ^ block2[i];
+ }
+ return temp;
+ },
+
+ expandKey = function(key) {
+ // Expects a 1d number array
+ var w = [],
+ temp = [],
+ i,
+ r,
+ t,
+ flat = [],
+ j;
+
+ for (i = 0; i < Nk; i++) {
+ r = [key[4 * i], key[4 * i + 1], key[4 * i + 2], key[4 * i + 3]];
+ w[i] = r;
+ }
+
+ for (i = Nk; i < (4 * (Nr + 1)); i++) {
+ w[i] = [];
+ for (t = 0; t < 4; t++) {
+ temp[t] = w[i - 1][t];
+ }
+ if (i % Nk === 0) {
+ temp = subWord(rotWord(temp));
+ temp[0] ^= Rcon[i / Nk - 1];
+ } else if (Nk > 6 && i % Nk === 4) {
+ temp = subWord(temp);
+ }
+ for (t = 0; t < 4; t++) {
+ w[i][t] = w[i - Nk][t] ^ temp[t];
+ }
+ }
+ for (i = 0; i < (Nr + 1); i++) {
+ flat[i] = [];
+ for (j = 0; j < 4; j++) {
+ flat[i].push(w[i * 4 + j][0], w[i * 4 + j][1], w[i * 4 + j][2], w[i * 4 + j][3]);
+ }
+ }
+ return flat;
+ },
+
+ subWord = function(w) {
+ // apply SBox to 4-byte word w
+ for (var i = 0; i < 4; i++) {
+ w[i] = SBox[w[i]];
+ }
+ return w;
+ },
+
+ rotWord = function(w) {
+ // rotate 4-byte word w left by one byte
+ var tmp = w[0],
+ i;
+ for (i = 0; i < 3; i++) {
+ w[i] = w[i + 1];
+ }
+ w[3] = tmp;
+ return w;
+ },
+
+// jlcooke: 2012-07-12: added strhex + invertArr to compress G2X/G3X/G9X/GBX/GEX/SBox/SBoxInv/Rcon saving over 7KB, and added encString, decString
+ strhex = function(str,size) {
+ var i, ret = [];
+ for (i=0; i<str.length; i+=size){
+ ret[i/size] = parseInt(str.substr(i,size), 16);
+ }
+ return ret;
+ },
+ invertArr = function(arr) {
+ var i, ret = [];
+ for (i=0; i<arr.length; i++){
+ ret[arr[i]] = i;
+ }
+ return ret;
+ },
+ Gxx = function(a, b) {
+ var i, ret;
+
+ ret = 0;
+ for (i=0; i<8; i++) {
+ ret = ((b&1)===1) ? ret^a : ret;
+ /* xmult */
+ a = (a>0x7f) ? 0x11b^(a<<1) : (a<<1);
+ b >>>= 1;
+ }
+
+ return ret;
+ },
+ Gx = function(x) {
+ var i, r = [];
+ for (i=0; i<256; i++){
+ r[i] = Gxx(x, i);
+ }
+ return r;
+ },
+
+ // S-box
+/*
+ SBox = [
+ 99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171,
+ 118, 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164,
+ 114, 192, 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113,
+ 216, 49, 21, 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226,
+ 235, 39, 178, 117, 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214,
+ 179, 41, 227, 47, 132, 83, 209, 0, 237, 32, 252, 177, 91, 106, 203,
+ 190, 57, 74, 76, 88, 207, 208, 239, 170, 251, 67, 77, 51, 133, 69,
+ 249, 2, 127, 80, 60, 159, 168, 81, 163, 64, 143, 146, 157, 56, 245,
+ 188, 182, 218, 33, 16, 255, 243, 210, 205, 12, 19, 236, 95, 151, 68,
+ 23, 196, 167, 126, 61, 100, 93, 25, 115, 96, 129, 79, 220, 34, 42,
+ 144, 136, 70, 238, 184, 20, 222, 94, 11, 219, 224, 50, 58, 10, 73,
+ 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, 231, 200, 55, 109,
+ 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, 186, 120, 37,
+ 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, 112, 62,
+ 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, 225,
+ 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223,
+ 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187,
+ 22], //*/ SBox = strhex('637c777bf26b6fc53001672bfed7ab76ca82c97dfa5947f0add4a2af9ca472c0b7fd9326363ff7cc34a5e5f171d8311504c723c31896059a071280e2eb27b27509832c1a1b6e5aa0523bd6b329e32f8453d100ed20fcb15b6acbbe394a4c58cfd0efaafb434d338545f9027f503c9fa851a3408f929d38f5bcb6da2110fff3d2cd0c13ec5f974417c4a77e3d645d197360814fdc222a908846eeb814de5e0bdbe0323a0a4906245cc2d3ac629195e479e7c8376d8dd54ea96c56f4ea657aae08ba78252e1ca6b4c6e8dd741f4bbd8b8a703eb5664803f60e613557b986c11d9ee1f8981169d98e949b1e87e9ce5528df8ca1890dbfe6426841992d0fb054bb16',2),
+
+ // Precomputed lookup table for the inverse SBox
+/* SBoxInv = [
+ 82, 9, 106, 213, 48, 54, 165, 56, 191, 64, 163, 158, 129, 243, 215,
+ 251, 124, 227, 57, 130, 155, 47, 255, 135, 52, 142, 67, 68, 196, 222,
+ 233, 203, 84, 123, 148, 50, 166, 194, 35, 61, 238, 76, 149, 11, 66,
+ 250, 195, 78, 8, 46, 161, 102, 40, 217, 36, 178, 118, 91, 162, 73,
+ 109, 139, 209, 37, 114, 248, 246, 100, 134, 104, 152, 22, 212, 164, 92,
+ 204, 93, 101, 182, 146, 108, 112, 72, 80, 253, 237, 185, 218, 94, 21,
+ 70, 87, 167, 141, 157, 132, 144, 216, 171, 0, 140, 188, 211, 10, 247,
+ 228, 88, 5, 184, 179, 69, 6, 208, 44, 30, 143, 202, 63, 15, 2,
+ 193, 175, 189, 3, 1, 19, 138, 107, 58, 145, 17, 65, 79, 103, 220,
+ 234, 151, 242, 207, 206, 240, 180, 230, 115, 150, 172, 116, 34, 231, 173,
+ 53, 133, 226, 249, 55, 232, 28, 117, 223, 110, 71, 241, 26, 113, 29,
+ 41, 197, 137, 111, 183, 98, 14, 170, 24, 190, 27, 252, 86, 62, 75,
+ 198, 210, 121, 32, 154, 219, 192, 254, 120, 205, 90, 244, 31, 221, 168,
+ 51, 136, 7, 199, 49, 177, 18, 16, 89, 39, 128, 236, 95, 96, 81,
+ 127, 169, 25, 181, 74, 13, 45, 229, 122, 159, 147, 201, 156, 239, 160,
+ 224, 59, 77, 174, 42, 245, 176, 200, 235, 187, 60, 131, 83, 153, 97,
+ 23, 43, 4, 126, 186, 119, 214, 38, 225, 105, 20, 99, 85, 33, 12,
+ 125], //*/ SBoxInv = invertArr(SBox),
+
+ // Rijndael Rcon
+/*
+ Rcon = [1, 2, 4, 8, 16, 32, 64, 128, 27, 54, 108, 216, 171, 77, 154, 47, 94,
+ 188, 99, 198, 151, 53, 106, 212, 179, 125, 250, 239, 197, 145],
+//*/ Rcon = strhex('01020408102040801b366cd8ab4d9a2f5ebc63c697356ad4b37dfaefc591',2),
+
+/*
+ G2X = [
+ 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16,
+ 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e,
+ 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e, 0x40, 0x42, 0x44, 0x46,
+ 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e,
+ 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76,
+ 0x78, 0x7a, 0x7c, 0x7e, 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e,
+ 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e, 0xa0, 0xa2, 0xa4, 0xa6,
+ 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe,
+ 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6,
+ 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee,
+ 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe, 0x1b, 0x19, 0x1f, 0x1d,
+ 0x13, 0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05,
+ 0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35, 0x2b, 0x29, 0x2f, 0x2d,
+ 0x23, 0x21, 0x27, 0x25, 0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55,
+ 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45, 0x7b, 0x79, 0x7f, 0x7d,
+ 0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65,
+ 0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d,
+ 0x83, 0x81, 0x87, 0x85, 0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5,
+ 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5, 0xdb, 0xd9, 0xdf, 0xdd,
+ 0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5,
+ 0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed,
+ 0xe3, 0xe1, 0xe7, 0xe5
+ ], //*/ G2X = Gx(2),
+
+/* G3X = [
+ 0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d,
+ 0x14, 0x17, 0x12, 0x11, 0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39,
+ 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21, 0x60, 0x63, 0x66, 0x65,
+ 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71,
+ 0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59, 0x48, 0x4b, 0x4e, 0x4d,
+ 0x44, 0x47, 0x42, 0x41, 0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9,
+ 0xd8, 0xdb, 0xde, 0xdd, 0xd4, 0xd7, 0xd2, 0xd1, 0xf0, 0xf3, 0xf6, 0xf5,
+ 0xfc, 0xff, 0xfa, 0xf9, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1,
+ 0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9, 0xb8, 0xbb, 0xbe, 0xbd,
+ 0xb4, 0xb7, 0xb2, 0xb1, 0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99,
+ 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81, 0x9b, 0x98, 0x9d, 0x9e,
+ 0x97, 0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89, 0x8a,
+ 0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2, 0xb3, 0xb0, 0xb5, 0xb6,
+ 0xbf, 0xbc, 0xb9, 0xba, 0xfb, 0xf8, 0xfd, 0xfe, 0xf7, 0xf4, 0xf1, 0xf2,
+ 0xe3, 0xe0, 0xe5, 0xe6, 0xef, 0xec, 0xe9, 0xea, 0xcb, 0xc8, 0xcd, 0xce,
+ 0xc7, 0xc4, 0xc1, 0xc2, 0xd3, 0xd0, 0xd5, 0xd6, 0xdf, 0xdc, 0xd9, 0xda,
+ 0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46,
+ 0x4f, 0x4c, 0x49, 0x4a, 0x6b, 0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62,
+ 0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a, 0x3b, 0x38, 0x3d, 0x3e,
+ 0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a,
+ 0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16,
+ 0x1f, 0x1c, 0x19, 0x1a
+ ], //*/ G3X = Gx(3),
+
+/*
+ G9X = [
+ 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53,
+ 0x6c, 0x65, 0x7e, 0x77, 0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf,
+ 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7, 0x3b, 0x32, 0x29, 0x20,
+ 0x1f, 0x16, 0x0d, 0x04, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c,
+ 0xab, 0xa2, 0xb9, 0xb0, 0x8f, 0x86, 0x9d, 0x94, 0xe3, 0xea, 0xf1, 0xf8,
+ 0xc7, 0xce, 0xd5, 0xdc, 0x76, 0x7f, 0x64, 0x6d, 0x52, 0x5b, 0x40, 0x49,
+ 0x3e, 0x37, 0x2c, 0x25, 0x1a, 0x13, 0x08, 0x01, 0xe6, 0xef, 0xf4, 0xfd,
+ 0xc2, 0xcb, 0xd0, 0xd9, 0xae, 0xa7, 0xbc, 0xb5, 0x8a, 0x83, 0x98, 0x91,
+ 0x4d, 0x44, 0x5f, 0x56, 0x69, 0x60, 0x7b, 0x72, 0x05, 0x0c, 0x17, 0x1e,
+ 0x21, 0x28, 0x33, 0x3a, 0xdd, 0xd4, 0xcf, 0xc6, 0xf9, 0xf0, 0xeb, 0xe2,
+ 0x95, 0x9c, 0x87, 0x8e, 0xb1, 0xb8, 0xa3, 0xaa, 0xec, 0xe5, 0xfe, 0xf7,
+ 0xc8, 0xc1, 0xda, 0xd3, 0xa4, 0xad, 0xb6, 0xbf, 0x80, 0x89, 0x92, 0x9b,
+ 0x7c, 0x75, 0x6e, 0x67, 0x58, 0x51, 0x4a, 0x43, 0x34, 0x3d, 0x26, 0x2f,
+ 0x10, 0x19, 0x02, 0x0b, 0xd7, 0xde, 0xc5, 0xcc, 0xf3, 0xfa, 0xe1, 0xe8,
+ 0x9f, 0x96, 0x8d, 0x84, 0xbb, 0xb2, 0xa9, 0xa0, 0x47, 0x4e, 0x55, 0x5c,
+ 0x63, 0x6a, 0x71, 0x78, 0x0f, 0x06, 0x1d, 0x14, 0x2b, 0x22, 0x39, 0x30,
+ 0x9a, 0x93, 0x88, 0x81, 0xbe, 0xb7, 0xac, 0xa5, 0xd2, 0xdb, 0xc0, 0xc9,
+ 0xf6, 0xff, 0xe4, 0xed, 0x0a, 0x03, 0x18, 0x11, 0x2e, 0x27, 0x3c, 0x35,
+ 0x42, 0x4b, 0x50, 0x59, 0x66, 0x6f, 0x74, 0x7d, 0xa1, 0xa8, 0xb3, 0xba,
+ 0x85, 0x8c, 0x97, 0x9e, 0xe9, 0xe0, 0xfb, 0xf2, 0xcd, 0xc4, 0xdf, 0xd6,
+ 0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62,
+ 0x5d, 0x54, 0x4f, 0x46
+ ], //*/ G9X = Gx(9),
+
+/* GBX = [
+ 0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45,
+ 0x74, 0x7f, 0x62, 0x69, 0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81,
+ 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9, 0x7b, 0x70, 0x6d, 0x66,
+ 0x57, 0x5c, 0x41, 0x4a, 0x23, 0x28, 0x35, 0x3e, 0x0f, 0x04, 0x19, 0x12,
+ 0xcb, 0xc0, 0xdd, 0xd6, 0xe7, 0xec, 0xf1, 0xfa, 0x93, 0x98, 0x85, 0x8e,
+ 0xbf, 0xb4, 0xa9, 0xa2, 0xf6, 0xfd, 0xe0, 0xeb, 0xda, 0xd1, 0xcc, 0xc7,
+ 0xae, 0xa5, 0xb8, 0xb3, 0x82, 0x89, 0x94, 0x9f, 0x46, 0x4d, 0x50, 0x5b,
+ 0x6a, 0x61, 0x7c, 0x77, 0x1e, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24, 0x2f,
+ 0x8d, 0x86, 0x9b, 0x90, 0xa1, 0xaa, 0xb7, 0xbc, 0xd5, 0xde, 0xc3, 0xc8,
+ 0xf9, 0xf2, 0xef, 0xe4, 0x3d, 0x36, 0x2b, 0x20, 0x11, 0x1a, 0x07, 0x0c,
+ 0x65, 0x6e, 0x73, 0x78, 0x49, 0x42, 0x5f, 0x54, 0xf7, 0xfc, 0xe1, 0xea,
+ 0xdb, 0xd0, 0xcd, 0xc6, 0xaf, 0xa4, 0xb9, 0xb2, 0x83, 0x88, 0x95, 0x9e,
+ 0x47, 0x4c, 0x51, 0x5a, 0x6b, 0x60, 0x7d, 0x76, 0x1f, 0x14, 0x09, 0x02,
+ 0x33, 0x38, 0x25, 0x2e, 0x8c, 0x87, 0x9a, 0x91, 0xa0, 0xab, 0xb6, 0xbd,
+ 0xd4, 0xdf, 0xc2, 0xc9, 0xf8, 0xf3, 0xee, 0xe5, 0x3c, 0x37, 0x2a, 0x21,
+ 0x10, 0x1b, 0x06, 0x0d, 0x64, 0x6f, 0x72, 0x79, 0x48, 0x43, 0x5e, 0x55,
+ 0x01, 0x0a, 0x17, 0x1c, 0x2d, 0x26, 0x3b, 0x30, 0x59, 0x52, 0x4f, 0x44,
+ 0x75, 0x7e, 0x63, 0x68, 0xb1, 0xba, 0xa7, 0xac, 0x9d, 0x96, 0x8b, 0x80,
+ 0xe9, 0xe2, 0xff, 0xf4, 0xc5, 0xce, 0xd3, 0xd8, 0x7a, 0x71, 0x6c, 0x67,
+ 0x56, 0x5d, 0x40, 0x4b, 0x22, 0x29, 0x34, 0x3f, 0x0e, 0x05, 0x18, 0x13,
+ 0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f,
+ 0xbe, 0xb5, 0xa8, 0xa3
+ ], //*/ GBX = Gx(0xb),
+
+/*
+ GDX = [
+ 0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f,
+ 0x5c, 0x51, 0x46, 0x4b, 0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3,
+ 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b, 0xbb, 0xb6, 0xa1, 0xac,
+ 0x8f, 0x82, 0x95, 0x98, 0xd3, 0xde, 0xc9, 0xc4, 0xe7, 0xea, 0xfd, 0xf0,
+ 0x6b, 0x66, 0x71, 0x7c, 0x5f, 0x52, 0x45, 0x48, 0x03, 0x0e, 0x19, 0x14,
+ 0x37, 0x3a, 0x2d, 0x20, 0x6d, 0x60, 0x77, 0x7a, 0x59, 0x54, 0x43, 0x4e,
+ 0x05, 0x08, 0x1f, 0x12, 0x31, 0x3c, 0x2b, 0x26, 0xbd, 0xb0, 0xa7, 0xaa,
+ 0x89, 0x84, 0x93, 0x9e, 0xd5, 0xd8, 0xcf, 0xc2, 0xe1, 0xec, 0xfb, 0xf6,
+ 0xd6, 0xdb, 0xcc, 0xc1, 0xe2, 0xef, 0xf8, 0xf5, 0xbe, 0xb3, 0xa4, 0xa9,
+ 0x8a, 0x87, 0x90, 0x9d, 0x06, 0x0b, 0x1c, 0x11, 0x32, 0x3f, 0x28, 0x25,
+ 0x6e, 0x63, 0x74, 0x79, 0x5a, 0x57, 0x40, 0x4d, 0xda, 0xd7, 0xc0, 0xcd,
+ 0xee, 0xe3, 0xf4, 0xf9, 0xb2, 0xbf, 0xa8, 0xa5, 0x86, 0x8b, 0x9c, 0x91,
+ 0x0a, 0x07, 0x10, 0x1d, 0x3e, 0x33, 0x24, 0x29, 0x62, 0x6f, 0x78, 0x75,
+ 0x56, 0x5b, 0x4c, 0x41, 0x61, 0x6c, 0x7b, 0x76, 0x55, 0x58, 0x4f, 0x42,
+ 0x09, 0x04, 0x13, 0x1e, 0x3d, 0x30, 0x27, 0x2a, 0xb1, 0xbc, 0xab, 0xa6,
+ 0x85, 0x88, 0x9f, 0x92, 0xd9, 0xd4, 0xc3, 0xce, 0xed, 0xe0, 0xf7, 0xfa,
+ 0xb7, 0xba, 0xad, 0xa0, 0x83, 0x8e, 0x99, 0x94, 0xdf, 0xd2, 0xc5, 0xc8,
+ 0xeb, 0xe6, 0xf1, 0xfc, 0x67, 0x6a, 0x7d, 0x70, 0x53, 0x5e, 0x49, 0x44,
+ 0x0f, 0x02, 0x15, 0x18, 0x3b, 0x36, 0x21, 0x2c, 0x0c, 0x01, 0x16, 0x1b,
+ 0x38, 0x35, 0x22, 0x2f, 0x64, 0x69, 0x7e, 0x73, 0x50, 0x5d, 0x4a, 0x47,
+ 0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3,
+ 0x80, 0x8d, 0x9a, 0x97
+ ], //*/ GDX = Gx(0xd),
+
+/*
+ GEX = [
+ 0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62,
+ 0x48, 0x46, 0x54, 0x5a, 0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca,
+ 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba, 0xdb, 0xd5, 0xc7, 0xc9,
+ 0xe3, 0xed, 0xff, 0xf1, 0xab, 0xa5, 0xb7, 0xb9, 0x93, 0x9d, 0x8f, 0x81,
+ 0x3b, 0x35, 0x27, 0x29, 0x03, 0x0d, 0x1f, 0x11, 0x4b, 0x45, 0x57, 0x59,
+ 0x73, 0x7d, 0x6f, 0x61, 0xad, 0xa3, 0xb1, 0xbf, 0x95, 0x9b, 0x89, 0x87,
+ 0xdd, 0xd3, 0xc1, 0xcf, 0xe5, 0xeb, 0xf9, 0xf7, 0x4d, 0x43, 0x51, 0x5f,
+ 0x75, 0x7b, 0x69, 0x67, 0x3d, 0x33, 0x21, 0x2f, 0x05, 0x0b, 0x19, 0x17,
+ 0x76, 0x78, 0x6a, 0x64, 0x4e, 0x40, 0x52, 0x5c, 0x06, 0x08, 0x1a, 0x14,
+ 0x3e, 0x30, 0x22, 0x2c, 0x96, 0x98, 0x8a, 0x84, 0xae, 0xa0, 0xb2, 0xbc,
+ 0xe6, 0xe8, 0xfa, 0xf4, 0xde, 0xd0, 0xc2, 0xcc, 0x41, 0x4f, 0x5d, 0x53,
+ 0x79, 0x77, 0x65, 0x6b, 0x31, 0x3f, 0x2d, 0x23, 0x09, 0x07, 0x15, 0x1b,
+ 0xa1, 0xaf, 0xbd, 0xb3, 0x99, 0x97, 0x85, 0x8b, 0xd1, 0xdf, 0xcd, 0xc3,
+ 0xe9, 0xe7, 0xf5, 0xfb, 0x9a, 0x94, 0x86, 0x88, 0xa2, 0xac, 0xbe, 0xb0,
+ 0xea, 0xe4, 0xf6, 0xf8, 0xd2, 0xdc, 0xce, 0xc0, 0x7a, 0x74, 0x66, 0x68,
+ 0x42, 0x4c, 0x5e, 0x50, 0x0a, 0x04, 0x16, 0x18, 0x32, 0x3c, 0x2e, 0x20,
+ 0xec, 0xe2, 0xf0, 0xfe, 0xd4, 0xda, 0xc8, 0xc6, 0x9c, 0x92, 0x80, 0x8e,
+ 0xa4, 0xaa, 0xb8, 0xb6, 0x0c, 0x02, 0x10, 0x1e, 0x34, 0x3a, 0x28, 0x26,
+ 0x7c, 0x72, 0x60, 0x6e, 0x44, 0x4a, 0x58, 0x56, 0x37, 0x39, 0x2b, 0x25,
+ 0x0f, 0x01, 0x13, 0x1d, 0x47, 0x49, 0x5b, 0x55, 0x7f, 0x71, 0x63, 0x6d,
+ 0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5,
+ 0x9f, 0x91, 0x83, 0x8d
+ ], //*/ GEX = Gx(0xe),
+
+ enc = function(string, pass, binary) {
+ // string, password in plaintext
+ var salt = randArr(8),
+ pbe = openSSLKey(s2a(pass, binary), salt),
+ key = pbe.key,
+ iv = pbe.iv,
+ cipherBlocks,
+ saltBlock = [[83, 97, 108, 116, 101, 100, 95, 95].concat(salt)];
+ string = s2a(string, binary);
+ cipherBlocks = rawEncrypt(string, key, iv);
+ // Spells out 'Salted__'
+ cipherBlocks = saltBlock.concat(cipherBlocks);
+ return Base64.encode(cipherBlocks);
+ },
+
+ dec = function(string, pass, binary) {
+ // string, password in plaintext
+ var cryptArr = Base64.decode(string),
+ salt = cryptArr.slice(8, 16),
+ pbe = openSSLKey(s2a(pass, binary), salt),
+ key = pbe.key,
+ iv = pbe.iv;
+ cryptArr = cryptArr.slice(16, cryptArr.length);
+ // Take off the Salted__ffeeddcc
+ string = rawDecrypt(cryptArr, key, iv, binary);
+ return string;
+ },
+
+ MD5 = function(numArr) {
+
+ function rotateLeft(lValue, iShiftBits) {
+ return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits));
+ }
+
+ function addUnsigned(lX, lY) {
+ var lX4,
+ lY4,
+ lX8,
+ lY8,
+ lResult;
+ lX8 = (lX & 0x80000000);
+ lY8 = (lY & 0x80000000);
+ lX4 = (lX & 0x40000000);
+ lY4 = (lY & 0x40000000);
+ lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF);
+ if (lX4 & lY4) {
+ return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
+ }
+ if (lX4 | lY4) {
+ if (lResult & 0x40000000) {
+ return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
+ } else {
+ return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
+ }
+ } else {
+ return (lResult ^ lX8 ^ lY8);
+ }
+ }
+
+ function f(x, y, z) {
+ return (x & y) | ((~x) & z);
+ }
+ function g(x, y, z) {
+ return (x & z) | (y & (~z));
+ }
+ function h(x, y, z) {
+ return (x ^ y ^ z);
+ }
+ function funcI(x, y, z) {
+ return (y ^ (x | (~z)));
+ }
+
+ function ff(a, b, c, d, x, s, ac) {
+ a = addUnsigned(a, addUnsigned(addUnsigned(f(b, c, d), x), ac));
+ return addUnsigned(rotateLeft(a, s), b);
+ }
+
+ function gg(a, b, c, d, x, s, ac) {
+ a = addUnsigned(a, addUnsigned(addUnsigned(g(b, c, d), x), ac));
+ return addUnsigned(rotateLeft(a, s), b);
+ }
+
+ function hh(a, b, c, d, x, s, ac) {
+ a = addUnsigned(a, addUnsigned(addUnsigned(h(b, c, d), x), ac));
+ return addUnsigned(rotateLeft(a, s), b);
+ }
+
+ function ii(a, b, c, d, x, s, ac) {
+ a = addUnsigned(a, addUnsigned(addUnsigned(funcI(b, c, d), x), ac));
+ return addUnsigned(rotateLeft(a, s), b);
+ }
+
+ function convertToWordArray(numArr) {
+ var lWordCount,
+ lMessageLength = numArr.length,
+ lNumberOfWords_temp1 = lMessageLength + 8,
+ lNumberOfWords_temp2 = (lNumberOfWords_temp1 - (lNumberOfWords_temp1 % 64)) / 64,
+ lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16,
+ lWordArray = [],
+ lBytePosition = 0,
+ lByteCount = 0;
+ while (lByteCount < lMessageLength) {
+ lWordCount = (lByteCount - (lByteCount % 4)) / 4;
+ lBytePosition = (lByteCount % 4) * 8;
+ lWordArray[lWordCount] = (lWordArray[lWordCount] | (numArr[lByteCount] << lBytePosition));
+ lByteCount++;
+ }
+ lWordCount = (lByteCount - (lByteCount % 4)) / 4;
+ lBytePosition = (lByteCount % 4) * 8;
+ lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition);
+ lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
+ lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
+ return lWordArray;
+ }
+
+ function wordToHex(lValue) {
+ var lByte,
+ lCount,
+ wordToHexArr = [];
+ for (lCount = 0; lCount <= 3; lCount++) {
+ lByte = (lValue >>> (lCount * 8)) & 255;
+ wordToHexArr = wordToHexArr.concat(lByte);
+ }
+ return wordToHexArr;
+ }
+
+ /*function utf8Encode(string) {
+ string = string.replace(/\r\n/g, "\n");
+ var utftext = "",
+ n,
+ c;
+
+ for (n = 0; n < string.length; n++) {
+
+ c = string.charCodeAt(n);
+
+ if (c < 128) {
+ utftext += String.fromCharCode(c);
+ }
+ else if ((c > 127) && (c < 2048)) {
+ utftext += String.fromCharCode((c >> 6) | 192);
+ utftext += String.fromCharCode((c & 63) | 128);
+ }
+ else {
+ utftext += String.fromCharCode((c >> 12) | 224);
+ utftext += String.fromCharCode(((c >> 6) & 63) | 128);
+ utftext += String.fromCharCode((c & 63) | 128);
+ }
+
+ }
+
+ return utftext;
+ }*/
+
+ var x = [],
+ k,
+ AA,
+ BB,
+ CC,
+ DD,
+ a,
+ b,
+ c,
+ d,
+ rnd = strhex('67452301efcdab8998badcfe10325476d76aa478e8c7b756242070dbc1bdceeef57c0faf4787c62aa8304613fd469501698098d88b44f7afffff5bb1895cd7be6b901122fd987193a679438e49b40821f61e2562c040b340265e5a51e9b6c7aad62f105d02441453d8a1e681e7d3fbc821e1cde6c33707d6f4d50d87455a14eda9e3e905fcefa3f8676f02d98d2a4c8afffa39428771f6816d9d6122fde5380ca4beea444bdecfa9f6bb4b60bebfbc70289b7ec6eaa127fad4ef308504881d05d9d4d039e6db99e51fa27cf8c4ac5665f4292244432aff97ab9423a7fc93a039655b59c38f0ccc92ffeff47d85845dd16fa87e4ffe2ce6e0a30143144e0811a1f7537e82bd3af2352ad7d2bbeb86d391',8);
+
+ x = convertToWordArray(numArr);
+
+ a = rnd[0];
+ b = rnd[1];
+ c = rnd[2];
+ d = rnd[3];
+
+ for (k = 0; k < x.length; k += 16) {
+ AA = a;
+ BB = b;
+ CC = c;
+ DD = d;
+ a = ff(a, b, c, d, x[k + 0], 7, rnd[4]);
+ d = ff(d, a, b, c, x[k + 1], 12, rnd[5]);
+ c = ff(c, d, a, b, x[k + 2], 17, rnd[6]);
+ b = ff(b, c, d, a, x[k + 3], 22, rnd[7]);
+ a = ff(a, b, c, d, x[k + 4], 7, rnd[8]);
+ d = ff(d, a, b, c, x[k + 5], 12, rnd[9]);
+ c = ff(c, d, a, b, x[k + 6], 17, rnd[10]);
+ b = ff(b, c, d, a, x[k + 7], 22, rnd[11]);
+ a = ff(a, b, c, d, x[k + 8], 7, rnd[12]);
+ d = ff(d, a, b, c, x[k + 9], 12, rnd[13]);
+ c = ff(c, d, a, b, x[k + 10], 17, rnd[14]);
+ b = ff(b, c, d, a, x[k + 11], 22, rnd[15]);
+ a = ff(a, b, c, d, x[k + 12], 7, rnd[16]);
+ d = ff(d, a, b, c, x[k + 13], 12, rnd[17]);
+ c = ff(c, d, a, b, x[k + 14], 17, rnd[18]);
+ b = ff(b, c, d, a, x[k + 15], 22, rnd[19]);
+ a = gg(a, b, c, d, x[k + 1], 5, rnd[20]);
+ d = gg(d, a, b, c, x[k + 6], 9, rnd[21]);
+ c = gg(c, d, a, b, x[k + 11], 14, rnd[22]);
+ b = gg(b, c, d, a, x[k + 0], 20, rnd[23]);
+ a = gg(a, b, c, d, x[k + 5], 5, rnd[24]);
+ d = gg(d, a, b, c, x[k + 10], 9, rnd[25]);
+ c = gg(c, d, a, b, x[k + 15], 14, rnd[26]);
+ b = gg(b, c, d, a, x[k + 4], 20, rnd[27]);
+ a = gg(a, b, c, d, x[k + 9], 5, rnd[28]);
+ d = gg(d, a, b, c, x[k + 14], 9, rnd[29]);
+ c = gg(c, d, a, b, x[k + 3], 14, rnd[30]);
+ b = gg(b, c, d, a, x[k + 8], 20, rnd[31]);
+ a = gg(a, b, c, d, x[k + 13], 5, rnd[32]);
+ d = gg(d, a, b, c, x[k + 2], 9, rnd[33]);
+ c = gg(c, d, a, b, x[k + 7], 14, rnd[34]);
+ b = gg(b, c, d, a, x[k + 12], 20, rnd[35]);
+ a = hh(a, b, c, d, x[k + 5], 4, rnd[36]);
+ d = hh(d, a, b, c, x[k + 8], 11, rnd[37]);
+ c = hh(c, d, a, b, x[k + 11], 16, rnd[38]);
+ b = hh(b, c, d, a, x[k + 14], 23, rnd[39]);
+ a = hh(a, b, c, d, x[k + 1], 4, rnd[40]);
+ d = hh(d, a, b, c, x[k + 4], 11, rnd[41]);
+ c = hh(c, d, a, b, x[k + 7], 16, rnd[42]);
+ b = hh(b, c, d, a, x[k + 10], 23, rnd[43]);
+ a = hh(a, b, c, d, x[k + 13], 4, rnd[44]);
+ d = hh(d, a, b, c, x[k + 0], 11, rnd[45]);
+ c = hh(c, d, a, b, x[k + 3], 16, rnd[46]);
+ b = hh(b, c, d, a, x[k + 6], 23, rnd[47]);
+ a = hh(a, b, c, d, x[k + 9], 4, rnd[48]);
+ d = hh(d, a, b, c, x[k + 12], 11, rnd[49]);
+ c = hh(c, d, a, b, x[k + 15], 16, rnd[50]);
+ b = hh(b, c, d, a, x[k + 2], 23, rnd[51]);
+ a = ii(a, b, c, d, x[k + 0], 6, rnd[52]);
+ d = ii(d, a, b, c, x[k + 7], 10, rnd[53]);
+ c = ii(c, d, a, b, x[k + 14], 15, rnd[54]);
+ b = ii(b, c, d, a, x[k + 5], 21, rnd[55]);
+ a = ii(a, b, c, d, x[k + 12], 6, rnd[56]);
+ d = ii(d, a, b, c, x[k + 3], 10, rnd[57]);
+ c = ii(c, d, a, b, x[k + 10], 15, rnd[58]);
+ b = ii(b, c, d, a, x[k + 1], 21, rnd[59]);
+ a = ii(a, b, c, d, x[k + 8], 6, rnd[60]);
+ d = ii(d, a, b, c, x[k + 15], 10, rnd[61]);
+ c = ii(c, d, a, b, x[k + 6], 15, rnd[62]);
+ b = ii(b, c, d, a, x[k + 13], 21, rnd[63]);
+ a = ii(a, b, c, d, x[k + 4], 6, rnd[64]);
+ d = ii(d, a, b, c, x[k + 11], 10, rnd[65]);
+ c = ii(c, d, a, b, x[k + 2], 15, rnd[66]);
+ b = ii(b, c, d, a, x[k + 9], 21, rnd[67]);
+ a = addUnsigned(a, AA);
+ b = addUnsigned(b, BB);
+ c = addUnsigned(c, CC);
+ d = addUnsigned(d, DD);
+ }
+
+ return wordToHex(a).concat(wordToHex(b), wordToHex(c), wordToHex(d));
+ },
+
+ encString = function(plaintext, key, iv) {
+ var i;
+ plaintext = s2a(plaintext);
+
+ key = s2a(key);
+ for (i=key.length; i<32; i++){
+ key[i] = 0;
+ }
+
+ if (iv === undefined) {
+ // TODO: This is not defined anywhere... commented out...
+ // iv = genIV();
+ } else {
+ iv = s2a(iv);
+ for (i=iv.length; i<16; i++){
+ iv[i] = 0;
+ }
+ }
+
+ var ct = rawEncrypt(plaintext, key, iv);
+ var ret = [iv];
+ for (i=0; i<ct.length; i++){
+ ret[ret.length] = ct[i];
+ }
+ return Base64.encode(ret);
+ },
+
+ decString = function(ciphertext, key) {
+ var tmp = Base64.decode(ciphertext);
+ var iv = tmp.slice(0, 16);
+ var ct = tmp.slice(16, tmp.length);
+ var i;
+
+ key = s2a(key);
+ for (i=key.length; i<32; i++){
+ key[i] = 0;
+ }
+
+ var pt = rawDecrypt(ct, key, iv, false);
+ return pt;
+ },
+
+ Base64 = (function(){
+ // Takes a Nx16x1 byte array and converts it to Base64
+ var _chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
+ chars = _chars.split(''),
+
+ encode = function(b, withBreaks) {
+ var flatArr = [],
+ b64 = '',
+ i,
+ broken_b64,
+ totalChunks = Math.floor(b.length * 16 / 3);
+ for (i = 0; i < b.length * 16; i++) {
+ flatArr.push(b[Math.floor(i / 16)][i % 16]);
+ }
+ for (i = 0; i < flatArr.length; i = i + 3) {
+ b64 += chars[flatArr[i] >> 2];
+ b64 += chars[((flatArr[i] & 3) << 4) | (flatArr[i + 1] >> 4)];
+ if ( flatArr[i + 1] !== undefined ) {
+ b64 += chars[((flatArr[i + 1] & 15) << 2) | (flatArr[i + 2] >> 6)];
+ } else {
+ b64 += '=';
+ }
+ if ( flatArr[i + 2] !== undefined ) {
+ b64 += chars[flatArr[i + 2] & 63];
+ } else {
+ b64 += '=';
+ }
+ }
+ // OpenSSL is super particular about line breaks
+ broken_b64 = b64.slice(0, 64) + '\n';
+ for (i = 1; i < (Math.ceil(b64.length / 64)); i++) {
+ broken_b64 += b64.slice(i * 64, i * 64 + 64) + (Math.ceil(b64.length / 64) === i + 1 ? '': '\n');
+ }
+ return broken_b64;
+ },
+
+ decode = function(string) {
+ string = string.replace(/\n/g, '');
+ var flatArr = [],
+ c = [],
+ b = [],
+ i;
+ for (i = 0; i < string.length; i = i + 4) {
+ c[0] = _chars.indexOf(string.charAt(i));
+ c[1] = _chars.indexOf(string.charAt(i + 1));
+ c[2] = _chars.indexOf(string.charAt(i + 2));
+ c[3] = _chars.indexOf(string.charAt(i + 3));
+
+ b[0] = (c[0] << 2) | (c[1] >> 4);
+ b[1] = ((c[1] & 15) << 4) | (c[2] >> 2);
+ b[2] = ((c[2] & 3) << 6) | c[3];
+ flatArr.push(b[0], b[1], b[2]);
+ }
+ flatArr = flatArr.slice(0, flatArr.length - (flatArr.length % 16));
+ return flatArr;
+ };
+
+ //internet explorer
+ if(typeof Array.indexOf === "function") {
+ _chars = chars;
+ }
+
+ /*
+ //other way to solve internet explorer problem
+ if(!Array.indexOf){
+ Array.prototype.indexOf = function(obj){
+ for(var i=0; i<this.length; i++){
+ if(this[i]===obj){
+ return i;
+ }
+ }
+ return -1;
+ }
+ }
+ */
+
+
+ return {
+ "encode": encode,
+ "decode": decode
+ };
+ })();
+
+ return {
+ "size": size,
+ "h2a":h2a,
+ "expandKey":expandKey,
+ "encryptBlock":encryptBlock,
+ "decryptBlock":decryptBlock,
+ "Decrypt":Decrypt,
+ "s2a":s2a,
+ "rawEncrypt":rawEncrypt,
+ "rawDecrypt":rawDecrypt,
+ "dec":dec,
+ "openSSLKey":openSSLKey,
+ "a2h":a2h,
+ "enc":enc,
+ "Hash":{"MD5":MD5},
+ "Base64":Base64
+ };
+
+})); \ No newline at end of file
diff --git a/libgpl/http_request/class.http.php b/libgpl/http_request/class.http.php
new file mode 100644
index 0000000..a41d070
--- /dev/null
+++ b/libgpl/http_request/class.http.php
@@ -0,0 +1,1190 @@
+<?php
+
+/**
+ * HTTP Class
+ *
+ * This is a wrapper HTTP class that uses either cURL or fsockopen to
+ * harvest resources from web. This can be used with scripts that need
+ * a way to communicate with various APIs who support REST.
+ *
+ * @author Md Emran Hasan <phpfour@gmail.com>
+ * @package HTTP Library
+ * @copyright 2007-2008 Md Emran Hasan
+ * @link http://www.phpfour.com/lib/http
+ * @since Version 0.1
+ */
+
+class MyRCHttp
+{
+ /**
+ * Contains the target URL
+ *
+ * @var string
+ */
+ var $target;
+
+ /**
+ * Contains the target host
+ *
+ * @var string
+ */
+ var $host;
+
+ /**
+ * Contains the target port
+ *
+ * @var integer
+ */
+ var $port;
+
+ /**
+ * Contains the target path
+ *
+ * @var string
+ */
+ var $path;
+
+ /**
+ * Contains the target schema
+ *
+ * @var string
+ */
+ var $schema;
+
+ /**
+ * Contains the http method (GET or POST)
+ *
+ * @var string
+ */
+ var $method;
+
+ /**
+ * Contains the parameters for request
+ *
+ * @var array
+ */
+ var $params;
+
+ /**
+ * Contains the cookies for request
+ *
+ * @var array
+ */
+ var $cookies;
+
+ /**
+ * Contains the cookies retrieved from response
+ *
+ * @var array
+ */
+ var $_cookies;
+
+ /**
+ * Number of seconds to timeout
+ *
+ * @var integer
+ */
+ var $timeout;
+
+ /**
+ * Whether to use cURL or not
+ *
+ * @var boolean
+ */
+ var $useCurl;
+
+ /**
+ * Contains the referrer URL
+ *
+ * @var string
+ */
+ var $referrer;
+
+ /**
+ * Contains the User agent string
+ *
+ * @var string
+ */
+ var $userAgent;
+
+ /**
+ * Contains the cookie path (to be used with cURL)
+ *
+ * @var string
+ */
+ var $cookiePath;
+
+ /**
+ * Whether to use cookie at all
+ *
+ * @var boolean
+ */
+ var $useCookie;
+
+ /**
+ * Whether to store cookie for subsequent requests
+ *
+ * @var boolean
+ */
+ var $saveCookie;
+
+ /**
+ * Contains the Username (for authentication)
+ *
+ * @var string
+ */
+ var $username;
+
+ /**
+ * Contains the Password (for authentication)
+ *
+ * @var string
+ */
+ var $password;
+
+ /**
+ * Contains the fetched web source
+ *
+ * @var string
+ */
+ var $result;
+
+ /**
+ * Contains the last headers
+ *
+ * @var string
+ */
+ var $headers;
+
+ /**
+ * Contains the last call's http status code
+ *
+ * @var string
+ */
+ var $status;
+
+ /**
+ * Whether to follow http redirect or not
+ *
+ * @var boolean
+ */
+ var $redirect;
+
+ /**
+ * The maximum number of redirect to follow
+ *
+ * @var integer
+ */
+ var $maxRedirect;
+
+ /**
+ * The current number of redirects
+ *
+ * @var integer
+ */
+ var $curRedirect;
+
+ /**
+ * Contains any error occurred
+ *
+ * @var string
+ */
+ var $error;
+
+ /**
+ * Store the next token
+ *
+ * @var string
+ */
+ var $nextToken;
+
+ /**
+ * Whether to keep debug messages
+ *
+ * @var boolean
+ */
+ var $debug;
+
+ /**
+ * Stores the debug messages
+ *
+ * @var array
+ * @todo will keep debug messages
+ */
+ var $debugMsg;
+
+ /**
+ * Constructor for initializing the class with default values.
+ *
+ * @return void
+ */
+ function Http()
+ {
+ $this->clear();
+ }
+
+ /**
+ * Initialize preferences
+ *
+ * This function will take an associative array of config values and
+ * will initialize the class variables using them.
+ *
+ * Example use:
+ *
+ * <pre>
+ * $httpConfig['method'] = 'GET';
+ * $httpConfig['target'] = 'http://www.somedomain.com/index.html';
+ * $httpConfig['referrer'] = 'http://www.somedomain.com';
+ * $httpConfig['user_agent'] = 'My Crawler';
+ * $httpConfig['timeout'] = '30';
+ * $httpConfig['params'] = array('var1' => 'testvalue', 'var2' => 'somevalue');
+ *
+ * $http = new Http();
+ * $http->initialize($httpConfig);
+ * </pre>
+ *
+ * @param array Config values as associative array
+ * @return void
+ */
+ function initialize($config = array())
+ {
+ $this->clear();
+ foreach ($config as $key => $val)
+ {
+ if (isset($this->$key))
+ {
+ $method = 'set' . ucfirst(str_replace('_', '', $key));
+
+ if (method_exists($this, $method))
+ {
+ $this->$method($val);
+ }
+ else
+ {
+ $this->$key = $val;
+ }
+ }
+ }
+ }
+
+ /**
+ * Clear Everything
+ *
+ * Clears all the properties of the class and sets the object to
+ * the beginning state. Very handy if you are doing subsequent calls
+ * with different data.
+ *
+ * @return void
+ */
+ function clear()
+ {
+ // Set the request defaults
+ $this->host = '';
+ $this->port = 0;
+ $this->path = '';
+ $this->target = '';
+ $this->method = 'GET';
+ $this->schema = 'http';
+ $this->params = array();
+ $this->headers = array();
+ $this->cookies = array();
+ $this->_cookies = array();
+
+ // Set the config details
+ $this->debug = FALSE;
+ $this->error = '';
+ $this->status = 0;
+ $this->timeout = '25';
+ $this->useCurl = TRUE;
+ $this->referrer = '';
+ $this->username = '';
+ $this->password = '';
+ $this->redirect = TRUE;
+
+ // Set the cookie and agent defaults
+ $this->nextToken = '';
+ $this->useCookie = TRUE;
+ $this->saveCookie = TRUE;
+ $this->maxRedirect = 3;
+ $this->cookiePath = 'cookie.txt';
+ $this->userAgent = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.6) Gecko/20070725 Firefox/2.0.0.9';
+ }
+
+ /**
+ * Set target URL
+ *
+ * @param string URL of target resource
+ * @return void
+ */
+ function setTarget($url)
+ {
+ if ($url)
+ {
+ $this->target = $url;
+ }
+ }
+
+ /**
+ * Set http method
+ *
+ * @param string HTTP method to use (GET or POST)
+ * @return void
+ */
+ function setMethod($method)
+ {
+ if ($method == 'GET' || $method == 'POST')
+ {
+ $this->method = $method;
+ }
+ }
+
+ /**
+ * Set referrer URL
+ *
+ * @param string URL of referrer page
+ * @return void
+ */
+ function setReferrer($referrer)
+ {
+ if ($referrer)
+ {
+ $this->referrer = $referrer;
+ }
+ }
+
+ /**
+ * Set User agent string
+ *
+ * @param string Full user agent string
+ * @return void
+ */
+ function setUseragent($agent)
+ {
+ if ($agent)
+ {
+ $this->userAgent = $agent;
+ }
+ }
+
+ /**
+ * Set timeout of execution
+ *
+ * @param integer Timeout delay in seconds
+ * @return void
+ */
+ function setTimeout($seconds)
+ {
+ if ($seconds > 0)
+ {
+ $this->timeout = $seconds;
+ }
+ }
+
+ /**
+ * Set cookie path (cURL only)
+ *
+ * @param string File location of cookiejar
+ * @return void
+ */
+ function setCookiepath($path)
+ {
+ if ($path)
+ {
+ $this->cookiePath = $path;
+ }
+ }
+
+ /**
+ * Set request parameters
+ *
+ * @param array All the parameters for GET or POST
+ * @return void
+ */
+ function setParams($dataArray)
+ {
+ if (is_array($dataArray))
+ {
+ $this->params = array_merge($this->params, $dataArray);
+ }
+ }
+
+ /**
+ * Set basic http authentication realm
+ *
+ * @param string Username for authentication
+ * @param string Password for authentication
+ * @return void
+ */
+ function setAuth($username, $password)
+ {
+ if (!empty($username) && !empty($password))
+ {
+ $this->username = $username;
+ $this->password = $password;
+ }
+ }
+
+ /**
+ * Set maximum number of redirection to follow
+ *
+ * @param integer Maximum number of redirects
+ * @return void
+ */
+ function setMaxredirect($value)
+ {
+ if (!empty($value))
+ {
+ $this->maxRedirect = $value;
+ }
+ }
+
+ /**
+ * Add request parameters
+ *
+ * @param string Name of the parameter
+ * @param string Value of the parameter
+ * @return void
+ */
+ function addParam($name, $value)
+ {
+ if (!empty($name) && !empty($value))
+ {
+ $this->params[$name] = $value;
+ }
+ }
+
+ /**
+ * Add a cookie to the request
+ *
+ * @param string Name of cookie
+ * @param string Value of cookie
+ * @return void
+ */
+ function addCookie($name, $value)
+ {
+ if (!empty($name) && !empty($value))
+ {
+ $this->cookies[$name] = $value;
+ }
+ }
+
+ /**
+ * Whether to use cURL or not
+ *
+ * @param boolean Whether to use cURL or not
+ * @return void
+ */
+ function useCurl($value = TRUE)
+ {
+ if (is_bool($value))
+ {
+ $this->useCurl = $value;
+ }
+ }
+
+ /**
+ * Whether to use cookies or not
+ *
+ * @param boolean Whether to use cookies or not
+ * @return void
+ */
+ function useCookie($value = TRUE)
+ {
+ if (is_bool($value))
+ {
+ $this->useCookie = $value;
+ }
+ }
+
+ /**
+ * Whether to save persistent cookies in subsequent calls
+ *
+ * @param boolean Whether to save persistent cookies or not
+ * @return void
+ */
+ function saveCookie($value = TRUE)
+ {
+ if (is_bool($value))
+ {
+ $this->saveCookie = $value;
+ }
+ }
+
+ /**
+ * Whether to follow HTTP redirects
+ *
+ * @param boolean Whether to follow HTTP redirects or not
+ * @return void
+ */
+ function followRedirects($value = TRUE)
+ {
+ if (is_bool($value))
+ {
+ $this->redirect = $value;
+ }
+ }
+
+ /**
+ * Get execution result body
+ *
+ * @return string output of execution
+ */
+ function getResult()
+ {
+ return $this->result;
+ }
+
+ /**
+ * Get execution result headers
+ *
+ * @return array last headers of execution
+ */
+ function getHeaders()
+ {
+ return $this->headers;
+ }
+
+ /**
+ * Get execution status code
+ *
+ * @return integer last http status code
+ */
+ function getStatus()
+ {
+ return $this->status;
+ }
+
+ /**
+ * Get last execution error
+ *
+ * @return string last error message (if any)
+ */
+ function getError()
+ {
+ return $this->error;
+ }
+
+ /**
+ * Execute a HTTP request
+ *
+ * Executes the http fetch using all the set properties. Intellegently
+ * switch to fsockopen if cURL is not present. And be smart to follow
+ * redirects (if asked so).
+ *
+ * @param string URL of the target page (optional)
+ * @param string URL of the referrer page (optional)
+ * @param string The http method (GET or POST) (optional)
+ * @param array Parameter array for GET or POST (optional)
+ * @return string Response body of the target page
+ */
+ function execute($target = '', $referrer = '', $method = '', $data = array())
+ {
+ // Populate the properties
+ $this->target = ($target) ? $target : $this->target;
+ $this->method = ($method) ? $method : $this->method;
+
+ $this->referrer = ($referrer) ? $referrer : $this->referrer;
+
+ // Add the new params
+ if (is_array($data) && count($data) > 0)
+ {
+ $this->params = array_merge($this->params, $data);
+ }
+
+ // Process data, if presented
+ if(is_array($this->params) && count($this->params) > 0)
+ {
+ // Get a blank slate
+ $tempString = array();
+
+ // Convert data array into a query string (ie animal=dog&sport=baseball)
+ foreach ($this->params as $key => $value)
+ {
+ if(strlen(trim($value))>0)
+ {
+ $tempString[] = $key . "=" . urlencode($value);
+ }
+ }
+
+ $queryString = join('&', $tempString);
+ }
+
+ // If cURL is not installed, we'll force fscokopen
+ $this->useCurl = $this->useCurl && in_array('curl', get_loaded_extensions());
+
+ // GET method configuration
+ if($this->method == 'GET')
+ {
+ if(isset($queryString))
+ {
+ $this->target = $this->target . "?" . $queryString;
+ }
+ }
+
+ // Parse target URL
+ $urlParsed = parse_url($this->target);
+
+ // Handle SSL connection request
+ if ($urlParsed['scheme'] == 'https')
+ {
+ $this->host = 'ssl://' . $urlParsed['host'];
+ $this->port = ($this->port != 0) ? $this->port : 443;
+ }
+ else
+ {
+ $this->host = $urlParsed['host'];
+ $this->port = ($this->port != 0) ? $this->port : 80;
+ }
+
+ // Finalize the target path
+ $this->path = (isset($urlParsed['path']) ? $urlParsed['path'] : '/') . (isset($urlParsed['query']) ? '?' . $urlParsed['query'] : '');
+ $this->schema = $urlParsed['scheme'];
+
+ // Pass the requred cookies
+ $this->_passCookies();
+
+ // Process cookies, if requested
+ if(is_array($this->cookies) && count($this->cookies) > 0)
+ {
+ // Get a blank slate
+ $tempString = array();
+
+ // Convert cookiesa array into a query string (ie animal=dog&sport=baseball)
+ foreach ($this->cookies as $key => $value)
+ {
+ if(strlen(trim($value)) > 0)
+ {
+ $tempString[] = $key . "=" . urlencode($value);
+ }
+ }
+
+ $cookieString = join('&', $tempString);
+ }
+
+ // Do we need to use cURL
+ if ($this->useCurl)
+ {
+ // Initialize PHP cURL handle
+ $ch = curl_init();
+
+ // GET method configuration
+ if($this->method == 'GET')
+ {
+ curl_setopt ($ch, CURLOPT_HTTPGET, TRUE);
+ curl_setopt ($ch, CURLOPT_POST, FALSE);
+ }
+ // POST method configuration
+ else
+ {
+ if(isset($queryString))
+ {
+ curl_setopt ($ch, CURLOPT_POSTFIELDS, $queryString);
+ }
+
+ curl_setopt ($ch, CURLOPT_POST, TRUE);
+ curl_setopt ($ch, CURLOPT_HTTPGET, FALSE);
+ }
+
+ // Basic Authentication configuration
+ if ($this->username && $this->password)
+ {
+ curl_setopt($ch, CURLOPT_USERPWD, $this->username . ':' . $this->password);
+ }
+
+ // Custom cookie configuration
+ if($this->useCookie && isset($cookieString))
+ {
+ curl_setopt ($ch, CURLOPT_COOKIE, $cookieString);
+ }
+
+ curl_setopt($ch, CURLOPT_HEADER, TRUE); // No need of headers
+ curl_setopt($ch, CURLOPT_NOBODY, FALSE); // Return body
+
+ curl_setopt($ch, CURLOPT_COOKIEJAR, $this->cookiePath); // Cookie management.
+ curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout); // Timeout
+ curl_setopt($ch, CURLOPT_USERAGENT, $this->userAgent); // Webbot name
+ curl_setopt($ch, CURLOPT_URL, $this->target); // Target site
+ curl_setopt($ch, CURLOPT_REFERER, $this->referrer); // Referer value
+
+ curl_setopt($ch, CURLOPT_VERBOSE, FALSE); // Minimize logs
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); // No certificate
+ if(!ini_get('safe_mode') && !ini_get('open_basedir')){
+ curl_setopt($ch, CURLOPT_FOLLOWLOCATION, $this->redirect); // Follow redirects
+ }
+ curl_setopt($ch, CURLOPT_MAXREDIRS, $this->maxRedirect); // Limit redirections to four
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); // Return in string
+
+ // Get the target contents
+ $content = curl_exec($ch);
+ $contentArray = explode("\r\n\r\n", $content);
+
+ // Get the request info
+ $status = curl_getinfo($ch);
+
+ // Store the contents
+ $this->result = $contentArray[count($contentArray) - 1];
+
+ // Parse the headers
+ $this->_parseHeaders($contentArray[count($contentArray) - 2]);
+
+ // Store the error (is any)
+ $this->_setError(curl_error($ch));
+
+ // Close PHP cURL handle
+ curl_close($ch);
+ }
+ else
+ {
+ // Get a file pointer
+ $filePointer = fsockopen($this->host, $this->port, $errorNumber, $errorString, $this->timeout);
+
+ // We have an error if pointer is not there
+ if (!$filePointer)
+ {
+ $this->_setError('Failed opening http socket connection: ' . $errorString . ' (' . $errorNumber . ')');
+ return FALSE;
+ }
+
+ // Set http headers with host, user-agent and content type
+ $requestHeader = $this->method . " " . $this->path . " HTTP/1.1\r\n";
+ $requestHeader .= "Host: " . $urlParsed['host'] . "\r\n";
+ $requestHeader .= "User-Agent: " . $this->userAgent . "\r\n";
+ $requestHeader .= "Content-Type: application/x-www-form-urlencoded\r\n";
+
+ // Specify the custom cookies
+ if ($this->useCookie && $cookieString != '')
+ {
+ $requestHeader.= "Cookie: " . $cookieString . "\r\n";
+ }
+
+ // POST method configuration
+ if ($this->method == "POST")
+ {
+ $requestHeader.= "Content-Length: " . strlen($queryString) . "\r\n";
+ }
+
+ // Specify the referrer
+ if ($this->referrer != '')
+ {
+ $requestHeader.= "Referer: " . $this->referrer . "\r\n";
+ }
+
+ // Specify http authentication (basic)
+ if ($this->username && $this->password)
+ {
+ $requestHeader.= "Authorization: Basic " . base64_encode($this->username . ':' . $this->password) . "\r\n";
+ }
+
+ $requestHeader.= "Connection: close\r\n\r\n";
+
+ // POST method configuration
+ if ($this->method == "POST")
+ {
+ $requestHeader .= $queryString;
+ }
+
+ // We're ready to launch
+ fwrite($filePointer, $requestHeader);
+
+ // Clean the slate
+ $responseHeader = '';
+ $responseContent = '';
+
+ // 3...2...1...Launch !
+ do
+ {
+ $responseHeader .= fread($filePointer, 1);
+ }
+ while (!preg_match('/\\r\\n\\r\\n$/', $responseHeader));
+
+ // Parse the headers
+ $this->_parseHeaders($responseHeader);
+
+ // Do we have a 301/302 redirect ?
+ if (($this->status == '301' || $this->status == '302') && $this->redirect == TRUE)
+ {
+ if ($this->curRedirect < $this->maxRedirect)
+ {
+ // Let's find out the new redirect URL
+ $newUrlParsed = parse_url($this->headers['location']);
+
+ if ($newUrlParsed['host'])
+ {
+ $newTarget = $this->headers['location'];
+ }
+ else
+ {
+ $newTarget = $this->schema . '://' . $this->host . '/' . $this->headers['location'];
+ }
+
+ // Reset some of the properties
+ $this->port = 0;
+ $this->status = 0;
+ $this->params = array();
+ $this->method = 'GET';
+ $this->referrer = $this->target;
+
+ // Increase the redirect counter
+ $this->curRedirect++;
+
+ // Let's go, go, go !
+ $this->result = $this->execute($newTarget);
+ }
+ else
+ {
+ $this->_setError('Too many redirects.');
+ return FALSE;
+ }
+ }
+ else
+ {
+ // Nope...so lets get the rest of the contents (non-chunked)
+ if ($this->headers['transfer-encoding'] != 'chunked')
+ {
+ while (!feof($filePointer))
+ {
+ $responseContent .= fgets($filePointer, 128);
+ }
+ }
+ else
+ {
+ // Get the contents (chunked)
+ while ($chunkLength = hexdec(fgets($filePointer)))
+ {
+ $responseContentChunk = '';
+ $readLength = 0;
+
+ while ($readLength < $chunkLength)
+ {
+ $responseContentChunk .= fread($filePointer, $chunkLength - $readLength);
+ $readLength = strlen($responseContentChunk);
+ }
+
+ $responseContent .= $responseContentChunk;
+ fgets($filePointer);
+ }
+ }
+
+ // Store the target contents
+ $this->result = chop($responseContent);
+ }
+ }
+
+ // There it is! We have it!! Return to base !!!
+ return $this->result;
+ }
+
+ /**
+ * Parse Headers (internal)
+ *
+ * Parse the response headers and store them for finding the resposne
+ * status, redirection location, cookies, etc.
+ *
+ * @param string Raw header response
+ * @return void
+ * @access private
+ */
+ function _parseHeaders($responseHeader)
+ {
+ // Break up the headers
+ $headers = explode("\r\n", $responseHeader);
+
+ // Clear the header array
+ $this->_clearHeaders();
+
+ // Get response status
+ if($this->status == 0)
+ {
+
+ // Oooops!
+ if(!preg_match("/^http\/[0-9]+\\.[0-9]+[ \t]+([0-9]+)[ \t]*(.*)\$/i", $headers[0], $matches))
+ {
+ $this->_setError('Unexpected HTTP response status');
+ return FALSE;
+ }
+
+ // Gotcha!
+ $this->status = $matches[1];
+ array_shift($headers);
+ }
+
+ // Prepare all the other headers
+ foreach ($headers as $header)
+ {
+ // Get name and value
+ $headerName = strtolower($this->_tokenize($header, ':'));
+ $headerValue = trim(chop($this->_tokenize("\r\n")));
+
+ // If its already there, then add as an array. Otherwise, just keep there
+ if(isset($this->headers[$headerName]))
+ {
+ if(gettype($this->headers[$headerName]) == "string")
+ {
+ $this->headers[$headerName] = array($this->headers[$headerName]);
+ }
+
+ $this->headers[$headerName][] = $headerValue;
+ }
+ else
+ {
+ $this->headers[$headerName] = $headerValue;
+ }
+ }
+
+ // Save cookies if asked
+ if ($this->saveCookie && isset($this->headers['set-cookie']))
+ {
+ $this->_parseCookie();
+ }
+ }
+
+ /**
+ * Clear the headers array (internal)
+ *
+ * @return void
+ * @access private
+ */
+ function _clearHeaders()
+ {
+ $this->headers = array();
+ }
+
+ /**
+ * Parse Cookies (internal)
+ *
+ * Parse the set-cookie headers from response and add them for inclusion.
+ *
+ * @return void
+ * @access private
+ */
+ function _parseCookie()
+ {
+ // Get the cookie header as array
+ if(gettype($this->headers['set-cookie']) == "array")
+ {
+ $cookieHeaders = $this->headers['set-cookie'];
+ }
+ else
+ {
+ $cookieHeaders = array($this->headers['set-cookie']);
+ }
+
+ // Loop through the cookies
+ for ($cookie = 0; $cookie < count($cookieHeaders); $cookie++)
+ {
+ $cookieName = trim($this->_tokenize($cookieHeaders[$cookie], "="));
+ $cookieValue = $this->_tokenize(";");
+
+ $urlParsed = parse_url($this->target);
+
+ $domain = $urlParsed['host'];
+ $secure = '0';
+
+ $path = "/";
+ $expires = "";
+
+ while(($name = trim(urldecode($this->_tokenize("=")))) != "")
+ {
+ $value = urldecode($this->_tokenize(";"));
+
+ switch($name)
+ {
+ case "path" : $path = $value; break;
+ case "domain" : $domain = $value; break;
+ case "secure" : $secure = ($value != '') ? '1' : '0'; break;
+ }
+ }
+
+ $this->_setCookie($cookieName, $cookieValue, $expires, $path , $domain, $secure);
+ }
+ }
+
+ /**
+ * Set cookie (internal)
+ *
+ * Populate the internal _cookies array for future inclusion in
+ * subsequent requests. This actually validates and then populates
+ * the object properties with a dimensional entry for cookie.
+ *
+ * @param string Cookie name
+ * @param string Cookie value
+ * @param string Cookie expire date
+ * @param string Cookie path
+ * @param string Cookie domain
+ * @param string Cookie security (0 = non-secure, 1 = secure)
+ * @return void
+ * @access private
+ */
+ function _setCookie($name, $value, $expires = "" , $path = "/" , $domain = "" , $secure = 0)
+ {
+ if(strlen($name) == 0)
+ {
+ return($this->_setError("No valid cookie name was specified."));
+ }
+
+ if(strlen($path) == 0 || strcmp($path[0], "/"))
+ {
+ return($this->_setError("$path is not a valid path for setting cookie $name."));
+ }
+
+ if($domain == "" || !strpos($domain, ".", $domain[0] == "." ? 1 : 0))
+ {
+ return($this->_setError("$domain is not a valid domain for setting cookie $name."));
+ }
+
+ $domain = strtolower($domain);
+
+ if(!strcmp($domain[0], "."))
+ {
+ $domain = substr($domain, 1);
+ }
+
+ $name = $this->_encodeCookie($name, true);
+ $value = $this->_encodeCookie($value, false);
+
+ $secure = intval($secure);
+
+ $this->_cookies[] = array( "name" => $name,
+ "value" => $value,
+ "domain" => $domain,
+ "path" => $path,
+ "expires" => $expires,
+ "secure" => $secure
+ );
+ }
+
+ /**
+ * Encode cookie name/value (internal)
+ *
+ * @param string Value of cookie to encode
+ * @param string Name of cookie to encode
+ * @return string encoded string
+ * @access private
+ */
+ function _encodeCookie($value, $name)
+ {
+ return($name ? str_replace("=", "%25", $value) : str_replace(";", "%3B", $value));
+ }
+
+ /**
+ * Pass Cookies (internal)
+ *
+ * Get the cookies which are valid for the current request. Checks
+ * domain and path to decide the return.
+ *
+ * @return void
+ * @access private
+ */
+ function _passCookies()
+ {
+ if (is_array($this->_cookies) && count($this->_cookies) > 0)
+ {
+ $urlParsed = parse_url($this->target);
+ $tempCookies = array();
+
+ foreach($this->_cookies as $cookie)
+ {
+ if ($this->_domainMatch($urlParsed['host'], $cookie['domain']) && (0 === strpos($urlParsed['path'], $cookie['path']))
+ && (empty($cookie['secure']) || $urlParsed['protocol'] == 'https'))
+ {
+ $tempCookies[$cookie['name']][strlen($cookie['path'])] = $cookie['value'];
+ }
+ }
+
+ // cookies with longer paths go first
+ foreach ($tempCookies as $name => $values)
+ {
+ krsort($values);
+ foreach ($values as $value)
+ {
+ $this->addCookie($name, $value);
+ }
+ }
+ }
+ }
+
+ /**
+ * Checks if cookie domain matches a request host (internal)
+ *
+ * Cookie domain can begin with a dot, it also must contain at least
+ * two dots.
+ *
+ * @param string Request host
+ * @param string Cookie domain
+ * @return bool Match success
+ * @access private
+ */
+ function _domainMatch($requestHost, $cookieDomain)
+ {
+ if ('.' != $cookieDomain{0})
+ {
+ return $requestHost == $cookieDomain;
+ }
+ elseif (substr_count($cookieDomain, '.') < 2)
+ {
+ return false;
+ }
+ else
+ {
+ return substr('.'. $requestHost, - strlen($cookieDomain)) == $cookieDomain;
+ }
+ }
+
+ /**
+ * Tokenize String (internal)
+ *
+ * Tokenize string for various internal usage. Omit the second parameter
+ * to tokenize the previous string that was provided in the prior call to
+ * the function.
+ *
+ * @param string The string to tokenize
+ * @param string The seperator to use
+ * @return string Tokenized string
+ * @access private
+ */
+ function _tokenize($string, $separator = '')
+ {
+ if(!strcmp($separator, ''))
+ {
+ $separator = $string;
+ $string = $this->nextToken;
+ }
+
+ for($character = 0; $character < strlen($separator); $character++)
+ {
+ if(gettype($position = strpos($string, $separator[$character])) == "integer")
+ {
+ $found = (isset($found) ? min($found, $position) : $position);
+ }
+ }
+
+ if(isset($found))
+ {
+ $this->nextToken = substr($string, $found + 1);
+ return(substr($string, 0, $found));
+ }
+ else
+ {
+ $this->nextToken = '';
+ return($string);
+ }
+ }
+
+ /**
+ * Set error message (internal)
+ *
+ * @param string Error message
+ * @return string Error message
+ * @access private
+ */
+ function _setError($error)
+ {
+ if ($error != '')
+ {
+ $this->error = $error;
+ return $error;
+ }
+ }
+}
+
+?> \ No newline at end of file
diff --git a/libgpl/ical/ical_sync.php b/libgpl/ical/ical_sync.php
new file mode 100644
index 0000000..b513574
--- /dev/null
+++ b/libgpl/ical/ical_sync.php
@@ -0,0 +1,144 @@
+<?php
+/**
+ * iCalendar sync for the Calendar plugin
+ *
+ * @version @package_version@
+ * @author Daniel Morlock <daniel.morlock@awesome-it.de>
+ *
+ * Copyright (C) 2013, Awesome IT GbR <info@awesome-it.de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+class ical_sync
+{
+ const ACTION_NONE = 1;
+ const ACTION_UPDATE = 2;
+ const ACTION_CREATE = 4;
+
+ private $cal_id = null;
+ private $url = null;
+ private $user = null;
+ private $pass = null;
+ private $ical = null;
+
+ public $sync = 0;
+
+ /**
+ * Default constructor for calendar synchronization adapter.
+ *
+ * @param int Calendar id.
+ * @param array Hash array with ical properties:
+ * url: Absolute URL to iCAL resource.
+ */
+ public function __construct($cal_id, $props)
+ {
+ $this->ical = libcalendaring::get_ical();
+ $this->cal_id = $cal_id;
+
+ $this->url = $props["url"];
+ $this->user = isset($props["user"]) ? $props["user"] : null;
+ $this->pass = isset($props["pass"]) ? $props["pass"] : null;
+ $this->sync = isset($props["sync"]) ? $props["sync"] : 0;
+ }
+
+ /**
+ * Determines whether current calendar needs to be synced.
+ *
+ * @return True if the current calendar needs to be synced, false otherwise.
+ */
+ public function is_synced()
+ {
+ // No change to check that so far.
+ return false;
+ }
+
+ /**
+ * Fetches events from iCAL resource and returns updates.
+ *
+ * @param array List of local events.
+ * @return array Tuple containing the following lists:
+ *
+ * Hash list for iCAL events to be created or to be updated with the keys:
+ * local_event: The local event in case of an update.
+ * remote_event: The current event retrieved from caldav server.
+ *
+ * A list of event ids that are in sync.
+ */
+ public function get_updates($events)
+ {
+ $context = null;
+ if($this->user != null && $this->pass != null)
+ {
+ $context = stream_context_create(array(
+ 'http' => array(
+ 'header' => "Authorization: Basic " . base64_encode("$this->user:$this->pass") . "\r\n" .
+ "User-Agent: PHP/" . PHP_VERSION
+ )
+ ));
+ }
+
+ $vcal = file_get_contents($this->url, false, $context);
+ $charset = 'UTF-8';
+ foreach($http_response_header as $c => $h)
+ {
+ if(stristr($h, 'content-type') && stristr($h, 'charset'))
+ {
+ preg_match('@Content-Type:\s+([\w/+]+)(;\s+charset=(\S+))?@i', $h, $matches);
+ if(isset($matches[3]))
+ {
+ $charset = strtoupper(trim($matches[3]));
+ }
+ }
+ if(stristr($h, 'content-encoding') && stristr($h, 'gzip'))
+ {
+ $vcal = gzinflate(substr($vcal, 10, -8));
+ }
+ }
+
+ $updates = array();
+ $synced = array();
+ if($vcal !== false)
+ {
+ // Hash existing events by uid.
+ $events_hash = array();
+ foreach($events as $event) {
+ $events_hash[$event['uid']] = $event;
+ }
+ foreach ($this->ical->import($vcal, $charset, false, false) as $remote_event) {
+ // Attach remote event to current calendar
+ $remote_event["calendar"] = $this->cal_id;
+
+ $local_event = null;
+ if($events_hash[$remote_event['uid']])
+ $local_event = $events_hash[$remote_event['uid']];
+
+ // Determine whether event don't need an update.
+ if($local_event && $local_event["changed"] >= $remote_event["changed"])
+ {
+ array_push($synced, $local_event["id"]);
+ }
+ else
+ {
+ array_push($updates, array('local_event' => $local_event, 'remote_event' => $remote_event));
+ }
+ }
+ }
+
+ return array($updates, $synced);
+ }
+}
+
+;
+?> \ No newline at end of file
diff --git a/libgpl/jquery_migrate/jquery.migrate.js b/libgpl/jquery_migrate/jquery.migrate.js
new file mode 100644
index 0000000..5e73954
--- /dev/null
+++ b/libgpl/jquery_migrate/jquery.migrate.js
@@ -0,0 +1,521 @@
+/*!
+ * jQuery Migrate - v1.2.1 - 2013-05-08
+ * https://github.com/jquery/jquery-migrate
+ * Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors; Licensed MIT
+ */
+(function( jQuery, window, undefined ) {
+// See http://bugs.jquery.com/ticket/13335
+// "use strict";
+
+
+var warnedAbout = {};
+
+// List of warnings already given; public read only
+jQuery.migrateWarnings = [];
+
+// Set to true to prevent console output; migrateWarnings still maintained
+jQuery.migrateMute = true;
+
+// Show a message on the console so devs know we're active
+if ( !jQuery.migrateMute && window.console && window.console.log ) {
+ window.console.log("JQMIGRATE: Logging is active");
+}
+
+// Set to false to disable traces that appear with warnings
+if ( jQuery.migrateTrace === undefined ) {
+ jQuery.migrateTrace = true;
+}
+
+// Forget any warnings we've already given; public
+jQuery.migrateReset = function() {
+ warnedAbout = {};
+ jQuery.migrateWarnings.length = 0;
+};
+
+function migrateWarn( msg) {
+ var console = window.console;
+ if ( !warnedAbout[ msg ] ) {
+ warnedAbout[ msg ] = true;
+ jQuery.migrateWarnings.push( msg );
+ if ( console && console.warn && !jQuery.migrateMute ) {
+ console.warn( "JQMIGRATE: " + msg );
+ if ( jQuery.migrateTrace && console.trace ) {
+ console.trace();
+ }
+ }
+ }
+}
+
+function migrateWarnProp( obj, prop, value, msg ) {
+ if ( Object.defineProperty ) {
+ // On ES5 browsers (non-oldIE), warn if the code tries to get prop;
+ // allow property to be overwritten in case some other plugin wants it
+ try {
+ Object.defineProperty( obj, prop, {
+ configurable: true,
+ enumerable: true,
+ get: function() {
+ migrateWarn( msg );
+ return value;
+ },
+ set: function( newValue ) {
+ migrateWarn( msg );
+ value = newValue;
+ }
+ });
+ return;
+ } catch( err ) {
+ // IE8 is a dope about Object.defineProperty, can't warn there
+ }
+ }
+
+ // Non-ES5 (or broken) browser; just set the property
+ jQuery._definePropertyBroken = true;
+ obj[ prop ] = value;
+}
+
+if ( document.compatMode === "BackCompat" ) {
+ // jQuery has never supported or tested Quirks Mode
+ migrateWarn( "jQuery is not compatible with Quirks Mode" );
+}
+
+
+var attrFn = jQuery( "<input/>", { size: 1 } ).attr("size") && jQuery.attrFn,
+ oldAttr = jQuery.attr,
+ valueAttrGet = jQuery.attrHooks.value && jQuery.attrHooks.value.get ||
+ function() { return null; },
+ valueAttrSet = jQuery.attrHooks.value && jQuery.attrHooks.value.set ||
+ function() { return undefined; },
+ rnoType = /^(?:input|button)$/i,
+ rnoAttrNodeType = /^[238]$/,
+ rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
+ ruseDefault = /^(?:checked|selected)$/i;
+
+// jQuery.attrFn
+migrateWarnProp( jQuery, "attrFn", attrFn || {}, "jQuery.attrFn is deprecated" );
+
+jQuery.attr = function( elem, name, value, pass ) {
+ var lowerName = name.toLowerCase(),
+ nType = elem && elem.nodeType;
+
+ if ( pass ) {
+ // Since pass is used internally, we only warn for new jQuery
+ // versions where there isn't a pass arg in the formal params
+ if ( oldAttr.length < 4 ) {
+ migrateWarn("jQuery.fn.attr( props, pass ) is deprecated");
+ }
+ if ( elem && !rnoAttrNodeType.test( nType ) &&
+ (attrFn ? name in attrFn : jQuery.isFunction(jQuery.fn[name])) ) {
+ return jQuery( elem )[ name ]( value );
+ }
+ }
+
+ // Warn if user tries to set `type`, since it breaks on IE 6/7/8; by checking
+ // for disconnected elements we don't warn on $( "<button>", { type: "button" } ).
+ if ( name === "type" && value !== undefined && rnoType.test( elem.nodeName ) && elem.parentNode ) {
+ migrateWarn("Can't change the 'type' of an input or button in IE 6/7/8");
+ }
+
+ // Restore boolHook for boolean property/attribute synchronization
+ if ( !jQuery.attrHooks[ lowerName ] && rboolean.test( lowerName ) ) {
+ jQuery.attrHooks[ lowerName ] = {
+ get: function( elem, name ) {
+ // Align boolean attributes with corresponding properties
+ // Fall back to attribute presence where some booleans are not supported
+ var attrNode,
+ property = jQuery.prop( elem, name );
+ return property === true || typeof property !== "boolean" &&
+ ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ?
+
+ name.toLowerCase() :
+ undefined;
+ },
+ set: function( elem, value, name ) {
+ var propName;
+ if ( value === false ) {
+ // Remove boolean attributes when set to false
+ jQuery.removeAttr( elem, name );
+ } else {
+ // value is true since we know at this point it's type boolean and not false
+ // Set boolean attributes to the same name and set the DOM property
+ propName = jQuery.propFix[ name ] || name;
+ if ( propName in elem ) {
+ // Only set the IDL specifically if it already exists on the element
+ elem[ propName ] = true;
+ }
+
+ elem.setAttribute( name, name.toLowerCase() );
+ }
+ return name;
+ }
+ };
+
+ // Warn only for attributes that can remain distinct from their properties post-1.9
+ if ( ruseDefault.test( lowerName ) ) {
+ migrateWarn( "jQuery.fn.attr('" + lowerName + "') may use property instead of attribute" );
+ }
+ }
+
+ return oldAttr.call( jQuery, elem, name, value );
+};
+
+// attrHooks: value
+jQuery.attrHooks.value = {
+ get: function( elem, name ) {
+ var nodeName = ( elem.nodeName || "" ).toLowerCase();
+ if ( nodeName === "button" ) {
+ return valueAttrGet.apply( this, arguments );
+ }
+ if ( nodeName !== "input" && nodeName !== "option" ) {
+ migrateWarn("jQuery.fn.attr('value') no longer gets properties");
+ }
+ return name in elem ?
+ elem.value :
+ null;
+ },
+ set: function( elem, value ) {
+ var nodeName = ( elem.nodeName || "" ).toLowerCase();
+ if ( nodeName === "button" ) {
+ return valueAttrSet.apply( this, arguments );
+ }
+ if ( nodeName !== "input" && nodeName !== "option" ) {
+ migrateWarn("jQuery.fn.attr('value', val) no longer sets properties");
+ }
+ // Does not return so that setAttribute is also used
+ elem.value = value;
+ }
+};
+
+
+var matched, browser,
+ oldInit = jQuery.fn.init,
+ oldParseJSON = jQuery.parseJSON,
+ // Note: XSS check is done below after string is trimmed
+ rquickExpr = /^([^<]*)(<[\w\W]+>)([^>]*)$/;
+
+// $(html) "looks like html" rule change
+jQuery.fn.init = function( selector, context, rootjQuery ) {
+ var match;
+
+ if ( selector && typeof selector === "string" && !jQuery.isPlainObject( context ) &&
+ (match = rquickExpr.exec( jQuery.trim( selector ) )) && match[ 0 ] ) {
+ // This is an HTML string according to the "old" rules; is it still?
+ if ( selector.charAt( 0 ) !== "<" ) {
+ migrateWarn("$(html) HTML strings must start with '<' character");
+ }
+ if ( match[ 3 ] ) {
+ migrateWarn("$(html) HTML text after last tag is ignored");
+ }
+ // Consistently reject any HTML-like string starting with a hash (#9521)
+ // Note that this may break jQuery 1.6.x code that otherwise would work.
+ if ( match[ 0 ].charAt( 0 ) === "#" ) {
+ migrateWarn("HTML string cannot start with a '#' character");
+ jQuery.error("JQMIGRATE: Invalid selector string (XSS)");
+ }
+ // Now process using loose rules; let pre-1.8 play too
+ if ( context && context.context ) {
+ // jQuery object as context; parseHTML expects a DOM object
+ context = context.context;
+ }
+ if ( jQuery.parseHTML ) {
+ return oldInit.call( this, jQuery.parseHTML( match[ 2 ], context, true ),
+ context, rootjQuery );
+ }
+ }
+ return oldInit.apply( this, arguments );
+};
+jQuery.fn.init.prototype = jQuery.fn;
+
+// Let $.parseJSON(falsy_value) return null
+jQuery.parseJSON = function( json ) {
+ if ( !json && json !== null ) {
+ migrateWarn("jQuery.parseJSON requires a valid JSON string");
+ return null;
+ }
+ return oldParseJSON.apply( this, arguments );
+};
+
+jQuery.uaMatch = function( ua ) {
+ ua = ua.toLowerCase();
+
+ var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) ||
+ /(webkit)[ \/]([\w.]+)/.exec( ua ) ||
+ /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
+ /(msie) ([\w.]+)/.exec( ua ) ||
+ ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ||
+ [];
+
+ return {
+ browser: match[ 1 ] || "",
+ version: match[ 2 ] || "0"
+ };
+};
+
+// Don't clobber any existing jQuery.browser in case it's different
+if ( !jQuery.browser ) {
+ matched = jQuery.uaMatch( navigator.userAgent );
+ browser = {};
+
+ if ( matched.browser ) {
+ browser[ matched.browser ] = true;
+ browser.version = matched.version;
+ }
+
+ // Chrome is Webkit, but Webkit is also Safari.
+ if ( browser.chrome ) {
+ browser.webkit = true;
+ } else if ( browser.webkit ) {
+ browser.safari = true;
+ }
+
+ jQuery.browser = browser;
+}
+
+// Warn if the code tries to get jQuery.browser
+migrateWarnProp( jQuery, "browser", jQuery.browser, "jQuery.browser is deprecated" );
+
+jQuery.sub = function() {
+ function jQuerySub( selector, context ) {
+ return new jQuerySub.fn.init( selector, context );
+ }
+ jQuery.extend( true, jQuerySub, this );
+ jQuerySub.superclass = this;
+ jQuerySub.fn = jQuerySub.prototype = this();
+ jQuerySub.fn.constructor = jQuerySub;
+ jQuerySub.sub = this.sub;
+ jQuerySub.fn.init = function init( selector, context ) {
+ if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
+ context = jQuerySub( context );
+ }
+
+ return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
+ };
+ jQuerySub.fn.init.prototype = jQuerySub.fn;
+ var rootjQuerySub = jQuerySub(document);
+ migrateWarn( "jQuery.sub() is deprecated" );
+ return jQuerySub;
+};
+
+
+// Ensure that $.ajax gets the new parseJSON defined in core.js
+jQuery.ajaxSetup({
+ converters: {
+ "text json": jQuery.parseJSON
+ }
+});
+
+
+var oldFnData = jQuery.fn.data;
+
+jQuery.fn.data = function( name ) {
+ var ret, evt,
+ elem = this[0];
+
+ // Handles 1.7 which has this behavior and 1.8 which doesn't
+ if ( elem && name === "events" && arguments.length === 1 ) {
+ ret = jQuery.data( elem, name );
+ evt = jQuery._data( elem, name );
+ if ( ( ret === undefined || ret === evt ) && evt !== undefined ) {
+ migrateWarn("Use of jQuery.fn.data('events') is deprecated");
+ return evt;
+ }
+ }
+ return oldFnData.apply( this, arguments );
+};
+
+
+var rscriptType = /\/(java|ecma)script/i,
+ oldSelf = jQuery.fn.andSelf || jQuery.fn.addBack;
+
+jQuery.fn.andSelf = function() {
+ migrateWarn("jQuery.fn.andSelf() replaced by jQuery.fn.addBack()");
+ return oldSelf.apply( this, arguments );
+};
+
+// Since jQuery.clean is used internally on older versions, we only shim if it's missing
+if ( !jQuery.clean ) {
+ jQuery.clean = function( elems, context, fragment, scripts ) {
+ // Set context per 1.8 logic
+ context = context || document;
+ context = !context.nodeType && context[0] || context;
+ context = context.ownerDocument || context;
+
+ migrateWarn("jQuery.clean() is deprecated");
+
+ var i, elem, handleScript, jsTags,
+ ret = [];
+
+ jQuery.merge( ret, jQuery.buildFragment( elems, context ).childNodes );
+
+ // Complex logic lifted directly from jQuery 1.8
+ if ( fragment ) {
+ // Special handling of each script element
+ handleScript = function( elem ) {
+ // Check if we consider it executable
+ if ( !elem.type || rscriptType.test( elem.type ) ) {
+ // Detach the script and store it in the scripts array (if provided) or the fragment
+ // Return truthy to indicate that it has been handled
+ return scripts ?
+ scripts.push( elem.parentNode ? elem.parentNode.removeChild( elem ) : elem ) :
+ fragment.appendChild( elem );
+ }
+ };
+
+ for ( i = 0; (elem = ret[i]) != null; i++ ) {
+ // Check if we're done after handling an executable script
+ if ( !( jQuery.nodeName( elem, "script" ) && handleScript( elem ) ) ) {
+ // Append to fragment and handle embedded scripts
+ fragment.appendChild( elem );
+ if ( typeof elem.getElementsByTagName !== "undefined" ) {
+ // handleScript alters the DOM, so use jQuery.merge to ensure snapshot iteration
+ jsTags = jQuery.grep( jQuery.merge( [], elem.getElementsByTagName("script") ), handleScript );
+
+ // Splice the scripts into ret after their former ancestor and advance our index beyond them
+ ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );
+ i += jsTags.length;
+ }
+ }
+ }
+ }
+
+ return ret;
+ };
+}
+
+var eventAdd = jQuery.event.add,
+ eventRemove = jQuery.event.remove,
+ eventTrigger = jQuery.event.trigger,
+ oldToggle = jQuery.fn.toggle,
+ oldLive = jQuery.fn.live,
+ oldDie = jQuery.fn.die,
+ ajaxEvents = "ajaxStart|ajaxStop|ajaxSend|ajaxComplete|ajaxError|ajaxSuccess",
+ rajaxEvent = new RegExp( "\\b(?:" + ajaxEvents + ")\\b" ),
+ rhoverHack = /(?:^|\s)hover(\.\S+|)\b/,
+ hoverHack = function( events ) {
+ if ( typeof( events ) !== "string" || jQuery.event.special.hover ) {
+ return events;
+ }
+ if ( rhoverHack.test( events ) ) {
+ migrateWarn("'hover' pseudo-event is deprecated, use 'mouseenter mouseleave'");
+ }
+ return events && events.replace( rhoverHack, "mouseenter$1 mouseleave$1" );
+ };
+
+// Event props removed in 1.9, put them back if needed; no practical way to warn them
+if ( jQuery.event.props && jQuery.event.props[ 0 ] !== "attrChange" ) {
+ jQuery.event.props.unshift( "attrChange", "attrName", "relatedNode", "srcElement" );
+}
+
+// Undocumented jQuery.event.handle was "deprecated" in jQuery 1.7
+if ( jQuery.event.dispatch ) {
+ migrateWarnProp( jQuery.event, "handle", jQuery.event.dispatch, "jQuery.event.handle is undocumented and deprecated" );
+}
+
+// Support for 'hover' pseudo-event and ajax event warnings
+jQuery.event.add = function( elem, types, handler, data, selector ){
+ if ( elem !== document && rajaxEvent.test( types ) ) {
+ migrateWarn( "AJAX events should be attached to document: " + types );
+ }
+ eventAdd.call( this, elem, hoverHack( types || "" ), handler, data, selector );
+};
+jQuery.event.remove = function( elem, types, handler, selector, mappedTypes ){
+ eventRemove.call( this, elem, hoverHack( types ) || "", handler, selector, mappedTypes );
+};
+
+jQuery.fn.error = function() {
+ var args = Array.prototype.slice.call( arguments, 0);
+ migrateWarn("jQuery.fn.error() is deprecated");
+ args.splice( 0, 0, "error" );
+ if ( arguments.length ) {
+ return this.bind.apply( this, args );
+ }
+ // error event should not bubble to window, although it does pre-1.7
+ this.triggerHandler.apply( this, args );
+ return this;
+};
+
+jQuery.fn.toggle = function( fn, fn2 ) {
+
+ // Don't mess with animation or css toggles
+ if ( !jQuery.isFunction( fn ) || !jQuery.isFunction( fn2 ) ) {
+ return oldToggle.apply( this, arguments );
+ }
+ migrateWarn("jQuery.fn.toggle(handler, handler...) is deprecated");
+
+ // Save reference to arguments for access in closure
+ var args = arguments,
+ guid = fn.guid || jQuery.guid++,
+ i = 0,
+ toggler = function( event ) {
+ // Figure out which function to execute
+ var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i;
+ jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 );
+
+ // Make sure that clicks stop
+ event.preventDefault();
+
+ // and execute the function
+ return args[ lastToggle ].apply( this, arguments ) || false;
+ };
+
+ // link all the functions, so any of them can unbind this click handler
+ toggler.guid = guid;
+ while ( i < args.length ) {
+ args[ i++ ].guid = guid;
+ }
+
+ return this.click( toggler );
+};
+
+jQuery.fn.live = function( types, data, fn ) {
+ migrateWarn("jQuery.fn.live() is deprecated");
+ if ( oldLive ) {
+ return oldLive.apply( this, arguments );
+ }
+ jQuery( this.context ).on( types, this.selector, data, fn );
+ return this;
+};
+
+jQuery.fn.die = function( types, fn ) {
+ migrateWarn("jQuery.fn.die() is deprecated");
+ if ( oldDie ) {
+ return oldDie.apply( this, arguments );
+ }
+ jQuery( this.context ).off( types, this.selector || "**", fn );
+ return this;
+};
+
+// Turn global events into document-triggered events
+jQuery.event.trigger = function( event, data, elem, onlyHandlers ){
+ if ( !elem && !rajaxEvent.test( event ) ) {
+ migrateWarn( "Global events are undocumented and deprecated" );
+ }
+ return eventTrigger.call( this, event, data, elem || document, onlyHandlers );
+};
+jQuery.each( ajaxEvents.split("|"),
+ function( _, name ) {
+ jQuery.event.special[ name ] = {
+ setup: function() {
+ var elem = this;
+
+ // The document needs no shimming; must be !== for oldIE
+ if ( elem !== document ) {
+ jQuery.event.add( document, name + "." + jQuery.guid, function() {
+ jQuery.event.trigger( name, null, elem, true );
+ });
+ jQuery._data( this, name, jQuery.guid++ );
+ }
+ return false;
+ },
+ teardown: function() {
+ if ( this !== document ) {
+ jQuery.event.remove( document, name + "." + jQuery._data( this, name ) );
+ }
+ return false;
+ }
+ };
+ }
+);
+
+
+})( jQuery, window ); \ No newline at end of file
diff --git a/libgpl/libcalendaring/libcalendaring.js b/libgpl/libcalendaring/libcalendaring.js
new file mode 100644
index 0000000..00878be
--- /dev/null
+++ b/libgpl/libcalendaring/libcalendaring.js
@@ -0,0 +1,676 @@
+/**
+ * Basic Javascript utilities for calendar-related plugins
+ *
+ * @version @package_version@
+ * @author Thomas Bruederli <bruederli@kolabsys.com>
+ *
+ * Copyright (C) 2012, Kolab Systems AG <contact@kolabsys.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+function rcube_libcalendaring(settings)
+{
+ // member vars
+ this.settings = settings;
+ this.alarm_ids = [];
+ this.alarm_dialog = null;
+ this.snooze_popup = null;
+ this.dismiss_link = null;
+
+ // private vars
+ var me = this;
+ var gmt_offset = (new Date().getTimezoneOffset() / -60) - (settings.timezone || 0) - (settings.dst || 0);
+ var client_timezone = new Date().getTimezoneOffset();
+
+ // general datepicker settings
+ var datepicker_settings = {
+ // translate from fullcalendar format to datepicker format
+ dateFormat: settings.date_format ? settings.date_format.replace(/M/g, 'm').replace(/mmmmm/, 'MM').replace(/mmm/, 'M').replace(/dddd/, 'DD').replace(/ddd/, 'D').replace(/yy/g, 'y') : 'yy-mm-dd',
+ firstDay : settings.first_day,
+ dayNamesMin: settings.days_short,
+ monthNames: settings.months,
+ monthNamesShort: settings.months,
+ changeMonth: false,
+ showOtherMonths: true,
+ selectOtherMonths: true
+ };
+
+
+ /**
+ * Quote html entities
+ */
+ var Q = this.quote_html = function(str)
+ {
+ return String(str).replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
+ };
+
+ /**
+ * Create a nice human-readable string for the date/time range
+ */
+ this.event_date_text = function(event)
+ {
+ if (!event.start)
+ return '';
+ if (!event.end)
+ event.end = event.start;
+
+ var fromto, duration = event.end.getTime() / 1000 - event.start.getTime() / 1000;
+ if (event.allDay && !event.allDayfake) {
+ fromto = this.format_datetime(event.start, 1)
+ + (duration > 86400 || event.start.getDay() != event.end.getDay() ? ' &mdash; ' + this.format_datetime(event.end, 1) : '');
+ }
+ else if (duration < 86400 && event.start.getDay() == event.end.getDay()) {
+ fromto = this.format_datetime(event.start, 0)
+ + (duration > 0 ? ' &mdash; ' + this.format_datetime(event.end, 2) : '');
+ }
+ else {
+ fromto = this.format_datetime(event.start, 0)
+ + (duration > 0 ? ' &mdash; ' + this.format_datetime(event.end, 0) : '');
+ }
+
+ return fromto;
+ };
+
+
+ /**
+ * From time and date strings to a real date object
+ */
+ this.parse_datetime = function(time, date)
+ {
+ // we use the utility function from datepicker to parse dates
+ var date = date ? $.datepicker.parseDate(datepicker_settings.dateFormat, date, datepicker_settings) : new Date();
+
+ var time_arr = time.replace(/\s*[ap][.m]*/i, '').replace(/0([0-9])/g, '$1').split(/[:.]/);
+ if (!isNaN(time_arr[0])) {
+ date.setHours(time_arr[0]);
+ if (time.match(/p[.m]*/i) && date.getHours() < 12)
+ date.setHours(parseInt(time_arr[0]) + 12);
+ else if (time.match(/a[.m]*/i) && date.getHours() == 12)
+ date.setHours(0);
+ }
+ if (!isNaN(time_arr[1]))
+ date.setMinutes(time_arr[1]);
+
+ return date;
+ }
+
+ /**
+ * Convert an ISO 8601 formatted date string from the server into a Date object.
+ * Timezone information will be ignored, the server already provides dates in user's timezone.
+ */
+ this.parseISO8601 = function(s)
+ {
+ // force d to be on check's YMD, for daylight savings purposes
+ var fixDate = function(d, check) {
+ if (+d) { // prevent infinite looping on invalid dates
+ while (d.getDate() != check.getDate()) {
+ d.setTime(+d + (d < check ? 1 : -1) * 3600000);
+ }
+ }
+ }
+
+ // derived from http://delete.me.uk/2005/03/iso8601.html
+ var m = s && s.match(/^([0-9]{4})(-([0-9]{2})(-([0-9]{2})([T ]([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?(Z|(([-+])([0-9]{2})(:?([0-9]{2}))?))?)?)?)?$/);
+ if (!m) {
+ return null;
+ }
+
+ var date = new Date(m[1], 0, 1),
+ check = new Date(m[1], 0, 1, 9, 0);
+ if (m[3]) {
+ date.setMonth(m[3] - 1);
+ check.setMonth(m[3] - 1);
+ }
+ if (m[5]) {
+ date.setDate(m[5]);
+ check.setDate(m[5]);
+ }
+ fixDate(date, check);
+ if (m[7]) {
+ date.setHours(m[7]);
+ }
+ if (m[8]) {
+ date.setMinutes(m[8]);
+ }
+ if (m[10]) {
+ date.setSeconds(m[10]);
+ }
+ if (m[12]) {
+ date.setMilliseconds(Number("0." + m[12]) * 1000);
+ }
+ fixDate(date, check);
+
+ return date;
+ }
+
+ /**
+ * Turn the given date into an ISO 8601 date string understandable by PHPs strtotime()
+ */
+ this.date2ISO8601 = function(date)
+ {
+ var zeropad = function(num) { return (num < 10 ? '0' : '') + num; };
+
+ return date.getFullYear() + '-' + zeropad(date.getMonth()+1) + '-' + zeropad(date.getDate())
+ + 'T' + zeropad(date.getHours()) + ':' + zeropad(date.getMinutes()) + ':' + zeropad(date.getSeconds());
+ };
+
+ /**
+ * Format the given date object according to user's prefs
+ */
+ this.format_datetime = function(date, mode)
+ {
+ var res = '';
+ if (!mode || mode == 1)
+ res += $.datepicker.formatDate(datepicker_settings.dateFormat, date, datepicker_settings);
+ if (!mode)
+ res += ' ';
+ if (!mode || mode == 2)
+ res += this.format_time(date);
+
+ return res;
+ }
+
+ /**
+ * Clone from fullcalendar.js
+ */
+ this.format_time = function(date)
+ {
+ var zeroPad = function(n) { return (n < 10 ? '0' : '') + n; }
+ var formatters = {
+ s : function(d) { return d.getSeconds() },
+ ss : function(d) { return zeroPad(d.getSeconds()) },
+ m : function(d) { return d.getMinutes() },
+ mm : function(d) { return zeroPad(d.getMinutes()) },
+ h : function(d) { return d.getHours() % 12 || 12 },
+ hh : function(d) { return zeroPad(d.getHours() % 12 || 12) },
+ H : function(d) { return d.getHours() },
+ HH : function(d) { return zeroPad(d.getHours()) },
+ t : function(d) { return d.getHours() < 12 ? 'a' : 'p' },
+ tt : function(d) { return d.getHours() < 12 ? 'am' : 'pm' },
+ T : function(d) { return d.getHours() < 12 ? 'A' : 'P' },
+ TT : function(d) { return d.getHours() < 12 ? 'AM' : 'PM' }
+ };
+
+ var i, i2, c, formatter, res = '', format = settings['time_format'];
+ for (i=0; i < format.length; i++) {
+ c = format.charAt(i);
+ for (i2=Math.min(i+2, format.length); i2 > i; i2--) {
+ if (formatter = formatters[format.substring(i, i2)]) {
+ res += formatter(date);
+ i = i2 - 1;
+ break;
+ }
+ }
+ if (i2 == i) {
+ res += c;
+ }
+ }
+
+ return res;
+ }
+
+ /**
+ * Convert the given Date object into a unix timestamp respecting browser's and user's timezone settings
+ */
+ this.date2unixtime = function(date)
+ {
+ var dst_offset = (client_timezone - date.getTimezoneOffset()) * 60; // adjust DST offset
+ return Math.round(date.getTime()/1000 + gmt_offset * 3600 + dst_offset);
+ }
+
+ /**
+ * Turn a unix timestamp value into a Date object
+ */
+ this.fromunixtime = function(ts)
+ {
+ ts -= gmt_offset * 3600;
+ var date = new Date(ts * 1000),
+ dst_offset = (client_timezone - date.getTimezoneOffset()) * 60;
+ if (dst_offset) // adjust DST offset
+ date.setTime((ts + 3600) * 1000);
+ return date;
+ }
+
+ /**
+ * Simple plaintext to HTML converter, makig URLs clickable
+ */
+ this.text2html = function(str, maxlen, maxlines)
+ {
+ var html = Q(String(str));
+
+ // limit visible text length
+ if (maxlen) {
+ var morelink = ' <a href="#more" onclick="$(this).hide().next().show();return false" class="morelink">'+rcmail.gettext('showmore','libcalendaring')+'</a><span style="display:none">',
+ lines = html.split(/\r?\n/),
+ words, out = '', len = 0;
+
+ for (var i=0; i < lines.length; i++) {
+ len += lines[i].length;
+ if (maxlines && i == maxlines - 1) {
+ out += lines[i] + '\n' + morelink;
+ maxlen = html.length * 2;
+ }
+ else if (len > maxlen) {
+ len = out.length;
+ words = lines[i].split(' ');
+ for (var j=0; j < words.length; j++) {
+ len += words[j].length + 1;
+ out += words[j] + ' ';
+ if (len > maxlen) {
+ out += morelink;
+ maxlen = html.length * 2;
+ }
+ }
+ out += '\n';
+ }
+ else
+ out += lines[i] + '\n';
+ }
+
+ if (maxlen > str.length)
+ out += '</span>';
+
+ html = out;
+ }
+
+ // simple link parser (similar to rcube_string_replacer class in PHP)
+ var utf_domain = '[^?&@"\'/\\(\\)\\s\\r\\t\\n]+\\.([^\x00-\x2f\x3b-\x40\x5b-\x60\x7b-\x7f]{2,}|xn--[a-z0-9]{2,})';
+ var url1 = '.:;,', url2 = 'a-z0-9%=#@+?&/_~\\[\\]-';
+ var link_pattern = new RegExp('([hf]t+ps?://)('+utf_domain+'(['+url1+']?['+url2+']+)*)?', 'ig');
+ var mailto_pattern = new RegExp('([^\\s\\n\\(\\);]+@'+utf_domain+')', 'ig');
+
+ return html
+ .replace(link_pattern, '<a href="$1$2" class="extlink" target="_blank">$1$2</a>')
+ .replace(mailto_pattern, '<a href="mailto:$1">$1</a>')
+ .replace(/(mailto:)([^"]+)"/g, '$1$2" onclick="rcmail.command(\'compose\', \'$2\');return false"')
+ .replace(/\n/g, "<br/>");
+ };
+
+ this.init_alarms_edit = function(prefix)
+ {
+ // register events on alarm fields
+ $(prefix+' select.edit-alarm-type').change(function(){
+ $(this).parent().find('span.edit-alarm-values')[(this.selectedIndex>0?'show':'hide')]();
+ });
+ $(prefix+' select.edit-alarm-offset').change(function(){
+ var mode = $(this).val() == '@' ? 'show' : 'hide';
+ $(this).parent().find('.edit-alarm-date, .edit-alarm-time')[mode]();
+ $(this).parent().find('.edit-alarm-value').prop('disabled', mode == 'show');
+ });
+
+ $(prefix+' .edit-alarm-date').datepicker(datepicker_settings);
+ }
+
+
+ /***** Alarms handling *****/
+
+ /**
+ * Display a notification for the given pending alarms
+ */
+ this.display_alarms = function(alarms)
+ {
+ if (parent.tabbed && !self.tabbed) { // Mod by Rosali (tabbed plugin compatibility)
+ return;
+ }
+
+ var focused = $(':focus');
+ var is_minimized = false;
+
+ // clear old alert first
+ if (this.alarm_dialog) {
+ // Begin Mod by Rosali (remove previously added divs)
+ this.alarm_dialog.dialog('destroy').remove();
+ if($('#dialog-extend-fixed-container').get(0)){
+ is_minimized = true;
+ }
+ $('#dialog-extend-fixed-container').remove();
+ // End Mod by Rosali
+ }
+
+ this.alarm_dialog = $('<div>').attr('id', 'alarm-display');
+
+ var actions, adismiss, asnooze, alarm, html, event_ids = [];
+ for (var i=0; i < alarms.length; i++) {
+ alarm = alarms[i];
+ alarm.start = this.parseISO8601(alarm.start);
+ alarm.end = this.parseISO8601(alarm.end);
+ event_ids.push(alarm.id);
+
+ html = '<h3 class="event-title">' + Q(alarm.title) + '</h3>';
+ html += '<div class="event-section">' + Q(alarm.location || '') + '</div>';
+ html += '<div class="event-section">' + Q(this.event_date_text(alarm)) + '</div>';
+
+ adismiss = $('<a href="#" class="alarm-action-dismiss"></a>').html(rcmail.gettext('dismiss','libcalendaring')).click(function(){
+ me.dismiss_link = $(this);
+ me.dismiss_alarm(me.dismiss_link.data('id'), 0);
+ });
+ asnooze = $('<a href="#" class="alarm-action-snooze"></a>').html(rcmail.gettext('snooze','libcalendaring')).click(function(e){
+ me.snooze_dropdown($(this));
+ e.stopPropagation();
+ return false;
+ });
+ actions = $('<div>').addClass('alarm-actions').append(adismiss.data('id', alarm.id)).append(asnooze.data('id', alarm.id));
+
+ $('<div>').addClass('alarm-item').html(html).append(actions).appendTo(this.alarm_dialog);
+ }
+
+ var buttons = {};
+ buttons[rcmail.gettext('dismissall','libcalendaring')] = function() {
+ // submit dismissed event_ids to server
+ me.dismiss_alarm(me.alarm_ids.join(','), 0);
+ $(this).dialog('close');
+ };
+
+ // Begin Mod by Rosali
+ // dialog-extend options
+ var dialogExtendOptions = {
+ 'closable' : true,
+ 'maximizable' : false,
+ 'minimizable' : true,
+ 'minimizeLocation' : 'right',
+ 'collapsable' : false,
+ 'dblclick' : 'maximize',
+ 'load' : function(evt, dlg) {
+ if ((rcmail.task == 'mail' && (rcmail.env.action == 'compose' || rcmail.env.action == 'show')) || is_minimized == true) {
+ $('#alarm-display').dialogExtend('minimize');
+ $('#dialog-extend-fixed-container').children().width(300);
+ if (focused.is('input') || focused.is('textarea')) {
+ $(focused).focus();
+ }
+ else if (typeof tinymce == 'object') {
+ window.setTimeout("tinymce.get(rcmail.env.composebody).getBody().focus();", 100);
+ }
+ }
+ },
+ 'minimize' : function (evt, dlg) {
+ $('#dialog-extend-fixed-container').children().width(300);
+ },
+ };
+ // End Mod by Rosali
+
+ this.alarm_dialog.appendTo(document.body).dialog({
+ modal: false,
+ resizable: true,
+ closeOnEscape: false,
+ dialogClass: 'alarm',
+ title: '<span class="ui-icon ui-icon-alarms" style="float:left; margin:0 4px 0 0"></span>' + rcmail.gettext('alarmtitle','libcalendaring'),
+ buttons: buttons,
+ close: function() {
+ $('#alarm-snooze-dropdown').hide();
+ $(this).dialog('destroy').remove();
+ me.alarm_dialog = null;
+ me.alarm_ids = null;
+ },
+ drag: function(event, ui) {
+ $('#alarm-snooze-dropdown').hide();
+ }
+ }).dialogExtend(dialogExtendOptions); // Mod by Rosali
+
+ this.alarm_ids = event_ids;
+ };
+
+ /**
+ * Show a drop-down menu with a selection of snooze times
+ */
+ this.snooze_dropdown = function(link)
+ {
+ if (!this.snooze_popup) {
+ this.snooze_popup = $('#alarm-snooze-dropdown');
+ // create popup if not found
+ if (!this.snooze_popup.length) {
+ this.snooze_popup = $('<div>').attr('id', 'alarm-snooze-dropdown').addClass('popupmenu').appendTo(document.body);
+ this.snooze_popup.html(rcmail.env.snooze_select)
+ }
+ $('#alarm-snooze-dropdown a').click(function(e){
+ var time = String(this.href).replace(/.+#/, '');
+ me.dismiss_alarm($('#alarm-snooze-dropdown').data('id'), time);
+ return false;
+ });
+ }
+
+ // hide visible popup
+ if (this.snooze_popup.is(':visible') && this.snooze_popup.data('id') == link.data('id')) {
+ this.snooze_popup.hide();
+ this.dismiss_link = null;
+ }
+ else { // open popup below the clicked link
+ var pos = link.offset();
+ pos.top += link.height() + 2;
+ this.snooze_popup.data('id', link.data('id')).css({ top:Math.floor(pos.top)+'px', left:Math.floor(pos.left)+'px' }).show();
+ this.dismiss_link = link;
+ }
+ };
+
+ /**
+ * Dismiss or snooze alarms for the given event
+ */
+ this.dismiss_alarm = function(id, snooze)
+ {
+ $('#alarm-snooze-dropdown').hide();
+ rcmail.http_post('utils/plugin.alarms', { action:'dismiss', data:{ id:id, snooze:snooze } });
+
+ // remove dismissed alarm from list
+ if (this.dismiss_link) {
+ this.dismiss_link.closest('div.alarm-item').hide();
+ var new_ids = jQuery.grep(this.alarm_ids, function(v){ return v != id; });
+ if (new_ids.length)
+ this.alarm_ids = new_ids;
+ else
+ this.alarm_dialog.dialog('close');
+ }
+
+ this.dismiss_link = null;
+ };
+
+ /***** Recurrence form handling *****/
+
+ /**
+ * Install event handlers on recurrence form elements
+ */
+ this.init_recurrence_edit = function(prefix)
+ {
+ // toggle recurrence frequency forms
+ $('#edit-recurrence-frequency').change(function(e){
+ var freq = $(this).val().toLowerCase();
+ $('.recurrence-form').hide();
+ if (freq) {
+ $('#recurrence-form-'+freq).show();
+ if (freq != 'rdate')
+ $('#recurrence-form-until').show();
+ }
+ });
+ $('#recurrence-form-rdate input.button.add').click(function(e){
+ var dt, dv = $('#edit-recurrence-rdate-input').val();
+ if (dv && (dt = me.parse_datetime('12:00', dv))) {
+ me.add_rdate(dt);
+ me.sort_rdates();
+ $('#edit-recurrence-rdate-input').val('')
+ }
+ else {
+ $('#edit-recurrence-rdate-input').select();
+ }
+ });
+ $('#edit-recurrence-rdates').on('click', 'a.delete', function(e){
+ $(this).closest('li').remove();
+ return false;
+ });
+
+ $('#edit-recurrence-enddate').datepicker(datepicker_settings).click(function(){ $("#edit-recurrence-repeat-until").prop('checked', true) });
+ $('#edit-recurrence-repeat-times').change(function(e){ $('#edit-recurrence-repeat-count').prop('checked', true); });
+ $('#edit-recurrence-rdate-input').datepicker(datepicker_settings);
+ };
+
+ /**
+ * Set recurrence form according to the given event/task record
+ */
+ this.set_recurrence_edit = function(rec)
+ {
+ var recurrence = $('#edit-recurrence-frequency').val(rec.recurrence ? rec.recurrence.FREQ || (rec.recurrence.RDATE ? 'RDATE' : '') : '').change(),
+ interval = $('.recurrence-form select.edit-recurrence-interval').val(rec.recurrence ? rec.recurrence.INTERVAL || 1 : 1),
+ rrtimes = $('#edit-recurrence-repeat-times').val(rec.recurrence ? rec.recurrence.COUNT || 1 : 1),
+ rrenddate = $('#edit-recurrence-enddate').val(rec.recurrence && rec.recurrence.UNTIL ? this.format_datetime(this.parseISO8601(rec.recurrence.UNTIL), 1) : '');
+ $('.recurrence-form input.edit-recurrence-until:checked').prop('checked', false);
+ $('#edit-recurrence-rdates').html('');
+
+ var weekdays = ['SU','MO','TU','WE','TH','FR','SA'],
+ rrepeat_id = '#edit-recurrence-repeat-forever';
+ if (rec.recurrence && rec.recurrence.COUNT) rrepeat_id = '#edit-recurrence-repeat-count';
+ else if (rec.recurrence && rec.recurrence.UNTIL) rrepeat_id = '#edit-recurrence-repeat-until';
+ $(rrepeat_id).prop('checked', true);
+
+ if (rec.recurrence && rec.recurrence.BYDAY && rec.recurrence.FREQ == 'WEEKLY') {
+ var wdays = rec.recurrence.BYDAY.split(',');
+ $('input.edit-recurrence-weekly-byday').val(wdays);
+ }
+ if (rec.recurrence && rec.recurrence.BYMONTHDAY) {
+ $('input.edit-recurrence-monthly-bymonthday').val(String(rec.recurrence.BYMONTHDAY).split(','));
+ $('input.edit-recurrence-monthly-mode').val(['BYMONTHDAY']);
+ }
+ if (rec.recurrence && rec.recurrence.BYDAY && (rec.recurrence.FREQ == 'MONTHLY' || rec.recurrence.FREQ == 'YEARLY')) {
+ var byday, section = rec.recurrence.FREQ.toLowerCase();
+ if ((byday = String(rec.recurrence.BYDAY).match(/(-?[1-4])([A-Z]+)/))) {
+ $('#edit-recurrence-'+section+'-prefix').val(byday[1]);
+ $('#edit-recurrence-'+section+'-byday').val(byday[2]);
+ }
+ $('input.edit-recurrence-'+section+'-mode').val(['BYDAY']);
+ }
+ else if (rec.start) {
+ $('#edit-recurrence-monthly-byday').val(weekdays[rec.start.getDay()]);
+ }
+ if (rec.recurrence && rec.recurrence.BYMONTH) {
+ $('input.edit-recurrence-yearly-bymonth').val(String(rec.recurrence.BYMONTH).split(','));
+ }
+ else if (rec.start) {
+ $('input.edit-recurrence-yearly-bymonth').val([String(rec.start.getMonth()+1)]);
+ }
+ if (rec.recurrence && rec.recurrence.RDATE) {
+ $.each(rec.recurrence.RDATE, function(i,rdate){
+ me.add_rdate(me.parseISO8601(rdate));
+ });
+ }
+ };
+
+ /**
+ * Gather recurrence settings from form
+ */
+ this.serialize_recurrence = function(timestr)
+ {
+ var recurrence = '',
+ freq = $('#edit-recurrence-frequency').val();
+
+ if (freq != '') {
+ recurrence = {
+ FREQ: freq,
+ INTERVAL: $('#edit-recurrence-interval-'+freq.toLowerCase()).val()
+ };
+
+ var until = $('input.edit-recurrence-until:checked').val();
+
+ if (until == 'count')
+ recurrence.COUNT = $('#edit-recurrence-repeat-times').val();
+ else if (until == 'until')
+ recurrence.UNTIL = me.date2ISO8601(me.parse_datetime(timestr || '00:00', $('#edit-recurrence-enddate').val()));
+
+ if (freq == 'WEEKLY') {
+ var byday = [];
+ $('input.edit-recurrence-weekly-byday:checked').each(function(){ byday.push(this.value); });
+ if (byday.length)
+ recurrence.BYDAY = byday.join(',');
+ }
+ else if (freq == 'MONTHLY') {
+ var mode = $('input.edit-recurrence-monthly-mode:checked').val(), bymonday = [];
+ if (mode == 'BYMONTHDAY') {
+ $('input.edit-recurrence-monthly-bymonthday:checked').each(function(){ bymonday.push(this.value); });
+ if (bymonday.length)
+ recurrence.BYMONTHDAY = bymonday.join(',');
+ }
+ else
+ recurrence.BYDAY = $('#edit-recurrence-monthly-prefix').val() + $('#edit-recurrence-monthly-byday').val();
+ }
+ else if (freq == 'YEARLY') {
+ var byday, bymonth = [];
+ $('input.edit-recurrence-yearly-bymonth:checked').each(function(){ bymonth.push(this.value); });
+ if (bymonth.length)
+ recurrence.BYMONTH = bymonth.join(',');
+ if ((byday = $('#edit-recurrence-yearly-byday').val()))
+ recurrence.BYDAY = $('#edit-recurrence-yearly-prefix').val() + byday;
+ }
+ else if (freq == 'RDATE') {
+ recurrence = { RDATE:[] };
+ // take selected but not yet added date into account
+ if ($('#edit-recurrence-rdate-input').val() != '') {
+ $('#recurrence-form-rdate input.button.add').click();
+ }
+ $('#edit-recurrence-rdates li').each(function(i, li){
+ recurrence.RDATE.push($(li).attr('data-value'));
+ });
+ }
+ }
+
+ return recurrence;
+ };
+
+ // add the given date to the RDATE list
+ this.add_rdate = function(date)
+ {
+ var li = $('<li>')
+ .attr('data-value', this.date2ISO8601(date))
+ .html('<span>' + Q(this.format_datetime(date, 1)) + '</span>')
+ .appendTo('#edit-recurrence-rdates');
+
+ $('<a>').attr('href', '#del')
+ .addClass('iconbutton delete')
+ .html(rcmail.get_label('delete', 'libcalendaring'))
+ .attr('title', rcmail.get_label('delete', 'libcalendaring'))
+ .appendTo(li);
+ };
+
+ // re-sort the list items by their 'data-value' attribute
+ this.sort_rdates = function()
+ {
+ var mylist = $('#edit-recurrence-rdates'),
+ listitems = mylist.children('li').get();
+ listitems.sort(function(a, b) {
+ var compA = $(a).attr('data-value');
+ var compB = $(b).attr('data-value');
+ return (compA < compB) ? -1 : (compA > compB) ? 1 : 0;
+ })
+ $.each(listitems, function(idx, item) { mylist.append(item); });
+ };
+}
+
+
+// extend jQuery
+(function($){
+ $.fn.serializeJSON = function(){
+ var json = {};
+ jQuery.map($(this).serializeArray(), function(n, i) {
+ json[n['name']] = n['value'];
+ });
+ return json;
+ };
+})(jQuery);
+
+
+/* libcalendaring plugin initialization */
+window.rcmail && rcmail.addEventListener('init', function(evt) {
+ if (rcmail.env.libcal_settings) {
+ var libcal = new rcube_libcalendaring(rcmail.env.libcal_settings);
+ rcmail.addEventListener('plugin.display_alarms', function(alarms){ libcal.display_alarms(alarms); });
+ if (!rcmail.env.framed && !rcmail.env.extwin && rcmail.env.username) {
+ window.setTimeout("rcmail.http_post('refresh', '');", 1000); // Mod by Rosali (fetch reminders almost immediately)
+ }
+ }
+});
diff --git a/libgpl/libgpl.php b/libgpl/libgpl.php
new file mode 100644
index 0000000..de9747f
--- /dev/null
+++ b/libgpl/libgpl.php
@@ -0,0 +1,189 @@
+<?php
+#
+# This file is part of MyRoundcube "libgpl" plugin.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# Copyright (c) 2012 - 2015 Roland 'Rosali' Liebl
+# dev-team [at] myroundcube [dot] com
+# http://myroundcube.com
+#
+class libgpl extends rcube_plugin
+{
+ private $labels_merged;
+
+ /* unified plugin properties */
+ static private $plugin = 'libgpl';
+ static private $author = 'myroundcube@mail4us.net';
+ static private $authors_comments = '<a href="http://myroundcube.com/myroundcube-plugins/helper-plugin?libgpl" target="_blank">Documentation</a>';
+ static private $version = '1.0.38';
+ static private $date = '12-02-2014';
+ static private $licence = 'GPL';
+ static private $requirements = array(
+ 'Roundcube' => '1.0',
+ 'PHP' => '5.3',
+ 'required_plugins' => array(
+ 'jqueryui' => 'require_plugin',
+ ),
+ );
+ static private $f;
+
+ function init(){
+ self::$f = $this;
+ $this->add_texts('localization/');
+ $this->require_plugin('jqueryui');
+ $this->include_stylesheet('qtip/qtip.css');
+ $this->include_stylesheet($this->local_skin_path() . '/calendar.css');
+ $this->include_script('timepicker2/jquery.timepicker.js');
+ $this->include_stylesheet($this->local_skin_path() . '/timepicker2.css');
+ $this->include_script('dialogextend/jquery.dialogextend.js');
+ $this->include_script('libcalendaring/libcalendaring.js');
+ $this->include_script('jquery_migrate/jquery.migrate.js');
+ $this->include_script('qtip/qtip.js');
+ $this->add_hook('render_page', array($this, 'render_page'));
+ $this->add_hook('send_page', array($this, 'send_page'));
+ $this->add_hook('preferences_list', array($this, 'preferences_list'));
+ if(!class_exists('MyRCHttp')){
+ require_once('http_request/class.http.php');
+ }
+ if(!$this->labels_merged){
+ $this->labels_merged = true;
+ $this->_merge_labels(
+ array(
+ 'tasks' => 'calendar',
+ 'calendar_kolab' => 'calendar',
+ 'calendar_database' => 'calendar',
+ 'calendar_caldav' => 'calendar',
+ 'calendar_ical' => 'calendar',
+ 'calendar_google_xml' => 'calendar',
+ 'errorimportingtask' => 'calendar',
+ 'treat_as_allday' => 'calendar',
+ 'hours' => 'calendar',
+ 'movetotasks' => 'calendar',
+ 'movetocalendar' => 'calendar',
+ 'emailevent' => 'calendar',
+ 'movetonotes' => 'calendar',
+ 'quit' => 'calendar',
+ 'eventaction' => 'calendar',
+ 'gooledisabled' => 'calendar',
+ 'googledisabled_redirect' => 'calendar',
+ 'allowfreebusy' => 'calendar',
+ 'freebusy' => 'calendar',
+ 'sync_interval' => 'calendar',
+ 'minute_s' => 'calendar',
+ 'unabletoadddefaultcalendars' => 'calendar',
+ 'list' => 'tasklist',
+ 'editlist' => 'tasklist',
+ 'tags' => 'tasklist',
+ 'subscribe' => 'tasklist',
+ 'is_subtask' => 'tasklist',
+ 'due' => 'tasklist',
+ 'taskaction' => 'tasklist',
+ 'emailtask' => 'tasklist',
+ 'subscribed' => 'carddav',
+ )
+ );
+ }
+ }
+
+ static public function include_js($js){
+ self::$f->include_script($js);
+ }
+
+ static public function include_php($php){
+ require_once INSTALL_PATH . $php;
+ }
+
+ static public function about($keys = false){
+ $requirements = self::$requirements;
+ foreach(array('required_', 'recommended_') as $prefix){
+ if(is_array($requirements[$prefix.'plugins'])){
+ foreach($requirements[$prefix.'plugins'] as $plugin => $method){
+ if(class_exists($plugin) && method_exists($plugin, 'about')){
+ /* PHP 5.2.x workaround for $plugin::about() */
+ $class = new $plugin(false);
+ $requirements[$prefix.'plugins'][$plugin] = array(
+ 'method' => $method,
+ 'plugin' => $class->about($keys),
+ );
+ }
+ else{
+ $requirements[$prefix.'plugins'][$plugin] = array(
+ 'method' => $method,
+ 'plugin' => $plugin,
+ );
+ }
+ }
+ }
+ }
+ return array(
+ 'plugin' => self::$plugin,
+ 'version' => self::$version,
+ 'date' => self::$date,
+ 'author' => self::$author,
+ 'comments' => self::$authors_comments,
+ 'licence' => self::$licence,
+ 'requirements' => $requirements,
+ );
+ }
+
+ public function render_page($p){
+ if($this->rc->user->data['username']){
+ $this->rc->output->set_env('username', $this->rc->user->data['username']);
+ }
+ if($p['template'] == 'calendar.calendar' || $p['template'] == 'calendar.print' || $p['template'] == 'tasklist.mainview'){
+ $this->include_script('querystring/querystring.js');
+ $this->include_script('date/date.js');
+ $this->include_stylesheet($this->local_skin_path() . '/jquery.contextMenu.css');
+ $this->include_script('contextmenu/jquery.contextMenu.js');
+ $this->include_script('contextmenu/jquery.ui.position.js');
+ }
+ else if($p['template'] == 'sticky_notes.sticky_notes'){
+ $this->include_stylesheet('fancybox/jquery.fancybox-1.3.4.css');
+ $this->include_script("fancybox/jquery.fancybox-1.3.4.pack.js");
+ $this->include_script('date/date.js');
+ $this->include_stylesheet($this->local_skin_path() . '/jquery.contextMenu.css');
+ $this->include_script('contextmenu/jquery.contextMenu.js');
+ $this->include_script('contextmenu/jquery.ui.position.js');
+ }
+ if(class_exists('password_plus')){
+ $this->include_script('password/password.js');
+ }
+ return $p;
+ }
+
+ public function send_page($args)
+ {
+ $args['content'] = preg_replace('/<script type=\"text\/javascript\" src=\"plugins\/libcalendaring\/libcalendaring.js\?s\=[0-9]*\"><\/script>([\r\n\t])/', '', $args['content']);
+ $args['content'] = preg_replace('/<script type=\"text\/javascript\" src=\"plugins\/libcalendaring\/libcalendaring.min.js\?s\=[0-9]*\"><\/script>([\r\n\t])/', '', $args['content']);
+ if(class_exists('password_plus')){
+ $args['content'] = preg_replace('/<script type=\"text\/javascript\" src=\"plugins\/password\/password.js\?s\=[0-9]*\"><\/script>([\r\n\t])/', '', $args['content']);
+ $args['content'] = preg_replace('/<script type=\"text\/javascript\" src=\"plugins\/password\/password.min.js\?s\=[0-9]*\"><\/script>([\r\n\t])/', '', $args['content']);
+ }
+ return $args;
+ }
+
+ public function preferences_list($args){
+ if($args['section'] == 'calendarsharing'|| $args['section'] == 'addressbooksharing'){
+ $rcmail = rcube::get_instance();
+ if(!$args['current']){
+ $args['blocks']['view']['content'] = true;
+ return $args;
+ }
+ if($dsn = $rcmail->config->get('db_sabredav_dsn')){
+ $this->include_script('flashclipboard/flashclipboard_libgpl.js');
+ }
+ }
+ return $args;
+ }
+
+ private function _merge_labels($labels){
+ foreach($labels as $label => $env){
+ rcube::get_instance()->load_language(null, array(), array($env . '.' . $label => $this->gettext($label)));
+ }
+ }
+
+}
+?> \ No newline at end of file
diff --git a/libgpl/localization/cs_CZ.inc b/libgpl/localization/cs_CZ.inc
new file mode 100644
index 0000000..eca44df
--- /dev/null
+++ b/libgpl/localization/cs_CZ.inc
@@ -0,0 +1,48 @@
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/libgpl/localization/cs_CZ.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2015, Roland 'rosali' Liebl
+ |
+ +-----------------------------------------------------------------------+
+ | Author: tachec - 01/22/2015 08:02:38
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['calendar_caldav'] = 'CalDAV kalendář';
+$labels['calendar_kolab'] = 'Kolab kalendář';
+$labels['calendar_database'] = 'lokální kalendář';
+$labels['calendar_ical'] = 'iCAL kalendář';
+$labels['calendar_google_xml'] = 'Google XML kalendář';
+$labels['sync_interval'] = 'Synchronizovat každých';
+$labels['minute_s'] = 'minut(y)';
+$labels['tasks'] = 'Úkoly';
+$labels['errorimportingtask'] = 'Nepodařilo se naimportovat úkoly';
+$labels['treat_as_allday'] = 'Zobrazit událost jako celodenní pokud trvá déle než';
+$labels['hours'] = 'Hodin';
+$labels['movetotasks'] = 'Přesunout do úkolů';
+$labels['movetocalendar'] = 'Přesunout do kalendáře';
+$labels['emailevent'] = 'Poslat událost';
+$labels['emailnote'] = 'Poslat poznámku';
+$labels['emailtask'] = 'Poslat úkol';
+$labels['movetonotes'] = 'Přesunout do poznámek';
+$labels['quit'] = 'Ukončit';
+$labels['eventaction'] = 'Akce události...';
+$labels['googledisabled'] = 'Povolte prosím přístup k vašemu účtu Google (přejděte na "Nastavení" -> "Správa účtu" -> "Další nastavení účtu" a proveďte patřičná nastavení).';
+$labels['googledisabled_redirect'] = 'Povolte prosím přístup k vašemu účtu Google.';
+$labels['allowfreebusy'] = 'Povolit požadavek na obsazenost';
+$labels['freebusy'] = 'Obsazenost';
+$labels['unabletoadddefaultcalendars'] = 'Nelze přidat výchozí kalendář';
+$labels['taskaction'] = 'Akce úkolu...';
+$labels['due'] = ' ';
+$labels['is_subtask'] = 'Dílčí úkol';
+$labels['subscribe'] = 'Abyste mohli vytvářet úkoly, tak si je prosím povolte ve svém kalendáři.';
+$labels['subscribed'] = 'Přihlášeno';
+$labels['tags'] = 'Kategorie';
+$labels['list'] = 'Kalendář';
+$labels['editlist'] = 'Upravit kalendář';
+
+?> \ No newline at end of file
diff --git a/libgpl/localization/en_US.inc b/libgpl/localization/en_US.inc
new file mode 100644
index 0000000..22c7c1b
--- /dev/null
+++ b/libgpl/localization/en_US.inc
@@ -0,0 +1,36 @@
+<?php
+$labels = array();
+$labels['calendar_caldav'] = 'CalDAV Calendar';
+$labels['calendar_kolab'] = 'Kolab Calendar';
+$labels['calendar_database'] = 'Local Calendar';
+$labels['calendar_ical'] = 'iCAL Calendar';
+$labels['calendar_google_xml'] = 'Google XML Calendar';
+$labels['sync_interval'] = 'Synchronization every';
+$labels['minute_s'] = 'minute(s)';
+$labels['tasks'] = 'Tasks';
+$labels['errorimportingtask'] = 'Failed to import the task';
+$labels['treat_as_allday'] = 'Show event as all-day if it takes more than';
+$labels['hours'] = 'Hours';
+$labels['movetotasks'] = 'Move to tasks';
+$labels['movetocalendar'] = 'Move to calendar';
+$labels['emailevent'] = 'Email event';
+$labels['emailnote'] = 'Email note';
+$labels['emailtask'] = 'Email task';
+$labels['movetonotes'] = 'Move to notes';
+$labels['quit'] = 'Quit';
+$labels['eventaction'] = 'Event action...';
+$labels['googledisabled'] = 'Please authorize access to your Google account (browse to <i>"Settings"</i> -> <i>"Account Administration" </i> -> <i>"Other account\'s settings"</i> and proceed).';
+$labels['googledisabled_redirect'] = 'Please authorize access to your Google account.';
+$labels['allowfreebusy'] = 'Allow freebusy requests';
+$labels['freebusy'] = 'Freebusy';
+$labels['unabletoadddefaultcalendars'] = 'Unable to add default calendars';
+$labels['taskaction'] = 'Task action...';
+$labels['due'] = 'due';
+$labels['is_subtask'] = 'Subtask';
+$labels['subscribe'] = 'Please subscribe to a calendar in order to create a task.';
+$labels['subscribed'] = 'Subscribed';
+$labels['tags'] = 'Categories';
+$labels['list'] = 'Calendar';
+$labels['editlist'] = 'Edit calendar';
+
+?> \ No newline at end of file
diff --git a/libgpl/localization/es_ES.inc b/libgpl/localization/es_ES.inc
new file mode 100644
index 0000000..d84590b
--- /dev/null
+++ b/libgpl/localization/es_ES.inc
@@ -0,0 +1,48 @@
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/libgpl/localization/es_ES.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2015, Roland 'rosali' Liebl
+ |
+ +-----------------------------------------------------------------------+
+ | Author: Yoni - 01/10/2015 10:46:25
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['calendar_caldav'] = 'Calendario CalDAV';
+$labels['calendar_kolab'] = 'Calendario Kolab';
+$labels['calendar_database'] = 'Calendario Local';
+$labels['calendar_ical'] = 'Calendario iCAL';
+$labels['calendar_google_xml'] = 'Calendario Google XML';
+$labels['sync_interval'] = 'Sincronización cada';
+$labels['minute_s'] = 'minuto(s)';
+$labels['tasks'] = 'Tareas';
+$labels['errorimportingtask'] = 'No se pudo importar la tarea';
+$labels['treat_as_allday'] = 'Mostrar evento como \'todo el día\' si toma más de';
+$labels['hours'] = 'Horas';
+$labels['movetotasks'] = 'Mover a tareas';
+$labels['movetocalendar'] = 'Mover al calendario';
+$labels['emailevent'] = 'Enviar evento por correo';
+$labels['emailnote'] = 'Enviar nota por correo';
+$labels['emailtask'] = 'Enviar tarea por correo';
+$labels['movetonotes'] = 'Mover a notas';
+$labels['quit'] = 'Salir';
+$labels['eventaction'] = 'Acción de evento...';
+$labels['googledisabled'] = 'Please authorize access to your Google account (browse to "Settings" -> "Account Administration" -> "Other account\'s settings" and proceed). Por favor, autorizar el acceso a su cuenta de Google (vaya a "Configuración" -> "Administración de Cuenta" -> "Otros ajustes de cuentas" y proceda).';
+$labels['googledisabled_redirect'] = 'Por favor, autorizar el acceso a su cuenta de Google.';
+$labels['allowfreebusy'] = 'Permitir solicitudes Libre/Ocupado';
+$labels['freebusy'] = 'Libre/Ocupado';
+$labels['unabletoadddefaultcalendars'] = 'No se pudo agregar calendarios predeterminados';
+$labels['taskaction'] = 'Acción de tarea...';
+$labels['due'] = 'debido el';
+$labels['is_subtask'] = 'Subtarea';
+$labels['subscribe'] = 'Por favor, suscribirse a un calendario para poder crear tarea.';
+$labels['subscribed'] = 'Suscrito';
+$labels['tags'] = 'Categorías';
+$labels['list'] = 'Calendario';
+$labels['editlist'] = 'Editar calendario';
+
+?> \ No newline at end of file
diff --git a/libgpl/localization/fi_FI.inc b/libgpl/localization/fi_FI.inc
new file mode 100644
index 0000000..021ab3d
--- /dev/null
+++ b/libgpl/localization/fi_FI.inc
@@ -0,0 +1,48 @@
+<?php
+/*
+ +-----------------------------------------------------------------------+
+ | ./plugins/libgpl/localization/fi_FI.inc
+ |
+ | Language file of MyRoundcube Plugins Bundle
+ | Copyright (C) 2010-2015, Roland 'rosali' Liebl
+ |
+ +-----------------------------------------------------------------------+
+ | Author: Markku Virtanen - 01/12/2015 07:37:20
+ +-----------------------------------------------------------------------+
+*/
+
+$labels = array();
+$labels['calendar_caldav'] = 'CalDAV kalenteri';
+$labels['calendar_kolab'] = 'Kolab kalenteri';
+$labels['calendar_database'] = 'Paikallinen kalenteri';
+$labels['calendar_ical'] = 'iCal kalenteri';
+$labels['calendar_google_xml'] = 'Google XML kalenteri';
+$labels['sync_interval'] = 'Synkronisointi joka';
+$labels['minute_s'] = 'minuutti(a)';
+$labels['tasks'] = 'Tehtävät';
+$labels['errorimportingtask'] = 'Tehtävän tuonti epäonnistui';
+$labels['treat_as_allday'] = 'Näytä tapahtumat koko päivän tapahtumana jos ne kestävät enemmän kuin';
+$labels['hours'] = 'Tuntia';
+$labels['movetotasks'] = 'Siirrä tehtäviin';
+$labels['movetocalendar'] = 'Siirrä kalenteriin';
+$labels['emailevent'] = 'Lähetä tapahtuma';
+$labels['emailnote'] = 'Lähetä viesti';
+$labels['emailtask'] = 'Lähetä tehtävä';
+$labels['movetonotes'] = 'Siirrä muistioon';
+$labels['quit'] = 'Poistu';
+$labels['eventaction'] = 'Tapahtuman toiminto...';
+$labels['googledisabled'] = 'Anna valtuutus Google tilille ("Asetukset" -> "Tilin hallinta" -> "Muut tilin asetukset")';
+$labels['googledisabled_redirect'] = 'Anna valtuutus Google tilillesi';
+$labels['allowfreebusy'] = 'Salli freebusy pyynnöt';
+$labels['freebusy'] = 'Freebusy';
+$labels['unabletoadddefaultcalendars'] = 'Oletuskalenterien lisäys epäonnistui';
+$labels['taskaction'] = 'Tehtävän toiminto...';
+$labels['due'] = 'valmistuu';
+$labels['is_subtask'] = 'Alatehtävä';
+$labels['subscribe'] = 'Tee tilaus kalenteriin jotta voit luoda tehtäviä.';
+$labels['subscribed'] = 'Tilattu';
+$labels['tags'] = 'Kategoriat';
+$labels['list'] = 'Kalenteri';
+$labels['editlist'] = 'Muokkaa kalenteria';
+
+?> \ No newline at end of file
diff --git a/libgpl/localization/fr_FR.inc b/libgpl/localization/fr_FR.inc
new file mode 100644
index 0000000..9344bc3
--- /dev/null
+++ b/libgpl/localization/fr_FR.inc
@@ -0,0 +1,51 @@
+<?php
+
+/*
++-----------------------------------------------------------------------+
+| language/fr_FR/labels.inc |
+| |
+| Language file of the RoundCube Webmail client |
+| Copyright (C) 2008-2012, RoundQube Dev. - Switzerland |
+| Licensed under the GNU GPL |
+| |
++-----------------------------------------------------------------------+
+| Author: Olivier Zolli - 01/11/2015 |
++-----------------------------------------------------------------------+
+
+*/
+
+$labels = array();
+$labels['calendar_caldav'] = 'Agenda CalDAV';
+$labels['calendar_kolab'] = 'Agenda Kolab';
+$labels['calendar_database'] = 'Agenda local';
+$labels['calendar_ical'] = 'Agenda iCAL';
+$labels['calendar_google_xml'] = 'Agenda Google XML';
+$labels['sync_interval'] = 'Synchronisation chaque';
+$labels['minute_s'] = 'minute(s)';
+$labels['tasks'] = 'Tâches';
+$labels['errorimportingtask'] = 'Echec d\'importation de la tâche';
+$labels['treat_as_allday'] = 'Montrer l\'évènement comme "Toute la journée" s\'il dure plus de';
+$labels['hours'] = 'Heures';
+$labels['movetotasks'] = 'Déplacer vers les tâches';
+$labels['movetocalendar'] = 'Déplacer vers l\'agenda';
+$labels['emailevent'] = 'Evènement courriel';
+$labels['emailnote'] = 'Evènement note';
+$labels['emailtask'] = 'Evènement tâche';
+$labels['movetonotes'] = 'Déplacer vers les notes';
+$labels['quit'] = 'Quitter';
+$labels['eventaction'] = 'Action d\'évènement';
+$labels['googledisabled'] = 'Veuillez autoriser l\'accès à votre compte Google (<i>"Paramètres"</i> -> <i>"Administration du compte"</i> -> <i>"Autres paramètres du compte"</i>';
+$labels['googledisabled_redirect'] = 'Veuillez autoriser l\'accès à votre compte Google';
+$labels['allowfreebusy'] = 'Autoriser les requêtes Libre/Occupé';
+$labels['freebusy'] = 'Libre/Occupé';
+$labels['unabletoadddefaultcalendars'] = 'Impossible d\'ajouter les agendas par défaut';
+$labels['taskaction'] = 'Action de tâche';
+$labels['due'] = 'requis';
+$labels['is_subtask'] = 'Sous-tâche';
+$labels['subscribe'] = 'Veuillez vous inscrire à un agenda pour créer une tâche';
+$labels['subscribed'] = 'Inscrit';
+$labels['tags'] = 'Catégories';
+$labels['list'] = 'Agenda';
+$labels['editlist'] = 'Editer l\'agenda';
+
+?> \ No newline at end of file
diff --git a/libgpl/localization/revision.inc.php b/libgpl/localization/revision.inc.php
new file mode 100644
index 0000000..e9f587a
--- /dev/null
+++ b/libgpl/localization/revision.inc.php
@@ -0,0 +1,11 @@
+<?php
+
+$ps_localization_update = serialize(
+ array(
+ 'translator' => 'tachec',
+ 'language ' => 'cs_CZ',
+ 'date' => '01/22/2015 08:02:38'
+ )
+);
+
+?> \ No newline at end of file
diff --git a/libgpl/package.xml b/libgpl/package.xml
new file mode 100644
index 0000000..f9cc54d
--- /dev/null
+++ b/libgpl/package.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<package xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" packagerversion="1.9.0" version="2.0" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
+ http://pear.php.net/dtd/tasks-1.0.xsd
+ http://pear.php.net/dtd/package-2.0
+ http://pear.php.net/dtd/package-2.0.xsd">
+ <name>libgpl</name>
+ <lead>
+ <name>Myroundcube Dev Team</name>
+ <user>rosali</user>
+ <email>dev-team@myroundcube.com</email>
+ <active>yes</active>
+ </lead><date>2014-02-12</date>
+ <version>
+ <release>1.0.38</release>
+ <api>1.0.38</api>
+ </version>
+ <stability>
+ <release>stable</release>
+ <api>stable</api>
+ </stability>
+ <license uri="http://www.gnu.org/licenses/gpl.html">GNU GPLv3+</license>
+</package>
diff --git a/libgpl/password/password.js b/libgpl/password/password.js
new file mode 100644
index 0000000..6b17b64
--- /dev/null
+++ b/libgpl/password/password.js
@@ -0,0 +1,36 @@
+/**
+ * Password plugin script
+ * @version @package_version@
+ */
+
+if (window.rcmail) {
+ rcmail.addEventListener('init', function(evt) {
+
+ // register command handler
+ rcmail.register_command('plugin.password-save', function() {
+ var input_curpasswd = rcube_find_object('_curpasswd'),
+ input_newpasswd = rcube_find_object('_newpasswd'),
+ input_confpasswd = rcube_find_object('_confpasswd');
+ input_pwstrength = rcube_find_object('_pwstrength');
+
+ if (input_curpasswd && input_curpasswd.value == '') {
+ rcmail.display_message(rcmail.gettext('nocurpassword', 'password'), 'error');
+ input_curpasswd.focus();
+ } else if (input_newpasswd && input_newpasswd.value == '') {
+ rcmail.display_message(rcmail.gettext('nopassword', 'password'), 'error');
+ input_newpasswd.focus();
+ } else if (input_confpasswd && input_confpasswd.value == '') {
+ rcmail.display_message(rcmail.gettext('nopassword', 'password'), 'error');
+ input_confpasswd.focus();
+ } else if (input_newpasswd && input_confpasswd && input_newpasswd.value != input_confpasswd.value) {
+ rcmail.display_message(rcmail.gettext('passwordinconsistency', 'password'), 'error');
+ input_newpasswd.focus();
+ } else if (input_pwstrength.value == 0) {
+ rcmail.display_message(rcmail.gettext('passwordweak', 'pwstrength'), 'error');
+ input_newpasswd.focus();
+ } else {
+ rcmail.gui_objects.passform.submit();
+ }
+ }, true);
+ })
+}
diff --git a/libgpl/qtip/qtip.css b/libgpl/qtip/qtip.css
new file mode 100644
index 0000000..9147bd7
--- /dev/null
+++ b/libgpl/qtip/qtip.css
@@ -0,0 +1 @@
+.ui-tooltip-fluid{display:block;visibility:hidden;position:static!important;float:left!important;}.ui-tooltip,.qtip{position:absolute;left:-28000px;top:-28000px;display:none;max-width:280px;min-width:50px;font-size:10.5px;line-height:12px;}.ui-tooltip-content{position:relative;padding:5px 9px;overflow:hidden;border-width:1px;border-style:solid;text-align:left;word-wrap:break-word;overflow:hidden;}.ui-tooltip-titlebar{position:relative;min-height:14px;padding:5px 35px 5px 10px;overflow:hidden;border-width:1px 1px 0;border-style:solid;font-weight:bold;}.ui-tooltip-titlebar+.ui-tooltip-content{border-top-width:0!important;}/*!Default close button class */ .ui-tooltip-titlebar .ui-state-default{position:absolute;right:4px;top:50%;margin-top:-9px;cursor:pointer;outline:medium none;border-width:1px;border-style:solid;}* html .ui-tooltip-titlebar .ui-state-default{top:16px;}.ui-tooltip-titlebar .ui-icon,.ui-tooltip-icon .ui-icon{display:block;text-indent:-1000em;}.ui-tooltip-icon,.ui-tooltip-icon .ui-icon{-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;}.ui-tooltip-icon .ui-icon{width:18px;height:14px;text-align:center;text-indent:0;font:normal bold 10px/13px Tahoma,sans-serif;color:inherit;background:transparent none no-repeat -100em -100em;}/*!Default tooltip style */ .ui-tooltip-titlebar,.ui-tooltip-content{border-color:#F1D031;background-color:#FFFFA3;color:#555;}.ui-tooltip-titlebar{background-color:#FFEF93;}.ui-tooltip-titlebar .ui-tooltip-icon{border-color:#CCC;background:#F1F1F1;color:#777;}.ui-tooltip-titlebar .ui-state-hover{border-color:#AAA;color:#111;}/*!Light tooltip style */ .ui-tooltip-light .ui-tooltip-titlebar,.ui-tooltip-light .ui-tooltip-content{border-color:#E2E2E2;color:#454545;}.ui-tooltip-light .ui-tooltip-content{background-color:white;}.ui-tooltip-light .ui-tooltip-titlebar{background-color:#f1f1f1;}/*!Dark tooltip style */ .ui-tooltip-dark .ui-tooltip-titlebar,.ui-tooltip-dark .ui-tooltip-content{border-color:#303030;color:#f3f3f3;}.ui-tooltip-dark .ui-tooltip-content{background-color:#505050;}.ui-tooltip-dark .ui-tooltip-titlebar{background-color:#404040;}.ui-tooltip-dark .ui-tooltip-icon{border-color:#444;}.ui-tooltip-dark .ui-tooltip-titlebar .ui-state-hover{border-color:#303030;}/*!Cream tooltip style */ .ui-tooltip-cream .ui-tooltip-titlebar,.ui-tooltip-cream .ui-tooltip-content{border-color:#F9E98E;color:#A27D35;}.ui-tooltip-cream .ui-tooltip-content{background-color:#FBF7AA;}.ui-tooltip-cream .ui-tooltip-titlebar{background-color:#F0DE7D;}.ui-tooltip-cream .ui-state-default .ui-tooltip-icon{background-position:-82px 0;}/*!Red tooltip style */ .ui-tooltip-red .ui-tooltip-titlebar,.ui-tooltip-red .ui-tooltip-content{border-color:#D95252;color:#912323;}.ui-tooltip-red .ui-tooltip-content{background-color:#F78B83;}.ui-tooltip-red .ui-tooltip-titlebar{background-color:#F06D65;}.ui-tooltip-red .ui-state-default .ui-tooltip-icon{background-position:-102px 0;}.ui-tooltip-red .ui-tooltip-icon{border-color:#D95252;}.ui-tooltip-red .ui-tooltip-titlebar .ui-state-hover{border-color:#D95252;}/*!Green tooltip style */ .ui-tooltip-green .ui-tooltip-titlebar,.ui-tooltip-green .ui-tooltip-content{border-color:#90D93F;color:#3F6219;}.ui-tooltip-green .ui-tooltip-content{background-color:#CAED9E;}.ui-tooltip-green .ui-tooltip-titlebar{background-color:#B0DE78;}.ui-tooltip-green .ui-state-default .ui-tooltip-icon{background-position:-42px 0;}/*!Blue tooltip style */ .ui-tooltip-blue .ui-tooltip-titlebar,.ui-tooltip-blue .ui-tooltip-content{border-color:#ADD9ED;color:#5E99BD;}.ui-tooltip-blue .ui-tooltip-content{background-color:#E5F6FE;}.ui-tooltip-blue .ui-tooltip-titlebar{background-color:#D0E9F5;}.ui-tooltip-blue .ui-state-default .ui-tooltip-icon{background-position:-2px 0;}.ui-tooltip .ui-tooltip-tip{margin:0 auto;overflow:hidden;background:transparent!important;border:0 dashed transparent!important;z-index:10;}.ui-tooltip .ui-tooltip-tip,.ui-tooltip .ui-tooltip-tip *{position:absolute;line-height:.1px!important;font-size:.1px!important;color:#123456;background:transparent;border:0 dashed transparent;}.ui-tooltip .ui-tooltip-tip canvas{position:static;}#qtip-overlay{position:absolute;left:-10000em;top:-10000em;background-color:black;opacity:.7;filter:alpha(opacity=70);-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=70)";}/*!Add shadows to your tooltips in:FF3+,Chrome 2+,Opera 10.6+,IE6+,Safari 2+*/ .ui-tooltip-shadow{-webkit-box-shadow:1px 1px 3px 1px rgba(0,0,0,0.15);-moz-box-shadow:1px 1px 3px 1px rgba(0,0,0,0.15);box-shadow:1px 1px 3px 1px rgba(0,0,0,0.15);}.ui-tooltip-shadow .ui-tooltip-titlebar,.ui-tooltip-shadow .ui-tooltip-content{filter:progid:DXImageTransform.Microsoft.Shadow(Color='gray',Direction=135,Strength=3);-ms-filter:"progid:DXImageTransform.Microsoft.Shadow(Color='gray',Direction=135,Strength=3)";_margin-bottom:-3px;.margin-bottom:-3px;}/*!Add rounded corners to your tooltips in:FF3+,Chrome 2+,Opera 10.6+,IE9+,Safari 2+*/ .ui-tooltip-rounded,.ui-tooltip-rounded .ui-tooltip-content,.ui-tooltip-tipsy,.ui-tooltip-tipsy .ui-tooltip-content,.ui-tooltip-youtube,.ui-tooltip-youtube .ui-tooltip-content{-moz-border-radius:4px;-webkit-border-radius:4px;border-radius:4px;}.ui-tooltip-rounded .ui-tooltip-titlebar,.ui-tooltip-tipsy .ui-tooltip-titlebar,.ui-tooltip-youtube .ui-tooltip-titlebar{-moz-border-radius:5px 5px 0 0;-webkit-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0;}.ui-tooltip-rounded .ui-tooltip-titlebar+.ui-tooltip-content,.ui-tooltip-tipsy .ui-tooltip-titlebar+.ui-tooltip-content,.ui-tooltip-youtube .ui-tooltip-titlebar+.ui-tooltip-content{-moz-border-radius:0 0 5px 5px;-webkit-border-radius:0 0 5px 5px;border-radius:0 0 5px 5px;}/*!Youtube tooltip style */ .ui-tooltip-youtube{-webkit-box-shadow:0 0 3px #333;-moz-box-shadow:0 0 3px #333;box-shadow:0 0 3px #333;}.ui-tooltip-youtube .ui-tooltip-titlebar,.ui-tooltip-youtube .ui-tooltip-content{background:transparent;background:rgba(0,0,0,0.85);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#D9000000,endColorstr=#D9000000);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#D9000000,endColorstr=#D9000000)";color:white;border-color:#CCC;}.ui-tooltip-youtube .ui-tooltip-icon{border-color:#222;}.ui-tooltip-youtube .ui-tooltip-titlebar .ui-state-hover{border-color:#303030;}.ui-tooltip-jtools{background:#232323;background:rgba(0,0,0,0.7);background-image:-moz-linear-gradient(top,#717171,#232323);background-image:-webkit-gradient(linear,left top,left bottom,from(#717171),to(#232323));border:2px solid #ddd;border:2px solid rgba(241,241,241,1);-moz-border-radius:2px;-webkit-border-radius:2px;border-radius:2px;-webkit-box-shadow:0 0 12px #333;-moz-box-shadow:0 0 12px #333;box-shadow:0 0 12px #333;}.ui-tooltip-jtools .ui-tooltip-titlebar{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#717171,endColorstr=#4A4A4A);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#717171,endColorstr=#4A4A4A)";}.ui-tooltip-jtools .ui-tooltip-content{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#4A4A4A,endColorstr=#232323);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#4A4A4A,endColorstr=#232323)";}.ui-tooltip-jtools .ui-tooltip-titlebar,.ui-tooltip-jtools .ui-tooltip-content{background:transparent;color:white;border:0 dashed transparent;}.ui-tooltip-jtools .ui-tooltip-icon{border-color:#555;}.ui-tooltip-jtools .ui-tooltip-titlebar .ui-state-hover{border-color:#333;}.ui-tooltip-cluetip{-webkit-box-shadow:4px 4px 5px rgba(0,0,0,0.4);-moz-box-shadow:4px 4px 5px rgba(0,0,0,0.4);box-shadow:4px 4px 5px rgba(0,0,0,0.4);}.ui-tooltip-cluetip .ui-tooltip-titlebar{background-color:#87876A;color:white;border:0 dashed transparent;}.ui-tooltip-cluetip .ui-tooltip-content{background-color:#D9D9C2;color:#111;border:0 dashed transparent;}.ui-tooltip-cluetip .ui-tooltip-icon{border-color:#808064;}.ui-tooltip-cluetip .ui-tooltip-titlebar .ui-state-hover{border-color:#696952;color:#696952;}.ui-tooltip-tipsy{border:0;}.ui-tooltip-tipsy .ui-tooltip-titlebar,.ui-tooltip-tipsy .ui-tooltip-content{background:transparent;background:rgba(0,0,0,.87);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#D9000000,endColorstr=#D9000000);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#D9000000,endColorstr=#D9000000)";color:white;border:0 transparent;font-size:11px;font-family:'Lucida Grande',sans-serif;font-weight:bold;line-height:16px;text-shadow:0 1px black;}.ui-tooltip-tipsy .ui-tooltip-titlebar{padding:6px 35px 0 10;}.ui-tooltip-tipsy .ui-tooltip-content{padding:6px 10;}.ui-tooltip-tipsy .ui-tooltip-icon{border-color:#222;text-shadow:none;}.ui-tooltip-tipsy .ui-tooltip-titlebar .ui-state-hover{border-color:#303030;}.ui-tooltip-tipped .ui-tooltip-titlebar,.ui-tooltip-tipped .ui-tooltip-content{border:3px solid #959FA9;}.ui-tooltip-tipped .ui-tooltip-titlebar{background:#3A79B8;background-image:-moz-linear-gradient(top,#3A79B8,#2E629D);background-image:-webkit-gradient(linear,left top,left bottom,from(#3A79B8),to(#2E629D));filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#3A79B8,endColorstr=#2E629D);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#3A79B8,endColorstr=#2E629D)";color:white;font-weight:normal;font-family:serif;border-bottom-width:0;-moz-border-radius:3px 3px 0 0;-webkit-border-radius:3px 3px 0 0;border-radius:3px 3px 0 0;}.ui-tooltip-tipped .ui-tooltip-content{background-color:#F9F9F9;color:#454545;-moz-border-radius:0 0 3px 3px;-webkit-border-radius:0 0 3px 3px;border-radius:0 0 3px 3px;}.ui-tooltip-tipped .ui-tooltip-icon{border:2px solid #285589;background:#285589;}.ui-tooltip-tipped .ui-tooltip-icon .ui-icon{background-color:#FBFBFB;color:#555;} \ No newline at end of file
diff --git a/libgpl/qtip/qtip.js b/libgpl/qtip/qtip.js
new file mode 100644
index 0000000..7f5b9d9
--- /dev/null
+++ b/libgpl/qtip/qtip.js
@@ -0,0 +1,68 @@
+(function(c,C,N){function X(a){var b=this,f=a.elements,e=f.tooltip,g=".bgiframe-"+a.id;c.extend(b,{init:function(){f.bgiframe=c('<iframe class="ui-tooltip-bgiframe" frameborder="0" tabindex="-1" src="javascript:\'\';" style="display:block; position:absolute; z-index:-1; filter:alpha(opacity=0); -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";"></iframe>');f.bgiframe.appendTo(e);e.bind("tooltipmove"+g,b.adjust)},adjust:function(){var b=a.get("dimensions"),c=a.plugins.tip,h=f.tip,g,
+i;i=parseInt(e.css("border-left-width"),10)||0;i={left:-i,top:-i};c&&h&&(g="x"===c.corner.precedance?["width","left"]:["height","top"],i[g[1]]-=h[g[0]]());f.bgiframe.css(i).css(b)},destroy:function(){f.bgiframe.remove();e.unbind(g)}});b.init()}function Y(a){var b=this,f=a.options.show.modal,e=a.elements,r=e.tooltip,o=".qtipmodal"+a.id,m;a.checks.modal={"^show.modal.(on|blur)$":function(){b.init();e.overlay.toggle(r.is(":visible"))}};c.extend(b,{init:function(){if(!f.on)return b;m=b.create();r.attr("is-modal-qtip",
+p).unbind(".qtipmodal").unbind(o).bind("tooltipshow.qtipmodal tooltiphide.qtipmodal",function(a,c,f){b[a.type.replace("tooltip","")](a,f)}).bind("tooltipfocus.qtipmodal",function(a,c,b){m[0].style.zIndex=b-1}).bind("tooltipblur.qtipmodal",function(a){c("[is-modal-qtip]:visible").not(r).last().qtip("focus",a)});f.escape&&c(C).unbind(o).bind("keydown"+o,function(c){27===c.keyCode&&r.hasClass(P)&&a.hide(c)});f.blur&&e.overlay.unbind(o).bind("click"+o,function(c){r.hasClass(P)&&a.hide(c)});return b},
+create:function(){var a=c("#qtip-overlay");if(a.length)return e.overlay=a;m=e.overlay=c("<div />",{id:"qtip-overlay",css:{position:"absolute",top:0,left:0,display:"none"},mousedown:function(){return g}}).appendTo(document.body);c(C).unbind(".qtipmodal").bind("resize.qtipmodal",function(){m.css({height:Math.max(c(C).height(),c(document).height()),width:Math.max(c(C).width(),c(document).width())})}).trigger("resize");return m},toggle:function(a,q,i){if(a&&a.isDefaultPrevented())return b;var a=f.effect,
+o=q?"show":"hide",t=c("[is-modal-qtip]:visible").not(r);m||(m=b.create());if(m.is(":animated")&&!q||!q&&t.length)return b;q&&e.overlay.css("cursor",f.blur?"pointer":"");m.stop(p,g);c.isFunction(a)?a.call(m,q):a===g?m[o]():m.fadeTo(parseInt(i,10)||90,q?0.7:0,function(){q||c(this).hide()});return b},show:function(a,c){return b.toggle(a,p,c)},hide:function(a,c){return b.toggle(a,g,c)},destroy:function(){var b=m;b&&(b=1>c("[is-modal-qtip]").not(r).length,b?(e.overlay.remove(),c(C).unbind(".qtipmodal")):
+e.overlay.unbind(".qtipmodal"+a.id));return r.removeAttr("is-modal-qtip").unbind(".qtipmodal")}});b.init()}function Z(a){function b(a){var c="y"===a.precedance,b=A[c?"width":"height"],d=A[c?"height":"width"],f=-1<a.string().indexOf("center"),k=b*(f?0.5:1),u=Math.pow,a=Math.round,F=Math.sqrt(u(k,2)+u(d,2)),k=[v/k*F,v/d*F];k[2]=Math.sqrt(u(k[0],2)-u(v,2));k[3]=Math.sqrt(u(k[1],2)-u(v,2));f=(F+k[2]+k[3]+(f?0:k[0]))/F;b=[a(f*d),a(f*b)];return{height:b[c?0:1],width:b[c?1:0]}}function f(a,c,b){c=c?c:a[a.precedance];
+c="border-"+c+"-width";a=parseInt((i.titlebar&&"top"===a.y?i.titlebar:i.content).css(c),10);return(b?a||parseInt(n.css(c),10):a)||0}function e(b,d,f){if(i.tip){var b=c.extend({},h.corner),d=f.adjusted,e=a.options.position.adjust.method.split(" "),v=e[0],e=e[1]||e[0],k=g,u=g,F=0,K=0,l,D={},M;h.corner.fixed!==p&&("shift"===v&&"x"===b.precedance&&d.left&&"center"!==b.y?b.precedance="x"===b.precedance?"y":"x":"flip"===v&&d.left&&(b.x="center"===b.x?0<d.left?"left":"right":"left"===b.x?"right":"left"),
+"shift"===e&&"y"===b.precedance&&d.top&&"center"!==b.x?b.precedance="y"===b.precedance?"x":"y":"flip"===e&&d.top&&(b.y="center"===b.y?0<d.top?"top":"bottom":"top"===b.y?"bottom":"top"),b.string()!==r&&(o!==d.top||m!==d.left)&&h.update(b,g));l=h.position(b,d);l.right!==N&&(l.left=-l.right);l.bottom!==N&&(l.top=-l.bottom);l.user=Math.max(0,q.offset);if(k="shift"===v&&!!d.left)"center"===b.x?D["margin-left"]=F=l["margin-left"]-d.left:(M=l.right!==N?[d.left,-l.left]:[-d.left,l.left],(F=Math.max(M[0],
+M[1]))>M[0]&&(f.left-=d.left,k=g),D[l.right!==N?"right":"left"]=F);if(u="shift"===e&&!!d.top)"center"===b.y?D["margin-top"]=K=l["margin-top"]-d.top:(M=l.bottom!==N?[d.top,-l.top]:[-d.top,l.top],(K=Math.max(M[0],M[1]))>M[0]&&(f.top-=d.top,u=g),D[l.bottom!==N?"bottom":"top"]=K);i.tip.css(D).toggle(!(F&&K||"center"===b.x&&K||"center"===b.y&&F));f.left-=l.left.charAt?l.user:"shift"!==v||u||!k&&!u?l.left:0;f.top-=l.top.charAt?l.user:"shift"!==e||k||!k&&!u?l.top:0;m=d.left;o=d.top;r=b.string()}}var r,o,
+m,h=this,q=a.options.style.tip,i=a.elements,n=i.tooltip;m=o=0;r="";var A={width:q.width,height:q.height},y,d,v=q.border||0,G=c("<canvas />")[0].getContext;h.corner=x;h.mimic=x;h.position={};a.checks.tip={"^position.my|style.tip.(corner|mimic|border)$":function(){h.init()||h.destroy();a.reposition()},"^style.tip.(height|width)$":function(){A={width:q.width,height:q.height};h.create();h.update();a.reposition()},"^content.title.text|style.(classes|widget)$":function(){i.tip&&h.update()}};c.extend(h,
+{init:function(){var a=h.detectCorner()&&(G||c.browser.msie);a&&(h.create(),h.update(),n.unbind(".qtip-tip").bind("tooltipmove.qtip-tip",e));return a},detectCorner:function(){var b=q.corner,c=a.options.position,d=c.at,c=c.my.string?c.my.string():c.my;if(b===g||c===g&&d===g)return g;b===p?h.corner=new t.Corner(c):b.string||(h.corner=new t.Corner(b),h.corner.fixed=p);return"centercenter"!==h.corner.string()},detectColours:function(){var b,f,j=i.tip.css({backgroundColor:"",border:""});b=h.corner;var e=
+b[b.precedance],g="border-"+e+"-color";f="border"+e.charAt(0)+e.substr(1)+"Color";var e=/rgba?\(0, 0, 0(, 0)?\)|transparent/i,k=c(document.body).css("color"),u=a.elements.content.css("color"),F=i.titlebar&&("top"===b.y||"center"===b.y&&j.position().top+A.height/2+q.offset<i.titlebar.outerHeight(1))?i.titlebar:i.content;n.addClass("ui-tooltip-fluid");b=j.css("background-color")||"transparent";f=j[0].style[f];if(!b||e.test(b))y=F.css("background-color"),e.test(y)&&(y=n.css("background-color")||b);if(!f||
+e.test(f))if(d=n.css(g),e.test(d)||d===k)d=F.css(g),d===u&&(d=f);c("*",j).add(j).css("background-color","transparent").css("border","");n.removeClass("ui-tooltip-fluid")},create:function(){var a=A.width,b=A.height;i.tip&&i.tip.remove();i.tip=c("<div />",{"class":"ui-tooltip-tip"}).css({width:a,height:b}).prependTo(n);G?c("<canvas />").appendTo(i.tip)[0].getContext("2d").save():i.tip.html(v?'<vml:shape coordorigin="0,0" style="display:inline-block; position:absolute; behavior:url(#default#VML);"></vml:shape><vml:shape coordorigin="0,0" style="display:inline-block; position:absolute; behavior:url(#default#VML);"></vml:shape>':
+'<vml:shape coordorigin="0,0" style="display:inline-block; position:absolute; behavior:url(#default#VML);"></vml:shape>')},update:function(a,e){var j=i.tip,r=j.children(),o=A.width,k=A.height,u=q.mimic,F=Math.round,K,l,D,m,n;a||(a=h.corner);u===g?u=a:(u=new t.Corner(u),u.precedance=a.precedance,"inherit"===u.x?u.x=a.x:"inherit"===u.y?u.y=a.y:u.x===u.y&&(u[a.precedance]=a[a.precedance]));K=u.precedance;h.detectColours();v="transparent"===d||"#123456"===d?0:q.border===p?f(a,x,p):q.border;n=u;var B=
+o,S=Math.ceil(B/2),W=Math.ceil(k/2),B={bottomright:[[0,0],[B,k],[B,0]],bottomleft:[[0,0],[B,0],[0,k]],topright:[[0,k],[B,0],[B,k]],topleft:[[0,0],[0,k],[B,k]],topcenter:[[0,k],[S,0],[B,k]],bottomcenter:[[0,0],[B,0],[S,k]],rightcenter:[[0,0],[B,W],[0,k]],leftcenter:[[B,0],[B,k],[0,W]]};B.lefttop=B.bottomright;B.righttop=B.bottomleft;B.leftbottom=B.topright;B.rightbottom=B.topleft;D=B[n.string()];n=b(a);j.css(n);"y"===a.precedance?m=[F("left"===u.x?v:"right"===u.x?n.width-o-v:(n.width-o)/2),F("top"===
+u.y?n.height-k:0)]:m=[F("left"===u.x?n.width-o:0),F("top"===u.y?v:"bottom"===u.y?n.height-k-v:(n.height-k)/2)];G?(r.attr(n),l=r[0].getContext("2d"),l.restore(),l.save(),l.clearRect(0,0,3E3,3E3),l.translate(m[0],m[1]),l.beginPath(),l.moveTo(D[0][0],D[0][1]),l.lineTo(D[1][0],D[1][1]),l.lineTo(D[2][0],D[2][1]),l.closePath(),l.fillStyle=y,l.strokeStyle=d,l.lineWidth=2*v,l.lineJoin="miter",l.miterLimit=100,l.stroke(),l.fill()):(D="m"+D[0][0]+","+D[0][1]+" l"+D[1][0]+","+D[1][1]+" "+D[2][0]+","+D[2][1]+
+" xe",m[2]=v&&/^(r|b)/i.test(a.string())?8===parseFloat(c.browser.version,10)?2:1:0,r.css({antialias:""+(-1<u.string().indexOf("center")),left:m[0]-m[2]*Number("x"===K),top:m[1]-m[2]*Number("y"===K),width:o+v,height:k+v}).each(function(a){var b=c(this);b.attr({coordsize:o+v+" "+(k+v),path:D,fillcolor:y,filled:!!a,stroked:!a}).css({display:v||a?"block":"none"});!a&&0<v&&""===b.html()&&b.html('<vml:stroke weight="'+2*v+'px" color="'+d+'" miterlimit="1000" joinstyle="miter" style="behavior:url(#default#VML); display:inline-block;" />')}));
+e!==g&&h.position(a)},position:function(a){var d=i.tip,e={},r=Math.max(0,q.offset),m,k,u;if(q.corner===g||!d)return g;a=a||h.corner;m=a.precedance;k=b(a);u=[a.x,a.y];"x"===m&&u.reverse();c.each(u,function(b,d){var u;if("center"===d)u="y"===m?"left":"top",e[u]="50%",e["margin-"+u]=-Math.round(k["y"===m?"width":"height"]/2)+r;else{u=f(a,d,p);var g;g=c.browser.mozilla;var h=a.y+(g?"":"-")+a.x;g=(g?"-moz-":c.browser.webkit?"-webkit-":"")+(g?"border-radius-"+h:"border-"+h+"-radius");g=parseInt((i.titlebar&&
+"top"===a.y?i.titlebar:i.content).css(g),10)||parseInt(n.css(g),10)||0;e[d]=b?f(a,d):r+(g>u?g:0)}});e[a[m]]-=k["x"===m?"width":"height"];d.css({top:"",bottom:"",left:"",right:"",margin:""}).css(e);return e},destroy:function(){i.tip&&i.tip.remove();n.unbind(".qtip-tip")}});h.init()}function $(a){var b=this,f=a.elements.tooltip,e=a.options.content.ajax,r=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi;a.checks.ajax={"^content.ajax":function(a,c,g){"ajax"===c&&(e=g);"once"===c?b.init():e&&e.url?
+b.load():f.unbind(".qtip-ajax")}};c.extend(b,{init:function(){e&&e.url&&f.unbind(".qtip-ajax")[e.once?"one":"bind"]("tooltipshow.qtip-ajax",b.load);return b},load:function(o,m){function h(){p&&(f.css("visibility",""),m=g)}if(o&&o.isDefaultPrevented())return b;var q=e.url.indexOf(" "),i=e.url,n,p=e.once&&!e.loading&&m;p&&f.css("visibility","hidden");-1<q&&(n=i.substr(q),i=i.substr(0,q));c.ajax(c.extend({success:function(b){n&&(b=c("<div/>").append(b.replace(r,"")).find(n));a.set("content.text",b);
+h()},error:function(b,c,f){a.set("content.text",c+": "+f);h()},context:a},e,{url:i}));return b}});b.init()}function aa(a,b,f,e){function r(a,u,e,g){var g=0!==parseInt(g,10),l=".qtip-"+f,j=a&&b.show.target[0],u=u&&b.hide.target[0],h=e&&d.rendered&&w.tooltip[0],e=e&&d.rendered&&w.content[0],i=g&&b.position.container[0]===v?document:b.position.container[0],g=g&&C;d.rendered?c([]).pushStack(c.grep([j,u,h,i,e,g],function(a){return"object"===typeof a})).unbind(l):a&&b.show.target.unbind(l+"-create")}function o(k,
+u,e,h){function l(a){j.is(":visible")&&d.reposition(a)}function i(a){if(j.hasClass(L))return g;clearTimeout(d.timers.inactive);d.timers.inactive=setTimeout(function(){d.hide(a)},b.hide.inactive)}function r(a){if(j.hasClass(L))return g;var k=c(a.relatedTarget||a.target),f=k.closest(T)[0]===j[0],k=k[0]===q[0];clearTimeout(d.timers.show);clearTimeout(d.timers.hide);if("mouse"===t.target&&f||b.hide.fixed&&/mouse(out|leave|move)/.test(a.type)&&(f||k))return a.stopPropagation(),a.preventDefault(),g;0<b.hide.delay?
+d.timers.hide=setTimeout(function(){d.hide(a)},b.hide.delay):d.hide(a)}function m(a){if(j.hasClass(L))return g;q.trigger("qtip-"+f+"-inactive");clearTimeout(d.timers.show);clearTimeout(d.timers.hide);var c=function(){d.show(a)};0<b.show.delay?d.timers.show=setTimeout(c,b.show.delay):c()}var q,o,p,n=".qtip-"+f,t=b.position;q=b.show.target;o=b.hide.target;t.container[0]===v&&c(document);p=c(document);var y=c.trim(""+b.show.event).split(" "),z=c.trim(""+b.hide.event).split(" "),s=c.browser.msie&&6===
+parseInt(c.browser.version,10);e&&(b.hide.fixed&&(o=o.add(j),j.bind("mouseover"+n,function(){j.hasClass(L)||clearTimeout(d.timers.hide)})),"mouse"===t.target&&t.adjust.mouse&&b.hide.event&&j.bind("mouseleave"+n,function(a){(a.relatedTarget||a.target)!==q[0]&&d.hide(a)}),j.bind("mouseenter"+n,function(a){d["mouseenter"===a.type?"focus":"blur"](a)}),j.bind("mouseenter"+n+" mouseleave"+n,function(a){j.toggleClass(ba,"mouseenter"===a.type)}));u&&("number"===typeof b.hide.inactive&&(q.bind("qtip-"+f+"-inactive",
+i),c.each(H.inactiveEvents,function(a,b){o.add(w.tooltip).bind(b+n+"-inactive",i)})),/mouse(over|enter)/i.test(b.show.event)&&!/mouse(out|leave)/i.test(b.hide.event)&&o.bind("mouseleave"+n,function(){clearTimeout(d.timers.show)}),c.each(z,function(a,b){var k=c.inArray(b,y),d=c(o);-1<k&&d.add(q).length===d.length||"unfocus"===b?(q.bind(b+n,function(a){j.is(":visible")?r(a):m(a)}),delete y[k]):o.bind(b+n,r)}));k&&(c.each(y,function(a,b){q.bind(b+n,m)}),"number"===typeof b.hide.distance&&q.bind("mousemove"+
+n,function(a){var c=E.origin||{},k=b.hide.distance,f=Math.abs;c&&(f(a.pageX-c.pageX)>=k||f(a.pageY-c.pageY)>=k)&&d.hide(a)}));h&&((t.adjust.resize||t.viewport)&&c(c.event.special.resize?t.viewport:C).bind("resize"+n,l),(t.viewport||s&&"fixed"===j.css("position"))&&c(t.viewport).bind("scroll"+n,l),/unfocus/i.test(b.hide.event)&&p.bind("mousedown"+n,function(b){var k=c(b.target);0===k.parents(T).length&&1<k.add(a).length&&j.is(":visible")&&!j.hasClass(L)&&d.hide(b)}),b.hide.leave&&/mouseleave|mouseout/i.test(b.hide.event)&&
+c(C).bind("blur"+n+" mouse"+(-1<b.hide.leave.indexOf("frame")?"out":"leave")+n,function(a){a.relatedTarget||d.hide(a)}),"mouse"===t.target&&p.bind("mousemove"+n,function(a){t.adjust.mouse&&!j.hasClass(L)&&j.is(":visible")&&d.reposition(a||Q)}))}function m(k){function f(a){function b(){0===(c=c.not(this)).length&&(d.redraw(),d.reposition(E.event),a())}var c;if(0===(c=e.find("img:not([height]):not([width])")).length)return b.call(c);c.each(function(a,c){(function S(){var k=d.timers.img;if(c.height&&
+c.width)return clearTimeout(k[a]),b.call(c);k[a]=setTimeout(S,20)})()})}var e=w.content,k=k||b.content.text;if(!d.rendered||!k)return g;c.isFunction(k)&&(k=k.call(a,d)||"");k.jquery&&0<k.length?e.empty().append(k.css({display:"block"})):e.html(k);0>d.rendered?j.queue("fx",f):(J=0,f(c.noop));return d}function h(b){var f=w.title;if(!d.rendered||!b)return g;c.isFunction(b)&&(b=b.call(a,d)||"");b.jquery&&0<b.length?f.empty().append(b.css({display:"block"})):f.html(b);d.redraw();d.rendered&&j.is(":visible")&&
+d.reposition(E.event)}function q(){var a=G+"-title";w.titlebar&&n();w.titlebar=c("<div />",{"class":I+"-titlebar "+(b.style.widget?"ui-widget-header":"")}).append(w.title=c("<div />",{id:a,"class":I+"-title","aria-atomic":p})).insertBefore(w.content);b.content.title.button?i():d.rendered&&d.redraw()}function i(){var a=b.content.title.button,f="string"===typeof a?a:"Close tooltip";w.button&&w.button.remove();a.jquery?w.button=a:w.button=c("<a />",{"class":"ui-state-default "+(b.style.widget?"":I+"-icon"),
+title:f,"aria-label":f}).prepend(c("<span />",{"class":"ui-icon ui-icon-close",html:"&times;"}));w.button.appendTo(w.titlebar).attr("role","button").hover(function(a){c(this).toggleClass("ui-state-hover","mouseenter"===a.type)}).click(function(a){j.hasClass(L)||d.hide(a);return g}).bind("mousedown keydown mouseup keyup mouseout",function(a){c(this).toggleClass("ui-state-active ui-state-focus","down"===a.type.substr(-4))});d.redraw()}function n(){w.title&&(w.titlebar.remove(),w.titlebar=w.title=w.button=
+x,d.reposition())}function A(){var a=b.style.widget;j.toggleClass(V,a);w.content.toggleClass(V+"-content",a);w.titlebar&&w.titlebar.toggleClass(V+"-header",a);w.button&&w.button.toggleClass(I+"-icon",!a)}function y(a){for(var c=0,d,f=b,a=a.split(".");f=f[a[c++]];)c<a.length&&(d=f);return[d||b,a.pop()]}var d=this,v=document.body,G=I+"-"+f,R=0,J=0,j=c(),w,E;d.id=f;d.rendered=g;d.elements=w={target:a};d.timers={img:[]};d.options=b;d.checks={};d.plugins={};d.cache=E={event:{},target:x,disabled:g,attr:e};
+d.checks.builtin={"^id$":function(a,b,d){a=d===p?H.nextid:d;b=I+"-"+a;a!==g&&0<a.length&&!c("#"+b).length&&(j[0].id=b,w.content[0].id=b+"-content",w.title[0].id=b+"-title")},"^content.text$":function(a,b,c){m(c)},"^content.title.text$":function(a,b,c){if(!c)return n();!w.title&&c&&q();h(c)},"^content.title.button$":function(a,b,c){a=w.button;b=w.title;d.rendered&&(c?(b||q(),i()):a.remove())},"^position.(my|at)$":function(a,b,c){"string"===typeof c&&(a[b]=new t.Corner(c))},"^position.container$":function(a,
+b,c){d.rendered&&j.appendTo(c)},"^(show|hide).(event|target|fixed|delay|inactive)$":function(a,b,c,f,e){a=[1,0,0];a["show"===e[1]?"push":"unshift"](0);r.apply(d,a);o.apply(d,[1,1,0,0])},"^show.ready$":function(){d.rendered?d.show():d.render(1)},"^style.classes$":function(a,b,d){c.attr(j[0],"class",I+" qtip ui-helper-reset "+d)},"^style.widget|content.title":A,"^events.(render|show|move|hide|focus|blur)$":function(a,b,d){j[(c.isFunction(d)?"":"un")+"bind"]("tooltip"+b,d)}};c.extend(d,{render:function(k){if(d.rendered)return d;
+var f=b.content.title.text,e=c.Event("tooltiprender");c.attr(a[0],"aria-describedby",G);j=w.tooltip=c("<div/>",{id:G,"class":I+" qtip ui-helper-reset "+b.style.classes,width:b.style.width||"",role:"alert","aria-live":"polite","aria-atomic":g,"aria-describedby":G+"-content","aria-hidden":p}).toggleClass(L,E.disabled).data("qtip",d).appendTo(b.position.container).append(w.content=c("<div />",{"class":I+"-content",id:G+"-content","aria-atomic":p}));d.rendered=-1;J=1;f&&(q(),h(f));m();d.rendered=p;A();
+c.each(b.events,function(a,b){c.isFunction(b)&&j.bind("toggle"===a?"tooltipshow tooltiphide":"tooltip"+a,b)});c.each(t,function(){"render"===this.initialize&&this(d)});o(1,1,1,1);j.queue("fx",function(a){e.originalEvent=E.event;j.trigger(e,[d]);J=0;d.redraw();(b.show.ready||k)&&d.show(E.event);a()});return d},get:function(a){switch(a.toLowerCase()){case "dimensions":a={height:j.outerHeight(),width:j.outerWidth()};break;case "offset":a=t.offset(j,b.position.container);break;default:a=y(a.toLowerCase()),
+a=a[0][a[1]],a=a.precedance?a.string():a}return a},set:function(a,f){var e=/^position\.(my|at|adjust|target|container)|style|content|show\.ready/i,h=/^content\.(title|attr)|style/i,l=g,i=g,r=d.checks,q;"string"===typeof a?(q=a,a={},a[q]=f):a=c.extend(p,{},a);c.each(a,function(b,d){var f=y(b.toLowerCase()),g;g=f[0][f[1]];f[0][f[1]]="object"===typeof d&&d.nodeType?c(d):d;a[b]=[f[0],f[1],d,g];l=e.test(b)||l;i=h.test(b)||i});U(b);R=J=1;c.each(a,function(a,b){var c,f,k;for(c in r)for(f in r[c])if(k=RegExp(f,
+"i").exec(a))b.push(k),r[c][f].apply(d,b)});R=J=0;j.is(":visible")&&d.rendered&&(l&&d.reposition("mouse"===b.position.target?x:E.event),i&&d.redraw());return d},toggle:function(a,e){function h(){a?(c.browser.msie&&j[0].style.removeAttribute("filter"),j.css("overflow","")):j.css({display:"",visibility:"",width:"",opacity:"",left:"",top:""})}if(!d.rendered)if(a)d.render(1);else return d;var i=a?"show":"hide",l=b[i],r=j.is(":visible");(typeof a).search("boolean|number")&&(a=!r);if(r===a)return d;if(e){if(/over|enter/.test(e.type)&&
+/out|leave/.test(E.event.type)&&e.target===b.show.target[0]&&j.has(e.relatedTarget).length)return d;E.event=c.extend({},e)}r=c.Event("tooltip"+i);r.originalEvent=e?E.event:x;j.trigger(r,[d,90]);if(r.isDefaultPrevented())return d;c.attr(j[0],"aria-hidden",!a);a?(E.origin=c.extend({},Q),d.focus(e),c.isFunction(b.content.text)&&m(),d.reposition(e),l.solo&&c(T,l.solo).not(j).qtip("hide",r)):(clearTimeout(d.timers.show),delete E.origin,d.blur(e));j.stop(0,1);c.isFunction(l.effect)?(l.effect.call(j,d),
+j.queue("fx",function(a){h();a()})):l.effect===g?(j[i](),h.call(j)):j.fadeTo(90,a?1:0,h);a&&l.target.trigger("qtip-"+f+"-inactive");return d},show:function(a){return d.toggle(p,a)},hide:function(a){return d.toggle(g,a)},focus:function(a){if(!d.rendered)return d;var b=c(T),f=parseInt(j[0].style.zIndex,10),e=H.zindex+b.length,a=c.extend({},a),g;j.hasClass(P)||(g=c.Event("tooltipfocus"),g.originalEvent=a,j.trigger(g,[d,e]),g.isDefaultPrevented()||(f!==e&&(b.each(function(){this.style.zIndex>f&&(this.style.zIndex-=
+1)}),b.filter("."+P).qtip("blur",a)),j.addClass(P)[0].style.zIndex=e));return d},blur:function(a){var a=c.extend({},a),b;j.removeClass(P);b=c.Event("tooltipblur");b.originalEvent=a;j.trigger(b,[d]);return d},reposition:function(a,f){if(!d.rendered||R)return d;R=1;var e=b.position.target,h=b.position,l=h.my,i=h.at,r=h.adjust,q=r.method.split(" "),m=j.outerWidth(),n=j.outerHeight(),o=0,p=0,y=c.Event("tooltipmove"),w="fixed"===j.css("position"),z=h.viewport,s={left:0,top:0},A=(d.plugins.tip||{}).corner,
+x={horizontal:q[0],vertical:q[1]||q[0],tip:b.style.tip||{},left:function(a){var b="shift"===x.horizontal,c=z.offset.left+z.scrollLeft,d="left"===l.x?m:"right"===l.x?-m:-m/2,f="left"===i.x?o:"right"===i.x?-o:-o/2,e=x.tip.width+2*x.tip.border||0,g=A&&"x"===A.precedance&&!b?e:0,h=c-a-g,k=a+m-z.width-c+g,f=d-("x"===l.precedance||l.x===l.y?f:0),j="center"===l.x;b?(g=A&&"y"===A.precedance?e:0,f=("left"===l.x?1:-1)*d-g,s.left+=0<h?h:0<k?-k:0,s.left=Math.max(z.offset.left+(g&&"center"===A.x?x.tip.offset:
+0),a-f,Math.min(Math.max(z.offset.left+z.width,a+f),s.left))):(0<h&&("left"!==l.x||0<k)?s.left-=f+(j?0:2*r.x):0<k&&("right"!==l.x||0<h)&&(s.left-=j?-f:f+2*r.x),s.left!==a&&j&&(s.left-=r.x),s.left<c&&-s.left>k&&(s.left=a));return s.left-a},top:function(a){var b="shift"===x.vertical,c=z.offset.top+z.scrollTop,d="top"===l.y?n:"bottom"===l.y?-n:-n/2,f="top"===i.y?p:"bottom"===i.y?-p:-p/2,e=x.tip.height+2*x.tip.border||0,g=A&&"y"===A.precedance&&!b?e:0,h=c-a-g,c=a+n-z.height-c+g,f=d-("y"===l.precedance||
+l.x===l.y?f:0),k="center"===l.y;b?(g=A&&"x"===A.precedance?e:0,f=("top"===l.y?1:-1)*d-g,s.top+=0<h?h:0<c?-c:0,s.top=Math.max(z.offset.top+(g&&"center"===A.x?x.tip.offset:0),a-f,Math.min(Math.max(z.offset.top+z.height,a+f),s.top))):(0<h&&("top"!==l.y||0<c)?s.top-=f+(k?0:2*r.y):0<c&&("bottom"!==l.y||0<h)&&(s.top-=k?-f:f+2*r.y),s.top!==a&&k&&(s.top-=r.y),0>s.top&&-s.top>c&&(s.top=a));return s.top-a}};if("mouse"===e)i={x:"left",y:"top"},a=a&&("resize"===a.type||"scroll"===a.type)?E.event:!r.mouse&&E.origin?
+E.origin:Q&&(r.mouse||!a||!a.pageX)?{pageX:Q.pageX,pageY:Q.pageY}:a,s={top:a.pageY,left:a.pageX};else{"event"===e&&(a&&a.target&&"scroll"!==a.type&&"resize"!==a.type?e=E.target=c(a.target):e=E.target);e=c(e).eq(0);if(0===e.length)return d;e[0]===document||e[0]===C?(o=t.iOS?C.innerWidth:e.width(),p=t.iOS?C.innerHeight:e.height(),e[0]===C&&(s={top:!w||t.iOS?z.scrollTop():0,left:!w||t.iOS?z.scrollLeft():0})):e.is("area")&&t.imagemap?s=t.imagemap(e,i):"http://www.w3.org/2000/svg"===e[0].namespaceURI&&
+t.svg?s=t.svg(e,i):(o=e.outerWidth(),p=e.outerHeight(),s=t.offset(e,h.container,w));s.offset&&(o=s.width,p=s.height,s=s.offset);s.left+="right"===i.x?o:"center"===i.x?o/2:0;s.top+="bottom"===i.y?p:"center"===i.y?p/2:0}s.left+=r.x+("right"===l.x?-m:"center"===l.x?-m/2:0);s.top+=r.y+("bottom"===l.y?-n:"center"===l.y?-n/2:0);z.jquery&&e[0]!==C&&e[0]!==v&&"nonenone"!==x.vertical+x.horizontal?(z={elem:z,height:z[(z[0]===C?"h":"outerH")+"eight"](),width:z[(z[0]===C?"w":"outerW")+"idth"](),scrollLeft:z.scrollLeft(),
+scrollTop:z.scrollTop(),offset:z.offset()||{left:0,top:0}},s.adjusted={left:"none"!==x.horizontal?x.left(s.left):0,top:"none"!==x.vertical?x.top(s.top):0}):s.adjusted={left:0,top:0};j.attr("class",function(){return c.attr(this,"class").replace(/ui-tooltip-pos-\w+/i,"")}).addClass(I+"-pos-"+l.abbreviation());y.originalEvent=c.extend({},a);j.trigger(y,[d,s,z.elem||z]);if(y.isDefaultPrevented())return d;delete s.adjusted;f===g||isNaN(s.left)||isNaN(s.top)||!c.isFunction(h.effect)?j.css(s):c.isFunction(h.effect)&&
+(h.effect.call(j,d,c.extend({},s)),j.queue(function(a){c(this).css({opacity:"",height:""});c.browser.msie&&this.style.removeAttribute("filter");a()}));R=0;return d},redraw:function(){if(1>d.rendered||b.style.width||J)return d;var a=I+"-fluid",f=b.position.container,e,g,h;J=1;j.css("width","").addClass(a);e=j.width()+(c.browser.mozilla?1:0);g=j.css("max-width")||"";h=j.css("min-width")||"";f=-1<(g+h).indexOf("%")?f.width()/100:0;g=(-1<g.indexOf("%")?f:1)*parseInt(g,10)||e;h=(-1<h.indexOf("%")?f:1)*
+parseInt(h,10)||0;e=g+h?Math.min(Math.max(e,h),g):e;j.css("width",Math.round(e)).removeClass(a);J=0;return d},disable:function(a){var b=L;"boolean"!==typeof a&&(a=!j.hasClass(b)&&!E.disabled);d.rendered?(j.toggleClass(b,a),c.attr(j[0],"aria-disabled",a)):E.disabled=!!a;return d},enable:function(){return d.disable(g)},destroy:function(){var b=a[0],f=c.attr(b,O);d.rendered&&(j.remove(),c.each(d.plugins,function(){this.destroy&&this.destroy()}));clearTimeout(d.timers.show);clearTimeout(d.timers.hide);
+r(1,1,1,1);c.removeData(b,"qtip");f&&(c.attr(b,"title",f),a.removeAttr(O));a.removeAttr("aria-describedby").unbind(".qtip");return a}})}function U(a){var b;if(!a||"object"!==typeof a)return g;"object"!==typeof a.metadata&&(a.metadata={type:a.metadata});if("content"in a){if("object"!==typeof a.content||a.content.jquery)a.content={text:a.content};b=a.content.text||g;!c.isFunction(b)&&(!b&&!b.attr||1>b.length||"object"===typeof b&&!b.jquery)&&(a.content.text=g);"title"in a.content&&("object"!==typeof a.content.title&&
+(a.content.title={text:a.content.title}),b=a.content.title.text||g,!c.isFunction(b)&&(!b&&!b.attr||1>b.length||"object"===typeof b&&!b.jquery)&&(a.content.title.text=g))}"position"in a&&"object"!==typeof a.position&&(a.position={my:a.position,at:a.position});"show"in a&&"object"!==typeof a.show&&(a.show.jquery?a.show={target:a.show}:a.show={event:a.show});"hide"in a&&"object"!==typeof a.hide&&(a.hide.jquery?a.hide={target:a.hide}:a.hide={event:a.hide});"style"in a&&"object"!==typeof a.style&&(a.style=
+{classes:a.style});c.each(t,function(){this.sanitize&&this.sanitize(a)});return a}function ca(){var a=C.console;return a&&(a.error||a.log||c.noop).apply(a,arguments)}var p=!0,g=!1,x=null,H,t,Q,I="ui-tooltip",V="ui-widget",L="ui-state-disabled",T="div.qtip."+I,P=I+"-focus",ba=I+"-hover",O="oldtitle";H=c.fn.qtip=function(a,b,f){var e=(""+a).toLowerCase(),r=x,o="disable"===e?[p]:c.makeArray(arguments).slice(1,10),m=o[o.length-1],h=this[0]?c.data(this[0],"qtip"):x;if(!arguments.length&&h||"api"===e)return h;
+if("string"===typeof a)return this.each(function(){var a=c.data(this,"qtip");if(!a)return p;m&&m.timeStamp&&(a.cache.event=m);if("option"!==e&&"options"!==e||!b)a[e]&&a[e].apply(a[e],o);else if(c.isPlainObject(b)||f!==N)a.set(b,f);else return r=a.get(b),g}),r!==x?r:this;if("object"===typeof a||!arguments.length)return h=U(c.extend(p,{},a)),H.bind.call(this,h,m)};H.bind=function(a,b){return this.each(function(){function f(a){function b(){n.render("object"===typeof a||h.show.ready);o.unbind(e);m.unbind(r)}
+if(n.cache.disabled)return g;n.cache.event=c.extend({},a);0<h.show.delay?(clearTimeout(n.timers.show),n.timers.show=setTimeout(b,h.show.delay),e!==r&&m.bind(r,function(){clearTimeout(n.timers.show)})):b()}var e,r,o,m,h,q=!a.id||a.id===g||1>a.id.length||c("#"+I+"-"+a.id).length?H.nextid++:a.id,i=".qtip-"+q+"-create",n;a:{var A,y,d,v,G=c(this),C=c(document.body),J=this===document?C:G;y=G.metadata?G.metadata(a.metadata):x;v="html5"===a.metadata.type&&y?y[a.metadata.name]:x;var j=G.data(a.metadata.name||
+"qtipopts");try{j="string"===typeof j?(new Function("return "+j))():j}catch(w){ca("Unable to parse HTML5 attribute data: "+j)}v=c.extend(p,{},H.defaults,a,"object"===typeof j?U(j):x,U(v||y));y&&c.removeData(this,"metadata");y=v.position;v.id=q;if("boolean"===typeof v.content.text)if(d=G.attr(v.content.attr),v.content.attr!==g&&d)v.content.text=d;else{n=g;break a}y.container===g&&(y.container=C);y.target===g&&(y.target=J);v.show.target===g&&(v.show.target=J);v.show.solo===p&&(v.show.solo=C);v.hide.target===
+g&&(v.hide.target=J);v.position.viewport===p&&(v.position.viewport=y.container);y.at=new t.Corner(y.at);y.my=new t.Corner(y.my);if(c.data(this,"qtip"))if(v.overwrite)G.qtip("destroy");else if(v.overwrite===g){n=g;break a}c.attr(this,"title")&&(c.attr(this,O,c.attr(this,"title")),this.removeAttribute("title"));A=new aa(G,v,q,!!d);c.data(this,"qtip",A);G.bind("remove.qtip",function(){A.destroy()});n=A}if(n===g)return p;h=n.options;c.each(t,function(){"initialize"===this.initialize&&this(n)});o=h.show.target;
+m=h.hide.target;e=c.trim(""+h.show.event).replace(/ /g,i+" ")+i;r=c.trim(""+h.hide.event).replace(/ /g,i+" ")+i;/mouse(over|enter)/i.test(e)&&!/mouse(out|leave)/i.test(r)&&(r+=" mouseleave"+i);o.bind(e,f);(h.show.ready||h.prerender)&&f(b)})};t=H.plugins={Corner:function(a){a=(""+a).replace(/([A-Z])/," $1").replace(/middle/gi,"center").toLowerCase();this.x=(a.match(/left|right/i)||a.match(/center/)||["inherit"])[0].toLowerCase();this.y=(a.match(/top|bottom|center/i)||["inherit"])[0].toLowerCase();
+this.precedance=-1<a.charAt(0).search(/^(t|b)/)?"y":"x";this.string=function(){return"y"===this.precedance?this.y+this.x:this.x+this.y};this.abbreviation=function(){var a=this.x.substr(0,1),c=this.y.substr(0,1);return a===c?a:"c"===a||"c"!==a&&"c"!==c?c+a:a+c}},offset:function(a,b,f){var a=a.offset(),e=b,g=0,o=document.body,m;if(e){do{if(e[0]===o)break;"static"!==e.css("position")&&(m=e.position(),a.left-=m.left+(parseInt(e.css("borderLeftWidth"),10)||0),a.top-=m.top+(parseInt(e.css("borderTopWidth"),
+10)||0),g++)}while(e=e.offsetParent());if(b[0]!==o||1<g)a.left+=1*b.scrollLeft(),a.top+=1*b.scrollTop();if(4.1>t.iOS&&3.1<t.iOS||!t.iOS&&f)b=c(C),a.left+=-1*b.scrollLeft(),a.top+=-1*b.scrollTop()}return a},iOS:parseFloat((""+(/CPU.*OS ([0-9_]{1,3})|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent)||[0,""])[1]).replace("undefined","3_2").replace("_","."))||g,fn:{attr:function(a,b){if(this.length){var f=this[0],e=c.data(f,"qtip");if("title"===a){if(2>arguments.length)return c.attr(f,O);if("object"===
+typeof e)return e&&e.rendered&&"title"===e.options.content.attr&&e.cache.attr&&e.set("content.text",b),c.fn.attr_replacedByqTip.apply(this,arguments),c.attr(f,O,c.attr(f,"title")),this.removeAttr("title")}}},clone:function(a){c([]);return c.fn.clone_replacedByqTip.apply(this,arguments).filter("[oldtitle]").each(function(){c.attr(this,"title",c.attr(this,O));this.removeAttribute(O)}).end()},remove:c.ui?x:function(a,b){c(this).each(function(){b||(!a||c.filter(a,[this]).length)&&c("*",this).add(this).each(function(){c(this).triggerHandler("remove")})})}}};
+c.each(t.fn,function(a,b){if(!b)return p;var f=c.fn[a+"_replacedByqTip"]=c.fn[a];c.fn[a]=function(){return b.apply(this,arguments)||f.apply(this,arguments)}});c(document).bind("mousemove.qtip",function(a){Q={pageX:a.pageX,pageY:a.pageY,type:"mousemove"}});H.version="nightly";H.nextid=0;H.inactiveEvents="click dblclick mousedown mouseup mousemove mouseleave mouseenter".split(" ");H.zindex=15E3;H.defaults={prerender:g,id:g,overwrite:p,content:{text:p,attr:"title",title:{text:g,button:g}},position:{my:"top left",
+at:"bottom right",target:g,container:g,viewport:g,adjust:{x:0,y:0,mouse:p,resize:p,method:"flip flip"},effect:p},show:{target:g,event:"mouseenter",effect:p,delay:90,solo:g,ready:g},hide:{target:g,event:"mouseleave",effect:p,delay:0,fixed:g,inactive:g,leave:"window",distance:g},style:{classes:"",widget:g,width:g},events:{render:x,move:x,show:x,hide:x,toggle:x,focus:x,blur:x}};t.ajax=function(a){var b=a.plugins.ajax;return"object"===typeof b?b:a.plugins.ajax=new $(a)};t.ajax.initialize="render";t.ajax.sanitize=
+function(a){var b=a.content,c;b&&"ajax"in b&&(c=b.ajax,"object"!==typeof c&&(c=a.content.ajax={url:c}),"boolean"!==typeof c.once&&c.once&&(c.once=!!c.once))};c.extend(p,H.defaults,{content:{ajax:{loading:p,once:p}}});t.imagemap=function(a,b){var f=a.attr("shape").toLowerCase(),e=a.attr("coords").split(","),g=[],o=c('img[usemap="#'+a.parent("map").attr("name")+'"]'),m=o.offset(),h={width:0,height:0,offset:{top:1E10,right:0,bottom:0,left:1E10}},q=0,i=0;m.left+=Math.ceil((o.outerWidth()-o.width())/2);
+m.top+=Math.ceil((o.outerHeight()-o.height())/2);if("poly"===f)for(q=e.length;q--;)i=[parseInt(e[--q],10),parseInt(e[q+1],10)],i[0]>h.offset.right&&(h.offset.right=i[0]),i[0]<h.offset.left&&(h.offset.left=i[0]),i[1]>h.offset.bottom&&(h.offset.bottom=i[1]),i[1]<h.offset.top&&(h.offset.top=i[1]),g.push(i);else g=c.map(e,function(a){return parseInt(a,10)});switch(f){case "rect":h={width:Math.abs(g[2]-g[0]),height:Math.abs(g[3]-g[1]),offset:{left:g[0],top:g[1]}};break;case "circle":h={width:g[2]+2,height:g[2]+
+2,offset:{left:g[0],top:g[1]}};break;case "poly":c.extend(h,{width:Math.abs(h.offset.right-h.offset.left),height:Math.abs(h.offset.bottom-h.offset.top)});if("centercenter"===b.string())h.offset={left:h.offset.left+h.width/2,top:h.offset.top+h.height/2};else{for(var e=f=h,g=g.slice(),o=0,i=q=1,n=0,p=0,t=e.width,d=e.height;0<t&&0<d&&0<q&&0<i;){t=Math.floor(t/2);d=Math.floor(d/2);"left"===b.x?q=t:"right"===b.x?q=e.width-t:q+=Math.floor(t/2);"top"===b.y?i=d:"bottom"===b.y?i=e.height-d:i+=Math.floor(d/
+2);for(o=g.length;o--&&!(2>g.length);)n=g[o][0]-e.offset.left,p=g[o][1]-e.offset.top,("left"===b.x&&n>=q||"right"===b.x&&n<=q||"center"===b.x&&(n<q||n>e.width-q)||"top"===b.y&&p>=i||"bottom"===b.y&&p<=i||"center"===b.y&&(p<i||p>e.height-i))&&g.splice(o,1)}f.offset={left:g[0][0],top:g[0][1]}}h.width=h.height=0}h.offset.left+=m.left;h.offset.top+=m.top;return h};t.tip=function(a){var b=a.plugins.tip;return"object"===typeof b?b:a.plugins.tip=new Z(a)};t.tip.initialize="render";t.tip.sanitize=function(a){var b=
+a.style,c;b&&"tip"in b&&(c=a.style.tip,"object"!==typeof c&&(a.style.tip={corner:c}),/string|boolean/i.test(typeof c.corner)||(c.corner=p),"number"!==typeof c.width&&delete c.width,"number"!==typeof c.height&&delete c.height,"number"!==typeof c.border&&c.border!==p&&delete c.border,"number"!==typeof c.offset&&delete c.offset)};c.extend(p,H.defaults,{style:{tip:{corner:p,mimic:g,width:6,height:6,border:p,offset:0}}});t.svg=function(a){var b=c(document),f=a[0],a={width:0,height:0,offset:{top:1E10,left:1E10}},
+e,g,o;if(f.getBBox&&f.parentNode){e=f.getBBox();g=f.getScreenCTM();f=f.farthestViewportElement||f;if(!f.createSVGPoint)return a;f=f.createSVGPoint();f.x=e.x;f.y=e.y;o=f.matrixTransform(g);a.offset.left=o.x;a.offset.top=o.y;f.x+=e.width;f.y+=e.height;o=f.matrixTransform(g);a.width=o.x-a.offset.left;a.height=o.y-a.offset.top;a.offset.left+=b.scrollLeft();a.offset.top+=b.scrollTop()}return a};t.modal=function(a){var b=a.plugins.modal;return"object"===typeof b?b:a.plugins.modal=new Y(a)};t.modal.initialize=
+"render";t.modal.sanitize=function(a){a.show&&("object"!==typeof a.show.modal?a.show.modal={on:!!a.show.modal}:"undefined"===typeof a.show.modal.on&&(a.show.modal.on=p))};c.extend(p,H.defaults,{show:{modal:{on:g,effect:p,blur:p,escape:p}}});t.bgiframe=function(a){var b=c.browser,f=a.plugins.bgiframe;return 1>c("select, object").length||!b.msie||"6"!==b.version.charAt(0)?g:"object"===typeof f?f:a.plugins.bgiframe=new X(a)};t.bgiframe.initialize="render"})(jQuery,window); \ No newline at end of file
diff --git a/libgpl/querystring/querystring.js b/libgpl/querystring/querystring.js
new file mode 100644
index 0000000..c5d5b83
--- /dev/null
+++ b/libgpl/querystring/querystring.js
@@ -0,0 +1,34 @@
+function PageQuery(q) {
+ if(q.length > 1) this.q = q.substring(1, q.length);
+ else this.q = null;
+ this.keyValuePairs = new Array();
+ if(q) {
+ for(var i=0; i < this.q.split("&").length; i++) {
+ this.keyValuePairs[i] = this.q.split("&")[i];
+ }
+ }
+ this.getKeyValuePairs = function() { return this.keyValuePairs; }
+ this.getValue = function(s) {
+ for(var j=0; j < this.keyValuePairs.length; j++) {
+ if(this.keyValuePairs[j].split("=")[0] == s)
+ return this.keyValuePairs[j].split("=")[1];
+ }
+ return false;
+ }
+ this.getParameters = function() {
+ var a = new Array(this.getLength());
+ for(var j=0; j < this.keyValuePairs.length; j++) {
+ a[j] = this.keyValuePairs[j].split("=")[0];
+ }
+ return a;
+ }
+ this.getLength = function() { return this.keyValuePairs.length; }
+}
+function queryString(key){
+ var page = new PageQuery(window.location.search);
+ var query = page.getValue(key);
+ if(query !== false){
+ query = unescape(query);
+ }
+ return query;
+} \ No newline at end of file
diff --git a/libgpl/skins/classic/calendar.css b/libgpl/skins/classic/calendar.css
new file mode 100644
index 0000000..b9c3009
--- /dev/null
+++ b/libgpl/skins/classic/calendar.css
@@ -0,0 +1,4 @@
+.ui-dialog .ui-dialog-titlebar-close:hover { padding: 1px !important; }
+.ui-dialog .ui-dialog-titlebar-close { border: 1px solid #aaaaaa; background: #e6e6e7 url(images/ui-bg_highlight-hard_75_e6e6e7_1x100.png); height: 16px; width: 16px; }
+.ui-dialog .ui-dialog-title { min-width: 230px; }
+.ui-icon-closethick { background-position: -97px -129px; } \ No newline at end of file
diff --git a/libgpl/skins/classic/images/convert.png b/libgpl/skins/classic/images/convert.png
new file mode 100644
index 0000000..d57a19e
--- /dev/null
+++ b/libgpl/skins/classic/images/convert.png
Binary files differ
diff --git a/libgpl/skins/classic/images/delete.png b/libgpl/skins/classic/images/delete.png
new file mode 100644
index 0000000..af1ecaf
--- /dev/null
+++ b/libgpl/skins/classic/images/delete.png
Binary files differ
diff --git a/libgpl/skins/classic/images/door.png b/libgpl/skins/classic/images/door.png
new file mode 100644
index 0000000..369fc46
--- /dev/null
+++ b/libgpl/skins/classic/images/door.png
Binary files differ
diff --git a/libgpl/skins/classic/images/edit.png b/libgpl/skins/classic/images/edit.png
new file mode 100644
index 0000000..b93e776
--- /dev/null
+++ b/libgpl/skins/classic/images/edit.png
Binary files differ
diff --git a/libgpl/skins/classic/images/message.png b/libgpl/skins/classic/images/message.png
new file mode 100644
index 0000000..be1305e
--- /dev/null
+++ b/libgpl/skins/classic/images/message.png
Binary files differ
diff --git a/libgpl/skins/classic/images/note.png b/libgpl/skins/classic/images/note.png
new file mode 100644
index 0000000..6be00b6
--- /dev/null
+++ b/libgpl/skins/classic/images/note.png
Binary files differ
diff --git a/libgpl/skins/classic/images/task.png b/libgpl/skins/classic/images/task.png
new file mode 100644
index 0000000..2d0a5f8
--- /dev/null
+++ b/libgpl/skins/classic/images/task.png
Binary files differ
diff --git a/libgpl/skins/classic/images/ui-bg_highlight-hard_75_f8f8f8_1x100.png b/libgpl/skins/classic/images/ui-bg_highlight-hard_75_f8f8f8_1x100.png
new file mode 100644
index 0000000..e228645
--- /dev/null
+++ b/libgpl/skins/classic/images/ui-bg_highlight-hard_75_f8f8f8_1x100.png
Binary files differ
diff --git a/libgpl/skins/classic/images/ui-bg_highlight-hard_90_e6e6e7_1x100.png b/libgpl/skins/classic/images/ui-bg_highlight-hard_90_e6e6e7_1x100.png
new file mode 100644
index 0000000..d0a127f
--- /dev/null
+++ b/libgpl/skins/classic/images/ui-bg_highlight-hard_90_e6e6e7_1x100.png
Binary files differ
diff --git a/libgpl/skins/classic/images/ui-bg_highlight-soft_90_e4e4e4_1x100.png b/libgpl/skins/classic/images/ui-bg_highlight-soft_90_e4e4e4_1x100.png
new file mode 100644
index 0000000..675c051
--- /dev/null
+++ b/libgpl/skins/classic/images/ui-bg_highlight-soft_90_e4e4e4_1x100.png
Binary files differ
diff --git a/libgpl/skins/classic/images/ui-icons_004458_256x240.png b/libgpl/skins/classic/images/ui-icons_004458_256x240.png
new file mode 100644
index 0000000..083a564
--- /dev/null
+++ b/libgpl/skins/classic/images/ui-icons_004458_256x240.png
Binary files differ
diff --git a/libgpl/skins/classic/jquery.contextMenu.css b/libgpl/skins/classic/jquery.contextMenu.css
new file mode 100644
index 0000000..9512401
--- /dev/null
+++ b/libgpl/skins/classic/jquery.contextMenu.css
@@ -0,0 +1,141 @@
+/*!
+ * jQuery contextMenu - Plugin for simple contextMenu handling
+ *
+ * Version: git-master
+ *
+ * Authors: Rodney Rehm, Addy Osmani (patches for FF)
+ * Web: http://medialize.github.com/jQuery-contextMenu/
+ *
+ * Licensed under
+ * MIT License http://www.opensource.org/licenses/mit-license
+ * GPL v3 http://opensource.org/licenses/GPL-3.0
+ *
+ */
+
+.context-menu-list {
+ margin:0;
+ padding:0;
+
+ min-width: 120px;
+ max-width: 250px;
+ display: inline-block;
+ position: absolute;
+ list-style-type: none;
+
+ border: 1px solid #DDD;
+ background: #EEE;
+
+ -webkit-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
+ -moz-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
+ -ms-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
+ -o-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
+
+ font-family: Verdana, Arial, Helvetica, sans-serif;
+ font-size: 11px;
+}
+
+.context-menu-item {
+ padding: 2px 2px 2px 24px;
+ background-color: #EEE;
+ position: relative;
+ -webkit-user-select: none;
+ -moz-user-select: -moz-none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.context-menu-separator {
+ padding-bottom:0;
+ border-bottom: 1px solid #DDD;
+}
+
+.context-menu-item > label > input,
+.context-menu-item > label > textarea {
+ -webkit-user-select: text;
+ -moz-user-select: text;
+ -ms-user-select: text;
+ user-select: text;
+}
+
+.context-menu-item.hover {
+ cursor: pointer;
+}
+
+.context-menu-item.disabled {
+ color: #666;
+}
+
+.context-menu-input.hover,
+.context-menu-item.disabled.hover {
+ cursor: default;
+ background-color: #EEE;
+}
+
+.context-menu-submenu:after {
+ content: ">";
+ color: #666;
+ position: absolute;
+ top: 0;
+ right: 3px;
+ z-index: 1;
+}
+
+/* icons
+ #protip:
+ In case you want to use sprites for icons (which I would suggest you do) have a look at
+ http://css-tricks.com/13224-pseudo-spriting/ to get an idea of how to implement
+ .context-menu-item.icon:before {}
+ */
+.context-menu-item.icon { min-height: 16px; background-repeat: no-repeat; background-position: 4px 2px; }
+.context-menu-item.icon-message { background-image: url(images/message.png); }
+.context-menu-item.icon-task { background-image: url(../../../tasklist/skins/classic/createfrommail.png); }
+.context-menu-item.icon-note { background-image: url(images/note.png); }
+.context-menu-item.icon-event { background-image: url(../../../calendar/skins/classic/images/calendars.png); background-position: 3px 0; }
+.context-menu-item.icon-edit { background-image: url(images/edit.png); }
+.context-menu-item.icon-delete { background-image: url(images/delete.png); }
+.context-menu-item.icon-convert { background-image: url(images/actions.png); }
+
+/* vertically align inside labels */
+.context-menu-input > label > * { vertical-align: top; }
+
+/* position checkboxes and radios as icons */
+.context-menu-input > label > input[type="checkbox"],
+.context-menu-input > label > input[type="radio"] {
+ margin-left: -17px;
+}
+.context-menu-input > label > span {
+ margin-left: 5px;
+}
+
+.context-menu-input > label,
+.context-menu-input > label > input[type="text"],
+.context-menu-input > label > textarea,
+.context-menu-input > label > select {
+ display: block;
+ width: 100%;
+
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ -ms-box-sizing: border-box;
+ -o-box-sizing: border-box;
+ box-sizing: border-box;
+}
+
+.context-menu-input > label > textarea {
+ height: 100px;
+}
+.context-menu-item > .context-menu-list {
+ display: none;
+ /* re-positioned by js */
+ right: -5px;
+ top: 5px;
+}
+
+.context-menu-item.hover > .context-menu-list {
+ display: block;
+}
+
+.context-menu-accesskey {
+ text-decoration: underline;
+}
diff --git a/libgpl/skins/classic/timepicker2.css b/libgpl/skins/classic/timepicker2.css
new file mode 100644
index 0000000..ee43c69
--- /dev/null
+++ b/libgpl/skins/classic/timepicker2.css
@@ -0,0 +1,10 @@
+/* css for timepicker */
+.ui-timepicker-div .ui-widget-header { margin-bottom: 8px; }
+.ui-timepicker-div dl { text-align: left; }
+.ui-timepicker-div dl dt { height: 25px; margin-bottom: -25px; }
+.ui-timepicker-div dl dd { margin: 0 10px 10px 65px; }
+.ui-timepicker-div td { font-size: 90%; }
+.ui-tpicker-grid-label { background: none; border: none; margin: 0; padding: 0; }
+.ui-timepicker-rtl{ direction: rtl; }
+.ui-timepicker-rtl dl { text-align: right; }
+.ui-timepicker-rtl dl dd { margin: 0 65px 10px 10px; } \ No newline at end of file
diff --git a/libgpl/skins/larry/calendar.css b/libgpl/skins/larry/calendar.css
new file mode 100644
index 0000000..65c1ff0
--- /dev/null
+++ b/libgpl/skins/larry/calendar.css
@@ -0,0 +1,6 @@
+.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: 10px; top: 10px; margin: 0; z-index: 99999; width: 18px; height: 18px; }
+.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 0; background: url(images/ui-icons_004458_256x240.png) -79px -128px no-repeat; width: 18px; height: 18px; }
+.ui-dialog .ui-dialog-titlebar-close, .ui-dialog .ui-dialog-titlebar-close:focus { border: 1px solid #cccccc; background: #f8f8f8 url(images/ui-bg_highlight-hard_75_f8f8f8_1x100.png) 50% 50% repeat-x; }
+.ui-dialog .ui-dialog-titlebar-close:hover { border: 1px solid #cccccc; background: #e4e4e4 url(images/ui-bg_highlight-soft_90_e4e4e4_1x100.png) 50% 50% repeat-x; }
+.ui-dialog .ui-dialog-title { min-width: 230px; }
+.fc-event { cursor: pointer !important; }
diff --git a/libgpl/skins/larry/images/ui-bg_highlight-hard_75_f8f8f8_1x100.png b/libgpl/skins/larry/images/ui-bg_highlight-hard_75_f8f8f8_1x100.png
new file mode 100644
index 0000000..e228645
--- /dev/null
+++ b/libgpl/skins/larry/images/ui-bg_highlight-hard_75_f8f8f8_1x100.png
Binary files differ
diff --git a/libgpl/skins/larry/images/ui-bg_highlight-soft_90_e4e4e4_1x100.png b/libgpl/skins/larry/images/ui-bg_highlight-soft_90_e4e4e4_1x100.png
new file mode 100644
index 0000000..675c051
--- /dev/null
+++ b/libgpl/skins/larry/images/ui-bg_highlight-soft_90_e4e4e4_1x100.png
Binary files differ
diff --git a/libgpl/skins/larry/images/ui-icons_004458_256x240.png b/libgpl/skins/larry/images/ui-icons_004458_256x240.png
new file mode 100644
index 0000000..083a564
--- /dev/null
+++ b/libgpl/skins/larry/images/ui-icons_004458_256x240.png
Binary files differ
diff --git a/libgpl/skins/larry/jquery.contextMenu.css b/libgpl/skins/larry/jquery.contextMenu.css
new file mode 100644
index 0000000..7eeb275
--- /dev/null
+++ b/libgpl/skins/larry/jquery.contextMenu.css
@@ -0,0 +1,154 @@
+/*!
+ * jQuery contextMenu - Plugin for simple contextMenu handling
+ *
+ * Version: git-master
+ *
+ * Authors: Rodney Rehm, Addy Osmani (patches for FF)
+ * Web: http://medialize.github.com/jQuery-contextMenu/
+ *
+ * Licensed under
+ * MIT License http://www.opensource.org/licenses/mit-license
+ * GPL v3 http://opensource.org/licenses/GPL-3.0
+ *
+ */
+
+.context-menu-list {
+ margin:0;
+ padding:0;
+
+ min-width: 120px;
+ max-width: 250px;
+ display: inline-block;
+ position: absolute;
+ list-style-type: none;
+
+ border: 1px solid #999;
+ border-radius: 4px;
+ background: #444;
+
+ -webkit-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
+ -moz-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
+ -ms-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
+ -o-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
+
+ font-family: "Lucida Grande",Verdana,Arial,Helvetica,sans-serif;
+ color: #fff;
+ /*text-shadow: 0 1px 1px #333;*/
+ font-size: 11px;
+}
+
+.context-menu-item {
+ padding: 6px 6px 6px 30px;
+ height: 17px;
+ background-color: #444;
+ border-bottom: 1px solid #333;
+ border-top: 1px solid #5a5a5a;
+ position: relative;
+ -webkit-user-select: none;
+ -moz-user-select: -moz-none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.context-menu-item {
+ opacity: 0.2;
+ filter: alpha(opacity=20);
+}
+
+.context-menu-item:hover {
+ opacity: 0.94;
+ filter: alpha(opacity=94);
+ background-color: #008fc7;
+}
+
+.context-menu-separator {
+ padding-bottom:0;
+ border-bottom: 1px solid #DDD;
+}
+
+.context-menu-item > label > input,
+.context-menu-item > label > textarea {
+ -webkit-user-select: text;
+ -moz-user-select: text;
+ -ms-user-select: text;
+ user-select: text;
+}
+
+.context-menu-item.hover {
+ cursor: pointer;
+}
+
+.context-menu-item.disabled {
+ color: #666;
+}
+
+.context-menu-input.hover,
+.context-menu-item.disabled.hover {
+ cursor: default;
+ background-color: #EEE;
+}
+
+.context-menu-submenu:after {
+ content: ">";
+ color: #666;
+ position: absolute;
+ top: 0;
+ right: 3px;
+ z-index: 1;
+}
+
+.context-menu-root { min-width: 135px; white-space: nowrap; overflow: hidden; }
+
+.context-menu-item.icon { padding-right: 5px; background-image: url(../../../../skins/larry/images/listicons.png?v=017c.29530); background-repeat: no-repeat; }
+.context-menu-item.icon-message { background-position: 5px -1291px; }
+.context-menu-item.icon-task { background-position: 5px -2124px; }
+.context-menu-item.icon-note { background-position: 5px -2124px; }
+.context-menu-item.icon-event { background-position: 5px -2124px; }
+.context-menu-item.icon-edit { background-image: url(../../../../skins/larry/images/listicons.png?v=017c.29530); background-repeat: no-repeat; background-position: 5px -1388px; }
+.context-menu-item.icon-delete { background-image: url(../../../contextmenu/skins/larry/images/contexticons.png); background-repeat: no-repeat; background-position: 5px -96px; }
+
+
+/* vertically align inside labels */
+.context-menu-input > label > * { vertical-align: top; }
+
+/* position checkboxes and radios as icons */
+.context-menu-input > label > input[type="checkbox"],
+.context-menu-input > label > input[type="radio"] {
+ margin-left: -17px;
+}
+.context-menu-input > label > span {
+ margin-left: 5px;
+}
+
+.context-menu-input > label,
+.context-menu-input > label > input[type="text"],
+.context-menu-input > label > textarea,
+.context-menu-input > label > select {
+ display: block;
+ width: 100%;
+
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ -ms-box-sizing: border-box;
+ -o-box-sizing: border-box;
+ box-sizing: border-box;
+}
+
+.context-menu-input > label > textarea {
+ height: 100px;
+}
+.context-menu-item > .context-menu-list {
+ display: none;
+ /* re-positioned by js */
+ right: -5px;
+ top: 5px;
+}
+
+.context-menu-item.hover > .context-menu-list {
+ display: block;
+}
+
+.context-menu-accesskey {
+ text-decoration: underline;
+}
diff --git a/libgpl/skins/larry/timepicker2.css b/libgpl/skins/larry/timepicker2.css
new file mode 100644
index 0000000..150c9f3
--- /dev/null
+++ b/libgpl/skins/larry/timepicker2.css
@@ -0,0 +1,13 @@
+/* css for timepicker */
+
+.ui-timepicker-div .ui-widget-header { margin-bottom: 8px; }
+.ui-timepicker-div dl { text-align: left; }
+.ui-timepicker-div dl dt { height: 25px; margin-bottom: -25px; }
+.ui-timepicker-div dl dd { margin: 0 10px 10px 65px; }
+.ui-timepicker-div td { font-size: 90%; }
+.ui-tpicker-grid-label { background: none; border: none; margin: 0; padding: 0; }
+.ui-timepicker-rtl{ direction: rtl; }
+.ui-timepicker-rtl dl { text-align: right; }
+.ui-timepicker-rtl dl dd { margin: 0 65px 10px 10px; }
+.ui-slider { border: 1px solid #AAA; background: white 50% 50% repeat-x; color: black; height: 10px; }
+.ui-timepicker-div dt { margin-left: 5px; }
diff --git a/libgpl/timepicker/jquery.timepicker.css b/libgpl/timepicker/jquery.timepicker.css
new file mode 100644
index 0000000..cd75f13
--- /dev/null
+++ b/libgpl/timepicker/jquery.timepicker.css
@@ -0,0 +1,72 @@
+.ui-timepicker-wrapper {
+ overflow-y: auto;
+ height: 150px;
+ width: 6.5em;
+ background: #fff;
+ border: 1px solid #ddd;
+ -webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);
+ -moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);
+ box-shadow:0 5px 10px rgba(0,0,0,0.2);
+ outline: none;
+ z-index: 10001;
+ margin: 0;
+}
+
+.ui-timepicker-wrapper.ui-timepicker-with-duration {
+ width: 13em;
+}
+
+.ui-timepicker-wrapper.ui-timepicker-with-duration.ui-timepicker-step-30,
+.ui-timepicker-wrapper.ui-timepicker-with-duration.ui-timepicker-step-60 {
+ width: 11em;
+}
+
+.ui-timepicker-list {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+
+.ui-timepicker-duration {
+ margin-left: 5px; color: #888;
+}
+
+.ui-timepicker-list:hover .ui-timepicker-duration {
+ color: #888;
+}
+
+.ui-timepicker-list li {
+ padding: 3px 0 3px 5px;
+ cursor: pointer;
+ white-space: nowrap;
+ color: #000;
+ list-style: none;
+ margin: 0;
+}
+
+.ui-timepicker-list:hover .ui-timepicker-selected {
+ background: #fff; color: #000;
+}
+
+li.ui-timepicker-selected,
+.ui-timepicker-list li:hover,
+.ui-timepicker-list .ui-timepicker-selected:hover {
+ background: #1980EC; color: #fff;
+}
+
+li.ui-timepicker-selected .ui-timepicker-duration,
+.ui-timepicker-list li:hover .ui-timepicker-duration {
+ color: #ccc;
+}
+
+.ui-timepicker-list li.ui-timepicker-disabled,
+.ui-timepicker-list li.ui-timepicker-disabled:hover,
+.ui-timepicker-list li.ui-timepicker-selected.ui-timepicker-disabled {
+ color: #888;
+ cursor: default;
+}
+
+.ui-timepicker-list li.ui-timepicker-disabled:hover,
+.ui-timepicker-list li.ui-timepicker-selected.ui-timepicker-disabled {
+ background: #f2f2f2;
+}
diff --git a/libgpl/timepicker/jquery.timepicker.js b/libgpl/timepicker/jquery.timepicker.js
new file mode 100644
index 0000000..462d8fe
--- /dev/null
+++ b/libgpl/timepicker/jquery.timepicker.js
@@ -0,0 +1,1149 @@
+/************************
+jquery-timepicker v1.4.10
+http://jonthornton.github.com/jquery-timepicker/
+
+requires jQuery 1.7+
+************************/
+
+
+(function (factory) {
+ if (typeof exports === "object" && exports &&
+ typeof module === "object" && module && module.exports === exports) {
+ // Browserify. Attach to jQuery module.
+ factory(require("jquery"));
+ } else if (typeof define === 'function' && define.amd) {
+ // AMD. Register as an anonymous module.
+ define(['jquery'], factory);
+ } else {
+ // Browser globals
+ factory(jQuery);
+ }
+}(function ($) {
+ var _baseDate = _generateBaseDate();
+ var _ONE_DAY = 86400;
+ var _lang = {
+ am: 'am',
+ pm: 'pm',
+ AM: 'AM',
+ PM: 'PM',
+ decimal: '.',
+ mins: 'mins',
+ hr: 'hr',
+ hrs: 'hrs'
+ };
+
+ var methods =
+ {
+ init: function(options)
+ {
+ return this.each(function()
+ {
+ var self = $(this);
+
+ // pick up settings from data attributes
+ var attributeOptions = [];
+ for (var key in $.fn.timepicker.defaults) {
+ if (self.data(key)) {
+ attributeOptions[key] = self.data(key);
+ }
+ }
+
+ var settings = $.extend({}, $.fn.timepicker.defaults, attributeOptions, options);
+
+ if (settings.lang) {
+ _lang = $.extend(_lang, settings.lang);
+ }
+
+ settings = _parseSettings(settings);
+ self.data('timepicker-settings', settings);
+ self.addClass('ui-timepicker-input');
+
+ if (settings.useSelect) {
+ _render(self);
+ } else {
+ self.prop('autocomplete', 'off');
+ self.on('click.timepicker focus.timepicker', methods.show);
+ self.on('change.timepicker', _formatValue);
+ self.on('keydown.timepicker', _keydownhandler);
+ self.on('keyup.timepicker', _keyuphandler);
+
+ _formatValue.call(self.get(0));
+ }
+ });
+ },
+
+ show: function(e)
+ {
+ var self = $(this);
+ var settings = self.data('timepicker-settings');
+
+ if (e) {
+ if (!settings.showOnFocus) {
+ return true;
+ }
+
+ e.preventDefault();
+ }
+
+ if (settings.useSelect) {
+ self.data('timepicker-list').focus();
+ return;
+ }
+
+ if (_hideKeyboard(self)) {
+ // block the keyboard on mobile devices
+ self.blur();
+ }
+
+ var list = self.data('timepicker-list');
+
+ // check if input is readonly
+ if (self.prop('readonly')) {
+ return;
+ }
+
+ // check if list needs to be rendered
+ if (!list || list.length === 0 || typeof settings.durationTime === 'function') {
+ _render(self);
+ list = self.data('timepicker-list');
+ }
+
+ if (_isVisible(list)) {
+ return;
+ }
+
+ // make sure other pickers are hidden
+ methods.hide();
+
+ // position the dropdown relative to the input
+ list.show();
+ var listOffset = {};
+
+ if (settings.orientation == 'rtl') {
+ // right-align the dropdown
+ listOffset.left = self.offset().left + self.outerWidth() - list.outerWidth() + parseInt(list.css('marginLeft').replace('px', ''), 10);
+ } else {
+ // left-align the dropdown
+ listOffset.left = self.offset().left + parseInt(list.css('marginLeft').replace('px', ''), 10);
+ }
+
+ if ((self.offset().top + self.outerHeight(true) + list.outerHeight()) > $(window).height() + $(window).scrollTop()) {
+ // position the dropdown on top
+ listOffset.top = self.offset().top - list.outerHeight() + parseInt(list.css('marginTop').replace('px', ''), 10);
+ } else {
+ // put it under the input
+ listOffset.top = self.offset().top + self.outerHeight() + parseInt(list.css('marginTop').replace('px', ''), 10);
+ }
+
+ list.offset(listOffset);
+
+ // position scrolling
+ var selected = list.find('.ui-timepicker-selected');
+
+ if (!selected.length) {
+ if (_getTimeValue(self)) {
+ selected = _findRow(self, list, _time2int(_getTimeValue(self)));
+ } else if (settings.scrollDefault) {
+ selected = _findRow(self, list, settings.scrollDefault);
+ }
+ }
+
+ if (selected && selected.length) {
+ var topOffset = list.scrollTop() + selected.position().top - selected.outerHeight();
+ list.scrollTop(topOffset);
+ } else {
+ list.scrollTop(0);
+ }
+
+ // attach close handlers
+ $(document).on('touchstart.ui-timepicker mousedown.ui-timepicker', _closeHandler);
+ if (settings.closeOnWindowScroll) {
+ $(document).on('scroll.ui-timepicker', _closeHandler);
+ }
+
+ self.trigger('showTimepicker');
+
+ return this;
+ },
+
+ hide: function(e)
+ {
+ var self = $(this);
+ var settings = self.data('timepicker-settings');
+
+ if (settings && settings.useSelect) {
+ self.blur();
+ }
+
+ $('.ui-timepicker-wrapper').each(function() {
+ var list = $(this);
+ if (!_isVisible(list)) {
+ return;
+ }
+
+ var self = list.data('timepicker-input');
+ var settings = self.data('timepicker-settings');
+
+ if (settings && settings.selectOnBlur) {
+ _selectValue(self);
+ }
+
+ list.hide();
+ self.trigger('hideTimepicker');
+ });
+
+ return this;
+ },
+
+ option: function(key, value)
+ {
+ return this.each(function(){
+ var self = $(this);
+ var settings = self.data('timepicker-settings');
+ var list = self.data('timepicker-list');
+
+ if (typeof key == 'object') {
+ settings = $.extend(settings, key);
+
+ } else if (typeof key == 'string' && typeof value != 'undefined') {
+ settings[key] = value;
+
+ } else if (typeof key == 'string') {
+ return settings[key];
+ }
+
+ settings = _parseSettings(settings);
+
+ self.data('timepicker-settings', settings);
+
+ if (list) {
+ list.remove();
+ self.data('timepicker-list', false);
+ }
+
+ if (settings.useSelect) {
+ _render(self);
+ }
+ });
+ },
+
+ getSecondsFromMidnight: function()
+ {
+ return _time2int(_getTimeValue(this));
+ },
+
+ getTime: function(relative_date)
+ {
+ var self = this;
+
+ var time_string = _getTimeValue(self);
+ if (!time_string) {
+ return null;
+ }
+
+ if (!relative_date) {
+ relative_date = new Date();
+ }
+ var offset = _time2int(time_string);
+
+ // construct a Date with today's date, and offset's time
+ var time = new Date(relative_date);
+ time.setHours(offset / 3600);
+ time.setMinutes(offset % 3600 / 60);
+ time.setSeconds(offset % 60);
+ time.setMilliseconds(0);
+
+ return time;
+ },
+
+ setTime: function(value)
+ {
+ var self = this;
+ var settings = self.data('timepicker-settings');
+
+ if (settings.forceRoundTime) {
+ var prettyTime = _roundAndFormatTime(value, settings)
+ } else {
+ var prettyTime = _int2time(_time2int(value), settings.timeFormat);
+ }
+
+ _setTimeValue(self, prettyTime);
+ if (self.data('timepicker-list')) {
+ _setSelected(self, self.data('timepicker-list'));
+ }
+
+ return this;
+ },
+
+ remove: function()
+ {
+ var self = this;
+
+ // check if this element is a timepicker
+ if (!self.hasClass('ui-timepicker-input')) {
+ return;
+ }
+
+ var settings = self.data('timepicker-settings');
+ self.removeAttr('autocomplete', 'off');
+ self.removeClass('ui-timepicker-input');
+ self.removeData('timepicker-settings');
+ self.off('.timepicker');
+
+ // timepicker-list won't be present unless the user has interacted with this timepicker
+ if (self.data('timepicker-list')) {
+ self.data('timepicker-list').remove();
+ }
+
+ if (settings.useSelect) {
+ self.show();
+ }
+
+ self.removeData('timepicker-list');
+
+ return this;
+ }
+ };
+
+ // private methods
+
+ function _isVisible(elem)
+ {
+ var el = elem[0];
+ return el.offsetWidth > 0 && el.offsetHeight > 0;
+ }
+
+ function _parseSettings(settings)
+ {
+ if (settings.minTime) {
+ settings.minTime = _time2int(settings.minTime);
+ }
+
+ if (settings.maxTime) {
+ settings.maxTime = _time2int(settings.maxTime);
+ }
+
+ if (settings.durationTime && typeof settings.durationTime !== 'function') {
+ settings.durationTime = _time2int(settings.durationTime);
+ }
+
+ if (settings.scrollDefault == 'now') {
+ settings.scrollDefault = _time2int(new Date());
+ } else if (settings.scrollDefault) {
+ settings.scrollDefault = _time2int(settings.scrollDefault);
+ } else if (settings.minTime) {
+ settings.scrollDefault = settings.minTime;
+ }
+
+ if (settings.scrollDefault) {
+ settings.scrollDefault = _roundTime(settings.scrollDefault, settings);
+ }
+
+ if ($.type(settings.timeFormat) === "string" && settings.timeFormat.match(/[gh]/)) {
+ settings._twelveHourTime = true;
+ }
+
+ if (settings.disableTimeRanges.length > 0) {
+ // convert string times to integers
+ for (var i in settings.disableTimeRanges) {
+ settings.disableTimeRanges[i] = [
+ _time2int(settings.disableTimeRanges[i][0]),
+ _time2int(settings.disableTimeRanges[i][1])
+ ];
+ }
+
+ // sort by starting time
+ settings.disableTimeRanges = settings.disableTimeRanges.sort(function(a, b){
+ return a[0] - b[0];
+ });
+
+ // merge any overlapping ranges
+ for (var i = settings.disableTimeRanges.length-1; i > 0; i--) {
+ if (settings.disableTimeRanges[i][0] <= settings.disableTimeRanges[i-1][1]) {
+ settings.disableTimeRanges[i-1] = [
+ Math.min(settings.disableTimeRanges[i][0], settings.disableTimeRanges[i-1][0]),
+ Math.max(settings.disableTimeRanges[i][1], settings.disableTimeRanges[i-1][1])
+ ];
+ settings.disableTimeRanges.splice(i, 1);
+ }
+ }
+ }
+
+ return settings;
+ }
+
+ function _render(self)
+ {
+ var settings = self.data('timepicker-settings');
+ var list = self.data('timepicker-list');
+
+ if (list && list.length) {
+ list.remove();
+ self.data('timepicker-list', false);
+ }
+
+ if (settings.useSelect) {
+ list = $('<select />', { 'class': 'ui-timepicker-select' });
+ var wrapped_list = list;
+ } else {
+ list = $('<ul />', { 'class': 'ui-timepicker-list' });
+
+ var wrapped_list = $('<div />', { 'class': 'ui-timepicker-wrapper', 'tabindex': -1 });
+ wrapped_list.css({'display':'none', 'position': 'absolute' }).append(list);
+ }
+
+ if (settings.noneOption) {
+ if (settings.noneOption === true) {
+ settings.noneOption = (settings.useSelect) ? 'Time...' : 'None';
+ }
+
+ if ($.isArray(settings.noneOption)) {
+ for (var i in settings.noneOption) {
+ if (parseInt(i, 10) == i){
+ var noneElement = _generateNoneElement(settings.noneOption[i], settings.useSelect);
+ list.append(noneElement);
+ }
+ }
+ } else {
+ var noneElement = _generateNoneElement(settings.noneOption, settings.useSelect);
+ list.append(noneElement);
+ }
+ }
+
+ if (settings.className) {
+ wrapped_list.addClass(settings.className);
+ }
+
+ if ((settings.minTime !== null || settings.durationTime !== null) && settings.showDuration) {
+ wrapped_list.addClass('ui-timepicker-with-duration');
+ wrapped_list.addClass('ui-timepicker-step-'+settings.step);
+ }
+
+ var durStart = settings.minTime;
+ if (typeof settings.durationTime === 'function') {
+ durStart = _time2int(settings.durationTime());
+ } else if (settings.durationTime !== null) {
+ durStart = settings.durationTime;
+ }
+ var start = (settings.minTime !== null) ? settings.minTime : 0;
+ var end = (settings.maxTime !== null) ? settings.maxTime : (start + _ONE_DAY - 1);
+
+ if (end <= start) {
+ // make sure the end time is greater than start time, otherwise there will be no list to show
+ end += _ONE_DAY;
+ }
+
+ if (end === _ONE_DAY-1 && $.type(settings.timeFormat) === "string" && settings.timeFormat.indexOf('H') !== -1) {
+ // show a 24:00 option when using military time
+ end = _ONE_DAY;
+ }
+
+ var dr = settings.disableTimeRanges;
+ var drCur = 0;
+ var drLen = dr.length;
+
+ for (var i=start; i <= end; i += settings.step*60) {
+ var timeInt = i;
+ var timeString = _int2time(timeInt, settings.timeFormat);
+
+ if (settings.useSelect) {
+ var row = $('<option />', { 'value': timeString });
+ row.text(timeString);
+ } else {
+ var row = $('<li />');
+ row.data('time', (timeInt <= 86400 ? timeInt : timeInt % 86400));
+ row.text(timeString);
+ }
+
+ if ((settings.minTime !== null || settings.durationTime !== null) && settings.showDuration) {
+ var durationString = _int2duration(i - durStart, settings.step);
+ if (settings.useSelect) {
+ row.text(row.text()+' ('+durationString+')');
+ } else {
+ var duration = $('<span />', { 'class': 'ui-timepicker-duration' });
+ duration.text(' ('+durationString+')');
+ row.append(duration);
+ }
+ }
+
+ if (drCur < drLen) {
+ if (timeInt >= dr[drCur][1]) {
+ drCur += 1;
+ }
+
+ if (dr[drCur] && timeInt >= dr[drCur][0] && timeInt < dr[drCur][1]) {
+ if (settings.useSelect) {
+ row.prop('disabled', true);
+ } else {
+ row.addClass('ui-timepicker-disabled');
+ }
+ }
+ }
+
+ list.append(row);
+ }
+
+ wrapped_list.data('timepicker-input', self);
+ self.data('timepicker-list', wrapped_list);
+
+ if (settings.useSelect) {
+ if (self.val()) {
+ list.val(_roundAndFormatTime(self.val(), settings));
+ }
+
+ list.on('focus', function(){
+ $(this).data('timepicker-input').trigger('showTimepicker');
+ });
+ list.on('blur', function(){
+ $(this).data('timepicker-input').trigger('hideTimepicker');
+ });
+ list.on('change', function(){
+ _setTimeValue(self, $(this).val(), 'select');
+ });
+
+ _setTimeValue(self, list.val());
+ self.hide().after(list);
+ } else {
+ var appendTo = settings.appendTo;
+ if (typeof appendTo === 'string') {
+ appendTo = $(appendTo);
+ } else if (typeof appendTo === 'function') {
+ appendTo = appendTo(self);
+ }
+ appendTo.append(wrapped_list);
+ _setSelected(self, list);
+
+ list.on('mousedown', 'li', function(e) {
+
+ // hack: temporarily disable the focus handler
+ // to deal with the fact that IE fires 'focus'
+ // events asynchronously
+ self.off('focus.timepicker');
+ self.on('focus.timepicker-ie-hack', function(){
+ self.off('focus.timepicker-ie-hack');
+ self.on('focus.timepicker', methods.show);
+ });
+
+ if (!_hideKeyboard(self)) {
+ self[0].focus();
+ }
+
+ // make sure only the clicked row is selected
+ list.find('li').removeClass('ui-timepicker-selected');
+ $(this).addClass('ui-timepicker-selected');
+
+ if (_selectValue(self)) {
+ self.trigger('hideTimepicker');
+ wrapped_list.hide();
+ }
+ });
+ }
+ }
+
+ function _generateNoneElement(optionValue, useSelect)
+ {
+ var label, className, value;
+
+ if (typeof optionValue == 'object') {
+ label = optionValue.label;
+ className = optionValue.className;
+ value = optionValue.value;
+ } else if (typeof optionValue == 'string') {
+ label = optionValue;
+ } else {
+ $.error('Invalid noneOption value');
+ }
+
+ if (useSelect) {
+ return $('<option />', {
+ 'value': value,
+ 'class': className,
+ 'text': label
+ });
+ } else {
+ return $('<li />', {
+ 'class': className,
+ 'text': label
+ }).data('time', value);
+ }
+ }
+
+ function _roundTime(seconds, settings)
+ {
+ if (!$.isNumeric(seconds)) {
+ seconds = _time2int(seconds);
+ }
+
+ if (seconds === null) {
+ return null;
+ } else {
+ var offset = seconds % (settings.step*60); // step is in minutes
+
+ if (offset >= settings.step*30) {
+ // if offset is larger than a half step, round up
+ seconds += (settings.step*60) - offset;
+ } else {
+ // round down
+ seconds -= offset;
+ }
+
+ return seconds;
+ }
+ }
+
+ function _roundAndFormatTime(seconds, settings)
+ {
+ seconds = _roundTime(seconds, settings);
+ if (seconds !== null) {
+ return _int2time(seconds, settings.timeFormat);
+ }
+ }
+
+ function _generateBaseDate()
+ {
+ return new Date(1970, 1, 1, 0, 0, 0);
+ }
+
+ // event handler to decide whether to close timepicker
+ function _closeHandler(e)
+ {
+ var target = $(e.target);
+ var input = target.closest('.ui-timepicker-input');
+ if (input.length === 0 && target.closest('.ui-timepicker-wrapper').length === 0) {
+ methods.hide();
+ $(document).unbind('.ui-timepicker');
+ }
+ }
+
+ function _hideKeyboard(self)
+ {
+ var settings = self.data('timepicker-settings');
+ return ((window.navigator.msMaxTouchPoints || 'ontouchstart' in document) && settings.disableTouchKeyboard);
+ }
+
+ function _findRow(self, list, value)
+ {
+ if (!value && value !== 0) {
+ return false;
+ }
+
+ var settings = self.data('timepicker-settings');
+ var out = false;
+ var halfStep = settings.step*30;
+
+ // loop through the menu items
+ list.find('li').each(function(i, obj) {
+ var jObj = $(obj);
+ if (typeof jObj.data('time') != 'number') {
+ return;
+ }
+
+ var offset = jObj.data('time') - value;
+
+ // check if the value is less than half a step from each row
+ if (Math.abs(offset) < halfStep || offset == halfStep) {
+ out = jObj;
+ return false;
+ }
+ });
+
+ return out;
+ }
+
+ function _setSelected(self, list)
+ {
+ list.find('li').removeClass('ui-timepicker-selected');
+
+ var timeValue = _time2int(_getTimeValue(self), self.data('timepicker-settings'));
+ if (timeValue === null) {
+ return;
+ }
+
+ var selected = _findRow(self, list, timeValue);
+ if (selected) {
+
+ var topDelta = selected.offset().top - list.offset().top;
+
+ if (topDelta + selected.outerHeight() > list.outerHeight() || topDelta < 0) {
+ list.scrollTop(list.scrollTop() + selected.position().top - selected.outerHeight());
+ }
+
+ selected.addClass('ui-timepicker-selected');
+ }
+ }
+
+
+ function _formatValue(e)
+ {
+ if (this.value === '') {
+ return;
+ }
+
+ var self = $(this);
+ var list = self.data('timepicker-list');
+
+ if (self.is(':focus') && (!e || e.type != 'change')) {
+ return;
+ }
+
+ var seconds = _time2int(this.value);
+
+ if (seconds === null) {
+ self.trigger('timeFormatError');
+ return;
+ }
+
+ var settings = self.data('timepicker-settings');
+ var rangeError = false;
+ // check that the time in within bounds
+ if (settings.minTime !== null && seconds < settings.minTime) {
+ rangeError = true;
+ } else if (settings.maxTime !== null && seconds > settings.maxTime) {
+ rangeError = true;
+ }
+
+ // check that time isn't within disabled time ranges
+ $.each(settings.disableTimeRanges, function(){
+ if (seconds >= this[0] && seconds < this[1]) {
+ rangeError = true;
+ return false;
+ }
+ });
+
+ if (settings.forceRoundTime) {
+ var offset = seconds % (settings.step*60); // step is in minutes
+
+ if (offset >= settings.step*30) {
+ // if offset is larger than a half step, round up
+ seconds += (settings.step*60) - offset;
+ } else {
+ // round down
+ seconds -= offset;
+ }
+ }
+
+ var prettyTime = _int2time(seconds, settings.timeFormat);
+
+ if (rangeError) {
+ if (_setTimeValue(self, prettyTime, 'error')) {
+ self.trigger('timeRangeError');
+ }
+ } else {
+ _setTimeValue(self, prettyTime);
+ }
+ }
+
+ function _getTimeValue(self)
+ {
+ if (self.is('input')) {
+ return self.val();
+ } else {
+ // use the element's data attributes to store values
+ return self.data('ui-timepicker-value');
+ }
+ }
+
+ function _setTimeValue(self, value, source)
+ {
+ if (self.is('input')) {
+ self.val(value);
+
+ var settings = self.data('timepicker-settings');
+ if (settings.useSelect) {
+ self.data('timepicker-list').val(_roundAndFormatTime(value, settings));
+ }
+ }
+
+ if (self.data('ui-timepicker-value') != value) {
+ self.data('ui-timepicker-value', value);
+ if (source == 'select') {
+ self.trigger('selectTime').trigger('changeTime').trigger('change');
+ } else if (source != 'error') {
+ self.trigger('changeTime');
+ }
+
+ return true;
+ } else {
+ self.trigger('selectTime');
+ return false;
+ }
+ }
+
+ /*
+ * Keyboard navigation via arrow keys
+ */
+ function _keydownhandler(e)
+ {
+ var self = $(this);
+ var list = self.data('timepicker-list');
+
+ if (!list || !_isVisible(list)) {
+ if (e.keyCode == 40) {
+ // show the list!
+ methods.show.call(self.get(0));
+ list = self.data('timepicker-list');
+ if (!_hideKeyboard(self)) {
+ self.focus();
+ }
+ } else {
+ return true;
+ }
+ }
+
+ switch (e.keyCode) {
+
+ case 13: // return
+ if (_selectValue(self)) {
+ methods.hide.apply(this);
+ }
+
+ e.preventDefault();
+ return false;
+
+ case 38: // up
+ var selected = list.find('.ui-timepicker-selected');
+
+ if (!selected.length) {
+ list.find('li').each(function(i, obj) {
+ if ($(obj).position().top > 0) {
+ selected = $(obj);
+ return false;
+ }
+ });
+ selected.addClass('ui-timepicker-selected');
+
+ } else if (!selected.is(':first-child')) {
+ selected.removeClass('ui-timepicker-selected');
+ selected.prev().addClass('ui-timepicker-selected');
+
+ if (selected.prev().position().top < selected.outerHeight()) {
+ list.scrollTop(list.scrollTop() - selected.outerHeight());
+ }
+ }
+
+ return false;
+
+ case 40: // down
+ selected = list.find('.ui-timepicker-selected');
+
+ if (selected.length === 0) {
+ list.find('li').each(function(i, obj) {
+ if ($(obj).position().top > 0) {
+ selected = $(obj);
+ return false;
+ }
+ });
+
+ selected.addClass('ui-timepicker-selected');
+ } else if (!selected.is(':last-child')) {
+ selected.removeClass('ui-timepicker-selected');
+ selected.next().addClass('ui-timepicker-selected');
+
+ if (selected.next().position().top + 2*selected.outerHeight() > list.outerHeight()) {
+ list.scrollTop(list.scrollTop() + selected.outerHeight());
+ }
+ }
+
+ return false;
+
+ case 27: // escape
+ list.find('li').removeClass('ui-timepicker-selected');
+ methods.hide();
+ break;
+
+ case 9: //tab
+ methods.hide();
+ break;
+
+ default:
+ return true;
+ }
+ }
+
+ /*
+ * Time typeahead
+ */
+ function _keyuphandler(e)
+ {
+ var self = $(this);
+ var list = self.data('timepicker-list');
+
+ if (!list || !_isVisible(list)) {
+ return true;
+ }
+
+ if (!self.data('timepicker-settings').typeaheadHighlight) {
+ list.find('li').removeClass('ui-timepicker-selected');
+ return true;
+ }
+
+ switch (e.keyCode) {
+
+ case 96: // numpad numerals
+ case 97:
+ case 98:
+ case 99:
+ case 100:
+ case 101:
+ case 102:
+ case 103:
+ case 104:
+ case 105:
+ case 48: // numerals
+ case 49:
+ case 50:
+ case 51:
+ case 52:
+ case 53:
+ case 54:
+ case 55:
+ case 56:
+ case 57:
+ case 65: // a
+ case 77: // m
+ case 80: // p
+ case 186: // colon
+ case 8: // backspace
+ case 46: // delete
+ _setSelected(self, list);
+ break;
+
+ default:
+ // list.find('li').removeClass('ui-timepicker-selected');
+ return;
+ }
+ }
+
+ function _selectValue(self)
+ {
+ var settings = self.data('timepicker-settings');
+ var list = self.data('timepicker-list');
+ var timeValue = null;
+
+ var cursor = list.find('.ui-timepicker-selected');
+
+ if (cursor.hasClass('ui-timepicker-disabled')) {
+ return false;
+ }
+
+ if (cursor.length) {
+ // selected value found
+ timeValue = cursor.data('time');
+ }
+
+ if (timeValue !== null) {
+ if (typeof timeValue == 'string') {
+ self.val(timeValue);
+ } else {
+ var timeString = _int2time(timeValue, settings.timeFormat);
+ _setTimeValue(self, timeString, 'select');
+ }
+ }
+
+ //self.trigger('change').trigger('selectTime');
+ return true;
+ }
+
+ function _int2duration(seconds, step)
+ {
+ seconds = Math.abs(seconds);
+ var minutes = Math.round(seconds/60),
+ duration = [],
+ hours, mins;
+
+ if (minutes < 60) {
+ // Only show (x mins) under 1 hour
+ duration = [minutes, _lang.mins];
+ } else {
+ hours = Math.floor(minutes/60);
+ mins = minutes%60;
+
+ // Show decimal notation (eg: 1.5 hrs) for 30 minute steps
+ if (step == 30 && mins == 30) {
+ hours += _lang.decimal + 5;
+ }
+
+ duration.push(hours);
+ duration.push(hours == 1 ? _lang.hr : _lang.hrs);
+
+ // Show remainder minutes notation (eg: 1 hr 15 mins) for non-30 minute steps
+ // and only if there are remainder minutes to show
+ if (step != 30 && mins) {
+ duration.push(mins);
+ duration.push(_lang.mins);
+ }
+ }
+
+ return duration.join(' ');
+ }
+
+ function _int2time(seconds, format)
+ {
+ if (seconds === null) {
+ return;
+ }
+
+ var time = new Date(_baseDate.valueOf() + (seconds*1000));
+
+ if (isNaN(time.getTime())) {
+ return;
+ }
+
+ if ($.type(format) === "function") {
+ return format(time);
+ }
+
+ var output = '';
+ var hour, code;
+ for (var i=0; i<format.length; i++) {
+
+ code = format.charAt(i);
+ switch (code) {
+
+ case 'a':
+ output += (time.getHours() > 11) ? _lang.pm : _lang.am;
+ break;
+
+ case 'A':
+ output += (time.getHours() > 11) ? _lang.pm.toUpperCase() : _lang.am.toUpperCase();
+ break;
+
+ case 'g':
+ hour = time.getHours() % 12;
+ output += (hour === 0) ? '12' : hour;
+ break;
+
+ case 'G':
+ output += time.getHours();
+ break;
+
+ case 'h':
+ hour = time.getHours() % 12;
+
+ if (hour !== 0 && hour < 10) {
+ hour = '0'+hour;
+ }
+
+ output += (hour === 0) ? '12' : hour;
+ break;
+
+ case 'H':
+ hour = time.getHours();
+ if (seconds === _ONE_DAY) hour = 24;
+ output += (hour > 9) ? hour : '0'+hour;
+ break;
+
+ case 'i':
+ var minutes = time.getMinutes();
+ output += (minutes > 9) ? minutes : '0'+minutes;
+ break;
+
+ case 's':
+ seconds = time.getSeconds();
+ output += (seconds > 9) ? seconds : '0'+seconds;
+ break;
+
+ case '\\':
+ // escape character; add the next character and skip ahead
+ i++;
+ output += format.charAt(i);
+ break;
+
+ default:
+ output += code;
+ }
+ }
+
+ return output;
+ }
+
+ function _time2int(timeString, settings)
+ {
+ if (timeString === '') return null;
+ if (!timeString || timeString+0 == timeString) return timeString;
+
+ if (typeof(timeString) == 'object') {
+ return timeString.getHours()*3600 + timeString.getMinutes()*60 + timeString.getSeconds();
+ }
+
+ timeString = timeString.toLowerCase();
+
+ // if the last character is an "a" or "p", add the "m"
+ if (timeString.slice(-1) == 'a' || timeString.slice(-1) == 'p') {
+ timeString += 'm';
+ }
+
+ // try to parse time input
+ var pattern = new RegExp('^([0-2]?[0-9])\\W?([0-5][0-9])?\\W?([0-5][0-9])?\\s*('+_lang.am+'|'+_lang.pm+')?$');
+ var time = timeString.match(pattern);
+ if (!time) {
+ return null;
+ }
+
+ var hour = parseInt(time[1]*1, 10);
+ var ampm = time[4];
+ var hours = hour;
+
+ if (hour <= 12 && ampm) {
+ if (hour == 12) {
+ hours = (time[4] == _lang.pm) ? 12 : 0;
+ } else {
+ hours = (hour + (time[4] == _lang.pm ? 12 : 0));
+ }
+ }
+
+ var minutes = ( time[2]*1 || 0 );
+ var seconds = ( time[3]*1 || 0 );
+ var timeInt = hours*3600 + minutes*60 + seconds;
+
+ // if no am/pm provided, intelligently guess based on the scrollDefault
+ if (!ampm && settings && settings._twelveHourTime && settings.scrollDefault) {
+ var delta = timeInt - settings.scrollDefault;
+ if (delta < 0 && delta >= _ONE_DAY / -2) {
+ timeInt = (timeInt + (_ONE_DAY / 2)) % _ONE_DAY;
+ }
+ }
+
+ return timeInt
+ }
+
+ function _pad2(n) {
+ return ("0" + n).slice(-2);
+ }
+
+ // Plugin entry
+ $.fn.timepicker = function(method)
+ {
+ if (!this.length) return this;
+ if (methods[method]) {
+ // check if this element is a timepicker
+ if (!this.hasClass('ui-timepicker-input')) {
+ return this;
+ }
+ return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
+ }
+ else if(typeof method === "object" || !method) { return methods.init.apply(this, arguments); }
+ else { $.error("Method "+ method + " does not exist on jQuery.timepicker"); }
+ };
+ // Global defaults
+ $.fn.timepicker.defaults = {
+ className: null,
+ minTime: null,
+ maxTime: null,
+ durationTime: null,
+ step: 30,
+ showDuration: false,
+ showOnFocus: true,
+ timeFormat: 'g:ia',
+ scrollDefault: null,
+ selectOnBlur: false,
+ disableTouchKeyboard: false,
+ forceRoundTime: false,
+ appendTo: 'body',
+ orientation: 'ltr',
+ disableTimeRanges: [],
+ closeOnWindowScroll: false,
+ typeaheadHighlight: true,
+ noneOption: false
+ };
+}));
diff --git a/libgpl/timepicker/jquery.timepicker.min.js b/libgpl/timepicker/jquery.timepicker.min.js
new file mode 100644
index 0000000..04daf60
--- /dev/null
+++ b/libgpl/timepicker/jquery.timepicker.min.js
@@ -0,0 +1,7 @@
+/*!
+ * jquery-timepicker v1.4.10 - A jQuery timepicker plugin inspired by Google Calendar. It supports both mouse and keyboard navigation.
+ * Copyright (c) 2014 Jon Thornton - http://jonthornton.github.com/jquery-timepicker/
+ * License:
+ */
+
+!function(a){"object"==typeof exports&&exports&&"object"==typeof module&&module&&module.exports===exports?a(require("jquery")):"function"==typeof define&&define.amd?define(["jquery"],a):a(jQuery)}(function(a){function b(a){var b=a[0];return b.offsetWidth>0&&b.offsetHeight>0}function c(b){if(b.minTime&&(b.minTime=u(b.minTime)),b.maxTime&&(b.maxTime=u(b.maxTime)),b.durationTime&&"function"!=typeof b.durationTime&&(b.durationTime=u(b.durationTime)),"now"==b.scrollDefault?b.scrollDefault=u(new Date):b.scrollDefault?b.scrollDefault=u(b.scrollDefault):b.minTime&&(b.scrollDefault=b.minTime),b.scrollDefault&&(b.scrollDefault=f(b.scrollDefault,b)),"string"===a.type(b.timeFormat)&&b.timeFormat.match(/[gh]/)&&(b._twelveHourTime=!0),b.disableTimeRanges.length>0){for(var c in b.disableTimeRanges)b.disableTimeRanges[c]=[u(b.disableTimeRanges[c][0]),u(b.disableTimeRanges[c][1])];b.disableTimeRanges=b.disableTimeRanges.sort(function(a,b){return a[0]-b[0]});for(var c=b.disableTimeRanges.length-1;c>0;c--)b.disableTimeRanges[c][0]<=b.disableTimeRanges[c-1][1]&&(b.disableTimeRanges[c-1]=[Math.min(b.disableTimeRanges[c][0],b.disableTimeRanges[c-1][0]),Math.max(b.disableTimeRanges[c][1],b.disableTimeRanges[c-1][1])],b.disableTimeRanges.splice(c,1))}return b}function d(b){var c=b.data("timepicker-settings"),d=b.data("timepicker-list");if(d&&d.length&&(d.remove(),b.data("timepicker-list",!1)),c.useSelect){d=a("<select />",{"class":"ui-timepicker-select"});var f=d}else{d=a("<ul />",{"class":"ui-timepicker-list"});var f=a("<div />",{"class":"ui-timepicker-wrapper",tabindex:-1});f.css({display:"none",position:"absolute"}).append(d)}if(c.noneOption)if(c.noneOption===!0&&(c.noneOption=c.useSelect?"Time...":"None"),a.isArray(c.noneOption)){for(var h in c.noneOption)if(parseInt(h,10)==h){var i=e(c.noneOption[h],c.useSelect);d.append(i)}}else{var i=e(c.noneOption,c.useSelect);d.append(i)}c.className&&f.addClass(c.className),null===c.minTime&&null===c.durationTime||!c.showDuration||(f.addClass("ui-timepicker-with-duration"),f.addClass("ui-timepicker-step-"+c.step));var k=c.minTime;"function"==typeof c.durationTime?k=u(c.durationTime()):null!==c.durationTime&&(k=c.durationTime);var m=null!==c.minTime?c.minTime:0,n=null!==c.maxTime?c.maxTime:m+w-1;m>=n&&(n+=w),n===w-1&&"string"===a.type(c.timeFormat)&&-1!==c.timeFormat.indexOf("H")&&(n=w);for(var p=c.disableTimeRanges,q=0,v=p.length,h=m;n>=h;h+=60*c.step){var x=h,z=t(x,c.timeFormat);if(c.useSelect){var A=a("<option />",{value:z});A.text(z)}else{var A=a("<li />");A.data("time",86400>=x?x:x%86400),A.text(z)}if((null!==c.minTime||null!==c.durationTime)&&c.showDuration){var B=s(h-k,c.step);if(c.useSelect)A.text(A.text()+" ("+B+")");else{var C=a("<span />",{"class":"ui-timepicker-duration"});C.text(" ("+B+")"),A.append(C)}}v>q&&(x>=p[q][1]&&(q+=1),p[q]&&x>=p[q][0]&&x<p[q][1]&&(c.useSelect?A.prop("disabled",!0):A.addClass("ui-timepicker-disabled"))),d.append(A)}if(f.data("timepicker-input",b),b.data("timepicker-list",f),c.useSelect)b.val()&&d.val(g(b.val(),c)),d.on("focus",function(){a(this).data("timepicker-input").trigger("showTimepicker")}),d.on("blur",function(){a(this).data("timepicker-input").trigger("hideTimepicker")}),d.on("change",function(){o(b,a(this).val(),"select")}),o(b,d.val()),b.hide().after(d);else{var D=c.appendTo;"string"==typeof D?D=a(D):"function"==typeof D&&(D=D(b)),D.append(f),l(b,d),d.on("mousedown","li",function(){b.off("focus.timepicker"),b.on("focus.timepicker-ie-hack",function(){b.off("focus.timepicker-ie-hack"),b.on("focus.timepicker",y.show)}),j(b)||b[0].focus(),d.find("li").removeClass("ui-timepicker-selected"),a(this).addClass("ui-timepicker-selected"),r(b)&&(b.trigger("hideTimepicker"),f.hide())})}}function e(b,c){var d,e,f;return"object"==typeof b?(d=b.label,e=b.className,f=b.value):"string"==typeof b?d=b:a.error("Invalid noneOption value"),c?a("<option />",{value:f,"class":e,text:d}):a("<li />",{"class":e,text:d}).data("time",f)}function f(b,c){if(a.isNumeric(b)||(b=u(b)),null===b)return null;var d=b%(60*c.step);return d>=30*c.step?b+=60*c.step-d:b-=d,b}function g(a,b){return a=f(a,b),null!==a?t(a,b.timeFormat):void 0}function h(){return new Date(1970,1,1,0,0,0)}function i(b){var c=a(b.target),d=c.closest(".ui-timepicker-input");0===d.length&&0===c.closest(".ui-timepicker-wrapper").length&&(y.hide(),a(document).unbind(".ui-timepicker"))}function j(a){var b=a.data("timepicker-settings");return(window.navigator.msMaxTouchPoints||"ontouchstart"in document)&&b.disableTouchKeyboard}function k(b,c,d){if(!d&&0!==d)return!1;var e=b.data("timepicker-settings"),f=!1,g=30*e.step;return c.find("li").each(function(b,c){var e=a(c);if("number"==typeof e.data("time")){var h=e.data("time")-d;return Math.abs(h)<g||h==g?(f=e,!1):void 0}}),f}function l(a,b){b.find("li").removeClass("ui-timepicker-selected");var c=u(n(a),a.data("timepicker-settings"));if(null!==c){var d=k(a,b,c);if(d){var e=d.offset().top-b.offset().top;(e+d.outerHeight()>b.outerHeight()||0>e)&&b.scrollTop(b.scrollTop()+d.position().top-d.outerHeight()),d.addClass("ui-timepicker-selected")}}}function m(b){if(""!==this.value){var c=a(this);if(c.data("timepicker-list"),!c.is(":focus")||b&&"change"==b.type){var d=u(this.value);if(null===d)return c.trigger("timeFormatError"),void 0;var e=c.data("timepicker-settings"),f=!1;if(null!==e.minTime&&d<e.minTime?f=!0:null!==e.maxTime&&d>e.maxTime&&(f=!0),a.each(e.disableTimeRanges,function(){return d>=this[0]&&d<this[1]?(f=!0,!1):void 0}),e.forceRoundTime){var g=d%(60*e.step);g>=30*e.step?d+=60*e.step-g:d-=g}var h=t(d,e.timeFormat);f?o(c,h,"error")&&c.trigger("timeRangeError"):o(c,h)}}}function n(a){return a.is("input")?a.val():a.data("ui-timepicker-value")}function o(a,b,c){if(a.is("input")){a.val(b);var d=a.data("timepicker-settings");d.useSelect&&a.data("timepicker-list").val(g(b,d))}return a.data("ui-timepicker-value")!=b?(a.data("ui-timepicker-value",b),"select"==c?a.trigger("selectTime").trigger("changeTime").trigger("change"):"error"!=c&&a.trigger("changeTime"),!0):(a.trigger("selectTime"),!1)}function p(c){var d=a(this),e=d.data("timepicker-list");if(!e||!b(e)){if(40!=c.keyCode)return!0;y.show.call(d.get(0)),e=d.data("timepicker-list"),j(d)||d.focus()}switch(c.keyCode){case 13:return r(d)&&y.hide.apply(this),c.preventDefault(),!1;case 38:var f=e.find(".ui-timepicker-selected");return f.length?f.is(":first-child")||(f.removeClass("ui-timepicker-selected"),f.prev().addClass("ui-timepicker-selected"),f.prev().position().top<f.outerHeight()&&e.scrollTop(e.scrollTop()-f.outerHeight())):(e.find("li").each(function(b,c){return a(c).position().top>0?(f=a(c),!1):void 0}),f.addClass("ui-timepicker-selected")),!1;case 40:return f=e.find(".ui-timepicker-selected"),0===f.length?(e.find("li").each(function(b,c){return a(c).position().top>0?(f=a(c),!1):void 0}),f.addClass("ui-timepicker-selected")):f.is(":last-child")||(f.removeClass("ui-timepicker-selected"),f.next().addClass("ui-timepicker-selected"),f.next().position().top+2*f.outerHeight()>e.outerHeight()&&e.scrollTop(e.scrollTop()+f.outerHeight())),!1;case 27:e.find("li").removeClass("ui-timepicker-selected"),y.hide();break;case 9:y.hide();break;default:return!0}}function q(c){var d=a(this),e=d.data("timepicker-list");if(!e||!b(e))return!0;if(!d.data("timepicker-settings").typeaheadHighlight)return e.find("li").removeClass("ui-timepicker-selected"),!0;switch(c.keyCode){case 96:case 97:case 98:case 99:case 100:case 101:case 102:case 103:case 104:case 105:case 48:case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:case 65:case 77:case 80:case 186:case 8:case 46:l(d,e);break;default:return}}function r(a){var b=a.data("timepicker-settings"),c=a.data("timepicker-list"),d=null,e=c.find(".ui-timepicker-selected");if(e.hasClass("ui-timepicker-disabled"))return!1;if(e.length&&(d=e.data("time")),null!==d)if("string"==typeof d)a.val(d);else{var f=t(d,b.timeFormat);o(a,f,"select")}return!0}function s(a,b){a=Math.abs(a);var c,d,e=Math.round(a/60),f=[];return 60>e?f=[e,x.mins]:(c=Math.floor(e/60),d=e%60,30==b&&30==d&&(c+=x.decimal+5),f.push(c),f.push(1==c?x.hr:x.hrs),30!=b&&d&&(f.push(d),f.push(x.mins))),f.join(" ")}function t(b,c){if(null!==b){var d=new Date(v.valueOf()+1e3*b);if(!isNaN(d.getTime())){if("function"===a.type(c))return c(d);for(var e,f,g="",h=0;h<c.length;h++)switch(f=c.charAt(h)){case"a":g+=d.getHours()>11?x.pm:x.am;break;case"A":g+=d.getHours()>11?x.pm.toUpperCase():x.am.toUpperCase();break;case"g":e=d.getHours()%12,g+=0===e?"12":e;break;case"G":g+=d.getHours();break;case"h":e=d.getHours()%12,0!==e&&10>e&&(e="0"+e),g+=0===e?"12":e;break;case"H":e=d.getHours(),b===w&&(e=24),g+=e>9?e:"0"+e;break;case"i":var i=d.getMinutes();g+=i>9?i:"0"+i;break;case"s":b=d.getSeconds(),g+=b>9?b:"0"+b;break;case"\\":h++,g+=c.charAt(h);break;default:g+=f}return g}}}function u(a,b){if(""===a)return null;if(!a||a+0==a)return a;if("object"==typeof a)return 3600*a.getHours()+60*a.getMinutes()+a.getSeconds();a=a.toLowerCase(),("a"==a.slice(-1)||"p"==a.slice(-1))&&(a+="m");var c=new RegExp("^([0-2]?[0-9])\\W?([0-5][0-9])?\\W?([0-5][0-9])?\\s*("+x.am+"|"+x.pm+")?$"),d=a.match(c);if(!d)return null;var e=parseInt(1*d[1],10),f=d[4],g=e;12>=e&&f&&(g=12==e?d[4]==x.pm?12:0:e+(d[4]==x.pm?12:0));var h=1*d[2]||0,i=1*d[3]||0,j=3600*g+60*h+i;if(!f&&b&&b._twelveHourTime&&b.scrollDefault){var k=j-b.scrollDefault;0>k&&k>=w/-2&&(j=(j+w/2)%w)}return j}var v=h(),w=86400,x={am:"am",pm:"pm",AM:"AM",PM:"PM",decimal:".",mins:"mins",hr:"hr",hrs:"hrs"},y={init:function(b){return this.each(function(){var e=a(this),f=[];for(var g in a.fn.timepicker.defaults)e.data(g)&&(f[g]=e.data(g));var h=a.extend({},a.fn.timepicker.defaults,f,b);h.lang&&(x=a.extend(x,h.lang)),h=c(h),e.data("timepicker-settings",h),e.addClass("ui-timepicker-input"),h.useSelect?d(e):(e.prop("autocomplete","off"),e.on("click.timepicker focus.timepicker",y.show),e.on("change.timepicker",m),e.on("keydown.timepicker",p),e.on("keyup.timepicker",q),m.call(e.get(0)))})},show:function(c){var e=a(this),f=e.data("timepicker-settings");if(c){if(!f.showOnFocus)return!0;c.preventDefault()}if(f.useSelect)return e.data("timepicker-list").focus(),void 0;j(e)&&e.blur();var g=e.data("timepicker-list");if(!e.prop("readonly")&&(g&&0!==g.length&&"function"!=typeof f.durationTime||(d(e),g=e.data("timepicker-list")),!b(g))){y.hide(),g.show();var h={};h.left="rtl"==f.orientation?e.offset().left+e.outerWidth()-g.outerWidth()+parseInt(g.css("marginLeft").replace("px",""),10):e.offset().left+parseInt(g.css("marginLeft").replace("px",""),10),h.top=e.offset().top+e.outerHeight(!0)+g.outerHeight()>a(window).height()+a(window).scrollTop()?e.offset().top-g.outerHeight()+parseInt(g.css("marginTop").replace("px",""),10):e.offset().top+e.outerHeight()+parseInt(g.css("marginTop").replace("px",""),10),g.offset(h);var l=g.find(".ui-timepicker-selected");if(l.length||(n(e)?l=k(e,g,u(n(e))):f.scrollDefault&&(l=k(e,g,f.scrollDefault))),l&&l.length){var m=g.scrollTop()+l.position().top-l.outerHeight();g.scrollTop(m)}else g.scrollTop(0);return a(document).on("touchstart.ui-timepicker mousedown.ui-timepicker",i),f.closeOnWindowScroll&&a(document).on("scroll.ui-timepicker",i),e.trigger("showTimepicker"),this}},hide:function(){var c=a(this),d=c.data("timepicker-settings");return d&&d.useSelect&&c.blur(),a(".ui-timepicker-wrapper").each(function(){var c=a(this);if(b(c)){var d=c.data("timepicker-input"),e=d.data("timepicker-settings");e&&e.selectOnBlur&&r(d),c.hide(),d.trigger("hideTimepicker")}}),this},option:function(b,e){return this.each(function(){var f=a(this),g=f.data("timepicker-settings"),h=f.data("timepicker-list");if("object"==typeof b)g=a.extend(g,b);else if("string"==typeof b&&"undefined"!=typeof e)g[b]=e;else if("string"==typeof b)return g[b];g=c(g),f.data("timepicker-settings",g),h&&(h.remove(),f.data("timepicker-list",!1)),g.useSelect&&d(f)})},getSecondsFromMidnight:function(){return u(n(this))},getTime:function(a){var b=this,c=n(b);if(!c)return null;a||(a=new Date);var d=u(c),e=new Date(a);return e.setHours(d/3600),e.setMinutes(d%3600/60),e.setSeconds(d%60),e.setMilliseconds(0),e},setTime:function(a){var b=this,c=b.data("timepicker-settings");if(c.forceRoundTime)var d=g(a,c);else var d=t(u(a),c.timeFormat);return o(b,d),b.data("timepicker-list")&&l(b,b.data("timepicker-list")),this},remove:function(){var a=this;if(a.hasClass("ui-timepicker-input")){var b=a.data("timepicker-settings");return a.removeAttr("autocomplete","off"),a.removeClass("ui-timepicker-input"),a.removeData("timepicker-settings"),a.off(".timepicker"),a.data("timepicker-list")&&a.data("timepicker-list").remove(),b.useSelect&&a.show(),a.removeData("timepicker-list"),this}}};a.fn.timepicker=function(b){return this.length?y[b]?this.hasClass("ui-timepicker-input")?y[b].apply(this,Array.prototype.slice.call(arguments,1)):this:"object"!=typeof b&&b?(a.error("Method "+b+" does not exist on jQuery.timepicker"),void 0):y.init.apply(this,arguments):this},a.fn.timepicker.defaults={className:null,minTime:null,maxTime:null,durationTime:null,step:30,showDuration:!1,showOnFocus:!0,timeFormat:"g:ia",scrollDefault:null,selectOnBlur:!1,disableTouchKeyboard:!1,forceRoundTime:!1,appendTo:"body",orientation:"ltr",disableTimeRanges:[],closeOnWindowScroll:!1,typeaheadHighlight:!0,noneOption:!1}}); \ No newline at end of file
diff --git a/libgpl/timepicker2/jquery.timepicker.js b/libgpl/timepicker2/jquery.timepicker.js
new file mode 100644
index 0000000..998d2f8
--- /dev/null
+++ b/libgpl/timepicker2/jquery.timepicker.js
@@ -0,0 +1,2223 @@
+/*! jQuery Timepicker Addon - v1.5.0 - 2014-09-01
+* http://trentrichardson.com/examples/timepicker
+* Copyright (c) 2014 Trent Richardson; Licensed MIT */
+(function ($) {
+
+ /*
+ * Lets not redefine timepicker, Prevent "Uncaught RangeError: Maximum call stack size exceeded"
+ */
+ $.ui.timepicker = $.ui.timepicker || {};
+ if ($.ui.timepicker.version) {
+ return;
+ }
+
+ /*
+ * Extend jQueryUI, get it started with our version number
+ */
+ $.extend($.ui, {
+ timepicker: {
+ version: "1.5.0"
+ }
+ });
+
+ /*
+ * Timepicker manager.
+ * Use the singleton instance of this class, $.timepicker, to interact with the time picker.
+ * Settings for (groups of) time pickers are maintained in an instance object,
+ * allowing multiple different settings on the same page.
+ */
+ var Timepicker = function () {
+ this.regional = []; // Available regional settings, indexed by language code
+ this.regional[''] = { // Default regional settings
+ currentText: 'Now',
+ closeText: 'Done',
+ amNames: ['AM', 'A'],
+ pmNames: ['PM', 'P'],
+ timeFormat: 'HH:mm',
+ timeSuffix: '',
+ timeOnlyTitle: 'Choose Time',
+ timeText: 'Time',
+ hourText: 'Hour',
+ minuteText: 'Minute',
+ secondText: 'Second',
+ millisecText: 'Millisecond',
+ microsecText: 'Microsecond',
+ timezoneText: 'Time Zone',
+ isRTL: false
+ };
+ this._defaults = { // Global defaults for all the datetime picker instances
+ showButtonPanel: true,
+ timeOnly: false,
+ timeOnlyShowDate: false,
+ showHour: null,
+ showMinute: null,
+ showSecond: null,
+ showMillisec: null,
+ showMicrosec: null,
+ showTimezone: null,
+ showTime: true,
+ stepHour: 1,
+ stepMinute: 1,
+ stepSecond: 1,
+ stepMillisec: 1,
+ stepMicrosec: 1,
+ hour: 0,
+ minute: 0,
+ second: 0,
+ millisec: 0,
+ microsec: 0,
+ timezone: null,
+ hourMin: 0,
+ minuteMin: 0,
+ secondMin: 0,
+ millisecMin: 0,
+ microsecMin: 0,
+ hourMax: 23,
+ minuteMax: 59,
+ secondMax: 59,
+ millisecMax: 999,
+ microsecMax: 999,
+ minDateTime: null,
+ maxDateTime: null,
+ maxTime: null,
+ minTime: null,
+ onSelect: null,
+ hourGrid: 0,
+ minuteGrid: 0,
+ secondGrid: 0,
+ millisecGrid: 0,
+ microsecGrid: 0,
+ alwaysSetTime: true,
+ separator: ' ',
+ altFieldTimeOnly: true,
+ altTimeFormat: null,
+ altSeparator: null,
+ altTimeSuffix: null,
+ altRedirectFocus: true,
+ pickerTimeFormat: null,
+ pickerTimeSuffix: null,
+ showTimepicker: true,
+ timezoneList: null,
+ addSliderAccess: false,
+ sliderAccessArgs: null,
+ controlType: 'slider',
+ defaultValue: null,
+ parse: 'strict'
+ };
+ $.extend(this._defaults, this.regional['']);
+ };
+
+ $.extend(Timepicker.prototype, {
+ $input: null,
+ $altInput: null,
+ $timeObj: null,
+ inst: null,
+ hour_slider: null,
+ minute_slider: null,
+ second_slider: null,
+ millisec_slider: null,
+ microsec_slider: null,
+ timezone_select: null,
+ maxTime: null,
+ minTime: null,
+ hour: 0,
+ minute: 0,
+ second: 0,
+ millisec: 0,
+ microsec: 0,
+ timezone: null,
+ hourMinOriginal: null,
+ minuteMinOriginal: null,
+ secondMinOriginal: null,
+ millisecMinOriginal: null,
+ microsecMinOriginal: null,
+ hourMaxOriginal: null,
+ minuteMaxOriginal: null,
+ secondMaxOriginal: null,
+ millisecMaxOriginal: null,
+ microsecMaxOriginal: null,
+ ampm: '',
+ formattedDate: '',
+ formattedTime: '',
+ formattedDateTime: '',
+ timezoneList: null,
+ units: ['hour', 'minute', 'second', 'millisec', 'microsec'],
+ support: {},
+ control: null,
+
+ /*
+ * Override the default settings for all instances of the time picker.
+ * @param {Object} settings object - the new settings to use as defaults (anonymous object)
+ * @return {Object} the manager object
+ */
+ setDefaults: function (settings) {
+ extendRemove(this._defaults, settings || {});
+ return this;
+ },
+
+ /*
+ * Create a new Timepicker instance
+ */
+ _newInst: function ($input, opts) {
+ var tp_inst = new Timepicker(),
+ inlineSettings = {},
+ fns = {},
+ overrides, i;
+
+ for (var attrName in this._defaults) {
+ if (this._defaults.hasOwnProperty(attrName)) {
+ var attrValue = $input.attr('time:' + attrName);
+ if (attrValue) {
+ try {
+ inlineSettings[attrName] = eval(attrValue);
+ } catch (err) {
+ inlineSettings[attrName] = attrValue;
+ }
+ }
+ }
+ }
+
+ overrides = {
+ beforeShow: function (input, dp_inst) {
+ if ($.isFunction(tp_inst._defaults.evnts.beforeShow)) {
+ return tp_inst._defaults.evnts.beforeShow.call($input[0], input, dp_inst, tp_inst);
+ }
+ },
+ onChangeMonthYear: function (year, month, dp_inst) {
+ // Update the time as well : this prevents the time from disappearing from the $input field.
+ tp_inst._updateDateTime(dp_inst);
+ if ($.isFunction(tp_inst._defaults.evnts.onChangeMonthYear)) {
+ tp_inst._defaults.evnts.onChangeMonthYear.call($input[0], year, month, dp_inst, tp_inst);
+ }
+ },
+ onClose: function (dateText, dp_inst) {
+ if (tp_inst.timeDefined === true && $input.val() !== '') {
+ tp_inst._updateDateTime(dp_inst);
+ }
+ if ($.isFunction(tp_inst._defaults.evnts.onClose)) {
+ tp_inst._defaults.evnts.onClose.call($input[0], dateText, dp_inst, tp_inst);
+ }
+ }
+ };
+ for (i in overrides) {
+ if (overrides.hasOwnProperty(i)) {
+ fns[i] = opts[i] || null;
+ }
+ }
+
+ tp_inst._defaults = $.extend({}, this._defaults, inlineSettings, opts, overrides, {
+ evnts: fns,
+ timepicker: tp_inst // add timepicker as a property of datepicker: $.datepicker._get(dp_inst, 'timepicker');
+ });
+ tp_inst.amNames = $.map(tp_inst._defaults.amNames, function (val) {
+ return val.toUpperCase();
+ });
+ tp_inst.pmNames = $.map(tp_inst._defaults.pmNames, function (val) {
+ return val.toUpperCase();
+ });
+
+ // detect which units are supported
+ tp_inst.support = detectSupport(
+ tp_inst._defaults.timeFormat +
+ (tp_inst._defaults.pickerTimeFormat ? tp_inst._defaults.pickerTimeFormat : '') +
+ (tp_inst._defaults.altTimeFormat ? tp_inst._defaults.altTimeFormat : ''));
+
+ // controlType is string - key to our this._controls
+ if (typeof(tp_inst._defaults.controlType) === 'string') {
+ if (tp_inst._defaults.controlType === 'slider' && typeof($.ui.slider) === 'undefined') {
+ tp_inst._defaults.controlType = 'select';
+ }
+ tp_inst.control = tp_inst._controls[tp_inst._defaults.controlType];
+ }
+ // controlType is an object and must implement create, options, value methods
+ else {
+ tp_inst.control = tp_inst._defaults.controlType;
+ }
+
+ // prep the timezone options
+ var timezoneList = [-720, -660, -600, -570, -540, -480, -420, -360, -300, -270, -240, -210, -180, -120, -60,
+ 0, 60, 120, 180, 210, 240, 270, 300, 330, 345, 360, 390, 420, 480, 525, 540, 570, 600, 630, 660, 690, 720, 765, 780, 840];
+ if (tp_inst._defaults.timezoneList !== null) {
+ timezoneList = tp_inst._defaults.timezoneList;
+ }
+ var tzl = timezoneList.length, tzi = 0, tzv = null;
+ if (tzl > 0 && typeof timezoneList[0] !== 'object') {
+ for (; tzi < tzl; tzi++) {
+ tzv = timezoneList[tzi];
+ timezoneList[tzi] = { value: tzv, label: $.timepicker.timezoneOffsetString(tzv, tp_inst.support.iso8601) };
+ }
+ }
+ tp_inst._defaults.timezoneList = timezoneList;
+
+ // set the default units
+ tp_inst.timezone = tp_inst._defaults.timezone !== null ? $.timepicker.timezoneOffsetNumber(tp_inst._defaults.timezone) :
+ ((new Date()).getTimezoneOffset() * -1);
+ tp_inst.hour = tp_inst._defaults.hour < tp_inst._defaults.hourMin ? tp_inst._defaults.hourMin :
+ tp_inst._defaults.hour > tp_inst._defaults.hourMax ? tp_inst._defaults.hourMax : tp_inst._defaults.hour;
+ tp_inst.minute = tp_inst._defaults.minute < tp_inst._defaults.minuteMin ? tp_inst._defaults.minuteMin :
+ tp_inst._defaults.minute > tp_inst._defaults.minuteMax ? tp_inst._defaults.minuteMax : tp_inst._defaults.minute;
+ tp_inst.second = tp_inst._defaults.second < tp_inst._defaults.secondMin ? tp_inst._defaults.secondMin :
+ tp_inst._defaults.second > tp_inst._defaults.secondMax ? tp_inst._defaults.secondMax : tp_inst._defaults.second;
+ tp_inst.millisec = tp_inst._defaults.millisec < tp_inst._defaults.millisecMin ? tp_inst._defaults.millisecMin :
+ tp_inst._defaults.millisec > tp_inst._defaults.millisecMax ? tp_inst._defaults.millisecMax : tp_inst._defaults.millisec;
+ tp_inst.microsec = tp_inst._defaults.microsec < tp_inst._defaults.microsecMin ? tp_inst._defaults.microsecMin :
+ tp_inst._defaults.microsec > tp_inst._defaults.microsecMax ? tp_inst._defaults.microsecMax : tp_inst._defaults.microsec;
+ tp_inst.ampm = '';
+ tp_inst.$input = $input;
+
+ if (tp_inst._defaults.altField) {
+ tp_inst.$altInput = $(tp_inst._defaults.altField);
+ if (tp_inst._defaults.altRedirectFocus === true) {
+ tp_inst.$altInput.css({
+ cursor: 'pointer'
+ }).focus(function () {
+ $input.trigger("focus");
+ });
+ }
+ }
+
+ if (tp_inst._defaults.minDate === 0 || tp_inst._defaults.minDateTime === 0) {
+ tp_inst._defaults.minDate = new Date();
+ }
+ if (tp_inst._defaults.maxDate === 0 || tp_inst._defaults.maxDateTime === 0) {
+ tp_inst._defaults.maxDate = new Date();
+ }
+
+ // datepicker needs minDate/maxDate, timepicker needs minDateTime/maxDateTime..
+ if (tp_inst._defaults.minDate !== undefined && tp_inst._defaults.minDate instanceof Date) {
+ tp_inst._defaults.minDateTime = new Date(tp_inst._defaults.minDate.getTime());
+ }
+ if (tp_inst._defaults.minDateTime !== undefined && tp_inst._defaults.minDateTime instanceof Date) {
+ tp_inst._defaults.minDate = new Date(tp_inst._defaults.minDateTime.getTime());
+ }
+ if (tp_inst._defaults.maxDate !== undefined && tp_inst._defaults.maxDate instanceof Date) {
+ tp_inst._defaults.maxDateTime = new Date(tp_inst._defaults.maxDate.getTime());
+ }
+ if (tp_inst._defaults.maxDateTime !== undefined && tp_inst._defaults.maxDateTime instanceof Date) {
+ tp_inst._defaults.maxDate = new Date(tp_inst._defaults.maxDateTime.getTime());
+ }
+ tp_inst.$input.bind('focus', function () {
+ tp_inst._onFocus();
+ });
+
+ return tp_inst;
+ },
+
+ /*
+ * add our sliders to the calendar
+ */
+ _addTimePicker: function (dp_inst) {
+ var currDT = (this.$altInput && this._defaults.altFieldTimeOnly) ? this.$input.val() + ' ' + this.$altInput.val() : this.$input.val();
+
+ this.timeDefined = this._parseTime(currDT);
+ this._limitMinMaxDateTime(dp_inst, false);
+ this._injectTimePicker();
+ },
+
+ /*
+ * parse the time string from input value or _setTime
+ */
+ _parseTime: function (timeString, withDate) {
+ if (!this.inst) {
+ this.inst = $.datepicker._getInst(this.$input[0]);
+ }
+
+ if (withDate || !this._defaults.timeOnly) {
+ var dp_dateFormat = $.datepicker._get(this.inst, 'dateFormat');
+ try {
+ var parseRes = parseDateTimeInternal(dp_dateFormat, this._defaults.timeFormat, timeString, $.datepicker._getFormatConfig(this.inst), this._defaults);
+ if (!parseRes.timeObj) {
+ return false;
+ }
+ $.extend(this, parseRes.timeObj);
+ } catch (err) {
+ $.timepicker.log("Error parsing the date/time string: " + err +
+ "\ndate/time string = " + timeString +
+ "\ntimeFormat = " + this._defaults.timeFormat +
+ "\ndateFormat = " + dp_dateFormat);
+ return false;
+ }
+ return true;
+ } else {
+ var timeObj = $.datepicker.parseTime(this._defaults.timeFormat, timeString, this._defaults);
+ if (!timeObj) {
+ return false;
+ }
+ $.extend(this, timeObj);
+ return true;
+ }
+ },
+
+ /*
+ * generate and inject html for timepicker into ui datepicker
+ */
+ _injectTimePicker: function () {
+ var $dp = this.inst.dpDiv,
+ o = this.inst.settings,
+ tp_inst = this,
+ litem = '',
+ uitem = '',
+ show = null,
+ max = {},
+ gridSize = {},
+ size = null,
+ i = 0,
+ l = 0;
+
+ // Prevent displaying twice
+ if ($dp.find("div.ui-timepicker-div").length === 0 && o.showTimepicker) {
+ var noDisplay = ' style="display:none;"',
+ html = '<div class="ui-timepicker-div' + (o.isRTL ? ' ui-timepicker-rtl' : '') + '"><dl>' + '<dt class="ui_tpicker_time_label"' + ((o.showTime) ? '' : noDisplay) + '>' + o.timeText + '</dt>' +
+ '<dd class="ui_tpicker_time"' + ((o.showTime) ? '' : noDisplay) + '></dd>';
+
+ // Create the markup
+ for (i = 0, l = this.units.length; i < l; i++) {
+ litem = this.units[i];
+ uitem = litem.substr(0, 1).toUpperCase() + litem.substr(1);
+ show = o['show' + uitem] !== null ? o['show' + uitem] : this.support[litem];
+
+ // Added by Peter Medeiros:
+ // - Figure out what the hour/minute/second max should be based on the step values.
+ // - Example: if stepMinute is 15, then minMax is 45.
+ max[litem] = parseInt((o[litem + 'Max'] - ((o[litem + 'Max'] - o[litem + 'Min']) % o['step' + uitem])), 10);
+ gridSize[litem] = 0;
+
+ html += '<dt class="ui_tpicker_' + litem + '_label"' + (show ? '' : noDisplay) + '>' + o[litem + 'Text'] + '</dt>' +
+ '<dd class="ui_tpicker_' + litem + '"><div class="ui_tpicker_' + litem + '_slider"' + (show ? '' : noDisplay) + '></div>';
+
+ if (show && o[litem + 'Grid'] > 0) {
+ html += '<div style="padding-left: 1px"><table class="ui-tpicker-grid-label"><tr>';
+
+ if (litem === 'hour') {
+ for (var h = o[litem + 'Min']; h <= max[litem]; h += parseInt(o[litem + 'Grid'], 10)) {
+ gridSize[litem]++;
+ var tmph = $.datepicker.formatTime(this.support.ampm ? 'hht' : 'HH', {hour: h}, o);
+ html += '<td data-for="' + litem + '">' + tmph + '</td>';
+ }
+ }
+ else {
+ for (var m = o[litem + 'Min']; m <= max[litem]; m += parseInt(o[litem + 'Grid'], 10)) {
+ gridSize[litem]++;
+ html += '<td data-for="' + litem + '">' + ((m < 10) ? '0' : '') + m + '</td>';
+ }
+ }
+
+ html += '</tr></table></div>';
+ }
+ html += '</dd>';
+ }
+
+ // Timezone
+ var showTz = o.showTimezone !== null ? o.showTimezone : this.support.timezone;
+ html += '<dt class="ui_tpicker_timezone_label"' + (showTz ? '' : noDisplay) + '>' + o.timezoneText + '</dt>';
+ html += '<dd class="ui_tpicker_timezone" ' + (showTz ? '' : noDisplay) + '></dd>';
+
+ // Create the elements from string
+ html += '</dl></div>';
+ var $tp = $(html);
+
+ // if we only want time picker...
+ if (o.timeOnly === true) {
+ $tp.prepend('<div class="ui-widget-header ui-helper-clearfix ui-corner-all">' + '<div class="ui-datepicker-title">' + o.timeOnlyTitle + '</div>' + '</div>');
+ $dp.find('.ui-datepicker-header, .ui-datepicker-calendar').hide();
+ }
+
+ // add sliders, adjust grids, add events
+ for (i = 0, l = tp_inst.units.length; i < l; i++) {
+ litem = tp_inst.units[i];
+ uitem = litem.substr(0, 1).toUpperCase() + litem.substr(1);
+ show = o['show' + uitem] !== null ? o['show' + uitem] : this.support[litem];
+
+ // add the slider
+ tp_inst[litem + '_slider'] = tp_inst.control.create(tp_inst, $tp.find('.ui_tpicker_' + litem + '_slider'), litem, tp_inst[litem], o[litem + 'Min'], max[litem], o['step' + uitem]);
+
+ // adjust the grid and add click event
+ if (show && o[litem + 'Grid'] > 0) {
+ size = 100 * gridSize[litem] * o[litem + 'Grid'] / (max[litem] - o[litem + 'Min']);
+ $tp.find('.ui_tpicker_' + litem + ' table').css({
+ width: size + "%",
+ marginLeft: o.isRTL ? '0' : ((size / (-2 * gridSize[litem])) + "%"),
+ marginRight: o.isRTL ? ((size / (-2 * gridSize[litem])) + "%") : '0',
+ borderCollapse: 'collapse'
+ }).find("td").click(function (e) {
+ var $t = $(this),
+ h = $t.html(),
+ n = parseInt(h.replace(/[^0-9]/g), 10),
+ ap = h.replace(/[^apm]/ig),
+ f = $t.data('for'); // loses scope, so we use data-for
+
+ if (f === 'hour') {
+ if (ap.indexOf('p') !== -1 && n < 12) {
+ n += 12;
+ }
+ else {
+ if (ap.indexOf('a') !== -1 && n === 12) {
+ n = 0;
+ }
+ }
+ }
+
+ tp_inst.control.value(tp_inst, tp_inst[f + '_slider'], litem, n);
+
+ tp_inst._onTimeChange();
+ tp_inst._onSelectHandler();
+ }).css({
+ cursor: 'pointer',
+ width: (100 / gridSize[litem]) + '%',
+ textAlign: 'center',
+ overflow: 'hidden'
+ });
+ } // end if grid > 0
+ } // end for loop
+
+ // Add timezone options
+ this.timezone_select = $tp.find('.ui_tpicker_timezone').append('<select></select>').find("select");
+ $.fn.append.apply(this.timezone_select,
+ $.map(o.timezoneList, function (val, idx) {
+ return $("<option />").val(typeof val === "object" ? val.value : val).text(typeof val === "object" ? val.label : val);
+ }));
+ if (typeof(this.timezone) !== "undefined" && this.timezone !== null && this.timezone !== "") {
+ var local_timezone = (new Date(this.inst.selectedYear, this.inst.selectedMonth, this.inst.selectedDay, 12)).getTimezoneOffset() * -1;
+ if (local_timezone === this.timezone) {
+ selectLocalTimezone(tp_inst);
+ } else {
+ this.timezone_select.val(this.timezone);
+ }
+ } else {
+ if (typeof(this.hour) !== "undefined" && this.hour !== null && this.hour !== "") {
+ this.timezone_select.val(o.timezone);
+ } else {
+ selectLocalTimezone(tp_inst);
+ }
+ }
+ this.timezone_select.change(function () {
+ tp_inst._onTimeChange();
+ tp_inst._onSelectHandler();
+ });
+ // End timezone options
+
+ // inject timepicker into datepicker
+ var $buttonPanel = $dp.find('.ui-datepicker-buttonpane');
+ if ($buttonPanel.length) {
+ $buttonPanel.before($tp);
+ } else {
+ $dp.append($tp);
+ }
+
+ this.$timeObj = $tp.find('.ui_tpicker_time');
+
+ if (this.inst !== null) {
+ var timeDefined = this.timeDefined;
+ this._onTimeChange();
+ this.timeDefined = timeDefined;
+ }
+
+ // slideAccess integration: http://trentrichardson.com/2011/11/11/jquery-ui-sliders-and-touch-accessibility/
+ if (this._defaults.addSliderAccess) {
+ var sliderAccessArgs = this._defaults.sliderAccessArgs,
+ rtl = this._defaults.isRTL;
+ sliderAccessArgs.isRTL = rtl;
+
+ setTimeout(function () { // fix for inline mode
+ if ($tp.find('.ui-slider-access').length === 0) {
+ $tp.find('.ui-slider:visible').sliderAccess(sliderAccessArgs);
+
+ // fix any grids since sliders are shorter
+ var sliderAccessWidth = $tp.find('.ui-slider-access:eq(0)').outerWidth(true);
+ if (sliderAccessWidth) {
+ $tp.find('table:visible').each(function () {
+ var $g = $(this),
+ oldWidth = $g.outerWidth(),
+ oldMarginLeft = $g.css(rtl ? 'marginRight' : 'marginLeft').toString().replace('%', ''),
+ newWidth = oldWidth - sliderAccessWidth,
+ newMarginLeft = ((oldMarginLeft * newWidth) / oldWidth) + '%',
+ css = { width: newWidth, marginRight: 0, marginLeft: 0 };
+ css[rtl ? 'marginRight' : 'marginLeft'] = newMarginLeft;
+ $g.css(css);
+ });
+ }
+ }
+ }, 10);
+ }
+ // end slideAccess integration
+
+ tp_inst._limitMinMaxDateTime(this.inst, true);
+ }
+ },
+
+ /*
+ * This function tries to limit the ability to go outside the
+ * min/max date range
+ */
+ _limitMinMaxDateTime: function (dp_inst, adjustSliders) {
+ var o = this._defaults,
+ dp_date = new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay);
+
+ if (!this._defaults.showTimepicker) {
+ return;
+ } // No time so nothing to check here
+
+ if ($.datepicker._get(dp_inst, 'minDateTime') !== null && $.datepicker._get(dp_inst, 'minDateTime') !== undefined && dp_date) {
+ var minDateTime = $.datepicker._get(dp_inst, 'minDateTime'),
+ minDateTimeDate = new Date(minDateTime.getFullYear(), minDateTime.getMonth(), minDateTime.getDate(), 0, 0, 0, 0);
+
+ if (this.hourMinOriginal === null || this.minuteMinOriginal === null || this.secondMinOriginal === null || this.millisecMinOriginal === null || this.microsecMinOriginal === null) {
+ this.hourMinOriginal = o.hourMin;
+ this.minuteMinOriginal = o.minuteMin;
+ this.secondMinOriginal = o.secondMin;
+ this.millisecMinOriginal = o.millisecMin;
+ this.microsecMinOriginal = o.microsecMin;
+ }
+
+ if (dp_inst.settings.timeOnly || minDateTimeDate.getTime() === dp_date.getTime()) {
+ this._defaults.hourMin = minDateTime.getHours();
+ if (this.hour <= this._defaults.hourMin) {
+ this.hour = this._defaults.hourMin;
+ this._defaults.minuteMin = minDateTime.getMinutes();
+ if (this.minute <= this._defaults.minuteMin) {
+ this.minute = this._defaults.minuteMin;
+ this._defaults.secondMin = minDateTime.getSeconds();
+ if (this.second <= this._defaults.secondMin) {
+ this.second = this._defaults.secondMin;
+ this._defaults.millisecMin = minDateTime.getMilliseconds();
+ if (this.millisec <= this._defaults.millisecMin) {
+ this.millisec = this._defaults.millisecMin;
+ this._defaults.microsecMin = minDateTime.getMicroseconds();
+ } else {
+ if (this.microsec < this._defaults.microsecMin) {
+ this.microsec = this._defaults.microsecMin;
+ }
+ this._defaults.microsecMin = this.microsecMinOriginal;
+ }
+ } else {
+ this._defaults.millisecMin = this.millisecMinOriginal;
+ this._defaults.microsecMin = this.microsecMinOriginal;
+ }
+ } else {
+ this._defaults.secondMin = this.secondMinOriginal;
+ this._defaults.millisecMin = this.millisecMinOriginal;
+ this._defaults.microsecMin = this.microsecMinOriginal;
+ }
+ } else {
+ this._defaults.minuteMin = this.minuteMinOriginal;
+ this._defaults.secondMin = this.secondMinOriginal;
+ this._defaults.millisecMin = this.millisecMinOriginal;
+ this._defaults.microsecMin = this.microsecMinOriginal;
+ }
+ } else {
+ this._defaults.hourMin = this.hourMinOriginal;
+ this._defaults.minuteMin = this.minuteMinOriginal;
+ this._defaults.secondMin = this.secondMinOriginal;
+ this._defaults.millisecMin = this.millisecMinOriginal;
+ this._defaults.microsecMin = this.microsecMinOriginal;
+ }
+ }
+
+ if ($.datepicker._get(dp_inst, 'maxDateTime') !== null && $.datepicker._get(dp_inst, 'maxDateTime') !== undefined && dp_date) {
+ var maxDateTime = $.datepicker._get(dp_inst, 'maxDateTime'),
+ maxDateTimeDate = new Date(maxDateTime.getFullYear(), maxDateTime.getMonth(), maxDateTime.getDate(), 0, 0, 0, 0);
+
+ if (this.hourMaxOriginal === null || this.minuteMaxOriginal === null || this.secondMaxOriginal === null || this.millisecMaxOriginal === null) {
+ this.hourMaxOriginal = o.hourMax;
+ this.minuteMaxOriginal = o.minuteMax;
+ this.secondMaxOriginal = o.secondMax;
+ this.millisecMaxOriginal = o.millisecMax;
+ this.microsecMaxOriginal = o.microsecMax;
+ }
+
+ if (dp_inst.settings.timeOnly || maxDateTimeDate.getTime() === dp_date.getTime()) {
+ this._defaults.hourMax = maxDateTime.getHours();
+ if (this.hour >= this._defaults.hourMax) {
+ this.hour = this._defaults.hourMax;
+ this._defaults.minuteMax = maxDateTime.getMinutes();
+ if (this.minute >= this._defaults.minuteMax) {
+ this.minute = this._defaults.minuteMax;
+ this._defaults.secondMax = maxDateTime.getSeconds();
+ if (this.second >= this._defaults.secondMax) {
+ this.second = this._defaults.secondMax;
+ this._defaults.millisecMax = maxDateTime.getMilliseconds();
+ if (this.millisec >= this._defaults.millisecMax) {
+ this.millisec = this._defaults.millisecMax;
+ this._defaults.microsecMax = maxDateTime.getMicroseconds();
+ } else {
+ if (this.microsec > this._defaults.microsecMax) {
+ this.microsec = this._defaults.microsecMax;
+ }
+ this._defaults.microsecMax = this.microsecMaxOriginal;
+ }
+ } else {
+ this._defaults.millisecMax = this.millisecMaxOriginal;
+ this._defaults.microsecMax = this.microsecMaxOriginal;
+ }
+ } else {
+ this._defaults.secondMax = this.secondMaxOriginal;
+ this._defaults.millisecMax = this.millisecMaxOriginal;
+ this._defaults.microsecMax = this.microsecMaxOriginal;
+ }
+ } else {
+ this._defaults.minuteMax = this.minuteMaxOriginal;
+ this._defaults.secondMax = this.secondMaxOriginal;
+ this._defaults.millisecMax = this.millisecMaxOriginal;
+ this._defaults.microsecMax = this.microsecMaxOriginal;
+ }
+ } else {
+ this._defaults.hourMax = this.hourMaxOriginal;
+ this._defaults.minuteMax = this.minuteMaxOriginal;
+ this._defaults.secondMax = this.secondMaxOriginal;
+ this._defaults.millisecMax = this.millisecMaxOriginal;
+ this._defaults.microsecMax = this.microsecMaxOriginal;
+ }
+ }
+
+ if (dp_inst.settings.minTime!==null) {
+ var tempMinTime=new Date("01/01/1970 " + dp_inst.settings.minTime);
+ if (this.hour<tempMinTime.getHours()) {
+ this.hour=this._defaults.hourMin=tempMinTime.getHours();
+ this.minute=this._defaults.minuteMin=tempMinTime.getMinutes();
+ } else if (this.hour===tempMinTime.getHours() && this.minute<tempMinTime.getMinutes()) {
+ this.minute=this._defaults.minuteMin=tempMinTime.getMinutes();
+ } else {
+ if (this._defaults.hourMin<tempMinTime.getHours()) {
+ this._defaults.hourMin=tempMinTime.getHours();
+ this._defaults.minuteMin=tempMinTime.getMinutes();
+ } else if (this._defaults.hourMin===tempMinTime.getHours()===this.hour && this._defaults.minuteMin<tempMinTime.getMinutes()) {
+ this._defaults.minuteMin=tempMinTime.getMinutes();
+ } else {
+ this._defaults.minuteMin=0;
+ }
+ }
+ }
+
+ if (dp_inst.settings.maxTime!==null) {
+ var tempMaxTime=new Date("01/01/1970 " + dp_inst.settings.maxTime);
+ if (this.hour>tempMaxTime.getHours()) {
+ this.hour=this._defaults.hourMax=tempMaxTime.getHours();
+ this.minute=this._defaults.minuteMax=tempMaxTime.getMinutes();
+ } else if (this.hour===tempMaxTime.getHours() && this.minute>tempMaxTime.getMinutes()) {
+ this.minute=this._defaults.minuteMax=tempMaxTime.getMinutes();
+ } else {
+ if (this._defaults.hourMax>tempMaxTime.getHours()) {
+ this._defaults.hourMax=tempMaxTime.getHours();
+ this._defaults.minuteMax=tempMaxTime.getMinutes();
+ } else if (this._defaults.hourMax===tempMaxTime.getHours()===this.hour && this._defaults.minuteMax>tempMaxTime.getMinutes()) {
+ this._defaults.minuteMax=tempMaxTime.getMinutes();
+ } else {
+ this._defaults.minuteMax=59;
+ }
+ }
+ }
+
+ if (adjustSliders !== undefined && adjustSliders === true) {
+ var hourMax = parseInt((this._defaults.hourMax - ((this._defaults.hourMax - this._defaults.hourMin) % this._defaults.stepHour)), 10),
+ minMax = parseInt((this._defaults.minuteMax - ((this._defaults.minuteMax - this._defaults.minuteMin) % this._defaults.stepMinute)), 10),
+ secMax = parseInt((this._defaults.secondMax - ((this._defaults.secondMax - this._defaults.secondMin) % this._defaults.stepSecond)), 10),
+ millisecMax = parseInt((this._defaults.millisecMax - ((this._defaults.millisecMax - this._defaults.millisecMin) % this._defaults.stepMillisec)), 10),
+ microsecMax = parseInt((this._defaults.microsecMax - ((this._defaults.microsecMax - this._defaults.microsecMin) % this._defaults.stepMicrosec)), 10);
+
+ if (this.hour_slider) {
+ this.control.options(this, this.hour_slider, 'hour', { min: this._defaults.hourMin, max: hourMax, step: this._defaults.stepHour });
+ this.control.value(this, this.hour_slider, 'hour', this.hour - (this.hour % this._defaults.stepHour));
+ }
+ if (this.minute_slider) {
+ this.control.options(this, this.minute_slider, 'minute', { min: this._defaults.minuteMin, max: minMax, step: this._defaults.stepMinute });
+ this.control.value(this, this.minute_slider, 'minute', this.minute - (this.minute % this._defaults.stepMinute));
+ }
+ if (this.second_slider) {
+ this.control.options(this, this.second_slider, 'second', { min: this._defaults.secondMin, max: secMax, step: this._defaults.stepSecond });
+ this.control.value(this, this.second_slider, 'second', this.second - (this.second % this._defaults.stepSecond));
+ }
+ if (this.millisec_slider) {
+ this.control.options(this, this.millisec_slider, 'millisec', { min: this._defaults.millisecMin, max: millisecMax, step: this._defaults.stepMillisec });
+ this.control.value(this, this.millisec_slider, 'millisec', this.millisec - (this.millisec % this._defaults.stepMillisec));
+ }
+ if (this.microsec_slider) {
+ this.control.options(this, this.microsec_slider, 'microsec', { min: this._defaults.microsecMin, max: microsecMax, step: this._defaults.stepMicrosec });
+ this.control.value(this, this.microsec_slider, 'microsec', this.microsec - (this.microsec % this._defaults.stepMicrosec));
+ }
+ }
+
+ },
+
+ /*
+ * when a slider moves, set the internal time...
+ * on time change is also called when the time is updated in the text field
+ */
+ _onTimeChange: function () {
+ if (!this._defaults.showTimepicker) {
+ return;
+ }
+ var hour = (this.hour_slider) ? this.control.value(this, this.hour_slider, 'hour') : false,
+ minute = (this.minute_slider) ? this.control.value(this, this.minute_slider, 'minute') : false,
+ second = (this.second_slider) ? this.control.value(this, this.second_slider, 'second') : false,
+ millisec = (this.millisec_slider) ? this.control.value(this, this.millisec_slider, 'millisec') : false,
+ microsec = (this.microsec_slider) ? this.control.value(this, this.microsec_slider, 'microsec') : false,
+ timezone = (this.timezone_select) ? this.timezone_select.val() : false,
+ o = this._defaults,
+ pickerTimeFormat = o.pickerTimeFormat || o.timeFormat,
+ pickerTimeSuffix = o.pickerTimeSuffix || o.timeSuffix;
+
+ if (typeof(hour) === 'object') {
+ hour = false;
+ }
+ if (typeof(minute) === 'object') {
+ minute = false;
+ }
+ if (typeof(second) === 'object') {
+ second = false;
+ }
+ if (typeof(millisec) === 'object') {
+ millisec = false;
+ }
+ if (typeof(microsec) === 'object') {
+ microsec = false;
+ }
+ if (typeof(timezone) === 'object') {
+ timezone = false;
+ }
+
+ if (hour !== false) {
+ hour = parseInt(hour, 10);
+ }
+ if (minute !== false) {
+ minute = parseInt(minute, 10);
+ }
+ if (second !== false) {
+ second = parseInt(second, 10);
+ }
+ if (millisec !== false) {
+ millisec = parseInt(millisec, 10);
+ }
+ if (microsec !== false) {
+ microsec = parseInt(microsec, 10);
+ }
+ if (timezone !== false) {
+ timezone = timezone.toString();
+ }
+
+ var ampm = o[hour < 12 ? 'amNames' : 'pmNames'][0];
+
+ // If the update was done in the input field, the input field should not be updated.
+ // If the update was done using the sliders, update the input field.
+ var hasChanged = (
+ hour !== parseInt(this.hour,10) || // sliders should all be numeric
+ minute !== parseInt(this.minute,10) ||
+ second !== parseInt(this.second,10) ||
+ millisec !== parseInt(this.millisec,10) ||
+ microsec !== parseInt(this.microsec,10) ||
+ (this.ampm.length > 0 && (hour < 12) !== ($.inArray(this.ampm.toUpperCase(), this.amNames) !== -1)) ||
+ (this.timezone !== null && timezone !== this.timezone.toString()) // could be numeric or "EST" format, so use toString()
+ );
+
+ if (hasChanged) {
+
+ if (hour !== false) {
+ this.hour = hour;
+ }
+ if (minute !== false) {
+ this.minute = minute;
+ }
+ if (second !== false) {
+ this.second = second;
+ }
+ if (millisec !== false) {
+ this.millisec = millisec;
+ }
+ if (microsec !== false) {
+ this.microsec = microsec;
+ }
+ if (timezone !== false) {
+ this.timezone = timezone;
+ }
+
+ if (!this.inst) {
+ this.inst = $.datepicker._getInst(this.$input[0]);
+ }
+
+ this._limitMinMaxDateTime(this.inst, true);
+ }
+ if (this.support.ampm) {
+ this.ampm = ampm;
+ }
+
+ // Updates the time within the timepicker
+ this.formattedTime = $.datepicker.formatTime(o.timeFormat, this, o);
+ if (this.$timeObj) {
+ if (pickerTimeFormat === o.timeFormat) {
+ this.$timeObj.text(this.formattedTime + pickerTimeSuffix);
+ }
+ else {
+ this.$timeObj.text($.datepicker.formatTime(pickerTimeFormat, this, o) + pickerTimeSuffix);
+ }
+ }
+
+ this.timeDefined = true;
+ if (hasChanged) {
+ this._updateDateTime();
+ //this.$input.focus(); // may automatically open the picker on setDate
+ }
+ },
+
+ /*
+ * call custom onSelect.
+ * bind to sliders slidestop, and grid click.
+ */
+ _onSelectHandler: function () {
+ var onSelect = this._defaults.onSelect || this.inst.settings.onSelect;
+ var inputEl = this.$input ? this.$input[0] : null;
+ if (onSelect && inputEl) {
+ onSelect.apply(inputEl, [this.formattedDateTime, this]);
+ }
+ },
+
+ /*
+ * update our input with the new date time..
+ */
+ _updateDateTime: function (dp_inst) {
+ dp_inst = this.inst || dp_inst;
+ var dtTmp = (dp_inst.currentYear > 0?
+ new Date(dp_inst.currentYear, dp_inst.currentMonth, dp_inst.currentDay) :
+ new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay)),
+ dt = $.datepicker._daylightSavingAdjust(dtTmp),
+ //dt = $.datepicker._daylightSavingAdjust(new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay)),
+ //dt = $.datepicker._daylightSavingAdjust(new Date(dp_inst.currentYear, dp_inst.currentMonth, dp_inst.currentDay)),
+ dateFmt = $.datepicker._get(dp_inst, 'dateFormat'),
+ formatCfg = $.datepicker._getFormatConfig(dp_inst),
+ timeAvailable = dt !== null && this.timeDefined;
+ this.formattedDate = $.datepicker.formatDate(dateFmt, (dt === null ? new Date() : dt), formatCfg);
+ var formattedDateTime = this.formattedDate;
+
+ // if a slider was changed but datepicker doesn't have a value yet, set it
+ if (dp_inst.lastVal === "") {
+ dp_inst.currentYear = dp_inst.selectedYear;
+ dp_inst.currentMonth = dp_inst.selectedMonth;
+ dp_inst.currentDay = dp_inst.selectedDay;
+ }
+
+ /*
+ * remove following lines to force every changes in date picker to change the input value
+ * Bug descriptions: when an input field has a default value, and click on the field to pop up the date picker.
+ * If the user manually empty the value in the input field, the date picker will never change selected value.
+ */
+ //if (dp_inst.lastVal !== undefined && (dp_inst.lastVal.length > 0 && this.$input.val().length === 0)) {
+ // return;
+ //}
+
+ if (this._defaults.timeOnly === true && this._defaults.timeOnlyShowDate === false) {
+ formattedDateTime = this.formattedTime;
+ } else if ((this._defaults.timeOnly !== true && (this._defaults.alwaysSetTime || timeAvailable)) || (this._defaults.timeOnly === true && this._defaults.timeOnlyShowDate === true)) {
+ formattedDateTime += this._defaults.separator + this.formattedTime + this._defaults.timeSuffix;
+ }
+
+ this.formattedDateTime = formattedDateTime;
+
+ if (!this._defaults.showTimepicker) {
+ this.$input.val(this.formattedDate);
+ } else if (this.$altInput && this._defaults.timeOnly === false && this._defaults.altFieldTimeOnly === true) {
+ this.$altInput.val(this.formattedTime);
+ this.$input.val(this.formattedDate);
+ } else if (this.$altInput) {
+ this.$input.val(formattedDateTime);
+ var altFormattedDateTime = '',
+ altSeparator = this._defaults.altSeparator !== null ? this._defaults.altSeparator : this._defaults.separator,
+ altTimeSuffix = this._defaults.altTimeSuffix !== null ? this._defaults.altTimeSuffix : this._defaults.timeSuffix;
+
+ if (!this._defaults.timeOnly) {
+ if (this._defaults.altFormat) {
+ altFormattedDateTime = $.datepicker.formatDate(this._defaults.altFormat, (dt === null ? new Date() : dt), formatCfg);
+ }
+ else {
+ altFormattedDateTime = this.formattedDate;
+ }
+
+ if (altFormattedDateTime) {
+ altFormattedDateTime += altSeparator;
+ }
+ }
+
+ if (this._defaults.altTimeFormat !== null) {
+ altFormattedDateTime += $.datepicker.formatTime(this._defaults.altTimeFormat, this, this._defaults) + altTimeSuffix;
+ }
+ else {
+ altFormattedDateTime += this.formattedTime + altTimeSuffix;
+ }
+ this.$altInput.val(altFormattedDateTime);
+ } else {
+ this.$input.val(formattedDateTime);
+ }
+
+ this.$input.trigger("change");
+ },
+
+ _onFocus: function () {
+ if (!this.$input.val() && this._defaults.defaultValue) {
+ this.$input.val(this._defaults.defaultValue);
+ var inst = $.datepicker._getInst(this.$input.get(0)),
+ tp_inst = $.datepicker._get(inst, 'timepicker');
+ if (tp_inst) {
+ if (tp_inst._defaults.timeOnly && (inst.input.val() !== inst.lastVal)) {
+ try {
+ $.datepicker._updateDatepicker(inst);
+ } catch (err) {
+ $.timepicker.log(err);
+ }
+ }
+ }
+ }
+ },
+
+ /*
+ * Small abstraction to control types
+ * We can add more, just be sure to follow the pattern: create, options, value
+ */
+ _controls: {
+ // slider methods
+ slider: {
+ create: function (tp_inst, obj, unit, val, min, max, step) {
+ var rtl = tp_inst._defaults.isRTL; // if rtl go -60->0 instead of 0->60
+ return obj.prop('slide', null).slider({
+ orientation: "horizontal",
+ value: rtl ? val * -1 : val,
+ min: rtl ? max * -1 : min,
+ max: rtl ? min * -1 : max,
+ step: step,
+ slide: function (event, ui) {
+ tp_inst.control.value(tp_inst, $(this), unit, rtl ? ui.value * -1 : ui.value);
+ tp_inst._onTimeChange();
+ },
+ stop: function (event, ui) {
+ tp_inst._onSelectHandler();
+ }
+ });
+ },
+ options: function (tp_inst, obj, unit, opts, val) {
+ if (tp_inst._defaults.isRTL) {
+ if (typeof(opts) === 'string') {
+ if (opts === 'min' || opts === 'max') {
+ if (val !== undefined) {
+ return obj.slider(opts, val * -1);
+ }
+ return Math.abs(obj.slider(opts));
+ }
+ return obj.slider(opts);
+ }
+ var min = opts.min,
+ max = opts.max;
+ opts.min = opts.max = null;
+ if (min !== undefined) {
+ opts.max = min * -1;
+ }
+ if (max !== undefined) {
+ opts.min = max * -1;
+ }
+ return obj.slider(opts);
+ }
+ if (typeof(opts) === 'string' && val !== undefined) {
+ return obj.slider(opts, val);
+ }
+ return obj.slider(opts);
+ },
+ value: function (tp_inst, obj, unit, val) {
+ if (tp_inst._defaults.isRTL) {
+ if (val !== undefined) {
+ return obj.slider('value', val * -1);
+ }
+ return Math.abs(obj.slider('value'));
+ }
+ if (val !== undefined) {
+ return obj.slider('value', val);
+ }
+ return obj.slider('value');
+ }
+ },
+ // select methods
+ select: {
+ create: function (tp_inst, obj, unit, val, min, max, step) {
+ var sel = '<select class="ui-timepicker-select ui-state-default ui-corner-all" data-unit="' + unit + '" data-min="' + min + '" data-max="' + max + '" data-step="' + step + '">',
+ format = tp_inst._defaults.pickerTimeFormat || tp_inst._defaults.timeFormat;
+
+ for (var i = min; i <= max; i += step) {
+ sel += '<option value="' + i + '"' + (i === val ? ' selected' : '') + '>';
+ if (unit === 'hour') {
+ sel += $.datepicker.formatTime($.trim(format.replace(/[^ht ]/ig, '')), {hour: i}, tp_inst._defaults);
+ }
+ else if (unit === 'millisec' || unit === 'microsec' || i >= 10) { sel += i; }
+ else {sel += '0' + i.toString(); }
+ sel += '</option>';
+ }
+ sel += '</select>';
+
+ obj.children('select').remove();
+
+ $(sel).appendTo(obj).change(function (e) {
+ tp_inst._onTimeChange();
+ tp_inst._onSelectHandler();
+ });
+
+ return obj;
+ },
+ options: function (tp_inst, obj, unit, opts, val) {
+ var o = {},
+ $t = obj.children('select');
+ if (typeof(opts) === 'string') {
+ if (val === undefined) {
+ return $t.data(opts);
+ }
+ o[opts] = val;
+ }
+ else { o = opts; }
+ return tp_inst.control.create(tp_inst, obj, $t.data('unit'), $t.val(), o.min || $t.data('min'), o.max || $t.data('max'), o.step || $t.data('step'));
+ },
+ value: function (tp_inst, obj, unit, val) {
+ var $t = obj.children('select');
+ if (val !== undefined) {
+ return $t.val(val);
+ }
+ return $t.val();
+ }
+ }
+ } // end _controls
+
+ });
+
+ $.fn.extend({
+ /*
+ * shorthand just to use timepicker.
+ */
+ timepicker: function (o) {
+ o = o || {};
+ var tmp_args = Array.prototype.slice.call(arguments);
+
+ if (typeof o === 'object') {
+ tmp_args[0] = $.extend(o, {
+ timeOnly: true
+ });
+ }
+
+ return $(this).each(function () {
+ $.fn.datetimepicker.apply($(this), tmp_args);
+ });
+ },
+
+ /*
+ * extend timepicker to datepicker
+ */
+ datetimepicker: function (o) {
+ o = o || {};
+ var tmp_args = arguments;
+
+ if (typeof(o) === 'string') {
+ if (o === 'getDate' || (o === 'option' && tmp_args.length === 2 && typeof (tmp_args[1]) === 'string')) {
+ return $.fn.datepicker.apply($(this[0]), tmp_args);
+ } else {
+ return this.each(function () {
+ var $t = $(this);
+ $t.datepicker.apply($t, tmp_args);
+ });
+ }
+ } else {
+ return this.each(function () {
+ var $t = $(this);
+ $t.datepicker($.timepicker._newInst($t, o)._defaults);
+ });
+ }
+ }
+ });
+
+ /*
+ * Public Utility to parse date and time
+ */
+ $.datepicker.parseDateTime = function (dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings) {
+ var parseRes = parseDateTimeInternal(dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings);
+ if (parseRes.timeObj) {
+ var t = parseRes.timeObj;
+ parseRes.date.setHours(t.hour, t.minute, t.second, t.millisec);
+ parseRes.date.setMicroseconds(t.microsec);
+ }
+
+ return parseRes.date;
+ };
+
+ /*
+ * Public utility to parse time
+ */
+ $.datepicker.parseTime = function (timeFormat, timeString, options) {
+ var o = extendRemove(extendRemove({}, $.timepicker._defaults), options || {}),
+ iso8601 = (timeFormat.replace(/\'.*?\'/g, '').indexOf('Z') !== -1);
+
+ // Strict parse requires the timeString to match the timeFormat exactly
+ var strictParse = function (f, s, o) {
+
+ // pattern for standard and localized AM/PM markers
+ var getPatternAmpm = function (amNames, pmNames) {
+ var markers = [];
+ if (amNames) {
+ $.merge(markers, amNames);
+ }
+ if (pmNames) {
+ $.merge(markers, pmNames);
+ }
+ markers = $.map(markers, function (val) {
+ return val.replace(/[.*+?|()\[\]{}\\]/g, '\\$&');
+ });
+ return '(' + markers.join('|') + ')?';
+ };
+
+ // figure out position of time elements.. cause js cant do named captures
+ var getFormatPositions = function (timeFormat) {
+ var finds = timeFormat.toLowerCase().match(/(h{1,2}|m{1,2}|s{1,2}|l{1}|c{1}|t{1,2}|z|'.*?')/g),
+ orders = {
+ h: -1,
+ m: -1,
+ s: -1,
+ l: -1,
+ c: -1,
+ t: -1,
+ z: -1
+ };
+
+ if (finds) {
+ for (var i = 0; i < finds.length; i++) {
+ if (orders[finds[i].toString().charAt(0)] === -1) {
+ orders[finds[i].toString().charAt(0)] = i + 1;
+ }
+ }
+ }
+ return orders;
+ };
+
+ var regstr = '^' + f.toString()
+ .replace(/([hH]{1,2}|mm?|ss?|[tT]{1,2}|[zZ]|[lc]|'.*?')/g, function (match) {
+ var ml = match.length;
+ switch (match.charAt(0).toLowerCase()) {
+ case 'h':
+ return ml === 1 ? '(\\d?\\d)' : '(\\d{' + ml + '})';
+ case 'm':
+ return ml === 1 ? '(\\d?\\d)' : '(\\d{' + ml + '})';
+ case 's':
+ return ml === 1 ? '(\\d?\\d)' : '(\\d{' + ml + '})';
+ case 'l':
+ return '(\\d?\\d?\\d)';
+ case 'c':
+ return '(\\d?\\d?\\d)';
+ case 'z':
+ return '(z|[-+]\\d\\d:?\\d\\d|\\S+)?';
+ case 't':
+ return getPatternAmpm(o.amNames, o.pmNames);
+ default: // literal escaped in quotes
+ return '(' + match.replace(/\'/g, "").replace(/(\.|\$|\^|\\|\/|\(|\)|\[|\]|\?|\+|\*)/g, function (m) { return "\\" + m; }) + ')?';
+ }
+ })
+ .replace(/\s/g, '\\s?') +
+ o.timeSuffix + '$',
+ order = getFormatPositions(f),
+ ampm = '',
+ treg;
+
+ treg = s.match(new RegExp(regstr, 'i'));
+
+ var resTime = {
+ hour: 0,
+ minute: 0,
+ second: 0,
+ millisec: 0,
+ microsec: 0
+ };
+
+ if (treg) {
+ if (order.t !== -1) {
+ if (treg[order.t] === undefined || treg[order.t].length === 0) {
+ ampm = '';
+ resTime.ampm = '';
+ } else {
+ ampm = $.inArray(treg[order.t].toUpperCase(), o.amNames) !== -1 ? 'AM' : 'PM';
+ resTime.ampm = o[ampm === 'AM' ? 'amNames' : 'pmNames'][0];
+ }
+ }
+
+ if (order.h !== -1) {
+ if (ampm === 'AM' && treg[order.h] === '12') {
+ resTime.hour = 0; // 12am = 0 hour
+ } else {
+ if (ampm === 'PM' && treg[order.h] !== '12') {
+ resTime.hour = parseInt(treg[order.h], 10) + 12; // 12pm = 12 hour, any other pm = hour + 12
+ } else {
+ resTime.hour = Number(treg[order.h]);
+ }
+ }
+ }
+
+ if (order.m !== -1) {
+ resTime.minute = Number(treg[order.m]);
+ }
+ if (order.s !== -1) {
+ resTime.second = Number(treg[order.s]);
+ }
+ if (order.l !== -1) {
+ resTime.millisec = Number(treg[order.l]);
+ }
+ if (order.c !== -1) {
+ resTime.microsec = Number(treg[order.c]);
+ }
+ if (order.z !== -1 && treg[order.z] !== undefined) {
+ resTime.timezone = $.timepicker.timezoneOffsetNumber(treg[order.z]);
+ }
+
+
+ return resTime;
+ }
+ return false;
+ };// end strictParse
+
+ // First try JS Date, if that fails, use strictParse
+ var looseParse = function (f, s, o) {
+ try {
+ var d = new Date('2012-01-01 ' + s);
+ if (isNaN(d.getTime())) {
+ d = new Date('2012-01-01T' + s);
+ if (isNaN(d.getTime())) {
+ d = new Date('01/01/2012 ' + s);
+ if (isNaN(d.getTime())) {
+ throw "Unable to parse time with native Date: " + s;
+ }
+ }
+ }
+
+ return {
+ hour: d.getHours(),
+ minute: d.getMinutes(),
+ second: d.getSeconds(),
+ millisec: d.getMilliseconds(),
+ microsec: d.getMicroseconds(),
+ timezone: d.getTimezoneOffset() * -1
+ };
+ }
+ catch (err) {
+ try {
+ return strictParse(f, s, o);
+ }
+ catch (err2) {
+ $.timepicker.log("Unable to parse \ntimeString: " + s + "\ntimeFormat: " + f);
+ }
+ }
+ return false;
+ }; // end looseParse
+
+ if (typeof o.parse === "function") {
+ return o.parse(timeFormat, timeString, o);
+ }
+ if (o.parse === 'loose') {
+ return looseParse(timeFormat, timeString, o);
+ }
+ return strictParse(timeFormat, timeString, o);
+ };
+
+ /**
+ * Public utility to format the time
+ * @param {string} format format of the time
+ * @param {Object} time Object not a Date for timezones
+ * @param {Object} [options] essentially the regional[].. amNames, pmNames, ampm
+ * @returns {string} the formatted time
+ */
+ $.datepicker.formatTime = function (format, time, options) {
+ options = options || {};
+ options = $.extend({}, $.timepicker._defaults, options);
+ time = $.extend({
+ hour: 0,
+ minute: 0,
+ second: 0,
+ millisec: 0,
+ microsec: 0,
+ timezone: null
+ }, time);
+
+ var tmptime = format,
+ ampmName = options.amNames[0],
+ hour = parseInt(time.hour, 10);
+
+ if (hour > 11) {
+ ampmName = options.pmNames[0];
+ }
+
+ tmptime = tmptime.replace(/(?:HH?|hh?|mm?|ss?|[tT]{1,2}|[zZ]|[lc]|'.*?')/g, function (match) {
+ switch (match) {
+ case 'HH':
+ return ('0' + hour).slice(-2);
+ case 'H':
+ return hour;
+ case 'hh':
+ return ('0' + convert24to12(hour)).slice(-2);
+ case 'h':
+ return convert24to12(hour);
+ case 'mm':
+ return ('0' + time.minute).slice(-2);
+ case 'm':
+ return time.minute;
+ case 'ss':
+ return ('0' + time.second).slice(-2);
+ case 's':
+ return time.second;
+ case 'l':
+ return ('00' + time.millisec).slice(-3);
+ case 'c':
+ return ('00' + time.microsec).slice(-3);
+ case 'z':
+ return $.timepicker.timezoneOffsetString(time.timezone === null ? options.timezone : time.timezone, false);
+ case 'Z':
+ return $.timepicker.timezoneOffsetString(time.timezone === null ? options.timezone : time.timezone, true);
+ case 'T':
+ return ampmName.charAt(0).toUpperCase();
+ case 'TT':
+ return ampmName.toUpperCase();
+ case 't':
+ return ampmName.charAt(0).toLowerCase();
+ case 'tt':
+ return ampmName.toLowerCase();
+ default:
+ return match.replace(/'/g, "");
+ }
+ });
+
+ return tmptime;
+ };
+
+ /*
+ * the bad hack :/ override datepicker so it doesn't close on select
+ // inspired: http://stackoverflow.com/questions/1252512/jquery-datepicker-prevent-closing-picker-when-clicking-a-date/1762378#1762378
+ */
+ $.datepicker._base_selectDate = $.datepicker._selectDate;
+ $.datepicker._selectDate = function (id, dateStr) {
+ var inst = this._getInst($(id)[0]),
+ tp_inst = this._get(inst, 'timepicker'),
+ was_inline;
+
+ if (tp_inst && inst.settings.showTimepicker) {
+ tp_inst._limitMinMaxDateTime(inst, true);
+ was_inline = inst.inline;
+ inst.inline = inst.stay_open = true;
+ //This way the onSelect handler called from calendarpicker get the full dateTime
+ this._base_selectDate(id, dateStr);
+ inst.inline = was_inline;
+ inst.stay_open = false;
+ this._notifyChange(inst);
+ this._updateDatepicker(inst);
+ } else {
+ this._base_selectDate(id, dateStr);
+ }
+ };
+
+ /*
+ * second bad hack :/ override datepicker so it triggers an event when changing the input field
+ * and does not redraw the datepicker on every selectDate event
+ */
+ $.datepicker._base_updateDatepicker = $.datepicker._updateDatepicker;
+ $.datepicker._updateDatepicker = function (inst) {
+
+ // don't popup the datepicker if there is another instance already opened
+ var input = inst.input[0];
+ if ($.datepicker._curInst && $.datepicker._curInst !== inst && $.datepicker._datepickerShowing && $.datepicker._lastInput !== input) {
+ return;
+ }
+
+ if (typeof(inst.stay_open) !== 'boolean' || inst.stay_open === false) {
+
+ this._base_updateDatepicker(inst);
+
+ // Reload the time control when changing something in the input text field.
+ var tp_inst = this._get(inst, 'timepicker');
+ if (tp_inst) {
+ tp_inst._addTimePicker(inst);
+ }
+ }
+ };
+
+ /*
+ * third bad hack :/ override datepicker so it allows spaces and colon in the input field
+ */
+ $.datepicker._base_doKeyPress = $.datepicker._doKeyPress;
+ $.datepicker._doKeyPress = function (event) {
+ var inst = $.datepicker._getInst(event.target),
+ tp_inst = $.datepicker._get(inst, 'timepicker');
+
+ if (tp_inst) {
+ if ($.datepicker._get(inst, 'constrainInput')) {
+ var ampm = tp_inst.support.ampm,
+ tz = tp_inst._defaults.showTimezone !== null ? tp_inst._defaults.showTimezone : tp_inst.support.timezone,
+ dateChars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat')),
+ datetimeChars = tp_inst._defaults.timeFormat.toString()
+ .replace(/[hms]/g, '')
+ .replace(/TT/g, ampm ? 'APM' : '')
+ .replace(/Tt/g, ampm ? 'AaPpMm' : '')
+ .replace(/tT/g, ampm ? 'AaPpMm' : '')
+ .replace(/T/g, ampm ? 'AP' : '')
+ .replace(/tt/g, ampm ? 'apm' : '')
+ .replace(/t/g, ampm ? 'ap' : '') +
+ " " + tp_inst._defaults.separator +
+ tp_inst._defaults.timeSuffix +
+ (tz ? tp_inst._defaults.timezoneList.join('') : '') +
+ (tp_inst._defaults.amNames.join('')) + (tp_inst._defaults.pmNames.join('')) +
+ dateChars,
+ chr = String.fromCharCode(event.charCode === undefined ? event.keyCode : event.charCode);
+ return event.ctrlKey || (chr < ' ' || !dateChars || datetimeChars.indexOf(chr) > -1);
+ }
+ }
+
+ return $.datepicker._base_doKeyPress(event);
+ };
+
+ /*
+ * Fourth bad hack :/ override _updateAlternate function used in inline mode to init altField
+ * Update any alternate field to synchronise with the main field.
+ */
+ $.datepicker._base_updateAlternate = $.datepicker._updateAlternate;
+ $.datepicker._updateAlternate = function (inst) {
+ var tp_inst = this._get(inst, 'timepicker');
+ if (tp_inst) {
+ var altField = tp_inst._defaults.altField;
+ if (altField) { // update alternate field too
+ var altFormat = tp_inst._defaults.altFormat || tp_inst._defaults.dateFormat,
+ date = this._getDate(inst),
+ formatCfg = $.datepicker._getFormatConfig(inst),
+ altFormattedDateTime = '',
+ altSeparator = tp_inst._defaults.altSeparator ? tp_inst._defaults.altSeparator : tp_inst._defaults.separator,
+ altTimeSuffix = tp_inst._defaults.altTimeSuffix ? tp_inst._defaults.altTimeSuffix : tp_inst._defaults.timeSuffix,
+ altTimeFormat = tp_inst._defaults.altTimeFormat !== null ? tp_inst._defaults.altTimeFormat : tp_inst._defaults.timeFormat;
+
+ altFormattedDateTime += $.datepicker.formatTime(altTimeFormat, tp_inst, tp_inst._defaults) + altTimeSuffix;
+ if (!tp_inst._defaults.timeOnly && !tp_inst._defaults.altFieldTimeOnly && date !== null) {
+ if (tp_inst._defaults.altFormat) {
+ altFormattedDateTime = $.datepicker.formatDate(tp_inst._defaults.altFormat, date, formatCfg) + altSeparator + altFormattedDateTime;
+ }
+ else {
+ altFormattedDateTime = tp_inst.formattedDate + altSeparator + altFormattedDateTime;
+ }
+ }
+ $(altField).val( inst.input.val() ? altFormattedDateTime : "");
+ }
+ }
+ else {
+ $.datepicker._base_updateAlternate(inst);
+ }
+ };
+
+ /*
+ * Override key up event to sync manual input changes.
+ */
+ $.datepicker._base_doKeyUp = $.datepicker._doKeyUp;
+ $.datepicker._doKeyUp = function (event) {
+ var inst = $.datepicker._getInst(event.target),
+ tp_inst = $.datepicker._get(inst, 'timepicker');
+
+ if (tp_inst) {
+ if (tp_inst._defaults.timeOnly && (inst.input.val() !== inst.lastVal)) {
+ try {
+ $.datepicker._updateDatepicker(inst);
+ } catch (err) {
+ $.timepicker.log(err);
+ }
+ }
+ }
+
+ return $.datepicker._base_doKeyUp(event);
+ };
+
+ /*
+ * override "Today" button to also grab the time.
+ */
+ $.datepicker._base_gotoToday = $.datepicker._gotoToday;
+ $.datepicker._gotoToday = function (id) {
+ var inst = this._getInst($(id)[0]),
+ $dp = inst.dpDiv;
+ this._base_gotoToday(id);
+ var tp_inst = this._get(inst, 'timepicker');
+ selectLocalTimezone(tp_inst);
+ var now = new Date();
+ this._setTime(inst, now);
+ this._setDate(inst, now);
+ };
+
+ /*
+ * Disable & enable the Time in the datetimepicker
+ */
+ $.datepicker._disableTimepickerDatepicker = function (target) {
+ var inst = this._getInst(target);
+ if (!inst) {
+ return;
+ }
+
+ var tp_inst = this._get(inst, 'timepicker');
+ $(target).datepicker('getDate'); // Init selected[Year|Month|Day]
+ if (tp_inst) {
+ inst.settings.showTimepicker = false;
+ tp_inst._defaults.showTimepicker = false;
+ tp_inst._updateDateTime(inst);
+ }
+ };
+
+ $.datepicker._enableTimepickerDatepicker = function (target) {
+ var inst = this._getInst(target);
+ if (!inst) {
+ return;
+ }
+
+ var tp_inst = this._get(inst, 'timepicker');
+ $(target).datepicker('getDate'); // Init selected[Year|Month|Day]
+ if (tp_inst) {
+ inst.settings.showTimepicker = true;
+ tp_inst._defaults.showTimepicker = true;
+ tp_inst._addTimePicker(inst); // Could be disabled on page load
+ tp_inst._updateDateTime(inst);
+ }
+ };
+
+ /*
+ * Create our own set time function
+ */
+ $.datepicker._setTime = function (inst, date) {
+ var tp_inst = this._get(inst, 'timepicker');
+ if (tp_inst) {
+ var defaults = tp_inst._defaults;
+
+ // calling _setTime with no date sets time to defaults
+ tp_inst.hour = date ? date.getHours() : defaults.hour;
+ tp_inst.minute = date ? date.getMinutes() : defaults.minute;
+ tp_inst.second = date ? date.getSeconds() : defaults.second;
+ tp_inst.millisec = date ? date.getMilliseconds() : defaults.millisec;
+ tp_inst.microsec = date ? date.getMicroseconds() : defaults.microsec;
+
+ //check if within min/max times..
+ tp_inst._limitMinMaxDateTime(inst, true);
+
+ tp_inst._onTimeChange();
+ tp_inst._updateDateTime(inst);
+ }
+ };
+
+ /*
+ * Create new public method to set only time, callable as $().datepicker('setTime', date)
+ */
+ $.datepicker._setTimeDatepicker = function (target, date, withDate) {
+ var inst = this._getInst(target);
+ if (!inst) {
+ return;
+ }
+
+ var tp_inst = this._get(inst, 'timepicker');
+
+ if (tp_inst) {
+ this._setDateFromField(inst);
+ var tp_date;
+ if (date) {
+ if (typeof date === "string") {
+ tp_inst._parseTime(date, withDate);
+ tp_date = new Date();
+ tp_date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec);
+ tp_date.setMicroseconds(tp_inst.microsec);
+ } else {
+ tp_date = new Date(date.getTime());
+ tp_date.setMicroseconds(date.getMicroseconds());
+ }
+ if (tp_date.toString() === 'Invalid Date') {
+ tp_date = undefined;
+ }
+ this._setTime(inst, tp_date);
+ }
+ }
+
+ };
+
+ /*
+ * override setDate() to allow setting time too within Date object
+ */
+ $.datepicker._base_setDateDatepicker = $.datepicker._setDateDatepicker;
+ $.datepicker._setDateDatepicker = function (target, _date) {
+ var inst = this._getInst(target);
+ var date = _date;
+ if (!inst) {
+ return;
+ }
+
+ if (typeof(_date) === 'string') {
+ date = new Date(_date);
+ if (!date.getTime()) {
+ this._base_setDateDatepicker.apply(this, arguments);
+ date = $(target).datepicker('getDate');
+ }
+ }
+
+ var tp_inst = this._get(inst, 'timepicker');
+ var tp_date;
+ if (date instanceof Date) {
+ tp_date = new Date(date.getTime());
+ tp_date.setMicroseconds(date.getMicroseconds());
+ } else {
+ tp_date = date;
+ }
+
+ // This is important if you are using the timezone option, javascript's Date
+ // object will only return the timezone offset for the current locale, so we
+ // adjust it accordingly. If not using timezone option this won't matter..
+ // If a timezone is different in tp, keep the timezone as is
+ if (tp_inst && tp_date) {
+ // look out for DST if tz wasn't specified
+ if (!tp_inst.support.timezone && tp_inst._defaults.timezone === null) {
+ tp_inst.timezone = tp_date.getTimezoneOffset() * -1;
+ }
+ date = $.timepicker.timezoneAdjust(date, tp_inst.timezone);
+ tp_date = $.timepicker.timezoneAdjust(tp_date, tp_inst.timezone);
+ }
+
+ this._updateDatepicker(inst);
+ this._base_setDateDatepicker.apply(this, arguments);
+ this._setTimeDatepicker(target, tp_date, true);
+ };
+
+ /*
+ * override getDate() to allow getting time too within Date object
+ */
+ $.datepicker._base_getDateDatepicker = $.datepicker._getDateDatepicker;
+ $.datepicker._getDateDatepicker = function (target, noDefault) {
+ var inst = this._getInst(target);
+ if (!inst) {
+ return;
+ }
+
+ var tp_inst = this._get(inst, 'timepicker');
+
+ if (tp_inst) {
+ // if it hasn't yet been defined, grab from field
+ if (inst.lastVal === undefined) {
+ this._setDateFromField(inst, noDefault);
+ }
+
+ var date = this._getDate(inst);
+ if (date && tp_inst._parseTime($(target).val(), tp_inst.timeOnly)) {
+ date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec);
+ date.setMicroseconds(tp_inst.microsec);
+
+ // This is important if you are using the timezone option, javascript's Date
+ // object will only return the timezone offset for the current locale, so we
+ // adjust it accordingly. If not using timezone option this won't matter..
+ if (tp_inst.timezone != null) {
+ // look out for DST if tz wasn't specified
+ if (!tp_inst.support.timezone && tp_inst._defaults.timezone === null) {
+ tp_inst.timezone = date.getTimezoneOffset() * -1;
+ }
+ date = $.timepicker.timezoneAdjust(date, tp_inst.timezone);
+ }
+ }
+ return date;
+ }
+ return this._base_getDateDatepicker(target, noDefault);
+ };
+
+ /*
+ * override parseDate() because UI 1.8.14 throws an error about "Extra characters"
+ * An option in datapicker to ignore extra format characters would be nicer.
+ */
+ $.datepicker._base_parseDate = $.datepicker.parseDate;
+ $.datepicker.parseDate = function (format, value, settings) {
+ var date;
+ try {
+ date = this._base_parseDate(format, value, settings);
+ } catch (err) {
+ // Hack! The error message ends with a colon, a space, and
+ // the "extra" characters. We rely on that instead of
+ // attempting to perfectly reproduce the parsing algorithm.
+ if (err.indexOf(":") >= 0) {
+ date = this._base_parseDate(format, value.substring(0, value.length - (err.length - err.indexOf(':') - 2)), settings);
+ $.timepicker.log("Error parsing the date string: " + err + "\ndate string = " + value + "\ndate format = " + format);
+ } else {
+ throw err;
+ }
+ }
+ return date;
+ };
+
+ /*
+ * override formatDate to set date with time to the input
+ */
+ $.datepicker._base_formatDate = $.datepicker._formatDate;
+ $.datepicker._formatDate = function (inst, day, month, year) {
+ var tp_inst = this._get(inst, 'timepicker');
+ if (tp_inst) {
+ tp_inst._updateDateTime(inst);
+ return tp_inst.$input.val();
+ }
+ return this._base_formatDate(inst);
+ };
+
+ /*
+ * override options setter to add time to maxDate(Time) and minDate(Time). MaxDate
+ */
+ $.datepicker._base_optionDatepicker = $.datepicker._optionDatepicker;
+ $.datepicker._optionDatepicker = function (target, name, value) {
+ var inst = this._getInst(target),
+ name_clone;
+ if (!inst) {
+ return null;
+ }
+
+ var tp_inst = this._get(inst, 'timepicker');
+ if (tp_inst) {
+ var min = null,
+ max = null,
+ onselect = null,
+ overrides = tp_inst._defaults.evnts,
+ fns = {},
+ prop,
+ ret,
+ oldVal,
+ $target;
+ if (typeof name === 'string') { // if min/max was set with the string
+ if (name === 'minDate' || name === 'minDateTime') {
+ min = value;
+ } else if (name === 'maxDate' || name === 'maxDateTime') {
+ max = value;
+ } else if (name === 'onSelect') {
+ onselect = value;
+ } else if (overrides.hasOwnProperty(name)) {
+ if (typeof (value) === 'undefined') {
+ return overrides[name];
+ }
+ fns[name] = value;
+ name_clone = {}; //empty results in exiting function after overrides updated
+ }
+ } else if (typeof name === 'object') { //if min/max was set with the JSON
+ if (name.minDate) {
+ min = name.minDate;
+ } else if (name.minDateTime) {
+ min = name.minDateTime;
+ } else if (name.maxDate) {
+ max = name.maxDate;
+ } else if (name.maxDateTime) {
+ max = name.maxDateTime;
+ }
+ for (prop in overrides) {
+ if (overrides.hasOwnProperty(prop) && name[prop]) {
+ fns[prop] = name[prop];
+ }
+ }
+ }
+ for (prop in fns) {
+ if (fns.hasOwnProperty(prop)) {
+ overrides[prop] = fns[prop];
+ if (!name_clone) { name_clone = $.extend({}, name); }
+ delete name_clone[prop];
+ }
+ }
+ if (name_clone && isEmptyObject(name_clone)) { return; }
+ if (min) { //if min was set
+ if (min === 0) {
+ min = new Date();
+ } else {
+ min = new Date(min);
+ }
+ tp_inst._defaults.minDate = min;
+ tp_inst._defaults.minDateTime = min;
+ } else if (max) { //if max was set
+ if (max === 0) {
+ max = new Date();
+ } else {
+ max = new Date(max);
+ }
+ tp_inst._defaults.maxDate = max;
+ tp_inst._defaults.maxDateTime = max;
+ } else if (onselect) {
+ tp_inst._defaults.onSelect = onselect;
+ }
+
+ // Datepicker will override our date when we call _base_optionDatepicker when
+ // calling minDate/maxDate, so we will first grab the value, call
+ // _base_optionDatepicker, then set our value back.
+ if(min || max){
+ $target = $(target);
+ oldVal = $target.datetimepicker('getDate');
+ ret = this._base_optionDatepicker.call($.datepicker, target, name_clone || name, value);
+ $target.datetimepicker('setDate', oldVal);
+ return ret;
+ }
+ }
+ if (value === undefined) {
+ return this._base_optionDatepicker.call($.datepicker, target, name);
+ }
+ return this._base_optionDatepicker.call($.datepicker, target, name_clone || name, value);
+ };
+
+ /*
+ * jQuery isEmptyObject does not check hasOwnProperty - if someone has added to the object prototype,
+ * it will return false for all objects
+ */
+ var isEmptyObject = function (obj) {
+ var prop;
+ for (prop in obj) {
+ if (obj.hasOwnProperty(prop)) {
+ return false;
+ }
+ }
+ return true;
+ };
+
+ /*
+ * jQuery extend now ignores nulls!
+ */
+ var extendRemove = function (target, props) {
+ $.extend(target, props);
+ for (var name in props) {
+ if (props[name] === null || props[name] === undefined) {
+ target[name] = props[name];
+ }
+ }
+ return target;
+ };
+
+ /*
+ * Determine by the time format which units are supported
+ * Returns an object of booleans for each unit
+ */
+ var detectSupport = function (timeFormat) {
+ var tf = timeFormat.replace(/'.*?'/g, '').toLowerCase(), // removes literals
+ isIn = function (f, t) { // does the format contain the token?
+ return f.indexOf(t) !== -1 ? true : false;
+ };
+ return {
+ hour: isIn(tf, 'h'),
+ minute: isIn(tf, 'm'),
+ second: isIn(tf, 's'),
+ millisec: isIn(tf, 'l'),
+ microsec: isIn(tf, 'c'),
+ timezone: isIn(tf, 'z'),
+ ampm: isIn(tf, 't') && isIn(timeFormat, 'h'),
+ iso8601: isIn(timeFormat, 'Z')
+ };
+ };
+
+ /*
+ * Converts 24 hour format into 12 hour
+ * Returns 12 hour without leading 0
+ */
+ var convert24to12 = function (hour) {
+ hour %= 12;
+
+ if (hour === 0) {
+ hour = 12;
+ }
+
+ return String(hour);
+ };
+
+ var computeEffectiveSetting = function (settings, property) {
+ return settings && settings[property] ? settings[property] : $.timepicker._defaults[property];
+ };
+
+ /*
+ * Splits datetime string into date and time substrings.
+ * Throws exception when date can't be parsed
+ * Returns {dateString: dateString, timeString: timeString}
+ */
+ var splitDateTime = function (dateTimeString, timeSettings) {
+ // The idea is to get the number separator occurrences in datetime and the time format requested (since time has
+ // fewer unknowns, mostly numbers and am/pm). We will use the time pattern to split.
+ var separator = computeEffectiveSetting(timeSettings, 'separator'),
+ format = computeEffectiveSetting(timeSettings, 'timeFormat'),
+ timeParts = format.split(separator), // how many occurrences of separator may be in our format?
+ timePartsLen = timeParts.length,
+ allParts = dateTimeString.split(separator),
+ allPartsLen = allParts.length;
+
+ if (allPartsLen > 1) {
+ return {
+ dateString: allParts.splice(0, allPartsLen - timePartsLen).join(separator),
+ timeString: allParts.splice(0, timePartsLen).join(separator)
+ };
+ }
+
+ return {
+ dateString: dateTimeString,
+ timeString: ''
+ };
+ };
+
+ /*
+ * Internal function to parse datetime interval
+ * Returns: {date: Date, timeObj: Object}, where
+ * date - parsed date without time (type Date)
+ * timeObj = {hour: , minute: , second: , millisec: , microsec: } - parsed time. Optional
+ */
+ var parseDateTimeInternal = function (dateFormat, timeFormat, dateTimeString, dateSettings, timeSettings) {
+ var date,
+ parts,
+ parsedTime;
+
+ parts = splitDateTime(dateTimeString, timeSettings);
+ date = $.datepicker._base_parseDate(dateFormat, parts.dateString, dateSettings);
+
+ if (parts.timeString === '') {
+ return {
+ date: date
+ };
+ }
+
+ parsedTime = $.datepicker.parseTime(timeFormat, parts.timeString, timeSettings);
+
+ if (!parsedTime) {
+ throw 'Wrong time format';
+ }
+
+ return {
+ date: date,
+ timeObj: parsedTime
+ };
+ };
+
+ /*
+ * Internal function to set timezone_select to the local timezone
+ */
+ var selectLocalTimezone = function (tp_inst, date) {
+ if (tp_inst && tp_inst.timezone_select) {
+ var now = date || new Date();
+ tp_inst.timezone_select.val(-now.getTimezoneOffset());
+ }
+ };
+
+ /*
+ * Create a Singleton Instance
+ */
+ $.timepicker = new Timepicker();
+
+ /**
+ * Get the timezone offset as string from a date object (eg '+0530' for UTC+5.5)
+ * @param {number} tzMinutes if not a number, less than -720 (-1200), or greater than 840 (+1400) this value is returned
+ * @param {boolean} iso8601 if true formats in accordance to iso8601 "+12:45"
+ * @return {string}
+ */
+ $.timepicker.timezoneOffsetString = function (tzMinutes, iso8601) {
+ if (isNaN(tzMinutes) || tzMinutes > 840 || tzMinutes < -720) {
+ return tzMinutes;
+ }
+
+ var off = tzMinutes,
+ minutes = off % 60,
+ hours = (off - minutes) / 60,
+ iso = iso8601 ? ':' : '',
+ tz = (off >= 0 ? '+' : '-') + ('0' + Math.abs(hours)).slice(-2) + iso + ('0' + Math.abs(minutes)).slice(-2);
+
+ if (tz === '+00:00') {
+ return 'Z';
+ }
+ return tz;
+ };
+
+ /**
+ * Get the number in minutes that represents a timezone string
+ * @param {string} tzString formatted like "+0500", "-1245", "Z"
+ * @return {number} the offset minutes or the original string if it doesn't match expectations
+ */
+ $.timepicker.timezoneOffsetNumber = function (tzString) {
+ var normalized = tzString.toString().replace(':', ''); // excuse any iso8601, end up with "+1245"
+
+ if (normalized.toUpperCase() === 'Z') { // if iso8601 with Z, its 0 minute offset
+ return 0;
+ }
+
+ if (!/^(\-|\+)\d{4}$/.test(normalized)) { // possibly a user defined tz, so just give it back
+ return tzString;
+ }
+
+ return ((normalized.substr(0, 1) === '-' ? -1 : 1) * // plus or minus
+ ((parseInt(normalized.substr(1, 2), 10) * 60) + // hours (converted to minutes)
+ parseInt(normalized.substr(3, 2), 10))); // minutes
+ };
+
+ /**
+ * No way to set timezone in js Date, so we must adjust the minutes to compensate. (think setDate, getDate)
+ * @param {Date} date
+ * @param {string} toTimezone formatted like "+0500", "-1245"
+ * @return {Date}
+ */
+ $.timepicker.timezoneAdjust = function (date, toTimezone) {
+ var toTz = $.timepicker.timezoneOffsetNumber(toTimezone);
+ if (!isNaN(toTz)) {
+ date.setMinutes(date.getMinutes() + -date.getTimezoneOffset() - toTz);
+ }
+ return date;
+ };
+
+ /**
+ * Calls `timepicker()` on the `startTime` and `endTime` elements, and configures them to
+ * enforce date range limits.
+ * n.b. The input value must be correctly formatted (reformatting is not supported)
+ * @param {Element} startTime
+ * @param {Element} endTime
+ * @param {Object} options Options for the timepicker() call
+ * @return {jQuery}
+ */
+ $.timepicker.timeRange = function (startTime, endTime, options) {
+ return $.timepicker.handleRange('timepicker', startTime, endTime, options);
+ };
+
+ /**
+ * Calls `datetimepicker` on the `startTime` and `endTime` elements, and configures them to
+ * enforce date range limits.
+ * @param {Element} startTime
+ * @param {Element} endTime
+ * @param {Object} options Options for the `timepicker()` call. Also supports `reformat`,
+ * a boolean value that can be used to reformat the input values to the `dateFormat`.
+ * @param {string} method Can be used to specify the type of picker to be added
+ * @return {jQuery}
+ */
+ $.timepicker.datetimeRange = function (startTime, endTime, options) {
+ $.timepicker.handleRange('datetimepicker', startTime, endTime, options);
+ };
+
+ /**
+ * Calls `datepicker` on the `startTime` and `endTime` elements, and configures them to
+ * enforce date range limits.
+ * @param {Element} startTime
+ * @param {Element} endTime
+ * @param {Object} options Options for the `timepicker()` call. Also supports `reformat`,
+ * a boolean value that can be used to reformat the input values to the `dateFormat`.
+ * @return {jQuery}
+ */
+ $.timepicker.dateRange = function (startTime, endTime, options) {
+ $.timepicker.handleRange('datepicker', startTime, endTime, options);
+ };
+
+ /**
+ * Calls `method` on the `startTime` and `endTime` elements, and configures them to
+ * enforce date range limits.
+ * @param {string} method Can be used to specify the type of picker to be added
+ * @param {Element} startTime
+ * @param {Element} endTime
+ * @param {Object} options Options for the `timepicker()` call. Also supports `reformat`,
+ * a boolean value that can be used to reformat the input values to the `dateFormat`.
+ * @return {jQuery}
+ */
+ $.timepicker.handleRange = function (method, startTime, endTime, options) {
+ options = $.extend({}, {
+ minInterval: 0, // min allowed interval in milliseconds
+ maxInterval: 0, // max allowed interval in milliseconds
+ start: {}, // options for start picker
+ end: {} // options for end picker
+ }, options);
+
+ // for the mean time this fixes an issue with calling getDate with timepicker()
+ var timeOnly = false;
+ if(method === 'timepicker'){
+ timeOnly = true;
+ method = 'datetimepicker';
+ }
+
+ function checkDates(changed, other) {
+ var startdt = startTime[method]('getDate'),
+ enddt = endTime[method]('getDate'),
+ changeddt = changed[method]('getDate');
+
+ if (startdt !== null) {
+ var minDate = new Date(startdt.getTime()),
+ maxDate = new Date(startdt.getTime());
+
+ minDate.setMilliseconds(minDate.getMilliseconds() + options.minInterval);
+ maxDate.setMilliseconds(maxDate.getMilliseconds() + options.maxInterval);
+
+ if (options.minInterval > 0 && minDate > enddt) { // minInterval check
+ endTime[method]('setDate', minDate);
+ }
+ else if (options.maxInterval > 0 && maxDate < enddt) { // max interval check
+ endTime[method]('setDate', maxDate);
+ }
+ else if (startdt > enddt) {
+ other[method]('setDate', changeddt);
+ }
+ }
+ }
+
+ function selected(changed, other, option) {
+ if (!changed.val()) {
+ return;
+ }
+ var date = changed[method].call(changed, 'getDate');
+ if (date !== null && options.minInterval > 0) {
+ if (option === 'minDate') {
+ date.setMilliseconds(date.getMilliseconds() + options.minInterval);
+ }
+ if (option === 'maxDate') {
+ date.setMilliseconds(date.getMilliseconds() - options.minInterval);
+ }
+ }
+
+ if (date.getTime) {
+ other[method].call(other, 'option', option, date);
+ }
+ }
+
+ $.fn[method].call(startTime, $.extend({
+ timeOnly: timeOnly,
+ onClose: function (dateText, inst) {
+ checkDates($(this), endTime);
+ },
+ onSelect: function (selectedDateTime) {
+ selected($(this), endTime, 'minDate');
+ }
+ }, options, options.start));
+ $.fn[method].call(endTime, $.extend({
+ timeOnly: timeOnly,
+ onClose: function (dateText, inst) {
+ checkDates($(this), startTime);
+ },
+ onSelect: function (selectedDateTime) {
+ selected($(this), startTime, 'maxDate');
+ }
+ }, options, options.end));
+
+ checkDates(startTime, endTime);
+
+ selected(startTime, endTime, 'minDate');
+ selected(endTime, startTime, 'maxDate');
+
+ return $([startTime.get(0), endTime.get(0)]);
+ };
+
+ /**
+ * Log error or data to the console during error or debugging
+ * @param {Object} err pass any type object to log to the console during error or debugging
+ * @return {void}
+ */
+ $.timepicker.log = function () {
+ if (window.console) {
+ window.console.log.apply(window.console, Array.prototype.slice.call(arguments));
+ }
+ };
+
+ /*
+ * Add util object to allow access to private methods for testability.
+ */
+ $.timepicker._util = {
+ _extendRemove: extendRemove,
+ _isEmptyObject: isEmptyObject,
+ _convert24to12: convert24to12,
+ _detectSupport: detectSupport,
+ _selectLocalTimezone: selectLocalTimezone,
+ _computeEffectiveSetting: computeEffectiveSetting,
+ _splitDateTime: splitDateTime,
+ _parseDateTimeInternal: parseDateTimeInternal
+ };
+
+ /*
+ * Microsecond support
+ */
+ if (!Date.prototype.getMicroseconds) {
+ Date.prototype.microseconds = 0;
+ Date.prototype.getMicroseconds = function () { return this.microseconds; };
+ Date.prototype.setMicroseconds = function (m) {
+ this.setMilliseconds(this.getMilliseconds() + Math.floor(m / 1000));
+ this.microseconds = m % 1000;
+ return this;
+ };
+ }
+
+ /*
+ * Keep up with the version
+ */
+ $.timepicker.version = "1.5.0";
+
+})(jQuery); \ No newline at end of file